LabHub

GPU Operator 와 타임슬라이싱 · GPU 를 클러스터에 붙인다는 것 · 이론

ClusterPolicy·RuntimeClass·자원 광고

LabHub 에서 이어서 보기

한 줄 요약

GPU 파드가 뜨려면 서로 아무 관계가 없는 두 개의 관문을 통과해야 한다. 스케줄러가 보는 nvidia.com/gpu 자원과, 노드의 런타임이 보는 RuntimeClass 핸들러다. 하나만 갖추면 파드는 둘 중 어느 쪽에서 막혔는지도 알려 주지 않는다.

왜 이 구분이 필요한가

"GPU 파드가 안 뜬다" 는 신고를 받으면 증상은 딱 두 가지 중 하나다.

이 둘을 가르지 못하면 device plugin 로그를 뒤지면서 사실은 containerd 문제인 것을 몇 시간 붙잡게 된다. 반대도 마찬가지다. 두 관문이 왜 나뉘어 있는지 알면 첫 3분에 갈래를 정할 수 있다.

어떻게 동작하나

자원 쪽. GPU 는 cpu·memory 처럼 kubelet 이 스스로 세는 자원이 아니다. device plugin 이 노드에서 장치를 열어 보고 kubelet 에게 목록을 넘기면, kubelet 이 그 개수를 노드 오브젝트의 status.capacitystatus.allocatable 에 확장 자원으로 적는다. 스케줄러가 보는 것은 장치가 아니라 그 숫자다. 그래서 숫자만 있고 장치가 없어도 스케줄링은 성립하고(그게 이 코스 실습이 서 있는 자리다), 반대로 장치가 멀쩡한데 plugin 이 죽어 있으면 스케줄러는 그 노드에 GPU 가 없다고 판단한다.

확장 자원에는 규칙이 하나 더 있다. requestslimits 를 따로 줄 수 없다. limits 에 적은 값이 곧 requests 가 되고, 정수여야 한다. GPU 는 0.5장을 줄 수 없기 때문이다.

런타임 쪽. RuntimeClass 는 "이 파드는 어느 런타임 핸들러로 만들어라" 를 고르는 클러스터 스코프 오브젝트다.

apiVersion: node.k8s.io/v1kind: RuntimeClassmetadata:  name: nvidiahandler: nvidia          # 이 문자열이 containerd 설정의 runtimes.<이름> 과 맞아야 한다

kubelet 은 파드를 만들 때 이 handler 문자열을 CRI 요청에 실어 보내고, containerd 는 자기 설정의 runtimes 테이블에서 같은 이름을 찾는다. 없으면 컨테이너 생성이 거부된다. 여기서 중요한 것은 API 서버가 이 이름을 검증하지 않는다는 점이다. RuntimeClasskubectl apply 로 얼마든지 만들어지고, 존재하지 않는 핸들러를 가리켜도 아무도 경고하지 않는다. 그 어긋남은 파드를 만드는 순간, 그것도 그 노드에서만 드러난다.

두 관문의 관계를 한 줄로 정리하면 이렇다.

스케줄러  : nvidia.com/gpu 숫자를 보고 "어느 노드로 보낼까" 를 정한다kubelet   : RuntimeClass handler 를 containerd 에 넘겨 "어떻게 만들까" 를 정한다

현장에서 만나는 모습

첫째, runtimeClassName 을 안 써도 되는 클러스터가 많다. toolkit 이 containerd 의 default_runtime_name 을 아예 nvidia 로 바꿔 두는 배치가 흔하기 때문이다. 편하지만 대가가 있다 — GPU 를 안 쓰는 파드까지 nvidia 런타임을 타게 되고, 그 설정이 깨지면 GPU 파드가 아니라 클러스터의 모든 파드가 못 뜬다. 사고의 폭이 달라진다.

둘째, CDI 로 옮겨 가는 중이다. Container Device Interface 는 "장치를 컨테이너에 넣는 법" 을 런타임 종류와 무관한 JSON/YAML 스펙으로 표준화한 것이다. CDI 를 쓰면 nvidia 전용 런타임 바이너리 없이도 nvidia.com/gpu=all 같은 장치 이름으로 주입할 수 있다. 다만 containerd 쪽 CDI 지원은 버전마다 켜는 방법이 달라서, 지금 현장은 두 방식이 섞여 있다.

셋째, Pending 의 원인은 자원만이 아니다. GPU 노드에는 대개 nvidia.com/gpu=present:NoSchedule 같은 테인트가 붙어 있어서, 일반 워크로드가 비싼 노드를 차지하지 못하게 막는다. GPU 파드에 톨러레이션이 없으면 자원이 남아돌아도 스케줄되지 않는다. kubectl describe pod 의 마지막 이벤트가 언제나 첫 번째로 읽어야 할 문장인 이유다.

다음 퀴즈에서 확인할 것

두 관문이 각각 무엇을 막는지, 그리고 어느 증상이 어느 쪽을 가리키는지를 확인한다. 여기서 갈래를 정확히 나눌 수 있으면 뒤에 나오는 사고 이야기가 훨씬 빨리 읽힌다.