전공영역 공부 기록

kubernetes pod가 GPU를 사용하는 원리 그리고 쿠버네티스 설정

악분 2025. 6. 22. 19:33
반응형

이 글은 kubernetes에서 pod가 GPU를 사용하는 원리를 설명합니다. 그리고 pod가 GPU를 사용하기 위한 쿠버네티스 설정을 다룹니다.

 

 

1. pod가 GPU를 사용 = 프로세스가 GPU를 사용

kubernetes에서 GPU를 사용하려면 GPU operator, Container Toolkit 등 많은 컴퍼넌트들이 등장장하여, "왜 pod가 GPU를 사용하는데 이렇게 많은 컴퍼넌트가 필요하지?"라는 의문을 가지게 됩니다.'

 

제 생각에는 pod = 프로세스라는 것을 이해하면 컴퍼넌트가 많이 필요한지 이해하기 쉽다고 생각합니다.

 

pod는 결국 운영체제 입장에서 프로세스이기 때문에, pod가 GPU를 사용한다는 것은 프로세스가 GPU를 사용한다는 것과 같습니다. 결국, pod가 GPU를 사용하는 원리는 프로세스가 GPU를 사용하는 원리와 동일합니다. 복잡해 보이는 Kubernetes GPU 설정도 결국 이 기본 원리를 컨테이너 환경에 적용한 것에 불과합니다.

 

2. 프로세스가 GPU를 사용하는 방법

안타깝게도 프로세스는 GPU를 바로 사용하지 못하여 몇가지 설정이 필요합니다.

 

2.1 GPU 드라이버 설치

첫번째 설정은 GPU 드라이버 설치입니다. GPU 드라이버는 운영체제가 GPU를 제어하기 위한 필수 소프트웨어 입니다.

 

운영체제는 CPU, 메모리, 디스크 같은 표준 하드웨어 제어할 수 있지만 GPU는 제어하지 못합니다. GPU는 CPU와 메모리처럼 필수 하드웨어가 아니기도 하며, 모든 GPU 제조사에 맞춰 운영체제를 개발하는 것은 부담스럽니다. 따라서 운영체제가 직접 GPU를 제어하는 것이 아니라 GPU 드라이버에게 GPU제어를 위임합니다.

 

GPU 드라이버는 운영체제의 GPU 사용 요청을 GPU가 이해할 수 있는 명령어로 변환하는 역할을 합니다. 그 이외에 GPU 메모리 관리 및 할당, 전력 관리, 온도 제어 등의 역할을 수행합니다.

 

GPU 드라이버 설치는 GPU벤더사 홈페이지를 참고해야 합니다. 아래 예제는 리눅스 운영체제에서 nvidia GPU드라이버 설치를 확인한 것입니다.

lsmod | grep nvidia

 

 

nvidia GPU 드라이버는 아래 경로에 위치합니다. ko확장자 드라이버파일은 커널모듈에서 실행됩니다.

sudo find /lib/modules/$(uname -r) -type f -name "nvidia*.ko"

 

 

2.2 GPU 디바이스 파일

GPU 드라이버가 설치되었으면 GPU가 운영체제에 잘 인식되는지 확인해야 합니다. 리눅스 운영체제 기준으로 GPU가 잘 인식되면, /dev디렉터리에 GPU 디바이스 파일이 있습니다. 운영체제는 이 디바이스 파일을 사용하여 GPU에 접근합니다.

 

리눅스는 모든 것을 파일로 관리하기 때문에 하드웨어 장비 GPU도 파일로 관리됩니다. 이 파일을 디바이스 파일이라고 합니다. 아래 예제는 nvidia GPU가 장착된 인스턴스에서 디바이스 파일을 확인했습니다.

# nvidia GPU 디바이스파일 확인
ls -la /dev/nvidia*

 

 

3. 옵션이지만 필수인 GPU 라이브러리

3.1 GPU라이브러리가 있으면 좋은 이유(syscall)

GPU 라이브러리는 필수는 아니지만 개발하는 과정에 필수로 있어야 합니다. GPU라이브러리가 없으면 개발자는 아래 그림처럼 GPU syscall을 일일이 코드단에서 호출해야 합니다.

 

syscall이 필요한 이유는 GPU 드라이버가 커널모드에서 동작하기 때문입니다. 유저모드에서 실행되는 애플리케이션 또는 프로세스는 커널모드에 접근할 수 없기 때문에 syscall을 통해 GPU사용을 요청합니다.

 

GPU 라이브러리를 사용하면 개발자는 syscall 호출하지 않아도 GPU를 제어하는 코드를 쉽게 작성할 수 있습니다. GPU라이브러리가 내부적으로 syscall을 호출하기 때문입니다.




3.2 GPU 라이브러리를 한번 더 감싼 라이브러리

pytorch, tensorflow 등의 라이브러리는 내부적으로 GPU를 사용할 때 GPU 라이브러리를 사용합니다. 그리고 GPU 라이브러리를 쉽게 사용할 수 있도록 더 쉬운 방법을 제공합니다.

 

4. 그러면, pod에서 GPU를 사용하려면?

4.1 pod에서 GPU를 사용하려면?

pod에서 GPU를 사용하려면 2가지 설정이 필요합니다.

  1. 쿠버네티스 설정
  2. OS 설정

 

OS설정은 지금까지 살펴봤던 프로세스가 GPU를 사용하는 방법입니다. 즉, OS설정은 GPU 드라이버와 GPU device 파일입니다.

