제7부 엔터프라이즈 운영과 MLOps
7.2 쿠버네티스 GPU 운영 I — GPU Operator·디바이스 플러그인
7.2.1 이 장에서 배우는 것 / 선수 지식
6.8에서 NIM을 쿠버네티스에 배포하며 nvidia.com/gpu: 1로 GPU를 요청했다. 그것이 어떻게 동작하나? 쿠버네티스는 기본적으로 GPU를 모른다 — CPU·메모리만 안다. GPU를 스케줄 가능한 자원으로 만들려면 디바이스 플러그인이 필요하고, 그 위에 드라이버·컨테이너 런타임·모니터링·노드 라벨링까지 여러 컴포넌트가 설치되어야 한다. GPU Operator 는 이 전부를 자동화한다. 이 장은 그 기반 — 클러스터가 GPU를 다루는 메커니즘 — 을 판다. 제7부 운영 계층의 출발점이고, 6.8(NIM)·Triton·학습의 토대다.
핵심 통찰: k8s에서 GPU를 쓰려면 "노드마다 드라이버+런타임+플러그인+모니터링"을 설치해야 하는데, 이를 수동으로 모든 노드에 하는 것은 운영 부담이 매우 큰 작업이다. GPU Operator는 이를 선언적으로 자동 설치·관리한다 — 노드를 추가하면 자동으로 GPU 준비. 그리고 기본은 GPU 전체를 할당하므로, 작은 모델·공유는 타임슬라이싱(7.2.6)·MIG/MPS(7.4~7.5)가 필요하다.
배우는 것:
- k8s가 GPU를 모르는 이유와, 디바이스 플러그인이 GPU를
nvidia.com/gpu자원으로 노출하는 원리. - GPU에 필요한 컴포넌트 스택 — 드라이버·컨테이너 툴킷·디바이스 플러그인·DCGM·GPU Feature Discovery·MIG 매니저.
- GPU Operator — 이 전부를 자동 설치·관리하는 오퍼레이터, 컨테이너화 드라이버.
- 스케줄링 — 파드가 GPU를 요청 → 스케줄러 배치 → 플러그인 할당 → 컨테이너 접근.
- 타임슬라이싱 — 한 GPU를 여러 파드에 (오버서브스크립션, 격리 없음), MIG/MPS 예고(7.5).
- 노드 라벨·GPU 종류별 스케줄링(GPU Feature Discovery).
선수 지식: 6.8(NIM k8s 배포 — 이 메커니즘 위), 7.1(AI Enterprise에 Operator 포함), 4.10/7.5(MIG·공유), 0.3(컨테이너). DCGM·모니터링은 7.3, 공유는 7.5. 환경은 쿠버네티스 + GPU 노드.
정직: GPU Operator·디바이스 플러그인·Helm 차트의 설치 방식·버전·컴포넌트는 시점 의존이다 — 이 장은 GPU 스케줄링의 원리·컴포넌트 역할을 가르치고 명령은 한 형태를 예시("그 버전 문서로 확인"). k8s 일반은 가정한다. 모든 수치는 환경 의존.
7.2.2 k8s는 GPU를 모른다 — 디바이스 플러그인
쿠버네티스 스케줄러는 기본적으로 CPU·메모리만 자원으로 안다. GPU는?
디바이스 플러그인의 역할:
하지만 디바이스 플러그인만으로는 부족하다 — 그 아래·옆에 더 필요하다.
7.2.3 GPU에 필요한 컴포넌트 스택
k8s 노드에서 GPU 컨테이너가 실행해면 여러 층이 갖춰져야 한다:
이 전부를 '모든 GPU 노드에' 설치·버전 정합·업데이트해야 한다 — 수동 방식은 운영 부담이 매우 크다.
각 층:
- 드라이버: 호스트 커널 GPU 드라이버. CUDA·런타임과 버전 정합(5.2의 종속과 동형).
- 컨테이너 툴킷(nvidia-container-toolkit): 컨테이너 런타임이 GPU 디바이스·드라이버를 컨테이너에 노출하게 하는 훅. 없으면 컨테이너가 GPU를 못 봄.
- 디바이스 플러그인: GPU를 스케줄 가능 자원으로(위).
- DCGM exporter: GPU 메트릭을 Prometheus로(7.3).
- GPU Feature Discovery: 노드에 GPU 속성 라벨(모델·MIG 프로파일·메모리) →
nodeSelector로 GPU 종류별 스케줄링. - MIG 매니저: MIG 분할 구성·관리(7.5).
7.2.4 GPU Operator — 전부 자동화
이 스택을 모든 노드에 수동 설치·관리하는 것은 비현실적이다(노드 추가마다, 버전 업마다). GPU Operator 는 쿠버네티스 오퍼레이터 패턴으로 이 전부를 선언적으로 자동 설치·관리한다.
이점:
- 선언적·자동: Helm으로 한 번 설치하면 모든 GPU 노드가 자동 구성. 노드 추가 시 자동.
- 컨테이너화 드라이버: 드라이버를 컨테이너로 배포 가능 → 호스트 OS에 수동 설치·버전 관리 부담↓(노드 OS 일관성).
- 버전 정합: 드라이버·툴킷·플러그인의 호환 조합을 관리.
- AI Enterprise(7.1): NVAIE면 이 Operator가 검증·지원됨.
# GPU Operator 설치(Helm; 정확한 리포·값은 버전 확인)
helm install --wait gpu-operator \
nvidia/gpu-operator -n gpu-operator --create-namespace
# → 각 GPU 노드에 드라이버·툴킷·플러그인·DCGM·GFD 자동 배포
kubectl get pods -n gpu-operator # 컴포넌트 파드 확인
kubectl describe node <gpu-node> | grep nvidia.com/gpu # 자원 광고 확인
핵심: GPU Operator는 "GPU 노드 운영의 보일러플레이트를 없앤다". 수동으로 노드마다 드라이버·툴킷·플러그인을 설치하고 버전을 맞추는 대신, 오퍼레이터가 선언적으로. 대규모·동적 클러스터에서 결정적.
7.2.5 워크스루 — GPU 파드 스케줄링
GPU Operator가 설치된 클러스터에서 GPU 파드를 기동한다.
# gpu-pod.yaml — GPU 1개 요청
apiVersion: v1
kind: Pod
metadata: { name: cuda-test }
spec:
restartPolicy: Never
containers:
- name: cuda
image: nvcr.io/nvidia/cuda:<tag> # CUDA 컨테이너(버전 확인)
command: ["nvidia-smi"]
resources:
limits:
nvidia.com/gpu: 1 # ★ GPU 1개(limits에 — 정수)
kubectl apply -f gpu-pod.yaml
kubectl logs cuda-test # nvidia-smi 출력 → 할당된 GPU 보임
# → device plugin이 GPU 1개를 이 컨테이너에 할당, 컨테이너는 그것만 봄
GPU 종류별 스케줄링(GPU Feature Discovery 라벨 활용):
# 특정 GPU 모델에만 스케줄(라벨은 GFD가 자동 부여, 키 버전 확인)
spec:
nodeSelector:
nvidia.com/gpu.product: "<GPU-모델-라벨>" # 예: 특정 세대
containers: [ ... resources: { limits: { nvidia.com/gpu: 1 } } ]
핵심 규칙:
nvidia.com/gpu는 정수,limits에: GPU는 정수 단위로 할당(기본).requests만으로는 안 되고limits에 명시.- 기본은 전체 할당: GPU 1개를 요청하면 GPU 하나 전체가 그 컨테이너에. 분수 GPU는 기본 불가 → 공유는 MIG/MPS/타임슬라이싱(7.2.6·7.5).
- 격리: 할당된 GPU만 컨테이너에 보임(다른 파드와 분리).
7.2.6 타임슬라이싱 — 한 GPU를 여러 파드에
기본은 1 GPU = 1 파드라, 작은 모델·추론·개발에선 GPU가 낭비된다(5.12의 활용률). 타임슬라이싱은 디바이스 플러그인이 한 GPU를 여러 "가상" 자원으로 광고해 여러 파드가 공유하게 한다(오버서브스크립션).
특성: 격리 없음(메모리·연산 격리 안 됨 — 한 파드가 OOM 내면 영향)·오버서브스크립션(실제보다 많은 'GPU'를 광고 → 활용↑·경합 위험)·적합(개발·작은 추론·버스트 적은 워크로드, production 격리엔 부적합).
# 타임슬라이싱 config(개념 — device plugin/Operator 설정, 버전 확인)
# GPU 1개를 4개로 분할 광고
sharing:
timeSlicing:
resources:
- name: nvidia.com/gpu
replicas: 4
| 공유 방식 | 격리 | 적합 | 어디서 |
|---|---|---|---|
| 타임슬라이싱 | 없음(시간 분할) | 개발·작은 추론 | device plugin 설정 |
| MPS(7.5) | 약(공간 공유) | 작은 커널 동시 | 7.5 |
| MIG(4.10·7.5) | 강(하드 분할) | 멀티테넌트·예측 | MIG 매니저 |
견해: 타임슬라이싱은 "격리 없는 오버서브스크립션" — 개발·작은 추론에 GPU 활용을 높이지만 production 멀티테넌트엔 부적합(한 파드가 다른 파드에 영향). 격리·성능 예측이 필요하면 MIG(하드 분할), 작은 커널 동시 효율이면 MPS(7.5). 공유 방식 선택은 7.5에서 깊게.
7.2.7 중간 점검 (체크포인트)
- [ ] k8s가 기본적으로 GPU를 모르며, 디바이스 플러그인이 GPU를
nvidia.com/gpu자원으로 노출함을 안다. - [ ] GPU 노드에 필요한 컴포넌트 스택(드라이버·툴킷·플러그인·DCGM·GFD·MIG 매니저)과 각 역할을 제시한다.
- [ ] GPU Operator 가 이 전부를 선언적으로 자동 설치·관리함과 컨테이너화 드라이버의 이점을 안다.
- [ ] GPU 파드 스케줄링(
limits.nvidia.com/gpu정수·전체 할당·격리)과 GPU 종류별 nodeSelector를 안다. - [ ] 타임슬라이싱(격리 없는 오버서브스크립션)의 적합·한계와 MIG/MPS와의 차이(7.5)를 안다.
증상→의심: GPU 파드가 Pending → 자원 광고 안 됨(device plugin·Operator 미설치)·노드에 GPU 없음 → Operator·노드 확인. 컨테이너가 GPU 못 봄 → 컨테이너 툴킷 없음 → Operator·툴킷. 드라이버 버전 불일치 → 수동 설치 충돌 → 컨테이너화 드라이버·Operator. 작은 모델이 GPU 전체 낭비 → 기본 1/파드 → 타임슬라이싱·MIG(7.5). 타임슬라이싱 후 한 파드가 다른 파드 영향 → 격리 없음(정상) → MIG로. GPU 종류 섞여 잘못 배치 → nodeSelector 없음 → GFD 라벨로.
7.2.8 트레이드오프·대안
GPU 노드 운영 선택.
| 선택 | 누구에게 | 비고 |
|---|---|---|
| GPU Operator | 대부분·대규모·동적 클러스터 | 선언적 자동, 컨테이너화 드라이버, 표준 |
| 수동 설치 | 단일 노드·특수 환경·완전 제어 | 드라이버·툴킷·플러그인 직접, 부담·오류 |
| 매니지드 k8s GPU(클라우드) | 운영 최소화 | 클라우드가 GPU 노드풀 관리, 종속 |
| 타임슬라이싱 vs MIG/MPS(7.5) | 공유 방식 | 격리·활용 트레이드오프 |
견해: 거의 항상 GPU Operator 를 쓴다 — 수동으로 노드마다 드라이버·툴킷·플러그인을 설치하고 버전을 맞추는 것은 오류·부담이 크다. 클라우드 매니지드 k8s면 GPU 노드풀을 클라우드가 관리(Operator가 포함되기도). 공유는 워크로드로 — 개발·작은 추론은 타임슬라이싱, 멀티테넌트·격리는 MIG(7.5). AI Enterprise(7.1)면 Operator가 검증·지원.
비엔비디아 정직: k8s GPU 스케줄링은 device plugin 표준(다른 가속기도 같은 프레임워크) 위에 동작한다. GPU Operator의 강점은 NVIDIA 스택 전체 컴포넌트의 자동화·정합·컨테이너화 드라이버·NVAIE 지원이다. 클라우드 매니지드 k8s·다른 운영 방식도 대안 — 규모·운영 역량으로 판단. k8s 자체는 도구 중립.
7.2.9 흔한 함정
- device plugin/Operator 없이 GPU 기대. k8s는 GPU를 모름 → 파드 Pending. Operator(또는 플러그인) 설치.
- 컨테이너 툴킷 누락. 디바이스 플러그인이 자원을 광고해도 툴킷 없으면 컨테이너가 GPU에 접근 못 함. Operator가 함께.
- 드라이버 버전 충돌. 호스트 수동 드라이버 + 컨테이너 CUDA 버전 불일치 → 컨테이너화 드라이버·Operator로 정합.
requests만,limits누락.nvidia.com/gpu는limits에 정수로. 안 그러면 할당 안 됨.- 분수 GPU 기대. 기본은 전체 할당 — 0.5 GPU 불가. 공유는 타임슬라이싱(7.2.6)·MIG/MPS(7.4~7.5).
- 타임슬라이싱을 production 격리에. 격리 없어 한 파드가 다른 파드 영향(OOM·경합) → MIG.
- GPU 종류 무시. 이기종 클러스터(여러 GPU 모델)에서 nodeSelector 없으면 부적합 GPU에 배치 → GFD 라벨.
- 노드 추가 후 수동 구성. Operator면 자동 — 수동 가정하면 누락. Operator 신뢰.
7.2.10 연습문제
연습 1 (디바이스 플러그인). k8s에서 GPU 파드를 기동하는 전 과정을, 디바이스 플러그인의 역할을 중심으로 단계로 설명하라.
정답
① 자원 광고: NVIDIA device plugin이 노드의 GPU를 발견해 kubelet에 확장 자원 nvidia.com/gpu: N 으로 등록(k8s 기본은 GPU를 모르므로 이것이 없으면 스케줄 불가). ② 파드 요청: 파드가 resources.limits."nvidia.com/gpu": 2로 GPU 2개 요청. ③ 스케줄링: 스케줄러가 그 자원이 가용한 노드를 찾아 파드 배치. ④ 할당: device plugin이 그 노드의 특정 GPU 2개를 컨테이너에 할당(디바이스 마운트·환경변수). ⑤ 접근: 컨테이너 툴킷이 컨테이너가 그 GPU·드라이버에 접근하게 함 → 컨테이너는 할당된 GPU만 봄(다른 파드와 격리). device plugin이 없으면 ①이 안 되어 GPU 파드가 영원히 Pending. 툴킷이 없으면 ⑤가 안 되어 자원은 할당돼도 컨테이너가 GPU를 못 씀. 그래서 둘 다(+드라이버) 필요 — GPU Operator가 자동화.
연습 2 (컴포넌트 스택). GPU 파드가 Pending이거나 컨테이너가 GPU를 못 보는 두 증상 각각의 원인을, 컴포넌트 스택의 어느 층 문제인지로 설명하라.
정답
증상 1 — GPU 파드 Pending(스케줄 안 됨): 스케줄러가 배치할 nvidia.com/gpu 자원을 못 찾음 → 디바이스 플러그인 미설치/오류(자원 광고 안 됨), 또는 그 노드에 GPU가 없거나 이미 다 할당됨, 또는 GFD/nodeSelector 불일치. 진단: kubectl describe node로 nvidia.com/gpu 광고 여부, Operator 파드 상태. 해결: GPU Operator·device plugin 설치 확인. 증상 2 — 자원은 할당됐는데 컨테이너가 GPU 못 봄(nvidia-smi 실패): 디바이스 플러그인은 동작(자원 할당됨)하나 컨테이너 툴킷 누락/오류로 컨테이너 런타임이 GPU 디바이스·드라이버를 컨테이너에 노출 못 함, 또는 드라이버 문제(미설치·버전 불일치). 진단: 컨테이너 안 nvidia-smi·드라이버 로드. 해결: 컨테이너 툴킷·드라이버(GPU Operator가 둘 다 관리). 정리: Pending=상위(스케줄링/플러그인), GPU 안 보임=하위(툴킷/드라이버). Operator가 이 층들을 함께 관리해 정합을 맞춘다.
연습 3 (GPU Operator). 50개 GPU 노드 클러스터를 운영하고 수시로 노드를 추가한다. 수동 설치 대비 GPU Operator를 쓰는 이점 넷을 제시하라.
정답
① 자동·선언적 설치: Operator를 한 번 설치하면 모든 GPU 노드에 드라이버·툴킷·플러그인·DCGM·GFD를 자동 배포 — 50개 노드에 수동 설치(오류·시간)할 필요 없음. ② 노드 추가 자동 구성: 새 노드를 추가하면 Operator가 자동으로 GPU 스택을 배포해 즉시 사용 가능 — 수동이면 노드마다 반복 설치. ③ 버전 정합·수명주기: 드라이버·툴킷·플러그인의 호환 조합을 관리하고 업그레이드를 조율 — 수동이면 노드별 버전 드리프트·충돌. ④ 컨테이너화 드라이버: 드라이버를 컨테이너로 배포해 호스트 OS에 수동 드라이버 설치·관리 부담↓, 노드 OS 일관성. 추가: DCGM·GFD까지 통합 관리(7.3), NVAIE면 검증·지원(7.1). 대규모·동적 클러스터에서 수동은 비현실적 — Operator가 보일러플레이트를 없앤다.
연습 4 (전체 할당·공유). 7B 추론 모델이 GPU 메모리의 30%만 쓰는데 k8s가 GPU를 전체 할당해 낭비된다. (a) 왜 기본은 전체 할당인가, (b) 공유 옵션 셋과 격리 차이.
정답
(a) k8s 디바이스 플러그인은 GPU를 정수 단위 확장 자원으로 다루고, 기본적으로 분수 할당·하드웨어 분할을 모른다 → GPU 1개 요청 = GPU 하나 전체. GPU는 CPU처럼 임의 분할이 쉽지 않고(메모리·연산 컨텍스트), 기본 플러그인은 단순 정수 할당이라 작은 모델이 GPU를 독점·낭비. (b) 공유 옵션: ① 타임슬라이싱 — device plugin이 GPU 1개를 여러 가상 자원으로 광고(오버서브스크립션), 시간 분할 공유, 격리 없음(메모리·연산 미격리, 한 파드 OOM이 영향) → 개발·작은 추론. ② MPS(7.5) — 공간 공유(SM 나눔), 약한 격리, 작은 커널 동시 효율. ③ MIG(4.10·7.5) — 하드웨어 분할(SM·메모리·대역 격리), 강한 격리·성능 예측 → 멀티테넌트·production. 7B 30%면 MIG 슬라이스에 격리 배치하거나 타임슬라이싱(저위험)·multi-LoRA(6.4)로 활용↑. 격리 필요성으로 선택(7.5).
연습 5 (이기종 클러스터). 한 클러스터에 두 GPU 모델(구세대·신세대)이 섞여 있다. FP8이 필요한 추론을 신세대에만 스케줄하려면?
정답
GPU Feature Discovery(GFD) 가 각 노드에 GPU 속성 라벨(모델·세대·메모리·MIG 프로파일 등)을 자동 부여한다. 이를 이용해 파드에 nodeSelector(또는 nodeAffinity) 로 신세대 GPU 라벨을 지정 → 스케줄러가 그 라벨이 있는 노드에만 배치. 예: nodeSelector: { nvidia.com/gpu.product: "<신세대-모델-라벨>" }(키·값은 버전 확인). FP8은 Hopper+ 세대 종속(5.5)이라 구세대에 배치되면 가속 안 되거나 실패하므로 라벨로 강제. 더 정교하게는 세대·compute capability 라벨이나 taint/toleration으로 워크로드별 노드 분리(예: 학습은 신세대, 경량 추론은 구세대). 정리: 이기종 클러스터에서 GFD 라벨 + nodeSelector/affinity로 워크로드를 적합한 GPU에 배치 — nodeSelector 없으면 부적합 GPU에 떨어져 성능·호환 문제.
7.2.11 요약 · 다음 장
- 쿠버네티스는 기본적으로 GPU를 모른다 — 디바이스 플러그인이 GPU를
nvidia.com/gpu확장 자원으로 광고해야 스케줄 가능. 그 위에 드라이버·컨테이너 툴킷·DCGM·GFD·MIG 매니저가 필요하다. - GPU Operator 는 이 컴포넌트 스택 전부를 선언적으로 자동 설치·관리(컨테이너화 드라이버 포함) — 노드 추가 시 자동 구성. 대규모·동적 클러스터의 표준.
- 스케줄링:
limits.nvidia.com/gpu에 정수, 기본은 GPU 전체 할당·격리. GPU 종류별 배치는 GFD 라벨 + nodeSelector. - 분수·공유는 기본 불가 → 타임슬라이싱(격리 없는 오버서브스크립션, 개발·작은 추론)·MPS·MIG(7.5)로. 격리·성능 예측이 필요하면 MIG.
- 정직: Operator·플러그인·설치는 버전 의존, k8s GPU 스케줄링은 device plugin 표준, 공유 방식은 7.5에서 깊게.
다음 장: 7.3 쿠버네티스 GPU 운영 II — DCGM·모니터링·스케줄링. GPU를 스케줄했으니, 이제 관측·배치를 판다 — DCGM으로 GPU 메트릭(util·온도·전력·메모리·ECC)을 수집해 Prometheus·Grafana로 모니터링하고, GPU 활용률 기반 오토스케일(6.8)·배치(affinity·topology)·헬스를 운영으로 잇는다(실습).