Minikube GPU Tutorial

 

1. 개요

쿠버네티스 환경에서 pod 과 같은 쿠베 리소스가 노드의 GPU 를 사용하기 위해서는 설정해주어야 하는 몇 가지 작업이 있습니다. 본 문서에서는 특별히 Minikube 환경에서 GPU 를 사용하기 위해서 필요한 설정들을 순서대로 설명합니다. 일반적인 쿠버네티스 환경에서는 설정 방법이 다소 다른 것으로 알고 있으며, 이에 대해서는 추후 다루도록 하겠습니다.

2. 서론

Minikube 에서 NVDIA GPU 지원 방식에 대한 공식 문서를 보면, 안타깝게도 kvm2 와 none 를 제외한 driver 옵션들은 GPU passthrouh 를 지원하지 않기 때문에 macOS 와 Windows 에서는 minikube 로 gpu 사용은 할 수 없다고 합니다.

따라서 본 문서에서는 Ubuntu 16.04 환경을 기준으로 하며, --driver=kvm2 옵션은 추가적인 설정이 다소 필요하기에, 보다 쉬운 방법인 --driver=none 옵션으로 Minikube 를 생성하여 호스트의 GPU 를 사용하는 방법을 다루었습니다.

참고한 자료는 다음과 같습니다.

  • https://minikube.sigs.k8s.io/docs/tutorials/nvidia_gpu/
  • https://docs.nvidia.com/datacenter/kubernetes/kubernetes-upstream/index.html
  • https://ssaru.github.io/2019/07/25/20190725-Connect_GPU_to_Minikube/
  • https://github.com/NVIDIA/nvidia-docker
  • https://github.com/NVIDIA/k8s-device-plugin
  • https://www.tensorflow.org/install/docker#gpu_support

3. Prerequisites

본 문서는 다음과 같은 환경에서 검증되었습니다.

  • OS : Ubuntu 16.04
  • minikube : v1.12.3
  • docker-ce : 19.03.9
  • GPU : NVIDIA GeForce GTX 1070
  • nvidia graphics driver :
    • NVIDIA-SMI : 430.64
    • Driver Version: 430.64
    • CUDA Version: 10.1
  • nvidia-docker
    • nvidia-container-runtime
    • nvidia-container-toolkit

4. 시작하기

minikube 의 NVIDIA GPU Support 공식 문서를 보면 none driver 를 사용할 경우의 설치 및 사용 방법이 굉장히 간단하게 설명되어있지만, 실제로 설치를 시도해보면 생각처럼 쉽지 않습니다.

예를 들면 configure docker with nvidia as the default runtime 와 같이 굉장히 간략하게 설명된 부분으로 인하여 설치하는 데 어려운 부분이 있기 때문에 본 문서에서는 각 단계를 하나하나 조금 더 자세히 설명하겠습니다.

1) Install minikube

Minikube 바이너리를 설치하는 방법은 이전 포스트에서 확인하실 수 있습니다.

2) NVIDIA driver, NVIDIA docker 설치 및 설정

a) NVIDIA Driver 설치

본 글을 읽는 독자는 GPU 를 로컬에서는 이미 잘 사용하고 계신 분을 대상으로 하기에, 사용하시는 GPU 에 맞는 NVIDIA Driver 와 CUDA 는 이미 로컬에 잘 설치되었다고 가정하겠습니다.

혹시 GPU 를 처음 사용하시는 분이라면 다음 문서 등을 참고하시어 OS 와 GPU 에 맞는 driver 를 설치하시기 바랍니다.

정상적으로 설치되었다면 다음과 같은 결과가 출력됩니다.

$ nvidia-smi

 NVIDIA-SMI 430.64       Driver Version: 430.64       CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 1070    Off  | 00000000:01:00.0  On |                  N/A |
|  0%   40C    P8     7W / 170W |    881MiB /  8116MiB |      2%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0      1160      G   /usr/lib/xorg/Xorg                           496MiB |
|    0      2922      G   compiz                                        69MiB |
+-----------------------------------------------------------------------------+

