TT Lab
블로그 시작하기
배우기 러닝패스 코스

쿠버네티스 GPU 스케줄링과 AI 배치

KAI-Scheduler 로 갱·우선순위·GPU 쪼개기를 다룬다

TT Lab 에서 이어서 보기

이 실습은 진짜 쿠버네티스에서 돕니다

VM 안에 k3s 한 대가 떠 있고, 가짜 GPU 4장과 KAI-Scheduler v0.18.6 가 올라 있습니다. 쪼개기를 위해 fake-gpu-operator 의 예약 네임스페이스를 KAI 와 맞추고, KAI 가 RuntimeClass 를 넣지 않게 설정해 두었습니다(왜 그런지는 읽기 참고). 처음 뜨는 데 4~5분 걸립니다. 세션이 끝나면 VM 과 파일은 사라집니다.

목표

KAI 의 큐 계층·PodGroup·갱 스케줄링·우선순위 선점·GPU 쪼개기를 차례로 직접 일으키고, 그 결정이 PodGroup 과 이벤트에 어떤 문장으로 남는지 읽습니다.

왜 중요한가

GPU 클러스터에서 가장 비싼 낭비는 「일부만 떠서 기다리는 작업」 과 「한 장을 다 못 쓰는 작은 작업」 입니다. 갱 스케줄링은 앞의 것을, 쪼개기는 뒤의 것을 줄입니다. 그리고 우선순위가 선점과 쿼터를 어떻게 바꾸는지 알아야 「왜 내 학습이 밀려났나」 와 「왜 내 추론이 quota 를 못 넘나」 에 답할 수 있습니다. 실습 3단계의 함정은 실제 문서와 다른 동작이라 꼭 밟아 보세요.

단계

  1. 큐 lab·research·ops 를 /root/gsb-kai/queues.yaml 로 만듭니다.
  2. KAI 로 띄운 Pod p1 을 /root/gsb-kai/p1.yaml 로 만들고, 생긴 PodGroup 이름을 /root/gsb-kai/podgroup.txt 에 적습니다.
  3. limit 을 비운 큐 nolimit 에 Pod nl-1 을 넣어 Pending 사유를 /root/gsb-kai/nolimit.txt 에 담습니다.
  4. nolimit 의 gpu limit 을 -1 로 바꿔 nl-1 을 Running 으로 만듭니다.
  5. 갱 Job gang(1장 × 3, min-member 3)을 넣어 남은 2장에도 셋 다 Pending 인 사유를 /root/gsb-kai/gang.txt 에 담습니다.
  6. gang 을 지우고 train 파드 tr-1·tr-2 로 GPU 를 채운 뒤 build 파드 bd-1 로 하나를 밀어냅니다.
  7. 남은 train 파드를 지우고 gpu-fraction: "0.5" 파드 fr-1·fr-2 를 /root/gsb-kai/fraction.yaml 로 만들어 같은 GPU 를 나눠 받게 합니다.
  8. /root/gsb-kai/report.json 에 gpu_allocated, reservation_pods, shared_gpu 를 적습니다.

참고

큐 계층을 세운다

「/root/gsb-kai/queues.yaml」 에 KAI 큐 셋을 적어 적용하세요. 부모 lab(gpu quota 4, limit -1), 자식 research(부모 lab, gpu quota 2, limit 4), 자식 ops(부모 lab, gpu quota 2, limit -1). cpu·memory 는 셋 다 quota -1, limit -1 입니다.

apiVersion 은 scheduling.run.ai/v2, 종류는 Queue 입니다. 작업은 자식(잎) 큐에만 넣을 수 있습니다.

KAI 로 파드 하나를 띄우면 PodGroup 이 생긴다

kai-lab 네임스페이스에 Pod p1(GPU 1장, schedulerName: kai-scheduler, 라벨 kai.scheduler/queue: research)을 「/root/gsb-kai/p1.yaml」 로 만들어 Running 으로 두세요. KAI 가 만든 PodGroup 의 이름을 「/root/gsb-kai/podgroup.txt」 에 한 줄로 적으세요.

