Skip to content

Split View: NVIDIA GPU Operator 소개 — 원래 손으로 깔아야 했던 여섯 조각

✨ Learn with Quiz
|

NVIDIA GPU Operator 소개 — 원래 손으로 깔아야 했던 여섯 조각

들어가며 — GPU 노드 하나를 손으로 만든다면

CPU만 쓰는 워크로드라면 쿠버네티스 노드를 늘리는 일은 지루할 만큼 단순합니다. 노드를 붙이고, kubelet이 등록되고, 파드가 뜹니다. GPU가 끼면 이 단순함이 사라집니다. 노드에 카드가 꽂혀 있고 kubelet도 정상인데 파드는 계속 Pending이고, 노드의 allocatable 어디에도 GPU라는 단어가 없습니다.

이유는 간단합니다. 쿠버네티스는 GPU를 모릅니다. GPU를 자원으로 인식시키려면 노드마다 최소 여섯 조각을 맞춰 넣어야 하고, 그 조각들은 서로 버전이 맞아야 합니다. GPU Operator는 그 조각을 없애 주는 물건이 아니라, 그 조각들을 하나의 컨트롤러 아래로 옮겨 놓는 물건입니다. 이 차이를 이해하고 시작하는 것과 그렇지 않은 것은 장애가 났을 때 크게 갈립니다.

메트릭 이름과 설정은 2026-08-12에 공식 문서·저장소에서 확인했습니다. 버전에 따라 다를 수 있으니 사용 중인 버전에서 다시 확인하세요.

손으로 깔아야 했던 것들

Operator 없이 GPU 노드를 준비한다면 순서는 대략 이렇습니다. 각 단계가 앞 단계에 의존하기 때문에 순서를 바꿀 수 없습니다.

먼저 커널 모듈과 사용자 공간 라이브러리를 포함한 NVIDIA 드라이버를 노드에 설치합니다. 커널 버전이 올라가면 다시 빌드하거나 다시 설치해야 합니다. 다음으로 NVIDIA Container Toolkit을 설치하고 containerd나 CRI-O에 nvidia 런타임 핸들러를 등록합니다. 이것이 없으면 드라이버가 멀쩡해도 컨테이너 안에서는 장치 파일이 보이지 않습니다.

그다음이 디바이스 플러그인입니다. kubelet에 등록해서 nvidia.com/gpu라는 확장 리소스를 노드에 광고하는 역할입니다. 이 단계까지 와야 스케줄러가 GPU를 자원으로 취급합니다. 그리고 노드를 골라 스케줄하려면 어떤 카드가 몇 장 꽂혀 있는지 라벨이 필요한데, 그것이 GPU Feature Discovery이고 그 아래 깔린 범용 라벨링 도구가 Node Feature Discovery입니다. 마지막으로 온도, 전력, 오류 같은 텔레메트리를 뽑으려면 DCGM과 그 앞단의 exporter가 필요합니다.

여섯 조각을 노드 수만큼 곱하고, 여기에 커널 업데이트와 드라이버 업그레이드를 곱하면 왜 이것이 오퍼레이터로 묶였는지 알 수 있습니다.

GPU Operator가 묶는 것

공식 개요 문서는 오퍼레이터가 관리하는 구성 요소로 NVIDIA 드라이버, GPU용 쿠버네티스 디바이스 플러그인, NVIDIA Container Toolkit, 자동 노드 라벨링을 담당하는 GPU Feature Discovery, 모니터링을 위한 NVIDIA DCGM, MIG Manager, Validator, DCGM Exporter, Driver Manager 등을 나열합니다. 여기에 KubeVirt 디바이스 플러그인, vGPU Device Manager, GDS 드라이버, Kata Manager, GDRCopy 드라이버 같은 선택적 구성 요소가 붙습니다.

이 모든 것의 원하는 상태는 clusterpolicies.nvidia.com 커스텀 리소스 하나에 모입니다. 실무에서 중요한 규칙이 여기서 나옵니다. 데몬셋을 직접 고치면 오퍼레이터가 되돌립니다. 고칠 곳은 언제나 ClusterPolicy이거나 Helm 값입니다.

차트의 기본값을 보면 각 조각의 스위치가 그대로 드러납니다. 저장소의 deployments/gpu-operator/values.yaml에서 확인한 값입니다.

# deployments/gpu-operator/values.yaml (발췌, 2026-08-12 확인)
mig:
  strategy: single

