IT/Cloud & DevOps

Kubernetes의 Node와 Pod, Pod의 리소스 설정 (Request, Limit)

iamhyeon 2025. 4. 24. 12:14

💡 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/

 

반응형