pod-grouper 가 파드마다(또는 상위 워크로드마다) PodGroup 을 만들고 파드 주석 pod-group-name 에 그 이름을 적습니다.

limit 을 비운 큐의 함정

부모 lab 아래에 gpu quota 1 이고 「limit 을 적지 않은」 큐 nolimit 을 만들고, 그 큐에 GPU 1장짜리 Pod nl-1 을 넣으세요. quota 가 1인데도 nl-1 은 Pending 입니다. PodGroup 이 남긴 사유를 「/root/gsb-kai/nolimit.txt」 에 담으세요.

PodGroup 의 status.schedulingConditions 에 사유가 있습니다. limit 을 비우면 0 으로 읽힙니다.

limit 을 -1 로 적어 고친다

큐 nolimit 의 gpu limit 을 -1(상한 없음)로 바꾸세요. 기다리던 nl-1 이 Running 이 되어야 합니다.

kubectl patch 로 spec.resources.gpu.limit 만 바꿉니다. 다음 스케줄링 주기에 바로 반영됩니다.

모두 아니면 아무것도

GPU 1장짜리 파드 셋을 함께 놓아야 하는 Job gang(parallelism 3, 주석 kai.scheduler/batch-min-member: "3", 큐 research, KAI 스케줄러)을 넣으세요. 남은 GPU 가 2장이라 둘은 놓을 수 있지만 셋 다 Pending 이어야 합니다. PodGroup 의 사유를 「/root/gsb-kai/gang.txt」 에 담으세요.

큐 라벨은 Job 과 파드 템플릿 모두에, 주석은 Job 에 답니다. 기본 스케줄러라면 두 파드는 떴을 것입니다. 큐 research 의 limit(4)도 넘지 않게 장수를 맞췄습니다.

build 가 train 을 밀어낸다

Job gang 을 지우고, 우선순위 train 인 1장짜리 Pod tr-1, tr-2 를 큐 research 에 넣어 GPU 4장을 다 채우세요. 그다음 우선순위 build 인 1장짜리 Pod bd-1 을 같은 큐에 넣으세요. bd-1 이 Running 이 되고 train 파드 하나가 밀려나야 합니다.

우선순위는 파드의 priorityClassName 입니다. build(100)는 선점당하지 않는 대신 큐의 quota 안에서만 돌고, train(50)은 선점당할 수 있습니다.

GPU 한 장을 둘이 나눠 받는다

먼저 남은 train 파드를 지워 GPU 한 장을 비우세요. 그다음 주석 gpu-fraction: "0.5" 를 단 Pod fr-1, fr-2(큐 research, KAI 스케줄러, nvidia.com/gpu limits 없음)를 「/root/gsb-kai/fraction.yaml」 로 만들어 적용하세요. 둘 다 Running 이고 같은 GPU 를 받아야 합니다.

쪼갠 요청은 limits 가 아니라 주석으로 적습니다. 둘을 함께 쓰면 안 됩니다. KAI 는 kai-resource-reservation 에 예약 파드를 만들어 카드 한 장을 잡고, 두 파드에 같은 장치를 넘깁니다.

누가 GPU 를 쥐고 있나

「/root/gsb-kai/report.json」 에 gpu_allocated(노드에 배치된 Pending·Running 파드가 limits 로 요청한 nvidia.com/gpu 의 합, 모든 네임스페이스), reservation_pods(kai-resource-reservation 의 파드 수), shared_gpu(fr-1 이 받은 NVIDIA_VISIBLE_DEVICES 값) 세 키를 적으세요.

쪼갠 파드는 nvidia.com/gpu limits 가 없습니다. 그 몫은 예약 파드가 한 장으로 쥐고 있습니다. 그래서 노드 장부에는 예약 파드가 보입니다.