driver:
  enabled: true
  kernelModuleType: 'auto'
  usePrecompiled: false

toolkit:
  enabled: true
  image: container-toolkit
  installDir: '/usr/local/nvidia'

devicePlugin:
  enabled: true
  image: k8s-device-plugin

dcgm:
  # disabled by default to use embedded nv-hostengine by exporter
  enabled: false

dcgmExporter:
  enabled: true
  enablePodLabels: false
  enablePodUID: false
  serviceMonitor:
    enabled: true
    interval: 15s

gfd:
  enabled: true

migManager:
  enabled: true

dcgm.enabled가 기본으로 꺼져 있는 것에 주의할 만합니다. 주석이 이유를 그대로 말해 줍니다. exporter에 내장된 nv-hostengine을 쓰기 때문입니다. 별도 DCGM 데몬셋을 띄우는 것은 원격 hostengine을 쓰고 싶을 때의 선택지입니다.

목록에서 눈에 덜 띄지만 장애 대응에서 가장 자주 마주치는 것이 Validator입니다. 차트에는 validator 섹션으로 들어 있고, 클러스터에서는 nvidia-operator-validator라는 이름의 파드로 돕니다. 이 파드가 하는 일은 앞 단계들이 실제로 성공했는지를 순서대로 검증하는 것입니다. 드라이버가 올라왔는지, 툴킷이 런타임에 등록되었는지, 디바이스 플러그인이 자원을 광고하는지를 차례로 확인하고, 하나라도 실패하면 뒤따르는 구성 요소가 시작 단계에서 멈춥니다. 그래서 GPU 관련 파드가 초기화 단계에 걸려 있을 때 원인은 대개 그 파드 자신이 아니라 앞 단계에 있습니다. 이 사실 하나만 알아도 진단 순서가 크게 짧아집니다.

설치는 어떻게 생겼나

공식 시작 문서가 보여 주는 설치는 Helm 두 줄입니다.

helm repo add nvidia https://helm.ngc.nvidia.com/nvidia && helm repo update

helm install --wait --generate-name \
    -n gpu-operator --create-namespace \
    nvidia/gpu-operator \
    --version=v26.3.3

이미 드라이버가 노드에 깔려 있거나 컨테이너 툴킷이 이미 구성된 클러스터라면 해당 조각을 끄고 설치합니다.

helm install --wait --generate-name \
    -n gpu-operator --create-namespace \
    nvidia/gpu-operator \
    --version=v26.3.3 \
    --set driver.enabled=false \
    --set toolkit.enabled=false

설치 후 확인은 파드 목록과 ClusterPolicy 상태, 그리고 실제 allocatable입니다.

kubectl get pods -n gpu-operator
kubectl get clusterpolicy

# 노드가 GPU를 자원으로 광고하는지 확인
kubectl get nodes -o json \
  | jq '.items[] | select(.status.allocatable["nvidia.com/gpu"] != null)
        | {node: .metadata.name, gpu: .status.allocatable["nvidia.com/gpu"]}'

마지막으로 실제 워크로드 한 개를 태워 봅니다. 공식 문서의 샘플이 그대로 쓸 만합니다.

apiVersion: v1
kind: Pod
metadata:
  name: cuda-vectoradd
spec:
  restartPolicy: OnFailure
  containers:
    - name: cuda-vectoradd
      image: 'nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0-ubuntu22.04'
      resources:
        limits:
          nvidia.com/gpu: 1

설치 전에 확인할 것

문서가 명시하는 전제 조건 중 실제로 사람을 붙잡는 것은 네 가지입니다.

첫째, 워커 노드의 OS 버전이 같아야 하거나, 다르다면 드라이버가 미리 설치되어 있어야 합니다. 오퍼레이터가 드라이버를 컨테이너로 배포하는 방식이라 커널과 OS 조합마다 이미지가 갈립니다.

둘째, 컨테이너 엔진이 CRI-O나 containerd 같은 것으로 구성되어 있어야 합니다. 툴킷이 런타임 핸들러를 등록할 대상이 필요하기 때문입니다.

셋째, 클러스터가 Pod Security Admission으로 파드 동작을 제한한다면 오퍼레이터 네임스페이스의 enforcement 정책을 privileged로 라벨링해야 합니다. 드라이버 컨테이너가 커널 모듈을 다루기 때문에 피해 갈 수 없습니다.

