GPU는 "비싼 서버"가 아니라 별도 정책이 필요한 자원이다
AI 플랫폼에서 GPU는 가장 먼저 병목이 되고, 가장 늦게 증설되는 자원이다. CPU나 메모리처럼 조금씩 나눠 쓰기 어렵고, 특정 작업이 장시간 점유하는 경우도 많다. 학습 작업 하나가 GPU 여러 장을 몇 시간 또는 며칠 동안 사용할 수 있고, 추론 서비스는 짧은 요청을 계속 처리하면서 낮은 지연 시간을 요구한다.
따라서 Kubernetes에서 GPU를 다룰 때 핵심은 단순히 "GPU 노드에 Pod를 올리는 것"이 아니다. 누가, 어떤 목적으로, 몇 개의 GPU를, 얼마나 오래 사용할 수 있는지 정하는 운영 기준이 필요하다. 이 기준이 없으면 두 가지 문제가 반복된다.
첫째, 필요한 작업이 GPU를 받지 못해 대기한다. 둘째, 중요도가 낮은 실험 작업이 고가의 GPU를 오래 점유한다. GPU 부족은 대부분 하드웨어 부족만의 문제가 아니다. 스케줄링 정책, 쿼터, 우선순위, 관측 지표가 함께 부족할 때 더 크게 드러난다.
이 장에서는 작게 시작하는 AI 플랫폼에서 먼저 정해야 할 GPU 운영 원칙을 다룬다.
AI 생성 이미지
GPU를 Kubernetes 자원으로 보이게 만드는 구성 요소
Kubernetes는 기본적으로 CPU와 메모리는 이해하지만, GPU를 자동으로 인식해 컨테이너에 할당하지는 않는다. GPU는 확장 리소스, 즉 클러스터에 추가로 등록되는 특수 자원으로 다뤄진다. NVIDIA GPU를 사용하는 경우 일반적으로 nvidia.com/gpu 같은 이름의 리소스로 노출된다. Pod는 이 리소스를 요청해야 GPU가 있는 노드에 배치되고, 해당 컨테이너에서 GPU를 사용할 수 있다1.
여기서 필요한 대표 구성 요소가 NVIDIA Device Plugin이다. Device Plugin은 각 GPU 노드에 어떤 GPU가 있는지 Kubernetes에 알려주고, Pod가 요청한 GPU를 컨테이너에 연결하는 역할을 한다. Device Plugin이 없다면 Kubernetes 스케줄러는 노드에 GPU가 있는지, 몇 개가 남았는지 정확히 알 수 없다.
운영 환경에서는 Device Plugin만으로 끝나지 않는 경우가 많다. GPU 노드에는 드라이버, CUDA 실행 환경, 컨테이너 런타임 설정, 모니터링 에이전트, 노드 라벨링 도구 등이 함께 필요하다. 노드가 몇 대 안 될 때는 수동 설치도 가능하지만, 노드가 늘어나거나 드라이버 버전이 바뀌면 관리 부담이 커진다.
이때 GPU Operator를 검토할 수 있다. GPU Operator는 Kubernetes Operator 패턴을 이용해 GPU 드라이버, NVIDIA Container Toolkit, Device Plugin, GPU 모니터링 구성 요소 등을 자동으로 설치하고 관리한다2. 운영팀 입장에서는 GPU 노드마다 다른 절차로 설정하는 위험을 줄이고, 클러스터 전체의 GPU 소프트웨어 구성을 일관되게 유지할 수 있다.
초기 판단 기준은 단순하다.
GPU 노드가 1~2대이고 실험 중심이면 Device Plugin부터 시작할 수 있다.
여러 팀이 같은 GPU 클러스터를 쓰거나 노드 증설이 잦다면 GPU Operator가 유리하다.
규제나 보안 정책 때문에 드라이버 설치 방식을 엄격히 통제해야 한다면 Operator 도입 전 운영 절차를 먼저 검토해야 한다.
중요한 것은 도구 이름이 아니라 책임 경계다. Kubernetes가 GPU를 스케줄링하려면 "GPU를 클러스터 자원으로 등록하는 계층"과 "Pod가 GPU를 명시적으로 요청하는 방식"이 반드시 정리되어야 한다.
GPU 요청을 명시하지 않으면 생기는 문제
GPU 워크로드는 반드시 리소스 요청을 명확히 써야 한다. Kubernetes 공식 문서 기준으로 GPU는 보통 resources.limits에 지정한다. 예를 들어 nvidia.com/gpu: 1을 지정하면 해당 컨테이너는 GPU 1개를 요청한다. GPU는 requests만 단독으로 지정할 수 없고, requests와 limits를 함께 쓸 경우 두 값은 같아야 한다1.
간단한 예시는 다음과 같다.
resources:
limits:
nvidia.com/gpu: 1이 한 줄이 빠지면 여러 문제가 생긴다.
첫째, 스케줄러가 GPU 필요 여부를 알 수 없다. GPU가 필요한 학습 Pod가 일반 CPU 노드에 배치되어 실행 실패할 수 있다. 또는 GPU 노드에 올라가더라도 Kubernetes는 GPU 사용량을 예약한 것으로 보지 않기 때문에 다른 작업과 충돌할 수 있다.
둘째, 팀별 사용량을 통제하기 어렵다. ResourceQuota는 요청된 리소스를 기준으로 사용량을 계산한다. GPU 요청이 명시되지 않으면 "어느 팀이 GPU를 얼마나 예약했는지" 추적하기 어렵고, 비용 배분도 불명확해진다.
셋째, 운영 설정이 느슨한 환경에서는 자원 독점이 발생할 수 있다. 예를 들어 GPU 노드에 일반 Pod가 자유롭게 배치되고, 컨테이너 런타임 설정이 GPU 접근을 넓게 허용한다면 특정 컨테이너가 의도보다 많은 GPU를 사용할 위험이 있다. Kubernetes가 통제하지 않는 GPU 사용은 장애가 나도 원인 파악이 어렵다.
운영 기준은 명확해야 한다.
GPU가 필요한 Pod는 반드시
nvidia.com/gpu같은 GPU 리소스를 명시한다.GPU가 필요 없는 Pod는 GPU 노드에 배치되지 않도록 한다.
네임스페이스별 GPU 쿼터를 두어 팀 단위 사용량을 제한한다.
예외가 필요한 작업은 수동 배포가 아니라 별도 우선순위와 승인 절차로 관리한다.
이 정도 기준만 있어도 초기 GPU 낭비와 배치 실패를 상당히 줄일 수 있다.
GPU 워크로드를 분리하는 네 가지 방법
GPU 클러스터를 안정적으로 운영하려면 "어디에 배치할 것인가"를 정책으로 표현해야 한다. 대표적으로 노드 라벨, taint/toleration, affinity, MIG를 함께 사용한다.
노드 라벨: GPU 종류와 용도를 표시한다
노드 라벨은 노드의 특성을 표시하는 태그다. 예를 들어 GPU 모델, 메모리 크기, 용도에 따라 다음처럼 나눌 수 있다.
accelerator: nvidia
gpu-type: a100
workload: ai-training학습 작업은 gpu-type: a100 노드를 선택하고, 가벼운 추론 작업은 gpu-type: l4 노드를 선택하게 만들 수 있다. 이렇게 하면 고성능 GPU가 단순 테스트 작업에 소모되는 일을 줄일 수 있다.
taint/toleration: 일반 Pod가 GPU 노드에 올라오지 못하게 한다
GPU 노드에는 taint를 걸어두는 것이 좋다. taint는 "이 노드는 아무 Pod나 올 수 없다"는 표시다. toleration은 "나는 이 조건을 허용한다"는 Pod 쪽 선언이다.
예를 들어 GPU 노드에 다음과 같은 taint를 둘 수 있다.
nvidia.com/gpu=present:NoSchedule그러면 해당 toleration을 가진 Pod만 GPU 노드에 배치된다. 이 방식은 GPU 노드를 비싼 공용 좌석처럼 보호한다. GPU를 쓰지 않는 로그 수집기, 일반 API, 임시 배치 작업이 실수로 GPU 노드에 올라가는 일을 막는다.
affinity: 더 섬세한 배치 조건을 표현한다
nodeSelector가 단순한 "라벨 일치"라면, affinity는 더 유연한 배치 규칙이다. 예를 들어 특정 팀의 학습 작업은 특정 GPU 노드풀에 우선 배치하되, 여유가 없으면 다른 노드풀을 사용할 수 있게 만들 수 있다. 또는 같은 모델 서버 Pod가 한 노드에 몰리지 않도록 분산 배치할 수도 있다.
초기에는 nodeSelector와 taint/toleration만으로 충분한 경우가 많다. 다만 운영 서비스가 늘어나면 affinity를 통해 다음 기준을 추가하는 것이 좋다.
운영 추론 서비스는 실험용 학습 노드와 분리한다.
같은 서비스의 복제본은 가능한 한 서로 다른 노드에 배치한다.
특정 GPU 모델이 필요한 작업은 해당 모델이 있는 노드에만 배치한다.
MIG: 큰 GPU를 작은 단위로 나누는 선택지
MIG, 즉 Multi-Instance GPU는 하나의 물리 GPU를 여러 개의 독립적인 GPU 인스턴스로 나누는 기능이다. 작은 추론 서비스나 개발 테스트처럼 GPU 전체가 필요하지 않은 작업에 유용하다. Kubernetes에서는 MIG 단위가 별도 리소스처럼 노출될 수 있다. 예를 들어 작은 GPU 조각을 요청하는 방식으로 여러 Pod가 같은 물리 GPU를 나눠 쓸 수 있다3.
MIG는 GPU 공유를 더 안전하게 만들 수 있지만 모든 상황의 답은 아니다. 대규모 학습처럼 GPU 전체 메모리와 연산 성능이 필요한 작업에는 적합하지 않을 수 있다. 또한 운영팀은 어떤 GPU를 MIG로 나누고, 어떤 GPU를 전체 장치로 유지할지 미리 정해야 한다.
실무에서는 다음처럼 구분하는 방식이 이해하기 쉽다.
| 워크로드 | 권장 배치 전략 |
|---|---|
| 대규모 학습 | 전체 GPU 노드, 전용 노드풀, 우선순위 정책 |
| 파인튜닝 | GPU 모델별 라벨, 팀별 쿼터 |
| 개발 테스트 | 작은 GPU 또는 MIG, 낮은 우선순위 |
| 실시간 추론 | 운영 전용 노드풀, 복제본 분산, 관측 지표 기반 확장 |
| 배치 추론 | 큐 기반 실행, 야간·비피크 시간 활용 |
분리 전략의 목적은 복잡한 스케줄링을 만드는 것이 아니다. 중요한 작업과 실험 작업이 서로 방해하지 않게 하는 것이다.
팀별 ResourceQuota와 LimitRange로 과사용을 막는다
GPU는 개인이나 한 팀이 독점하기 쉬운 자원이다. 특히 연구 조직에서는 "잠깐만 쓰겠다"는 실험이 며칠 동안 남아 있는 일이 흔하다. 이를 운영자의 수작업 정리로 해결하려 하면 갈등이 생긴다. 처음부터 정책으로 제한하는 편이 낫다.
ResourceQuota는 네임스페이스 단위로 사용할 수 있는 리소스 총량을 제한한다. 예를 들어 ai-dev 네임스페이스에는 GPU 2개까지만, ai-prod에는 GPU 4개까지 허용할 수 있다. 팀별 네임스페이스를 운영한다면 팀마다 GPU 상한을 둘 수도 있다.
GPU처럼 Device Plugin으로 노출되는 확장 리소스는 오버커밋을 허용하지 않는다. 그래서 ResourceQuota에서도 CPU나 메모리처럼 requests와 limits를 둘 다 관리하기보다는, requests.nvidia.com/gpu처럼 요청량 기준의 쿼터를 둔다4. 예시는 다음과 같다.
apiVersion: v1
kind: ResourceQuota
metadata:
name: gpu-quota
namespace: ai-dev
spec:
hard:
requests.nvidia.com/gpu: "2"이 쿼터가 있으면 ai-dev 네임스페이스에서 동시에 요청할 수 있는 GPU 총량이 2개로 제한된다. 사용자가 그보다 많은 GPU를 요청하는 Pod나 Job을 만들면 Kubernetes API 서버가 생성 요청을 거부한다. 단, 이미 만들어진 Pod가 자동으로 정리되는 것은 아니므로, 장기 실행 작업을 어떻게 종료할지는 별도 운영 절차로 정해야 한다.
LimitRange는 개별 Pod나 컨테이너가 요청할 수 있는 기본값과 최대값을 제한하는 데 사용한다. 다만 GPU 같은 확장 리소스는 CPU·메모리처럼 기본 요청값을 손쉽게 넣어주는 방식만으로 운영하기 어렵다. GPU 요청 누락을 막고 싶다면 배포 템플릿, CI 검사, admission policy, 정책 도구를 함께 사용해 "GPU 워크로드는 반드시 GPU 리소스를 명시한다"는 규칙을 강제하는 편이 실무적이다.
권장 운영 기준은 다음과 같다.
개발 네임스페이스는 낮은 GPU 쿼터를 둔다.
운영 추론 네임스페이스는 별도 쿼터와 우선순위를 둔다.
학습 작업은 실행 시간, GPU 개수, 소유 팀, 만료 시간을 메타데이터로 남긴다.
장시간 유휴 상태인 GPU 작업은 알림 후 정리하는 절차를 둔다.
예외 증설은 구두 요청이 아니라 티켓이나 승인 흐름으로 남긴다.
이 정책은 통제를 위한 통제가 아니다. 제한이 있어야 팀들이 예측 가능한 방식으로 GPU를 사용할 수 있다. 또한 비용 보고와 증설 판단도 쉬워진다.
GPU 병목은 사용률만 보면 놓친다
GPU 운영에서 가장 많이 보는 지표는 GPU 사용률이다. 하지만 사용률 하나만으로는 부족하다. GPU 사용률이 낮다고 해서 낭비라고 단정할 수 없고, 사용률이 높다고 해서 항상 좋은 것도 아니다.
예를 들어 실시간 추론 서비스는 지연 시간을 낮추기 위해 GPU 사용률을 일부러 낮게 유지할 수 있다. 반대로 학습 작업은 GPU 사용률이 높아도 데이터 로딩이 느려 전체 학습 시간이 길어질 수 있다. 병목은 GPU 자체가 아니라 스토리지, 네트워크, 전처리, 스케줄링 대기열에 있을 수 있다.
초기에 반드시 볼 지표는 다섯 가지다.
| 지표 | 확인할 질문 |
|---|---|
| GPU 사용률 | 할당된 GPU가 실제 계산에 쓰이고 있는가? |
| GPU 메모리 사용량 | 모델과 배치 크기가 메모리 한계에 가까운가? |
| Pod Pending 시간 | GPU가 없어 작업이 대기하고 있는가? |
| 큐 길이 | 학습·배치 추론 요청이 얼마나 밀려 있는가? |
| 추론 지연 시간 | 사용자가 체감하는 응답 시간이 악화되고 있는가? |
GPU Operator를 사용하면 DCGM 기반 모니터링 구성을 함께 관리할 수 있다2. DCGM은 NVIDIA GPU 상태를 수집하는 도구로, GPU 사용률, 메모리, 온도, 전력 같은 지표를 관측하는 데 활용된다. 이 지표를 Prometheus와 Grafana 같은 관측 도구로 연결하면 팀별 사용량과 병목을 더 쉽게 볼 수 있다.
다만 지표는 숫자를 모으는 것보다 해석 기준이 중요하다. 예를 들어 다음과 같은 판단 규칙을 둘 수 있다.
GPU 사용률은 낮은데 큐가 길다면, 작업이 GPU까지 도달하기 전 단계가 막혔을 수 있다.
Pending 시간이 길다면, 쿼터가 부족하거나 특정 GPU 모델에 요청이 몰렸을 수 있다.
추론 지연 시간이 증가하는데 GPU 사용률도 높다면, 복제본 확장이나 모델 최적화가 필요할 수 있다.
GPU 메모리는 가득 찼지만 사용률이 낮다면, 배치 크기나 모델 로딩 방식이 비효율적일 수 있다.
이런 기준을 갖추면 "GPU가 부족하다"는 막연한 요구를 "어떤 워크로드에서, 어떤 시간대에, 어떤 자원이 부족한가"라는 운영 언어로 바꿀 수 있다.
초기 GPU 운영 체크리스트
GPU 운영은 처음부터 거창한 플랫폼을 만들 필요는 없다. 대신 다음 항목은 초기에 정해두는 것이 좋다.
GPU 노드에 Device Plugin 또는 GPU Operator가 일관되게 설치되어 있는가?
GPU Pod는
nvidia.com/gpu리소스를 명시적으로 요청하는가?GPU 노드에는 taint가 적용되어 일반 Pod 배치를 막고 있는가?
GPU 모델, 용도, 팀 기준의 노드 라벨이 정리되어 있는가?
개발, 검증, 운영 네임스페이스별 GPU 쿼터가 있는가?
학습, 파인튜닝, 추론, 배치 추론의 우선순위가 구분되어 있는가?
GPU 사용률뿐 아니라 Pending 시간, 큐 길이, 추론 지연 시간을 보고 있는가?
장시간 유휴 GPU 작업을 찾고 정리하는 절차가 있는가?
이 체크리스트를 통과하면 GPU를 완벽하게 최적화했다는 뜻은 아니다. 하지만 적어도 비싼 자원이 우연과 관성으로 배분되는 상태에서는 벗어난다.
GPU 스케줄링의 목표는 모든 GPU를 100% 사용하는 것이 아니다. 조직의 중요한 AI 워크로드가 필요한 시점에 필요한 만큼 GPU를 얻고, 실험과 운영 서비스가 서로 방해하지 않도록 만드는 것이다. 이 기준이 있어야 이후 데이터 파이프라인, 모델 서빙, 비용 최적화도 안정적으로 이어질 수 있다.
참고
2About the NVIDIA GPU Operator
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.