거절 대신 줄을 세운다
한 줄 요약
Kueue 는 파드를 배치하지 않습니다. Job 을 「멈춘(suspend) 채로 붙잡아 두었다가」, 큐의 쿼터가 허락하는 순간 풀어 줍니다. 이 「풀어 줌」 을 입장(admission)이라 부르고, 입장한 뒤의 배치는 여전히 기본 kube-scheduler 가 합니다. 입장과 배치를 나눈 것이 Kueue 설계의 전부라고 해도 과장이 아닙니다.
왜 이게 필요했나
쿠버네티스에도 쿼터가 있습니다. ResourceQuota 는 네임스페이스가 쓸 수 있는 양을 넘는 「생성을 거절」합니다. 웹 서비스에는 이것이 맞습니다. 한도를 넘는 배포는 실수일 가능성이 크고, 바로 실패해야 고칩니다.
배치 작업은 다릅니다. GPU 4장짜리 학습을 밤 열한 시에 제출했는데 팀 쿼터가 지금 꽉 찼다고 거절당하면, 사람은 다음 날 아침에야 알게 됩니다. 원하는 것은 거절이 아니라 「줄 서기」입니다. 지금은 못 들어가도 앞 작업이 끝나면 자동으로 들어가야 합니다. 여기에 팀끼리 남는 쿼터를 빌려 주기, 우선순위, 여러 파드를 한꺼번에 입장시키기가 더해지면 ResourceQuota 로는 표현할 수 없습니다. HPC 의 Slurm 이 오래 해 온 일이고, 이 플랫폼의 HPC 와 Slurm 코스에서 본 그 큐를 쿠버네티스 방식으로 다시 만든 것이 Kueue 입니다.
어떻게 동작하나
객체 다섯 개를 기억하면 됩니다.
ResourceFlavor 자원의 「맛」. 노드 라벨·테인트·톨러레이션을 담아, 입장할 때 파드에 붙여 준다
ClusterQueue 쿼터의 주인. 플레이버마다 자원별 nominalQuota, 같은 cohort 끼리 빌려 쓰기 규칙
LocalQueue 네임스페이스 안의 창구. 어느 ClusterQueue 로 갈지만 적는다
Workload Kueue 가 Job 마다 만드는 내부 객체. 파드 묶음(podSets)과 필요한 자원의 합
WorkloadPriorityClass 입장 순서와 선점에 쓰는 우선순위(파드의 PriorityClass 와 따로)
흐름은 이렇습니다.
Job 생성(라벨 kueue.x-k8s.io/queue-name: lq)
→ 웹훅이 spec.suspend=true 로 바꾼다 파드가 하나도 생기지 않는다
→ Workload 생성, LocalQueue → ClusterQueue 의 줄에 선다
→ 쿼터가 되면 입장: 플레이버의 노드 라벨을 파드 템플릿에 넣고 suspend=false
→ 이제 Job 컨트롤러가 파드를 만들고 kube-scheduler 가 노드를 고른다
실험 VM 에서 잰 값입니다(Kueue v0.20.3, 컨트롤러 메모리 60Mi, 설치부터 준비까지 16초). 그리고 API 판이 바뀌었다는 것을 꼭 기억해 두세요. 이 판의 CRD 는 kueue.x-k8s.io/v1beta2 만 내주고 v1beta1 은 더 이상 받지 않습니다. 인터넷의 예제 다수가 아직 v1beta1 이라 그대로 붙이면 no matches for kind 로 실패합니다.
현장에서 만나는 모습
- 「쿼터는 노드 용량이 아닙니다.」 실측에서 team-a 의 쿼터가 GPU 2장이고 cohort 에서 1장을 빌릴 수 있었는데 노드는 2장뿐이었습니다. Kueue 는 세 번째 작업을 입장시켰고(빌려 쓴 1장), 그 파드는 노드에서 자리를 못 찾아 Pending 이었습니다. Kueue 가 보는 것은 쿼터 장부이지 노드가 아닙니다. 쿼터의 합을 노드 용량보다 크게 잡으면 입장은 됐는데 못 뜨는 작업이 생깁니다.
- 「라벨 하나가 계약입니다.」 기본 설정(
manageJobsWithoutQueueName: false)에서는queue-name라벨이 없는 Job 을 Kueue 가 쳐다보지도 않습니다. 실습 6단계에서 그 Job 이 쿼터와 상관없이 GPU 를 가져가는 것을 직접 봅니다. 운영에서는 이 설정을 켜거나, 입장 정책(Kyverno·ValidatingAdmissionPolicy)으로 라벨 없는 GPU Job 을 막습니다. - 「쿼터는 자원마다 따로 셉니다.」 coveredResources 에 cpu·memory·nvidia.com/gpu 를 함께 적으면 셋 중 하나라도 모자랄 때 입장하지 못합니다. GPU 는 남는데 CPU 쿼터가 작아 막히는 일이 흔하니, 기다리는 Workload 의 사유에서 어느 자원이 모자란지 먼저 읽으세요.
- 「입장이 됐다고 Running 이 보장되지는 않습니다.」 그래서 Kueue 에는
waitForPodsReady가 있습니다. 정해진 시간 안에 파드가 다 뜨지 않으면 입장을 거두어 다시 줄을 세웁니다.
English corner
Kueue decides when a job may start; the scheduler decides where its pods run.
admission(입장), suspend(일시 정지), nominal quota(명목 쿼터)는 Kueue 문서의 기본 어휘입니다.
다음 실습에서 할 것
ResourceFlavor·ClusterQueue·LocalQueue 를 직접 세우고, GPU 1장짜리 Job 셋을 넣어 둘은 입장하고 하나는 줄 서는 것을 봅니다. 라벨 없는 Job 이 쿼터를 우회하는 것을 확인하고, ClusterQueue 의 장부를 읽은 뒤, 앞 작업을 지워 줄이 저절로 줄어드는 것을 봅니다.