넷째, Node Feature Discovery가 필요합니다. 차트가 기본으로 함께 배포하지만 이미 클러스터에 NFD가 있다면 중복 설치를 피해야 합니다. 여기서 충돌이 나면 증상이 GPU와 무관해 보여서 찾는 데 오래 걸립니다.

마치며 — Operator는 설치를 없애지 않고 옮긴다

GPU Operator를 쓴다고 드라이버 버전이나 커널 호환성 문제가 사라지지는 않습니다. 사라지는 것은 노드마다 사람이 접속해서 같은 일을 반복하는 부분이고, 대신 생기는 것은 오퍼레이터라는 새 계층입니다. 문제가 나면 이제 노드가 아니라 gpu-operator 네임스페이스의 파드 로그를 먼저 봐야 합니다.

그래서 이 시리즈는 계층 순서를 따라갑니다. 다음 글에서는 그 여섯 조각 중 스케줄링을 실제로 좌우하는 디바이스 플러그인을 열어 봅니다. nvidia.com/gpu라는 이름이 어디서 만들어지고, 왜 그 숫자를 소수점으로 쪼갤 수 없는지가 다음 주제입니다.

직접 해보기

  • K8s 실습 랩 — 매니페스트를 직접 고쳐 보며 리소스 요청이 스케줄링에 어떻게 반영되는지 확인해 보세요.
  • kubectl 명령어 찾기 — 위에서 쓴 확인 명령들을 상황별로 찾아보세요.
  • Kubestronaut 퀴즈 — 오퍼레이터와 커스텀 리소스 개념을 문제로 점검해 보세요.

시리즈

참고 자료

NVIDIA GPU Operator — The Six Pieces You Used to Install by Hand

Introduction — If You Built a GPU Node by Hand

For CPU-only workloads, adding a Kubernetes node is boring in the best way. You attach the node, the kubelet registers, pods land. Add a GPU and that simplicity evaporates. The card is seated, the kubelet looks healthy, and yet pods sit in Pending forever while the word GPU appears nowhere in the node allocatable.

The reason is plain: Kubernetes does not know what a GPU is. Making one visible as a schedulable resource takes at least six pieces on every node, and those pieces have to agree on versions. The GPU Operator does not make those pieces disappear. It moves them under one controller. Understanding that difference before you start is what separates a ten-minute incident from a two-day one.

Metric names and configuration were verified against the official documentation and repositories on 2026-08-12. They can differ between releases, so check again against the version you are running.

What You Used to Install by Hand

Without the Operator, preparing a GPU node runs roughly like this. Each step depends on the one before it, so the order is not negotiable.

First you install the NVIDIA driver, including the kernel modules and the userspace libraries, on the node. Bump the kernel and you rebuild or reinstall. Next comes the NVIDIA Container Toolkit, which registers an nvidia runtime handler with containerd or CRI-O. Without it, a perfectly healthy driver still leaves the device nodes invisible inside containers.

Then the device plugin. It registers with the kubelet and advertises an extended resource named nvidia.com/gpu on the node. Only at this point does the scheduler treat a GPU as a resource at all. To then target the right nodes you need labels describing which cards are present and how many, which is GPU Feature Discovery, sitting on top of the general-purpose labeler, Node Feature Discovery. Finally, to get temperature, power, and error telemetry out, you need DCGM and an exporter in front of it.

Multiply six pieces by your node count, then multiply again by kernel updates and driver upgrades, and it is obvious why this ended up wrapped in an operator.

What the GPU Operator Bundles

The official overview lists the managed components as the NVIDIA drivers, the Kubernetes device plugin for GPUs, the NVIDIA Container Toolkit, GPU Feature Discovery for automatic node labeling, NVIDIA DCGM for monitoring, the NVIDIA MIG Manager for Kubernetes, the Validator, the NVIDIA DCGM Exporter, and the NVIDIA Driver Manager for Kubernetes. Optional pieces layer on top: the KubeVirt GPU Device Plugin, the vGPU Device Manager, the GDS Driver, the Kata Manager, and the GDRCopy Driver.

The desired state for all of it converges on one custom resource, clusterpolicies.nvidia.com. A practical rule falls out of that: edit a DaemonSet directly and the operator reverts you. The place to make changes is always the ClusterPolicy or the Helm values.

