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

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

Kueue 로 GPU 쿼터를 세우고 줄을 세운다

TT Lab 에서 이어서 보기

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

VM 안에 k3s 한 대가 떠 있고, fake-gpu-operator 가 가짜 GPU 4장을, Kueue v0.20.3 가 큐를 맡습니다. 처음 뜨는 데 3~4분 걸립니다. 세션이 끝나면 VM 과 파일은 사라집니다.

목표

큐·쿼터·입장의 흐름을 직접 세워, 「입장은 Kueue 가, 배치는 스케줄러가」 를 눈으로 확인합니다.

왜 중요한가

GPU 를 여러 팀이 나눠 쓰기 시작하면 「누가 먼저, 얼마나」 가 곧바로 분쟁이 됩니다. ResourceQuota 는 거절만 할 수 있어 배치 작업에 맞지 않고, Kueue 는 그 자리에 줄을 세웁니다. 큐의 장부(ClusterQueue status)를 읽을 줄 알면 「내 학습이 왜 안 도는가」 에 한 줄로 답할 수 있습니다. 그리고 라벨 하나 빠뜨리면 그 장부를 통째로 지나친다는 함정도 같이 봅니다.

단계

  1. ResourceFlavor fake-gpu(nodeLabels nvidia.com/gpu.present: "true")를 /root/gsb-kueue/flavor.yaml 로 만듭니다.
  2. ClusterQueue team-a(cpu 2·memory 2Gi·nvidia.com/gpu 2)를 /root/gsb-kueue/cq.yaml 로 만들어 Active 로 둡니다.
  3. team-a 네임스페이스에 LocalQueue lq 를 /root/gsb-kueue/lq.yaml 로 만듭니다.
  4. GPU 1장짜리 Job train-1 을 /root/gsb-kueue/job-1.yaml 로 넣어 입장·Running 을 봅니다.
  5. train-2, train-3 을 넣고, 기다리는 train-3 의 사유를 /root/gsb-kueue/waiting.txt 에 담습니다.
  6. 라벨 없는 Job sneaky 를 넣어 Kueue 를 지나치는 것을 보고 /root/gsb-kueue/bypass.txt 에 suspended=, workload= 를 적습니다.
  7. ClusterQueue 장부를 /root/gsb-kueue/usage.json 에 admitted, pending, gpu_reserved 로 적습니다.
  8. train-1 을 지워 train-3 이 스스로 입장해 Running 이 되게 합니다.

참고

ResourceFlavor: 어떤 노드의 자원인가

ResourceFlavor fake-gpu 를 「/root/gsb-kueue/flavor.yaml」 로 만들어 적용하세요. spec.nodeLabels 에 nvidia.com/gpu.present: "true" 가 있어야 합니다(fake-gpu-operator 가 GPU 노드에 붙인 라벨입니다).

이 판의 Kueue 는 apiVersion kueue.x-k8s.io/v1beta2 만 받습니다. nodeLabels 는 입장할 때 파드의 nodeSelector 로 들어갑니다.

ClusterQueue: 쿼터의 주인

ClusterQueue team-a 를 「/root/gsb-kueue/cq.yaml」 로 만들어 적용하세요. 플레이버 fake-gpu 에서 cpu 2, memory 2Gi, nvidia.com/gpu 2 를 명목 쿼터로 두고, namespaceSelector: {{}} 로 모든 네임스페이스를 받습니다. 상태가 Active 여야 합니다.

coveredResources 에 적은 자원은 모든 플레이버가 빠짐없이 적어야 합니다. 플레이버가 아직 없으면 ClusterQueue 는 Active 가 되지 않습니다.

LocalQueue: 네임스페이스의 창구

team-a 네임스페이스에 LocalQueue lq 를 「/root/gsb-kueue/lq.yaml」 로 만들어 ClusterQueue team-a 에 잇고 적용하세요.

LocalQueue 는 쿼터를 갖지 않습니다. 어느 ClusterQueue 로 갈지만 적습니다.

첫 Job 이 입장한다

GPU 1장짜리 Job train-1 을 「/root/gsb-kueue/job-1.yaml」 로 만들어 team-a 에 넣으세요. 라벨 kueue.x-k8s.io/queue-name: lq 가 있어야 하고, 입장(admitted)해서 파드가 Running 이어야 합니다.

입장하면 Kueue 가 플레이버의 노드 라벨을 파드 템플릿의 nodeSelector 에 넣어 줍니다. 파드 스펙을 열어 확인해 보세요.

쿼터가 차면 줄을 선다

같은 꼴로 train-2, train-3 을 넣으세요. 쿼터가 2장이라 train-3 은 입장하지 못하고 멈춘(suspend) 채 기다립니다. 그 Workload 가 남긴 사유를 「/root/gsb-kueue/waiting.txt」 에 담으세요.

Kueue 가 Job 마다 만든 Workload 의 조건(QuotaReserved 등)에 사유가 있습니다. Job 의 spec.suspend 도 함께 보세요.

라벨 없는 Job 은 Kueue 를 지나친다

큐 라벨이 「없는」 GPU 1장짜리 Job sneaky 를 team-a 에 넣으세요. 쿼터가 찼는데도 바로 Running 이 됩니다. 확인한 것을 「/root/gsb-kueue/bypass.txt」 에 suspended=(sneaky 의 spec.suspend), workload=(Kueue 가 만든 Workload 이름, 없으면 none) 두 줄로 적으세요.

기본 설정에서 Kueue 는 queue-name 라벨이 있는 Job 만 관리합니다. 라벨이 없으면 Workload 도 만들지 않습니다.

ClusterQueue 의 장부를 읽는다

ClusterQueue team-a 의 status 에서 입장한 Workload 수, 기다리는 Workload 수, 예약된 GPU 수를 읽어 「/root/gsb-kueue/usage.json」 에 admitted, pending, gpu_reserved 세 키로 적으세요.

status.admittedWorkloads, status.pendingWorkloads, 그리고 status.flavorsReservation 안의 nvidia.com/gpu total 입니다. sneaky 는 이 장부에 없습니다.

앞 작업이 끝나면 줄이 저절로 줄어든다

train-1 을 지우세요. 그러면 기다리던 train-3 이 스스로 입장해 Running 이 됩니다. 아무것도 다시 제출하지 않습니다.

Job 을 지우면 그 Workload 가 사라지면서 쿼터가 풀리고, Kueue 가 줄의 다음 Workload 를 입장시킵니다. 파드가 SIGTERM 에 바로 끝나야 GPU 도 바로 풀립니다.