💡 Node 와 Pod
- Node는 Kubernetes 클러스터에서 실제로 Pod가 실행되는 가상머신(또는 물리 서버) 이다
- 쿠버네티스 안에서 실행 중인 Pod들은 논리적인 단위이기 때문에, 실제로는 물리적인 컴퓨터인 Node 안에서 프로세스로써 실행이 되는 것이다
- 파드는 언제나 노드 상에서 동작한다.
- 노드는 쿠버네티스에서 워커 머신을 말하며 클러스터에 따라 가상 또는 물리 머신일 수 있다.
- 각 노드는 컨트롤 플레인에 의해 관리된다.
- 하나의 노드는 여러 개의 파드를 가질 수 있고, 쿠버네티스 컨트롤 플레인은 클러스터 내 노드를 통해서 파드에 대한 스케쥴링을 자동으로 처리한다.
- 컨트롤 플레인의 자동 스케줄링은 각 노드의 사용 가능한 리소스를 모두 고려한다.
- Node 안에는 Kubelet, Kube-proxy, Container Runtime (예: Docker) 등이 있다
- GCP 같은 클라우드에선 VM 인스턴스를 말한다 (예: GCE 인스턴스)
- Kubelet은, 쿠버네티스 컨트롤 플레인과 노드 간 통신을 책임지는 프로세스이며,
- 하나의 머신 상에서 동작하는 파드와 컨테이너를 관리한다.
- 컨테이너 런타임(도커와 같은)은 레지스트리에서 컨테이너 이미지를 가져와 묶여 있는 것을 풀고 애플리케이션을 동작시키는 책임을 맡는다.

💡 Pod가 Node에서 실행된다는 것
- Pod는 애플리케이션 컨테이너들이 묶여 있는 가장 작은 단위이다
- 이 Pod가 어느 Node 위에서 실행될지를 Kubernetes가 결정하고, 해당 Node의 리소스를 사용해 실제 실행된다
- 분산되는 기준은 단순히 Pod의 개수를 기준으로 하는 것이 아니고, 실제 각 Pod들이 차지하는 컴퓨팅 자원의 사용량을 참고하여 분산된다
예)
클러스터
├── Node A (CPU 2vCPU, 4GB RAM)
│ ├── Pod 1 (nginx)
│ └── Pod 2 (redis)
├── Node B (CPU 4vCPU, 8GB RAM)
│ └── Pod 3 (spring app)
✅ 쿠버네티스 클러스가 인식하고 있는 Node 목록 확인
kubectl get nodes

💡 Pod의 성능은 어떻게 결정되나?
- 기본적으로 아무런 설정을 하지 않은 경우, Pod는 Node의 사양 안에서 자기가 필요한 만큼 유동적으로 자원을 가져다 쓴다
- 하나의 Pod가 많은 자원을 차지하면 같은 Node 안에 있는 다른 Pod의 성능이 영향을 받게 된다
💡 Pod의 Request와 Limit
- Pod를 정의할 때 Request와 Limit라는 걸 설정할 수 있다 (Pod의 CPU와 Memory 사용량을 조절하는 용도)
- Request : Pod가 가질 수 있는 최소 사양
- Limit : Pod가 가질 수 있는 최대 사양
| requests
- Pod을 스케줄링할 때 기준이 된다
- Node에 이만큼의 리소스가 남아 있어야만 해당 Node에 Pod이 배치된다
- 예약 보장: 실행되면 최소 이 정도는 확보된다
| limits
- Pod이 사용할 수 있는 리소스의 최대치 제한.
- 이걸 넘어서면:
- CPU: throttling (속도 제한) 걸린다. 죽진 않는다
- 메모리: OOM(Out Of Memory) 발생 → Pod이 죽을 수 있다
- Pod가 실행 중인 노드에 사용 가능한 리소스가 충분한 경우 컨테이너가 request 해당 리소스에 지정된 것보다 더 많은 리소스를 사용할 수 있다
- 예를 들어, 컨테이너에 대해 256MiB의 요청을 설정하고 memory해당 컨테이너가 8GiB 메모리가 있는 노드에 예약된 Pod에 있고 다른 Pod가 없는 경우, 컨테이너는 더 많은 RAM을 사용하려고 시도할 수 있다
- limit cpu과 memory limit 모두 kubelet(및 컨테이너 런타임), 그리고 궁극적으로 커널에 의해 적용된다
- 컨테이너가 cpu제한에 도달하면 커널은 컨테이너의 제한에 해당하는 CPU에 대한 액세스를 제한한다
- 컨테이너는 limit에 지정된 것보다 더 많은 CPU를 사용할 수 없다
- memory 제한은 커널에 의해 메모리 부족(OOM) 종료를 통해 적용된다
- 컨테이너가 memory제한을 초과하여 사용하면 커널이 컨테이너를 종료할 수 있다.
⚠️ 이전 블로그 글
2025.04.19 - [IT/Cloud & DevOps] - 클라우드 환경에서 쿠버네티스 클러스터 만들기
2025.04.18 - [IT/Cloud & DevOps] - 컨테이너 레지스트리란? GCP Artifact Registry 로 실습해보기
2025.04.21 - [IT/Cloud & DevOps] - Pod : 쿠버네티스에서 컨테이너 실행하는 방법
2025.04.21 - [IT/Cloud & DevOps] - ReplicaSet : 정해진 수의 Pod을 유지시켜주는 관리자
🔶 Request와 Limit 설정해보기
✅ sample-replicaset.yaml 작성
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: sample-replicaset
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27.0
resources:
requests:
cpu: "300m"
memory: "500Mi"
limits:
cpu: "300m"
memory: "500Mi"
ports:
- containerPort: 80
✅ 이전 replicaset 삭제