b) NVIDIA-docker 설치

Ubuntu 16.04 의 경우에는 다음 명령어를 실행하여 설치합니다.

$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit nvidia-container-runtime
sudo systemctl restart docker

정상적으로 설치되었는지 확인하기 위해 다음 명령어를 실행합니다.

  • cuda 9.x 대 GPU 를 사용하신다면, 아래 docker run ... 명령에서 cuda:10.0-base 대신 cuda:9.0-base 로 실행해야 합니다.
$ docker run --gpus all nvidia/cuda:10.0-base nvidia-smi

...
 NVIDIA-SMI 430.64       Driver Version: 430.64       CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 1070    Off  | 00000000:01:00.0  On |                  N/A |
|  0%   40C    P8     7W / 170W |      0MiB /  8116MiB |      2%      Default |
+-------------------------------+----------------------+----------------------+

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

$ nvidia-container-runtime --version
runc version spec: 1.0.1-dev

해당 명령어의 출력 결과에서 현재 GPU 를 사용하고 있는 Process 가 하나도 없다고 나오는 것이 이상하게 생각되실 수 있지만, docker 입장에서는 독립된 자기 자신의 내부 프로세스만 확인할 수 있기 때문에 이는 정상적인 상황입니다.

nvidia-docker2

다른 문서를 찾아보면 다음 명령어가 실행되어야 한다는 문서가 존재합니다. 하지만 본 가이드대로 nvidia-docker 를 설치한 경우는 다음 명령어가 아래와 같은 에러를 내며 실행되지 않더라도 문제되지 않습니다.

$ nvidia-docker version
nvidia-docker: command not found

$ nvidia-docker 는 depreated 된 버전인 nvidia-docker2 pkg 에서만 실행가능한 커맨드이며, nvidia-container-toolkit 과 같은 newest nvidia-docker 를 설치하였다면 실행되지 않는 게 정상이며 실행될 필요가 없다고 합니다.

c) docker default-runtime 변경

Minikube 는 docker default-runtime 을 Docker-CE 로 사용하지만, docker container 내에서 NVIDIA GPU 를 사용하기 위해서는 nvidia-docker 라는 docker-runtime 으로 docker container 를 생성해야 합니다.

  • nvidia-docker : 간단히 말하면 Docker-CE 의 확장판

따라서 Minikube 가 nvidia-docker 로 pod 내부의 container 를 생성할 수 있도록 호스트의 default-runtime 설정을 변경해주어야 합니다.

docker daemon config file 을 다음과 같이 수정합니다.

$ vi /etc/docker/daemon.json
{
  "default-runtime": "nvidia",
  "runtimes": {
      "nvidia": {
          "path": "nvidia-container-runtime",
          "runtimeArgs": []
   }
  }
}

수정 후 docker 를 재시작합니다.

$ sudo systemctl daemon-reload
$ sudo service docker restart

3) Start Minikube

root user 로 변경한 뒤, minikube 를 생성합니다. kubernetes-version 은 v1.15 이상이어야 합니다.

$ sudo su

$ minikube start --driver=none --kubernetes-version=v1.16.3

feature-gates=DevicePlugins=true parameter 를 추가해주어야 한다는 문서도 존재하지만, DevicePlugin 은 k8s v1.10 부터 beta version 으로 변경되었으므로 v1.16.3 버전에서는 따로 추가해주지 않아도 괜찮습니다.

  • 시스템 하드웨어 resource 를 kubelet 에 알리는 데 사용하는 device plugin framework 로 구현된 nvidia-device-plugin 의 사용을 위한 기능입니다.

minikube GPU 공식 문서에서 사용하는 apiserver-ips, apiserver-name parameter 또한 반드시 필요한 parameter 는 아니며, 특별히 필요한 경우에만 사용하시면 됩니다.

a) coredns loop plugin 비활성화