쿠버네티스 설정은 device plugin이 필요합니다. 쿠버네티스에서는 노드에 GPU가 있다는 것을 모릅니다. device plugin은 쿠버네티스에게 GPU 리소스의 존재를 알리고 관리를 위임받는 역할을 합니다. 관리는 당연히 kubelet이 담당합니다.

 

4.2 device plugin 설치

device plugin 설치는 벤더사 홈페이지를 참고해야 합니다. nvidia는 nvidia device plugin을 제공하고 helm chart로 설치할 수 있습니다.

 

helm chart 설치 예입니다.

helm repo add nvdp https://nvidia.github.io/k8s-device-plugin
helm repo update
helm upgrade -i nvdp nvdp/nvidia-device-plugin \
  --namespace nvidia-device-plugin \
  --create-namespace

 

device plugin은 daemonset으로 실행됩니다.

 

4.3 OS 설정

OS 설정은 GPU 드라이버 설치와 GPU 라이브러리 설치, GPU디바이스 파일이 있는지 확인하는 것입니다. pod에서 실행되는 컨테이너는 결국 프로세스이기 때문에 프로세스가 GPU를 실행하는 원리가 그대로 적용됩니다.

 

여기서 한가지 더 설정이 필요합니다. 바로 GPU 라이브러리와 GPU 디바이스 파일을 컨테이너에 마운트해야 합니다. pod에서 실행되는 컨테이너는 호스트의 커널을 사용하지만 애플리케이션 실행환경 즉 유저모드는 격리되서 실행됩니다. 따라서 커널모드로 실행되는 GPU 드라이버는 컨테이너가 그대로 사용할 수 있지만, 유저모드로 실행되는 GPU 라이브러리와 GPU 디바이스 파일은 격리되어 있어서 컨테이너가 이 파일들을 접근하지 못합니다.

 

이러한 이유로 컨테이너에 GPU 라이브러리와 GPU 디바이스 파일을 마운트해서 사용합니다. 아래는 docker 컨테이너를 실행할 때 파일을 마운트한 예제입니다. /dev/에 있는 nvidia 디바이스 파일과 nvidia 라이브러리 파일을 마운트했습니다.

docker run -it \
  --device=/dev/nvidia0:/dev/nvidia0 \
  --device=/dev/nvidiactl:/dev/nvidiactl \
  --device=/dev/nvidia-uvm:/dev/nvidia-uvm \
  --device=/dev/nvidia-uvm-tools:/dev/nvidia-uvm-tools \
  --volume=/usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1:/usr/lib/x86_64-linux-gnu/libnvidia-ml.so.1:ro \
  --volume=/usr/bin/nvidia-smi:/usr/bin/nvidia-smi:ro \
  my-gpu-app:latest

 

4.4 Container Toolkit

컨테이너가 GPU를 사용할 때마다 마운트를 해줘야하는 번거러움이 있는데, 이 번거러움을 없애는 방법이 있습니다. 바로 Container Toolkit을 사용하는 것입니다.

 

Container Toolkit은 컨테이너가 생성되고 실행되기전에 prestart hook을 걸어 GPU 라이브러리, GPU 드라이버 파일을 컨테이너에 주입합니다. 파일을 주입하기 때문에 pod의 마운트과정이 필요없습니다. 아래는 nvidia Container Toolkit아키텍처입니다.

참고자료: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/arch-overview.html

 



 

containerd기준 config.toml파일을 보면 컨테이너 실행 바이너리가 runc가 아니라 nvidia-container-runtime로 되어 있습니다.

 

injection하는 과정을 직접 보고 싶다면, nvidia-container-runtime 설정파일에서 로그위치를 설정하면 됩니다.

$ vi /etc/nvidia-container-runtime/config.toml
[nvidia-container-runtime]
debug = "/var/log/nvidia-container-runtime.log"
log-level = "debug"

 

로그파일을 보면 prehook, injection 과정이 보입니다. injection은 nvidia-ctk이 담당합니다.

cat /var/log/nvidia-container-runtime.log

 

 

NVIDIA container toolkit은 아래 공식문서를 참고하시면 됩니다.

 

5. 정리

쿠버네티스에서 pod가 GPU를 사용하기 위해서는 3가지 설정이 필요했습니다.

  1. GPU device plugin 설치: pod에서 resources.request.gpu, resources.limit.gpu을 사용하기 위해서 설치
  2. pod에 GPU 디바이스 파일 마운트: pod에서 GPU를 접근하기 위해 필요
  3. pod에 GPU 라이브러리 파일 마운트: pod에서 GPU 라이브러리를 사용하기 위해 필요

 

6. GPU관련 설치를 단순화한 NVIDIA GPU operator

NVIDIA GPU operator는 쿠버네티스에서 NVIDIA GPU를 사용하기 위한 3가지 설정을 쉽게 해줍니다. 쿠버네티스 operator패턴으로 NVIDIA GPU 드라이버, NVIDIA device plugin, NVIDIA container toolkit을 설치해줍니다.

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 \
     --set driver.enabled=true \
     --set toolkit.enabled=true

 

7. 이미 GPU drivder와 container toolkit가 설치되어 있는 EKS 가속화 AMI

EKS를 사용하면 이미 GPU 드라이버, container toolkit이 설치된 AMI를 제공합니다. 이를 EKS optimized AMI, 한국말로 가속화 이미지라고 합니다.

 

아쉽게도 device plugin은 직접 설치해야 합니다.

 

참고자료

반응형