본문 바로가기
삵
AI

DCGM Exporter로 쿠버네티스 GPU 모니터링

아아주라·2026년 11월 3일·조회 0

GPU 노드를 쿠버네티스에 붙여 놓고 나면 다음 질문은 항상 같다. 저 비싼 카드가 지금 얼마나 일하고 있나, 어느 파드가 메모리를 다 먹고 있나, 혹시 조용히 맛이 가고 있는 건 아닌가. CPU야 kubelet이 알아서 metrics를 뱉지만 GPU 내부는 드라이버 안쪽이라 밖에서는 안 보인다. 그래서 NVIDIA가 내놓은 DCGM Exporter를 하나 깔아 두는 게 사실상 표준이 됐다.

결론부터 말하자면, GPU Operator를 Helm으로 올리면 DCGM Exporter DaemonSet이 기본으로 따라오고, 포트 9400 /metrics에서 사용률, 온도, 프레임버퍼 메모리, 전력, XID 에러를 Prometheus 포맷으로 꺼내 쓸 수 있다. 4.8대에서는 파드별 매핑을 담당하는 PodMapper와 fallen-off-bus 같은 GPU 전역 헬스 사건까지 지표로 올라온다.

DCGM과 Exporter가 하는 일

DCGM(Data Center GPU Manager)은 NVIDIA가 만든 데이터센터 GPU 관리 라이브러리다. 드라이버에서 텔레메트리를 읽고, 헬스 체크와 진단을 돌리고, 카드별 상태를 들고 있는다. 사람이 직접 쓰기보다는 다른 도구가 호출하는 밑단 엔진이라고 보면 된다.

DCGM Exporter는 그 DCGM을 물고 앉아서, 읽어 온 값을 Prometheus가 긁어 갈 수 있는 텍스트 포맷으로 바꿔 포트 9400에 올려 주는 작은 프로그램이다. Go로 짜여 있고 컨테이너 이미지로 배포된다. 지표 이름은 DCGM 필드 이름을 거의 그대로 쓴다. 예를 들어 GPU 사용률은 DCGM_FI_DEV_GPU_UTIL, 코어 온도는 DCGM_FI_DEV_GPU_TEMP 식이다.

여기서 핵심 용어 하나. XID는 NVIDIA 드라이버가 뱉는 에러 코드다. ECC 메모리 오류, Xid 79번으로 유명한 fallen-off-bus(카드가 PCIe 버스에서 떨어져 나가 응답이 끊긴 상태), 전력 이상 같은 사건에 번호가 매겨져 있다. GPU가 죽는 전조는 대개 XID로 먼저 나타나기 때문에, 모니터링에서 이 값을 놓치면 안 된다.

GPU Operator로 DaemonSet 올리기

노드마다 드라이버, container toolkit, device plugin, 그리고 DCGM Exporter를 각각 수동으로 맞추는 건 고생길이다. GPU Operator가 이 묶음을 한 번에 깐다. DCGM Exporter는 dcgmExporter.enabled가 기본 true라 따로 켤 필요도 없다.

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

helm install gpu-operator -n gpu-operator --create-namespace \
  nvidia/gpu-operator

설치가 끝나면 GPU가 달린 노드마다 Exporter 파드가 하나씩 뜬다. DaemonSet이라 노드 수만큼 자동으로 스케줄된다.

$ kubectl -n gpu-operator get pods -l app=nvidia-dcgm-exporter
NAME                          READY   STATUS    RESTARTS   AGE
nvidia-dcgm-exporter-7fx9k    1/1     Running   0          3m
nvidia-dcgm-exporter-q2llm    1/1     Running   0          3m

값이 제대로 나오는지는 파드 안에서 직접 긁어 보는 게 제일 빠르다. 여기서 한 번 걸리는 지점이 있는데, Service가 아니라 파드 IP 9400으로 때려야 노드별 값이 섞이지 않는다.

$ kubectl -n gpu-operator exec -it nvidia-dcgm-exporter-7fx9k -- \
    curl -s localhost:9400/metrics | grep DCGM_FI_DEV_GPU_UTIL