minikube start --driver=none 으로 생성 시 로컬의 dns 설정에 따라 coredns pod 이 무한 loop 에 빠지는 경우가 발생할 수 있습니다.

minikube start 이후 kubectl get pod -A 로 coredns pod 이 CrashLoopBackOff 상태인 것을 확인하였다면, 여러 가지 해결 방법(링크)이 있지만, 로컬 머신의 설정을 건드리지 않고, 간단하게 해결할 수 있는 방법은 다음과 같습니다.

coredns pod 이 참고하는 configmap 을 수정하기 위해 다음을 입력합니다.

$ kubectl -n kube-system edit configmap coredns

data.Corefile 에서 loop 라고 써진 줄 전체를 지우고 :wq 를 통해 변경 사항을 저장합니다.

configmap/coredns edited

coredns pod 을 지우면, 자동으로 다시 생성되는 coredns pod 이 변경된 configmap 을 가지고 생성되게 됩니다.

$ kubectl -n kube-system delete pod -l k8s-app=kube-dns
pod "coredns-xxxxxxxxxx" deleted

이제 coredns pod 이 RUNNING 상태로 뜨는지 확인합니다.

$ kubectl -n kube-system get pod -l k8s-app=kube-dns

4) Install NVIDIA’s device plugin

nvidia 에서 DevicePlugin Framework 에 맞춰 gpu 사용을 위해 개발한 nvidia-device-plugin 을 배포합니다.

$ kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/1.0.0-beta4/nvidia-device-plugin.yml

nvidia-device-plugin 은 daemonset 으로 생성되지만, minikube 를 1 node 로 생성했으므로 1 개의 pod 이 RUNNING 상태로 생성되었는지 확인합니다.

$ kubectl get pod -A | grep nvidia

node 정보에 gpu 가 사용가능하도록 설정되었는지 확인합니다.

$ kubectl get nodes "-o=custom-columns=NAME:.metadata.name,GPU:.status.allocatable.nvidia\.com/gpu"
>>>
NAME       GPU
minikube   1
  • 설정되지 않은 경우, GPU 의 value 가 <none> 으로 표시됩니다.

5. GPU pod 사용하기

이제 k8s 환경에 nvidia gpu setting 을 끝냈으니, gpu 를 pod 이 사용할 수 있는지를 테스트해봅니다.

다음과 같이 cuda lib 를 포함하고 있는 nvidia/cuda:10.0-runtime 이미지로 pod 을 생성합니다.

  • 로컬의 GPU 에 맞는 cuda version 이미지로 생성해야 하는 것에 주의 바랍니다.
  • 적합한 cuda 를 포함한 이미지라면 어떤 이미지든 사용 가능합니다.
    • 예) tensorflow/tensorflow:2.2.0rc2-gpu-py3 등
    • cuda 를 포함하지 않은 일반 nginx 등의 이미지로 생성된 pod 의 경우에는 gpu 를 정상적으로 사용하지 못함에 주의 바랍니다.

spec.resources.requestsspec.resources.limitsnvidia.com/gpu 를 포함해야 pod 내에서 GPU 사용이 가능합니다.

apiVersion: v1
kind: Pod
metadata:
  name: gpu
spec:
  containers:
  - name: gpu-container
    image: nvidia/cuda:10.0-runtime
    command:
      - "/bin/sh"
      - "-c"
    args:
      - nvidia-smi && tail -f /dev/null
    resources:
      requests:
        nvidia.com/gpu: 1
      limits:
        nvidia.com/gpu: 1

kubectl logs 를 통해 방금 생성한 pod 내에서 nvidia-smi 가 정상적으로 수행된 것을 확인합니다.

 NVIDIA-SMI 430.64       Driver Version: 430.64       CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 1070    Off  | 00000000:01:00.0  On |                  N/A |
|  0%   40C    P8     7W / 170W |      0MiB /  8116MiB |      2%      Default |
+-------------------------------+----------------------+----------------------+

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