✅ replicaset 생성
kubectl apply -f sample-replicaset.yaml
kubectl get pods

✅ replicas 개수 변경

✅ yaml 파일 다시 적용하기
kubectl apply -f sample-replicaset.yaml
kubectl get pods


➡️ 쿠버네티스 클러스터 안의 Node 사양이 부족하기 때문에 몇개가 못뜨고 있는 상황
- 노드 자원이 부족해서 더 이상 스케줄할 수 없기 때문이다.
- Kubernetes는 각 Pod의 requests 자원을 기준으로 스케줄링을 시도한다
- Pod 하나가 최소 0.3 vCPU와 500Mi 메모리를 요구하는데, 클러스터의 노드가 이 요구를 충족하지 못할 경우 Pending 상태로 남게 된다
✅ 생성한 클러스터를 확인해보면
🔍 웹 콘솔에서 보는 방법) GCP 콘솔 접속 => 좌측 메뉴에서 Kubernetes Engine => 클러스터 => 원하는 클러스터 클릭

| n1-standard-1 검색

| 클러스터 사양 (n1-standard-1)
- vCPU: 1개
- 메모리: 3.75GiB
- allocatable: 약 940m CPU, 2.5GiB 메모리
- Kubernetes는 Pod당 리소스 요구(requests)를 기준으로 스케줄링한다
- 동시에 다른 시스템 Pod들(kube-system, monitoring 등)이 이미 각 노드에 리소스를 점유하고 있다
- 각 Pod이 requests: cpu 300m, memory 500Mi를 요청하고 있기 때문에, 자원이 한계에 도달했다
- cpu 300m × 6 = 1.8 vCPU, memory 500Mi × 6 = 3GB로는 괜찮아 보이지만,
- Kubernetes는 노드당 예약/시스템 리소스도 필요해서 실제 사용 가능 리소스는 이보다 작다
| CLI 에서 pod이 왜 pending인지 확인할 수 있다
kubectl describe pod `pod name`
C:\Users\hyeon\OneDrive\바탕 화면\HYEON\Study_Kubernetes_Cloud\replicaset>kubectl describe pod sample-replicaset-lfxt4
Name: sample-replicaset-lfxt4
Namespace: default
Priority: 0
Service Account: default
Node: gke-kube-study-default-pool-8377e644-7gjz/10.178.0.9
Start Time: Wed, 23 Apr 2025 16:22:57 +0900
Labels: app=nginx
Annotations: <none>
Status: Running
IP: 10.8.0.3
IPs:
IP: 10.8.0.3
Controlled By: ReplicaSet/sample-replicaset
Containers:
nginx:
Container ID: containerd://8465cf89ab4c21067ebec52923b805cb99c558e56ba1782e43e4f3bff747856c
Image: nginx:1.27.0
Image ID: docker.io/library/nginx@sha256:98f8ec75657d21b924fe4f69b6b9bff2f6550ea48838af479d8894a852000e40
Port: 80/TCP
Host Port: 0/TCP
State: Running
Started: Wed, 23 Apr 2025 16:23:12 +0900
Ready: True
Restart Count: 0
Limits:
cpu: 300m
memory: 500Mi
Requests:
cpu: 300m
memory: 500Mi
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-v52rn (ro)
Conditions:
Type Status
PodReadyToStartContainers True
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-v52rn:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: Guaranteed
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 4m41s default-scheduler 0/3 nodes are available: 3 Insufficient cpu. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod.
Normal Scheduled 3m59s default-scheduler Successfully assigned default/sample-replicaset-lfxt4 to gke-kube-study-default-pool-8377e644-7gjz
Normal TriggeredScaleUp 4m40s cluster-autoscaler pod triggered scale-up: [{https://www.googleapis.com/compute/v1/projects/rare-shadow-457105-s7/zones/asia-northeast3-a/instanceGroups/gke-kube-study-default-pool-8377e644-grp 3->4 (max: 4)}]
Normal Pulling 3m58s kubelet Pulling image "nginx:1.27.0"
Normal Pulled 3m45s kubelet Successfully pulled image "nginx:1.27.0" in 10.522s (12.523s including waiting). Image size: 70985469 bytes.
Normal Created 3m45s kubelet Created container: nginx
Normal Started 3m45s kubelet Started container nginx
✅ resources 다 지우고 replicas:8로 해서 적용해보기


=> request, limit 설정 안돼있는 상태니까 8개 pod 정상 가동한다
refer to
https://kubernetes.io/ko/docs/tutorials/kubernetes-basics/explore/explore-intro/
https://sysdig.com/blog/kubernetes-limits-requests/
https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
'IT > Cloud & DevOps' 카테고리의 다른 글
| Kubernetes ConfigMap과 Secret을 사용한 환경변수 관리 (0) | 2025.04.25 |
|---|---|
| GKE 노드풀과 클러스터 오토스케일러 (0) | 2025.04.24 |
| ReplicaSet : 정해진 수의 Pod을 유지시켜주는 관리자 (0) | 2025.04.21 |
| Pod : 쿠버네티스에서 컨테이너 실행하는 방법 (0) | 2025.04.21 |
| 컨테이너 레지스트리란? GCP Artifact Registry 로 실습해보기 (0) | 2025.04.20 |