資源の関門 — アドバタイズ・要求ルール・テイントで分かれるPending
한국어 원문으로 표시합니다.
목표
GPU 파드가 통과해야 하는 두 관문 중 자원 쪽을 끝까지 밟아 봅니다. 노드가 자원을 광고하게 만들고, 확장 자원의 요청 규칙 두 가지가 실제로 막는 것을 보고, 같은 Pending 이라도 원인이 테인트인지 자원인지 갈라 읽는 데까지 갑니다.
왜 중요한가
"GPU 파드가 안 뜬다" 는 신고에서 첫 3분에 갈래를 정하지 못하면 몇 시간을 잘못된 곳에서 씁니다. 파드가 노드에 배정조차 안 됐다면 그것은 스케줄러 단계이고, 스케줄러가 보는 것은 장치가 아니라 노드 status 에 적힌 숫자입니다. 그 숫자를 적어 주는 것이 device plugin 이고, 그 숫자가 없으면 장치가 멀쩡히 꽂혀 있어도 파드는 영영 대기합니다.
확장 자원에는 규칙이 둘 더 있습니다. requests 와 limits 가 같아야 하고 값이 정수여야 합니다. 오버커밋이 불가능하고 장치를 쪼갤 수 없기 때문입니다. 두 규칙 모두 apiserver 가 검사하므로 어기면 파드가 아예 만들어지지 않습니다. 마지막으로 GPU 노드에는 대개 테인트가 붙어 있어서, 자원이 남아돌아도 톨러레이션이 없으면 스케줄되지 않습니다. 이 셋이 자원 관문의 전부입니다.
환경
이 파드에는 GPU 도 device plugin 도 없습니다. 대신 kwok 이 띄운 진짜
컨트롤 플레인이 있어서, 노드 status 에 숫자를 적으면 진짜 스케줄러가 그것을
보고 판정합니다. 확장 자원의 검증도 진짜 apiserver 가 합니다. 작업 디렉터리는
/root/gpuwhy 이고, 매니페스트는 k8s/ 에 산출물은 out/ 에 둡니다.
단계
gpu-why네임스페이스를 만들고lab-node-0에 발견 라벨 넷을 붙입니다.- 그 노드의 status 에
nvidia.com/gpu: 2를 광고하고out/advertised.txt에 저장합니다. - 규칙을 어긴 매니페스트 둘을 만들어 거절 메시지를
out/rejected.txt에 저장합니다. trainer파드를 조건 없이 만들어 자원만으로 노드가 정해지는 것을 봅니다.- 노드에 테인트를 걸고
cpu-only가 대기하는 이유를out/tainted.txt에 저장합니다. - 톨러레이션을 붙인
trainer2로 두 관문을 함께 통과합니다. trainer3로 자리를 넘겨 대기 이유가 자원으로 바뀌는 것을out/exhausted.txt에 저장합니다.out/gate-report.txt에 일곱 줄로 정리합니다.
참고
- status 는 하위 리소스입니다.
kubectl patch node <이름> --subresource=status를 쓰고, JSON 포인터에서 슬래시는~1로 이스케이프합니다. capacity만 적고allocatable을 빠뜨리면 스케줄러가 쓸 자리가 생기지 않습니다. 흔한 실수라 3단계 뒤에도 파드가 계속 대기하면 여기를 먼저 보세요.- 5단계와 7단계는 둘 다 Pending 입니다. 두 파일을 나란히 놓고 메시지가 어떻게 다른지 비교해 보세요. 그 차이가 곧 다음에 볼 곳을 정합니다.
- 테인트를 지워서 통과시키지 마세요. GPU 노드를 예약해 둔 이유가 사라집니다.
GPU 노드에 발견 라벨을 붙인다
gpu-why 네임스페이스를 만들고 lab-node-0 에 라벨 네 개를 붙이세요. nvidia.com/gpu.present=true, nvidia.com/gpu.product=NVIDIA-A100-SXM4-40GB, nvidia.com/gpu.count=2, nvidia.com/gpu.deploy.device-plugin=true 입니다. 나머지 두 노드에는 붙이지 마세요.
실제 클러스터에서는 gpu-feature-discovery 데몬셋이 장치를 읽어 이 라벨들을 붙입니다. 오퍼레이터는 nvidia.com/gpu.deploy.* 라벨로 어느 노드에 어떤 데몬셋을 띄울지 게이팅합니다. 여기서는 그 결과만 손으로 만듭니다. kubectl label node <이름> <키>=<값> --overwrite 를 쓰고, 확인은 kubectl get node --show-labels 로 합니다.
노드 status 에 확장 자원을 광고한다
lab-node-0 의 status 에 nvidia.com/gpu 를 2 로 적으세요. capacity 와 allocatable 양쪽에 넣어야 합니다. 그다음 세 노드의 광고량을 /root/gpuwhy/out/advertised.txt 에 저장하세요.
확장 자원은 kubelet 이 스스로 세는 값이 아니라 device plugin 이 알려 준 것을 노드 status 에 적어 둔 숫자입니다. 여기서는 그 자리를 직접 씁니다. status 는 별도의 하위 리소스라 kubectl patch node <이름> --subresource=status --type=json -p '[...]' 로 고칩니다. JSON 포인터에서 슬래시는 ~1 로 이스케이프해야 하므로 경로가 /status/capacity/nvidia.com~1gpu 가 됩니다. capacity 만 적으면 스케줄러가 쓸 자리는 생기지 않습니다.
확장 자원의 두 규칙이 막는 것을 확인한다
거절당할 파드 매니페스트 두 개를 만드세요. /root/gpuwhy/k8s/bad-mismatch.yaml 은 nvidia.com/gpu 의 requests 와 limits 를 다르게 적고, /root/gpuwhy/k8s/bad-fraction.yaml 은 소수로 요청합니다. 둘을 적용해 보고 거절 메시지를 /root/gpuwhy/out/rejected.txt 에 저장하세요.
확장 자원은 오버커밋을 허용하지 않아 requests 와 limits 가 반드시 같아야 하고, 값은 정수여야 합니다. 장치는 쪼갤 수 없는 단위로 할당되기 때문입니다. 두 규칙 모두 apiserver 가 검사하므로 파드는 아예 만들어지지 않습니다. 명령이 실패하는 것이 정답이고, 메시지는 표준 오류로 나가므로 2>&1 로 받아야 파일에 남습니다.
조건을 주지 않아도 자원이 노드를 정한다
/root/gpuwhy/k8s/trainer.yaml 로 gpu-why 네임스페이스에 파드 trainer 를 만드세요. nvidia.com/gpu 를 limits 에만 1로 적고 nodeSelector 는 붙이지 마세요.
확장 자원은 limits 만 적으면 requests 가 같은 값으로 자동으로 채워집니다. 만든 뒤 kubectl -n gpu-why get pod trainer -o yaml 로 requests 가 채워진 것을 직접 확인하세요. 노드를 지정하지 않았는데도 GPU 를 광고하는 노드로 가는 것이 이 단계의 요점입니다. 스케줄러가 보는 것은 장치가 아니라 숫자입니다.
자원이 남아도 테인트가 막는다
lab-node-0 에 nvidia.com/gpu=present:NoSchedule 테인트를 걸고, /root/gpuwhy/k8s/cpu-only.yaml 로 GPU 를 쓰지 않는 파드 cpu-only 를 만드세요. 그 파드는 nvidia.com/gpu.present: "true" 노드셀렉터로 GPU 노드를 노려야 합니다. 대기 상태가 되면 스케줄 조건의 메시지를 /root/gpuwhy/out/tainted.txt 에 저장하세요.
GPU 노드는 대당 비용이 커서 일반 워크로드가 CPU 자리를 채우면 정작 GPU 파드가 들어갈 자리가 없어집니다. 테인트는 그 노드를 GPU 전용으로 예약하는 장치입니다. kubectl taint node <이름> <키>=<값>:<효과> 로 걸고, 대기 이유는 kubectl -n gpu-why get pod cpu-only -o jsonpath='{.status.conditions[?(@.type=="PodScheduled")].message}' 로 꺼냅니다. 이미 떠 있던 파드는 NoSchedule 로 쫓겨나지 않는다는 점도 함께 보세요.
톨러레이션을 붙여 두 관문을 함께 통과한다
/root/gpuwhy/k8s/trainer2.yaml 로 파드 trainer2 를 만드세요. 앞에서 건 테인트를 견디는 톨러레이션과 nvidia.com/gpu 1장 요청을 함께 넣습니다. 테인트는 지우지 마세요.
톨러레이션의 key·value·effect 가 노드의 테인트와 맞아야 합니다. 같은 노드에서 cpu-only 는 계속 대기하고 trainer2 만 들어가는 것이 확인 지점입니다. 테인트를 지워서 통과시키면 GPU 노드를 예약해 둔 이유가 사라집니다.
자리가 다 차면 같은 파드도 대기한다
/root/gpuwhy/k8s/trainer3.yaml 로 trainer2 와 똑같은 파드 trainer3 를 하나 더 만드세요. 대기 상태가 되면 스케줄 조건의 메시지를 /root/gpuwhy/out/exhausted.txt 에 저장하세요.
노드가 광고한 자리는 2개이고 앞의 두 파드가 이미 다 썼습니다. 톨러레이션은 그대로 두어야 이번 대기 이유가 테인트가 아니라 자원이라는 것이 드러납니다. 스케줄러의 메시지가 Insufficient nvidia.com/gpu 로 바뀌는 것을 확인하세요. 같은 Pending 이라도 이유가 다르면 볼 곳이 다릅니다.
관문을 숫자와 한 단어로 정리한다
/root/gpuwhy/out/gate-report.txt 에 일곱 줄을 적으세요. ALLOCATABLE, USED, PENDING, TAINT, REQUESTS_EQUAL_LIMITS, FRACTIONAL, SCHEDULER_SEES 입니다.
숫자 세 개는 짐작하지 말고 클러스터에서 세어 적습니다. USED 는 lab-node-0 에 배정된 파드들의 nvidia.com/gpu 요청 합이고, PENDING 은 gpu-why 네임스페이스에서 대기 중인 파드 수입니다. TAINT 는 5단계에서 건 것을 키=값:효과 형태로 적고, 나머지 셋은 3단계와 4단계에서 확인한 규칙을 한 단어로 적습니다. SCHEDULER_SEES 는 스케줄러가 장치를 보는지 숫자를 보는지에 대한 답입니다.