Pod 오버헤드

Pod 오버헤드 (Pod Overhead)

Pod가 노드에서 실행될 때, Pod 자체도 시스템 리소스를 조금 소비해요. 이 리소스는 Pod 안 컨테이너를 실행하는 데 필요한 리소스에 추가로 드는 것입니다. 쿠버네티스의 Pod Overhead(오버헤드) 는 컨테이너 요청·한도 위에 Pod 인프라가 소비하는 리소스를 회계(accounting)하는 방법이에요.

출처: 쿠버네티스 공식 문서 — Pod Overhead

기능 상태: Kubernetes v1.24 [stable]

Pod의 오버헤드는 Pod와 연결된 RuntimeClass에 따른 오버헤드에 따라 어드미션 시점에 설정됩니다.

Pod의 오버헤드는 Pod를 스케줄링할 때 컨테이너 리소스 요청의 합에 더해서 고려돼요. 마찬가지로 kubelet은 Pod cgroup 크기를 정할 때와 Pod 축출(eviction) 순위를 매길 때 Pod 오버헤드를 포함합니다.

Pod 오버헤드 설정 (Configuring Pod overhead)

overhead 필드를 정의하는 RuntimeClass를 사용해야 해요.

사용 예시 (Usage example)

Pod 오버헤드를 다루려면 overhead 필드를 정의하는 RuntimeClass가 필요합니다. 예를 들어, 가상머신과 게스트 OS에 Pod당 약 120MiB를 사용하는 가상화 컨테이너 런타임(여기서는 Firecracker 가상 머신 모니터와 결합된 Kata Containers)과 함께 아래 RuntimeClass 정의를 쓸 수 있어요.

# 이 예시를 실제 런타임 이름과, 컨테이너 런타임이 클러스터에서 추가하는 Pod당 리소스 오버헤드에 맞게 바꿔야 합니다.
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: kata-fc
handler: kata-fc
overhead:
  podFixed:
    memory: "120Mi"
    cpu: "250m"

kata-fc RuntimeClass 핸들러를 지정해 만든 워크로드는 리소스 쿼터 계산, 노드 스케줄링, Pod cgroup 크기 조정에 메모리·CPU 오버헤드를 반영해요.

예시 워크로드 test-pod를 실행한다고 해볼게요:

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  runtimeClassName: kata-fc
  containers:
  - name: busybox-ctr
    image: busybox:1.28
    stdin: true
    tty: true
    resources:
      limits:
        cpu: 500m
        memory: 100Mi
  - name: nginx-ctr
    image: nginx
    resources:
      limits:
        cpu: 1500m
        memory: 100Mi

참고: Pod 정의에 limits만 지정하면, kubelet은 그 한도에서 requests를 유추해 정의된 limits와 같게 설정해요.

어드미션 시점에 RuntimeClass 어드미션 컨트롤러는 RuntimeClass에 설명된 대로 워크로드의 PodSpec에 overhead를 포함하도록 업데이트합니다. PodSpec에 이미 이 필드가 정의되어 있으면 Pod는 거부됩니다. 예시에서는 RuntimeClass 이름만 지정했으므로, 어드미션 컨트롤러가 Pod에 overhead를 포함하도록 변경(mutate)해요.

수정 후 업데이트된 Pod 오버헤드 값을 확인할 수 있습니다:

kubectl get pod test-pod -o jsonpath='{.spec.overhead}'

출력:

map[cpu:250m memory:120Mi]

ResourceQuota가 정의되어 있으면 컨테이너 요청의 합과 overhead 필드가 모두 계산됩니다.

kube-scheduler가 새 Pod를 실행할 노드를 정할 때, 그 Pod의 overhead와 컨테이너 요청의 합을 고려해요. 이 예시에서 스케줄러는 요청과 오버헤드를 더하고, 2.25 CPU와 320 MiB 메모리가 남아 있는 노드를 찾습니다.

Pod가 노드에 스케줄링되면, 그 노드의 kubelet은 Pod를 위한 새 cgroup을 만듭니다. 이 cgroup 안에서 기본 컨테이너 런타임이 컨테이너를 만듭니다.

각 컨테이너에 리소스 한도가 정의되어 있으면(Guaranteed QoS, 또는 한도가 정의된 Burstable QoS), kubelet은 그 리소스와 연결된 pod cgroup에 상한을 설정해요(CPU는 cpu.cfs_quota_us, 메모리는 memory.limit_in_bytes). 이 상한은 컨테이너 한도의 합에 PodSpec에 정의된 overhead를 더한 값을 기반으로 합니다.

CPU의 경우, Pod가 Guaranteed 또는 Burstable QoS라면 kubelet은 컨테이너 요청의 합에 PodSpec의 overhead를 더한 값을 기반으로 cpu.shares를 설정합니다.

예시를 보며 워크로드의 컨테이너 요청을 확인해 볼게요:

kubectl get pod test-pod -o jsonpath='{.spec.containers[*].resources.limits}'

총 컨테이너 요청은 2000m CPU와 200MiB 메모리입니다:

map[cpu:500m memory:100Mi] map[cpu:1500m memory:100Mi]

이것을 노드가 관찰한 값과 비교해 보세요:

kubectl describe node | grep test-pod -B2

출력은 2250m CPU와 320MiB 메모리 요청을 보여줍니다. 요청에 Pod 오버헤드가 포함되어 있어요:

Namespace  Name      CPU Requests  CPU Limits  Memory Requests  Memory Limits  AGE
---------  ----      ------------  ----------  ---------------  -------------  ---
default    test-pod  2250m (56%)   2250m (56%) 320Mi (1%)       320Mi (1%)     36m

Pod cgroup 한도 확인 (Verify Pod cgroup limits)

워크로드가 실행 중인 노드에서 Pod의 메모리 cgroup을 확인해 보세요. 아래 예시는 노드에서 crictl을 사용합니다. crictl은 CRI 호환 컨테이너 런타임용 CLI를 제공해요. 이는 Pod 오버헤드 동작을 보여주는 고급 예시이며, 사용자가 노드에서 cgroup을 직접 확인해야 한다는 뜻은 아닙니다.

먼저 해당 노드에서 Pod 식별자를 확인하세요:

# Pod가 스케줄링된 노드에서 실행
POD_ID="$(sudo crictl pods --name test-pod -q)"

여기서 Pod의 cgroup 경로를 알아낼 수 있어요:

# Pod가 스케줄링된 노드에서 실행
sudo crictl inspectp -o json $POD_ID | grep cgroupsPath

결과 cgroup 경로에는 Pod의 pause 컨테이너가 포함됩니다. Pod 레벨 cgroup은 한 단계 위 디렉터리예요.

"cgroupsPath": "/kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2/7ccf55aee35dd16aca4189c952d83487297f3cd760f1bbf09620e206e7d0c27a"

이 경우 pod cgroup 경로는 kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2입니다. 메모리에 대한 Pod 레벨 cgroup 설정을 확인하세요:

# Pod가 스케줄링된 노드에서 실행
# 또한 cgroup 이름을 Pod에 할당된 cgroup과 일치하도록 바꾸세요.
cat /sys/fs/cgroup/memory/kubepods/podd7f4b509-cf94-4951-9417-d1087c92a5b2/memory.limit_in_bytes

예상대로 320 MiB입니다:

335544320

관측 가능성 (Observability)

kube-state-metrics에는 Pod 오버헤드가 사용되고 있는지 식별하고 오버헤드가 정의된 워크로드의 안정성을 관찰하는 데 도움이 되는 kube_pod_overhead_* 메트릭이 있습니다.

더 알아보기 (Learn more)