Published on

Kubernetes에서 GPU 사용하기

Authors
  • avatar
    Name
    Jay
    Twitter

container에서 GPU 사용하도록 설정

digialocean에서 설명된 방법으로 Docker를 Ubuntu20.04에 설치를 하였다.

sudo apt install -y apt-transport-https ca-certificates curl software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
apt-cache policy docker-ce
sudo apt install -y docker-ce

이제 gpus를 사용해서 docker container를 아래처럼 실행한다.

sudo docker run -it --runtime=nvidia --gpus all python:3.9 bash

하지만 아래와 같은 에러 메세지와 함께 nvidia로 설정하여 실행할 수가 없다.

docker: Error response from daemon: unknown or invalid runtime name: nvidia.
See 'docker run --help'

Container에서 nvida driver를 사용할 수 있도록 nvidia-container-toolkit을 설치해야 한다. 문서에 나온 것처럼 아래와 같이 설치를 한다.

curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
  && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
    sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
    sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list \
  && \
    sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker

docker config 파일이 아래처럼 nvidia-container-runtime을 사용하도록 설정된 것을 확인할 수 있다.

$ sudo cat /etc/docker/daemon.json
{
  "runtimes": {
      "nvidia": {
          "args": [],
          "path": "nvidia-container-runtime"
      }
  }

해당 config가 적용될 수 있도록 docker daemon을 재시작한다.

sudo systemctl restart docker

이제 runtime option을 nvidia로 설정을 해도 정상적으로 실행이 될 수 있다.

sudo docker run -it --runtime=nvidia --gpus all python:3.9 bash

pytorch 사용해보기

이제 pytorch를 containerization을 해서 사용해본다. 먼저 nvidia-smi로 CUDA version을 확인한다.

$ nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 470.199.02   Driver Version: 470.199.02   CUDA Version: 11.4     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  Tesla T4            On   | 00000000:00:05.0 Off |                  Off |
| N/A   27C    P8     8W /  70W |      0MiB / 16127MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

위에서처럼 CUDA version이 11.4라고 하면, torch를 11.4를 사용할 수 있도록 설치를 한다. 먼저 python 3.9 image로 container를 실행하고,

sudo docker run -it --runtime=nvidia --gpus all python:3.9 bash

원하는 버전의 package들을 설치한다.

pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 torchaudio==0.12.1+cu113 -f https://download.pytorch.org/whl/torch_stable.html

이제 torch가 설치가 완료되면 python interpreter를 실행해서 torch가 사용하는 CUDA version을 아래와 같이 확인한다. 아래처럼 11.3 값을 리턴하는 것을 확인할 수 있다.

>>> import torch
>>> torch.version.cuda
'11.3'

그리고 cuda를 사용가능한지 확인해보면 True가 리턴되는 것을 확인 할 수 있다.

>>> torch.cuda.is_available()
True

CUDA version이 상위 버전이면 아래와 같은 에러 메세지가 발생한다.

import torch
>>> torch.cuda.is_available()
/usr/local/lib/python3.9/site-packages/torch/cuda/__init__.py:138: UserWarning: CUDA initialization: The NVIDIA driver on your system is too old (found version 11040). Please update your GPU driver by downloading and installing a new version from the URL: http://www.nvidia.com/Download/index.aspx Alternatively, go to: https://pytorch.org to install a PyTorch version that has been compiled with your version of the CUDA driver. (Triggered internally at ../c10/cuda/CUDAFunctions.cpp:108.)
  return torch._C._cuda_getDeviceCount() > 0
False

Kubernetes에서 torch application을 실행하기

이제 kubernetes에서 pod로 container가 실행할 때 kubelet이 GPU를 사용하도록 설정을 해야 한다. Kubernetes에서는 device plugin를 제공하여 kubelet이 특정 device를 인지하고 사용할 수 있도록 한다. 따라서 NVIDIA에서 k8s-device-plugin을 제공한다.

device plugin을 DaemonSet object로 Host의 /var/lib/kubelet/device-plugins 경로에 mount하여 설정할 수 있다. 설치하는 DaemonSet의 manifest 파일을 확인하면 아래와 같다.

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nvidia-device-plugin-daemonset
  namespace: kube-system
spec:
  selector:
    matchLabels:
      name: nvidia-device-plugin-ds
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        name: nvidia-device-plugin-ds
    spec:
      tolerations:
        - key: nvidia.com/gpu
          operator: Exists
          effect: NoSchedule
      # Mark this pod as a critical add-on; when enabled, the critical add-on
      # scheduler reserves resources for critical add-on pods so that they can
      # be rescheduled after a failure.
      # See https://kubernetes.io/docs/tasks/administer-cluster/guaranteed-scheduling-critical-addon-pods/
      priorityClassName: 'system-node-critical'
      containers:
        - image: nvcr.io/nvidia/k8s-device-plugin:v0.14.1
          name: nvidia-device-plugin-ctr
          env:
            - name: FAIL_ON_INIT_ERROR
              value: 'false'
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop: ['ALL']
          volumeMounts:
            - name: device-plugin
              mountPath: /var/lib/kubelet/device-plugins
      volumes:
        - name: device-plugin
          hostPath:
            path: /var/lib/kubelet/device-plugins

테스트하는 kubernetes cluster의 container runtime이 containerd로 되어 있기 때문에, Docker 예제에서 한것처럼 문서를 따라서 아래와 같이 설정을 해준다.

sudo nvidia-ctk runtime configure --runtime=containerd
sudo systemctl restart containerd

그리고 마지막으로 테스트로 해당 Pod를 띄우면

$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: gpu-pod
spec:
  restartPolicy: Never
  containers:
    - name: cuda-container
      image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda10.2
      resources:
        limits:
          nvidia.com/gpu: 1 # requesting 1 GPU
  tolerations:
  - key: nvidia.com/gpu
    operator: Exists
    effect: NoSchedule
EOF

아래처럼 정상적으로 테스트를 통과한 Pod 로그를 확인할 수 있다.

Test PASSED
Done

이제 kubernetes에서 정상적으로 셋팅이 되었으니, GPU를 사용하여 torch application을 실행할 수 있다. 그런데 여기서 주의할 것은 kubeblet이 GPU hardware를 사용하도록 container을 실행할 때 아래와 같이 resource request/limit이 없으면 기본으로 CPU를 사용하도록 한다.

resources:
  limits:
    nvidia.com/gpu: 1 # requesting 1 GPU