01. 맥락
스터디 도중 팀원이 다음 의문을 제기했다.
"emptyDir 사용량이 일정 이상이면, 파드를 종료하는데,"
"kubelet 코드상에서 어떻게 구현하였는지 궁금하다."
그래서 삽질을 시작했다. (전혀 실용적이지 않은 이유다.)
02. 목표
우리의 목표는 간단하다.
emptyDir 을 오버해서 사용할 때, 코드상 어떤 부분에서 이 "오버하였음" 을 체크하는 것이고,
이를 어느 라인에서 죽이는 것일지 찾아보는 것.
03. 실마리
우선, 다음 YAML 을 이용해 파드를 배포하였다.
apiVersion: v1
kind: Pod
metadata:
name: empty-test1
spec:
nodeName: worker2
containers:
- name: test2
image: bash
command: ['sh', '-c', 'echo "The app is running!" && tail -f /dev/null']
volumeMounts:
- name: empty
mountPath: /test
volumes:
- name: empty
emptyDir:
sizeLimit: 1Mi
해당 파드에 exec 로 접속하여 다음 명령어로 /test 디렉토리 내부에 더미 파일을 생성했다.
dd if=/dev/zero of=/test/test.file bs=1K count=10000
다음과 같이 에러코드 137을 뿜으며 파드가 종료된다.
이 때 kubelet은 어떤 로그를 찍는지 확인해보았다.
Jan 16 13:58:48 worker2 kubelet[4102]: I0116 13:58:48.860149 4102 reconciler_common.go:251] "operationExecutor.VerifyControllerAttachedVolume started for volume \"kube-api-access-9kp6p\" (UniqueName: \"kubernetes.io/projected/5cf142d1-7a2d-4698-a7e0-f6ebfc0d4b7d-kube-api-access-9kp6p\") pod \"empty-test1\" (UID: \"5cf142d1-7a2d-4698-a7e0-f6ebfc0d4b7d\") " pod="default/empty-test1"
Jan 16 14:01:14 worker2 kubelet[4102]: I0116 14:01:14.596240 4102 pod_startup_latency_tracker.go:104] "Observed pod startup duration" pod="default/empty-test1" podStartSLOduration=145.120444584 podStartE2EDuration="2m26.596226637s" podCreationTimestamp="2025-01-16 13:58:48 +0000 UTC" firstStartedPulling="2025-01-16 13:58:49.238120102 +0000 UTC m=+32381.255600528" lastFinishedPulling="2025-01-16 13:58:50.713902177 +0000 UTC m=+32382.731382581" observedRunningTime="2025-01-16 13:58:50.961541756 +0000 UTC m=+32382.979022164" watchObservedRunningTime="2025-01-16 14:01:14.596226637 +0000 UTC m=+32526.613707043"
Jan 16 14:01:14 worker2 kubelet[4102]: I0116 14:01:14.657488 4102 eviction_manager.go:627] "Eviction manager: pod is evicted successfully" pod="default/empty-test1"
Jan 16 14:01:14 worker2 kubelet[4102]: I0116 14:01:14.657509 4102 eviction_manager.go:208] "Eviction manager: pods evicted, waiting for pod to be cleaned up" pods=["default/empty-test1"]
Jan 16 14:01:14 worker2 kubelet[4102]: I0116 14:01:14.756795 4102 reconciler_common.go:162] "operationExecutor.UnmountVolume started for volume \"kube-api-access-9kp6p\" (UniqueName: \"kubernetes.io/projected/5cf142d1-7a2d-4698-a7e0-f6ebfc0d4b7d-kube-api-access-9kp6p\") pod \"5cf142d1-7a2d-4698-a7e0-f6ebfc0d4b7d\" (UID: \"5cf142d1-7a2d-4698-a7e0-f6ebfc0d4b7d\") "
Jan 16 14:01:14 worker2 kubelet[4102]: I0116 14:01:14.757409 4102 reconciler_common.go:162] "operationExecutor.UnmountVolume started for volume \"empty\" (UniqueName: \"kubernetes.io/empty-dir/5cf142d1-7a2d-4698-a7e0-f6ebfc0d4b7d-empty\") pod \"5cf142d1-7a2d-4698-a7e0-f6ebfc0d4b7d\" (UID: \"5cf142d1-7a2d-4698-a7e0-f6ebfc0d4b7d\") "
Jan 16 14:01:14 worker2 kubelet[4102]: I0116 14:01:14.760034 4102 operation_generator.go:780] UnmountVolume.TearDown succeeded for volume "kubernetes.io/projected/5cf142d1-7a2d-4698-a7e0-f6ebfc0d4b7d-kube-api-access-9kp6p" (OuterVolumeSpecName: "kube-api-access-9kp6p") pod "5cf142d1-7a2d-4698-a7e0-f6ebfc0d4b7d" (UID: "5cf142d1-7a2d-4698-a7e0-f6ebfc0d4b7d"). InnerVolumeSpecName "kube-api-access-9kp6p". PluginName "kubernetes.io/projected", VolumeGIDValue ""
"eviction_manager.go:627" -> 여기를 보면 되겠군..!
kubernetes/pkg/kubelet/eviction/eviction_manager.go at 50fc400f178d2078d0ca46aee955ee26375fc437 · kubernetes/kubernetes
Production-Grade Container Scheduling and Management - kubernetes/kubernetes
github.com
04. 소스코드 딥다이브
해당 라인 찾아보니 다음 함수가 기다리더라..
"evictPod()"
해당 함수 4군데에서 호출중이었는데, 우리의 관심사에 맞는 코드는 다음부분인것 같았음.
다음 부분이 아무래도 emptyDir 의 크기 (used) 와 sizeLimit(추정) (*size) 를 비교하여 축출을 실행할지 결정하는 파트인듯
if used != nil && size != nil && size.Sign() == 1 && used.Cmp(*size) > 0 {
emptyDirLimitEviction() 이친구를 호출한 부모 함수를 추적하다 보니...
synchronize 라는 함수가 monitoringInterval 주기로 무한히 호출되고 있었음...
05. 결론
kubelet 은 monitoringInterval 주기로 synchronize 함수를 호출하는데,
해당 함수 내에서 emptyDir 사용량과 sizeLimit 을 비교하여 파드를 축출할지 결정한다.
+++
추가로 저 스토리지 사용량을 어디로부터 받는지도 추적하려고 했으나...
statsFunc(pod) 함수의 결과로 리턴된 podStats 를 받아서 보고는 있는데
statsFunc(pod) 이녀석을 정의한 녀석이 뭔지 타고 타고 올라가다보니
뭔가 초기의 목표를 벗어나는것 아닌가 하여 그만두었다.
'kubernetes' 카테고리의 다른 글
Node 의 CRI-O 재기동시 Pod 에 영향이 없을까? (4) | 2025.04.24 |
---|---|
Nginx Ingress - Internal/External IngressClass를 분리해보자 (0) | 2024.08.11 |
Grafana Dashboard 샘플 모음 (0) | 2024.08.04 |