# HELP DCGM_FI_DEV_GPU_UTIL GPU utilization (in %).
# TYPE DCGM_FI_DEV_GPU_UTIL gauge
DCGM_FI_DEV_GPU_UTIL{gpu="0",UUID="GPU-a1b2...",device="nvidia0",modelName="NVIDIA A100-SXM4-40GB",Hostname="gpu-node-1"} 73

버전 번호는 저장소 상태에 따라 다를 수 있다. 4.8대 Exporter를 쓰려면 GPU Operator 값에서 이미지 태그를 명시하거나, GPU Operator 자체를 4.8 Exporter가 포함된 릴리스로 맞춘다.

PodMapper가 지표에 파드 이름을 붙인다

기본 지표에는 gpu="0", UUID 같은 하드웨어 라벨만 달린다. 운영에서 정작 궁금한 건 "이 GPU를 지금 어느 파드가 쓰고 있나"인데, 그 연결을 해 주는 게 PodMapper다.

PodMapper는 kubelet의 pod-resources 소켓(/var/lib/kubelet/pod-resources)을 읽어 GPU UUID와 파드를 짝지은 뒤, 지표에 pod, namespace, container 라벨을 추가한다. GPU Operator로 깔면 이 마운트와 --kubernetes=true 설정이 이미 잡혀 있다. 4.8.2에서는 informer 캐싱이 들어가, 매핑을 매번 API로 조회하지 않고 캐시에서 끌어오도록 바뀌었다. 파드가 많은 노드에서 조회 부하가 줄어든다.

라벨이 붙은 지표는 이렇게 나온다.

DCGM_FI_DEV_FB_USED{gpu="0",UUID="GPU-a1b2...",
  pod="llm-serving-0",namespace="inference",container="vllm",
  Hostname="gpu-node-1"} 38204

이제 "inference 네임스페이스의 llm-serving 파드가 프레임버퍼 38GB를 쓰고 있다"가 한눈에 읽힌다. PromQL로 네임스페이스별 GPU 메모리 합계를 뽑는 것도 바로 된다.

sum by (namespace) (DCGM_FI_DEV_FB_USED)

Prometheus가 긁어 가게 연결

Prometheus Operator(kube-prometheus-stack)를 쓴다면 ServiceMonitor로 잡는 게 깔끔하다. GPU Operator가 만든 Service에 라벨 셀렉터를 맞춘다.

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: dcgm-exporter
  namespace: gpu-operator
  labels:
    release: kube-prometheus-stack
spec:
  selector:
    matchLabels:
      app: nvidia-dcgm-exporter
  endpoints:
    - port: gpu-metrics
      interval: 15s

여기서 자주 막히는 부분이 labels.release다. Prometheus Operator는 자기 serviceMonitorSelector에 맞는 ServiceMonitor만 집어 가는데, 이 라벨이 Helm 릴리스 이름과 안 맞으면 타깃에 아예 안 올라온다. 긁히는지는 Prometheus UI의 Status > Targets에서 dcgm-exporter 타깃이 UP인지로 확인한다.

Operator 없이 바닐라 Prometheus라면 kubernetes_sd_configs로 파드를 디스커버리하고 포트 9400만 남기면 된다.

Grafana 대시보드와 XID 헬스 경보

시각화는 바퀴를 새로 만들 필요가 없다. NVIDIA가 올려 둔 공식 대시보드가 Grafana.com에 ID 12239로 있다. Grafana에서 Import에 12239를 넣고 Prometheus 데이터소스를 고르면 사용률, 온도, 전력, 프레임버퍼 패널이 바로 뜬다.

진짜 가치는 경보 쪽에 있다. 4.8대에서 GPU 전역 헬스 사건, 그중에서도 fallen-off-bus 같은 치명적 XID가 지표로 올라오고, 4.8.3부터는 XID 누적 카운트와 헬스 심각도, 카테고리 메타데이터가 추가됐다. 마지막으로 발생한 XID 번호는 DCGM_FI_DEV_XID_ERRORS 게이지로 노출된다.

