LabHub

Rootless Podman 운영 · CDI 로 GPU 붙이기 · 이론

CDI 스펙 읽고 쓰기

LabHub 에서 이어서 보기

한 줄 요약

CDI 는 "이 장치를 컨테이너에 넣으려면 무엇을 해 줘야 하는가"를 YAML 로 적어 둔 명세다. 런타임 훅이라는 블랙박스를 표준 파일로 바꿨다.

왜 이게 필요했나

예전에 도커에서 GPU 를 쓰려면 nvidia-container-runtime 이라는 런타임 훅을 끼워야 했다. 컨테이너 시작 직전에 그 훅이 실행되어 드라이버 라이브러리를 마운트하고 장치 노드를 추가했다. 동작은 했지만 문제가 있었다.

CDI 는 이것을 선언적 명세로 바꿨다. /etc/cdi/*.yaml 에 "이 장치 이름을 요청하면 이런 디바이스 노드와 이런 마운트와 이런 환경변수를 추가하라" 를 적어 두면, CDI 를 지원하는 런타임(podman, containerd, CRI-O)이 그대로 실행한다.

어떻게 동작하나

스펙 구조

cdiVersion: "0.6.0"kind: nvidia.com/gpudevices:  - name: "0"    containerEdits:      deviceNodes:        - path: /dev/nvidia0        - path: /dev/nvidiactl        - path: /dev/nvidia-uvm      mounts:        - hostPath: /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.550.90.07          containerPath: /usr/lib/x86_64-linux-gnu/libnvidia-ml.so.550.90.07          options: ["ro", "nosuid", "nodev", "bind"]      env:        - NVIDIA_VISIBLE_DEVICES=0      hooks:        - hookName: createContainer          path: /usr/bin/nvidia-ctk          args: ["nvidia-ctk", "hook", "update-ldcache"]  - name: all    containerEdits:      deviceNodes:        - path: /dev/nvidia0        - path: /dev/nvidiactl

핵심 규칙들.

실제 사용

# 스펙 생성 (실제 GPU 가 있는 호스트에서)sudo nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml# 등록된 장치 확인nvidia-ctk cdi list# nvidia.com/gpu=0# nvidia.com/gpu=all# 컨테이너에서 사용podman run --rm --device nvidia.com/gpu=all nvidia/cuda:12.4.1-base nvidia-smi

docker 의 --gpus all 에 대응하는 것이 --device nvidia.com/gpu=all 이다. 최신 podman 은 --gpus 도 호환 플래그로 받지만 CDI 표기가 정식이다.

rootless 에서도 GPU 가 된다. GPU 드라이버는 커널 공간에서 동작하므로 컨테이너의 권한 수준과 성능은 무관하다. 시스템 전역 /etc/cdi/nvidia.yaml 을 읽을 수 있으면 그대로 쓰고, 안 되면 사용자 공간에 스펙을 생성해 그 디렉터리를 지정하면 된다.

containerd 쪽 등록

쿠버네티스에서는 containerd 가 CDI 를 읽는다. config.toml 에 활성화 설정이 필요하고, 런타임을 별도로 등록하는 옛 방식도 여전히 쓰인다.

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia]  runtime_type = "io.containerd.runc.v2"[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia.options]  BinaryName = "/usr/bin/nvidia-container-runtime"  SystemdCgroup = true

그리고 그 런타임을 쓰는 워크로드는 RuntimeClass 로 선택한다.

apiVersion: node.k8s.io/v1kind: RuntimeClassmetadata:  name: nvidiahandler: nvidia

default_runtime_name 을 nvidia 로 바꾸지 않는 것이 요령이다. 그러면 GPU 를 안 쓰는 파드까지 그 런타임을 거치게 된다. RuntimeClass 로 필요한 워크로드만 지정하는 편이 안전하다.

현장에서 만나는 모습

드라이버 업데이트 후 GPU 가 안 잡힌다. 십중팔구 CDI 스펙 재생성(nvidia-ctk cdi generate)을 잊은 것이다. 스펙에는 라이브러리 파일의 버전이 박힌 경로가 들어 있어서, 드라이버가 올라가면 그 경로가 사라진다.

컨테이너 안에서 nvidia-smi 는 되는데 CUDA 프로그램이 실패한다. 필요한 라이브러리 중 일부만 마운트된 경우다. 스펙의 mounts 목록을 확인해야 한다.

다음 실습에서 할 것

/etc/cdi/ 에 CDI 스펙을 직접 작성한다. 실제 GPU 는 없으므로 스펙의 문법과 배치, 그리고 --device 인자 형식을 채점한다. 현장에서 실수가 나는 지점이 정확히 거기다.