AEGLOSLAB 엔비디아 기술 스택

제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는?

기본 k8s 파드가 'GPU 1개 필요'를 표현할 방법이 없음 (스케줄러가 GPU를 모름) 디바이스 플러그인(device plugin)이 필요 노드의 GPU를 발견 kubelet에 'nvidia.com/gpu' 확장 자원으로 등록 스케줄러가 그 자원을 보고 배치 컨테이너에 특정 GPU 할당

디바이스 플러그인의 역할:

노드의 GPU들 NVIDIA device plugin kubelet에 광고: 'nvidia.com/ gpu: 8' 파드: resources.limits.'nvidia.com/ gpu': 2 요청 스케줄러: 그 자원이 있는 노드 찾아 배치 device plugin: 특정 GPU 2개를 컨테이너에 할당 (환경변수·디바이스 마운트) 컨테이너: 그 GPU만 보임 (다른 파드와 격리)

하지만 디바이스 플러그인만으로는 부족하다 — 그 아래·옆에 더 필요하다.

7.2.3 GPU에 필요한 컴포넌트 스택

k8s 노드에서 GPU 컨테이너가 실행해면 여러 층이 갖춰져야 한다:

NVIDIA 드라이버: 호스트 커널 드라이버 (→ GPU 동작) container toolkit: 컨테이너가 GPU에 접근·런타임 훅 (→ 컨테이너↔GPU) device plugin: GPU를 nvidia.com/gpu 자원으로 광고 (→ 스케줄링) MIG 매니저: MIG 분할 구성, 7.5 (→ 공유) DCGM exporter: GPU 메트릭 util·온도·전력, 7.3 (→ 모니터링) GPU Feature Discovery: 노드 라벨 GPU 모델·MIG· 메모리 (→ 스케줄링 조건)

이 전부를 '모든 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 는 쿠버네티스 오퍼레이터 패턴으로 이 전부를 선언적으로 자동 설치·관리한다.

GPU Operator 설치 (한 번) 각 GPU 노드에 자동 배포 (옵션) 컨테이너화된 드라이버 호스트에 드라이버 수동 설치 없이 컨테이너 툴킷 device plugin DCGM exporter (7.3) GPU Feature Discovery MIG 매니저 (7.5) 노드를 추가하면 자동으로 GPU 준비 (드라이버· 플러그인 등 배포) 버전 업그레이드· 수명주기 관리

이점:

  • 선언적·자동: 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를 여러 "가상" 자원으로 광고해 여러 파드가 공유하게 한다(오버서브스크립션).

device plugin이 GPU 1개를 'nvidia.com/gpu: 4'처럼 광고 (replicas=4) 4개 파드가 그 GPU에 스케줄 GPU를 시간 분할로 공유 (5.12·7.5)

특성: 격리 없음(메모리·연산 격리 안 됨 — 한 파드가 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)·헬스를 운영으로 잇는다(실습).