Xid 79(fallen-off-bus)는 카드가 버스에서 떨어진 상태라 사실상 노드 격리 대상이다. Prometheus 경보 규칙으로 바로 잡는다.

groups:
  - name: gpu-health
    rules:
      - alert: GpuFallenOffBus
        expr: DCGM_FI_DEV_XID_ERRORS == 79
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "GPU fallen off bus (Xid 79) on {{ $labels.Hostname }}"
      - alert: GpuXidError
        expr: DCGM_FI_DEV_XID_ERRORS > 0
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "XID {{ $value }} on {{ $labels.Hostname }} gpu {{ $labels.gpu }}"
      - alert: GpuTempHigh
        expr: DCGM_FI_DEV_GPU_TEMP > 85
        for: 5m
        labels:
          severity: warning

온도 임계값은 카드마다 다르다. A100, H100 계열은 85도 부근을 경고선으로 잡고, slowdown 임계는 데이터시트 값을 확인해서 맞춘다. 숫자는 환경에 따라 다르니 자기 카드 사양을 기준으로 조정한다.

경보가 울리기 시작하면 다음 단계는 노드를 어떻게 처리하느냐다. fallen-off-bus는 보통 재부팅이나 하드웨어 교체 전까지 복구가 안 되니, 경보에서 바로 kubectl cordon으로 스케줄을 막고 운영팀에 넘기는 식으로 Alertmanager 라우팅을 짜 두면 손이 덜 간다. 자동 cordon까지 엮을지는 클러스터 정책에 따라 정하면 된다.

자주 묻는 질문

DCGM Exporter를 GPU Operator 없이 단독으로 쓸 수 있나

쓸 수 있다. 공식 Helm 차트나 컨테이너 이미지로 DaemonSet만 따로 배포하면 된다. 다만 드라이버, container toolkit, device plugin을 직접 맞춰야 하므로 손이 많이 간다. 새로 구성한다면 GPU Operator가 이 묶음을 한 번에 깔아 주므로 더 편하다.

지표에 pod, namespace 라벨이 안 붙는다

PodMapper가 동작하지 않는 경우다. Exporter가 kubelet pod-resources 소켓(/var/lib/kubelet/pod-resources)을 마운트하고 --kubernetes=true로 떠 있는지 확인한다. GPU Operator로 배포하면 기본으로 잡혀 있지만, 수동 배포 시에는 이 마운트와 설정을 직접 넣어야 한다.

XID 에러 번호는 무슨 뜻인가

NVIDIA 드라이버가 뱉는 에러 코드다. 번호마다 원인이 다르며 Xid 79는 fallen-off-bus(카드가 PCIe 버스에서 떨어져 응답 끊김), 48은 더블 비트 ECC 오류 식이다. DCGM_FI_DEV_XID_ERRORS 게이지에 마지막 발생 번호가 담긴다. 번호별 의미는 NVIDIA XID 에러 문서를 참고한다.

Prometheus Targets에 dcgm-exporter가 안 보인다

ServiceMonitor의 라벨이 Prometheus Operator의 serviceMonitorSelector와 맞지 않을 때 흔하다. kube-prometheus-stack이면 보통 release 라벨을 Helm 릴리스 이름에 맞춰야 한다. 셀렉터가 맞는지, Service 포트 이름이 ServiceMonitor endpoints의 port와 일치하는지 확인한다.

Grafana 대시보드를 직접 만들어야 하나

NVIDIA 공식 대시보드가 Grafana.com에 ID 12239로 등록돼 있다. Grafana Import에서 12239를 입력하고 Prometheus 데이터소스를 지정하면 사용률, 온도, 전력, 메모리 패널이 바로 구성된다. 필요한 패널만 복제해 커스터마이즈하면 된다.

관련 글

댓글 0

로그인 후 댓글을 남길 수 있습니다.

아직 댓글이 없습니다.