The chart defaults lay out each switch plainly. These values come from deployments/gpu-operator/values.yaml in the repository.

# deployments/gpu-operator/values.yaml (excerpt, verified 2026-08-12)
mig:
  strategy: single

driver:
  enabled: true
  kernelModuleType: 'auto'
  usePrecompiled: false

toolkit:
  enabled: true
  image: container-toolkit
  installDir: '/usr/local/nvidia'

devicePlugin:
  enabled: true
  image: k8s-device-plugin

dcgm:
  # disabled by default to use embedded nv-hostengine by exporter
  enabled: false

dcgmExporter:
  enabled: true
  enablePodLabels: false
  enablePodUID: false
  serviceMonitor:
    enabled: true
    interval: 15s

gfd:
  enabled: true

migManager:
  enabled: true

dcgm.enabled defaulting to false is worth pausing on. The comment states the reason outright: the exporter uses an embedded nv-hostengine. Running a separate DCGM DaemonSet is the option you reach for when you want a remote hostengine instead.

Less conspicuous in the list, but the piece you meet most often during incidents, is the Validator. It appears in the chart as a validator section and runs in the cluster as a pod named nvidia-operator-validator. Its job is to verify, in order, that the preceding stages actually succeeded: that the driver came up, that the toolkit registered with the runtime, that the device plugin is advertising the resource. If any one of those fails, the components behind it stall at startup. So when a GPU-related pod is stuck initializing, the cause usually lives in an earlier stage rather than in that pod itself. Knowing only this one fact shortens diagnosis considerably.

What Installation Looks Like

The official getting-started page reduces installation to two Helm commands.

helm repo add nvidia https://helm.ngc.nvidia.com/nvidia && helm repo update

helm install --wait --generate-name \
    -n gpu-operator --create-namespace \
    nvidia/gpu-operator \
    --version=v26.3.3

If drivers are already on the nodes or the container toolkit is already configured, turn those pieces off at install time.

helm install --wait --generate-name \
    -n gpu-operator --create-namespace \
    nvidia/gpu-operator \
    --version=v26.3.3 \
    --set driver.enabled=false \
    --set toolkit.enabled=false

Verification after install means the pod list, the ClusterPolicy status, and the actual allocatable.

kubectl get pods -n gpu-operator
kubectl get clusterpolicy

# Confirm the node advertises GPUs as a resource
kubectl get nodes -o json \
  | jq '.items[] | select(.status.allocatable["nvidia.com/gpu"] != null)
        | {node: .metadata.name, gpu: .status.allocatable["nvidia.com/gpu"]}'

Finally, run one real workload through it. The sample from the official docs is fine as is.

apiVersion: v1
kind: Pod
metadata:
  name: cuda-vectoradd
spec:
  restartPolicy: OnFailure
  containers:
    - name: cuda-vectoradd
      image: 'nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0-ubuntu22.04'
      resources:
        limits:
          nvidia.com/gpu: 1

What to Check Before You Install

Of the prerequisites the docs list, four are the ones that actually trip people up.

First, worker nodes need to run the same OS version, or have drivers pre-installed if they do not. The operator ships drivers as containers, so images are split by kernel and OS combination.

Second, nodes must be configured with a container engine such as CRI-O or containerd. The toolkit needs something to register a runtime handler with.

Third, if your cluster uses Pod Security Admission to restrict pod behavior, you must label the operator namespace so the enforcement policy is privileged. The driver container touches kernel modules, so there is no way around it.

Fourth, Node Feature Discovery is required. The chart deploys it by default, but if NFD already exists in your cluster you need to avoid installing it twice. Conflicts here produce symptoms that look nothing like a GPU problem, which is why they take so long to find.

Closing — The Operator Relocates the Install, It Does Not Remove It

Adopting the GPU Operator does not make driver versions or kernel compatibility go away. What goes away is a human SSHing into every node to repeat the same work. What appears in its place is a new layer. When something breaks now, you read pod logs in the gpu-operator namespace before you read the node.

So this series walks the layers in order. The next post opens up the one piece that actually governs scheduling: the device plugin. Where the name nvidia.com/gpu comes from, and why you cannot split that number into a fraction, is the subject.

Try It Yourself

  • K8s Lab — edit manifests directly and watch how resource requests change scheduling.
  • kubectl Command Finder — look up the verification commands above by situation.
  • Kubestronaut Quiz — test your grip on operators and custom resources.

Series

References