• Wonhyuk Yang

microk8s을 활용한 gpu cluster 구축



Kubernetes에 gpu를 사용 가능한 리소르로 제공하기 위해서는, nvidia driver, toolkit과 plugin들을 설치해야 하며, 이 과정은 쉽고 간단하지 않다. 따라서 한 번에 쉽게 모든 환경을 구축할 수 있는 GPU OPERATOR가 굉장히 매력적으로 느껴졌다. 거기다 microk8s에서는 제공하는 커맨드로 해당 gpu operator을 설치할 수 있다. 따라서 해당 글에서는 microk8s를 이용하여 클러스터를 구축하려고 한다.


OS는 Ubuntu 20.04 LTS 서버이고 1080ti를 장착하고 있다.

microk8s를 이용한 GPU Operator 설치

  1. Nouveau driver 비활성화

GPU operator을 실행하기 전에, nouveau GPU driver가 사용 중이리면, blacklist에 등록해야 한다. 아래의 커맨드를 통해 모듈들이 사용되고 있는지 확인할 수 있다.

$ lsmod | grep -i -e cuda -e nvidia -e nouveau

사용 중이라면 아래의 커맨드를 통해 blacklist에 등록하고 해당 내용을 반영하고 재부팅하도록 한다.

$ cat << EOF | sudo tee /etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau
options nouveau modeset=0
EOF
$ sudo update-initramfs -u
$ sudo reboot

<After reboot..>
$ lsmod | grep -i -e cuda -e nvidia -e nouveau
$

위와 같이 lsmod를 했을 때 모듈들이 나오지 않으면 nouveau 드라이버를 하지 않는 중이라는 것이다.


microk8s install

microk8s 설치를 위해 아래의 커맨드들을 입력한다. 정확한 설치 절차는 해당 링크를 참고하라.

$ sudo snap install microk8s --classic
$ sudo usermod -a -G microk8s $USER
$ sudo chown -f -R $USER ~/.kube
$ su - $USER
$ microk8s status --wait-ready

이제 아래의 커맨드를 실행하여 gpu를 활성화하자.

아래처럼 파일을 수정하여야 동작을 해야 했다. 만약 다른 방법이 있다면 수정 바람.
$ sudo vim /etc/systemd/system/multi-user.target.wants/snap.microk8s.daemon-containerd.service
- Restart=on-failure
- Type=simple
+ Restart=always
+ Type=notify
+ Delegate=yes
+ KillMode=process

$ sudo systemctl daemon-reload
$ sudo systemctl restart snap.microk8s.daemon-containerd
$ microk8s stop
$ microk8s start
$ microk8s enable gpu 

gpu-operator-resources 네임 스페이스에 위치한 리소스들을 살벼보자.


$ microk8s kubectl get all -n gpu-operator-resources
NAME                                           READY   STATUS              RESTARTS   AGE
pod/nvidia-operator-validator-ng5kb            0/1     Init:0/4            0          20s
pod/nvidia-device-plugin-daemonset-jkw52       0/1     Init:0/1            0          20s
pod/nvidia-driver-daemonset-fdl8f              0/1     ContainerCreating   0          20s
pod/nvidia-container-toolkit-daemonset-xmphg   0/1     Init:0/1            0          20s
pod/nvidia-dcgm-exporter-snrwk                 0/1     Init:0/1            0          19s
pod/gpu-feature-discovery-pz8bh                0/1     Init:0/1            0          19s

NAME                           TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/nvidia-dcgm-exporter   ClusterIP   10.152.183.62   <none>        9400/TCP   19s

NAME                                                DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                                      AGE
daemonset.apps/nvidia-driver-daemonset              1         1         0       1            0           nvidia.com/gpu.deploy.driver=true                  20s
daemonset.apps/nvidia-container-toolkit-daemonset   1         1         0       1            0           nvidia.com/gpu.deploy.container-toolkit=true       20s
daemonset.apps/nvidia-operator-validator            1         1         0       1            0           nvidia.com/gpu.deploy.operator-validator=true      20s
daemonset.apps/nvidia-device-plugin-daemonset       1         1         0       1            0           nvidia.com/gpu.deploy.device-plugin=true           20s
daemonset.apps/nvidia-dcgm-exporter                 1         1         0       1            0           nvidia.com/gpu.deploy.dcgm-exporter=true           19s
daemonset.apps/nvidia-mig-manager                   0         0         0       0            0           nvidia.com/gpu.deploy.mig-manager=true             19s
daemonset.apps/gpu-feature-discovery                1         1         0       1            0           nvidia.com/gpu.deploy.gpu-feature-discovery=true   19s

위 로그에서 볼 수 있듯이 7개의 데몬 셋이 생성된다. 각각의 데몬 셋들은 node selector를 통해 해당하는 옵션(gpu.deploy.*)이 true일 때 실행된다.


그리고 시간이 지나면 아래와 같이 모든 파드가 생성이 된 것을 확인할 수 있다.

$ microk8s kubectl get all -n gpu-operator-resources
NAME                                           READY   STATUS      RESTARTS   AGE
pod/nvidia-driver-daemonset-fdl8f              1/1     Running     0          9m51s
pod/nvidia-container-toolkit-daemonset-xmphg   1/1     Running     0          9m51s
pod/nvidia-cuda-validator-x6kdl                0/1     Completed   0          7m2s
pod/nvidia-dcgm-exporter-snrwk                 1/1     Running     0          9m50s
pod/gpu-feature-discovery-pz8bh                1/1     Running     0          9m50s
pod/nvidia-device-plugin-daemonset-jkw52       1/1     Running     0          9m51s
pod/nvidia-device-plugin-validator-4l64w       0/1     Completed   0          5m40s
pod/nvidia-operator-validator-ng5kb            1/1     Running     0          9m51s
...

nvidia-driver-daemonset는 아래에서 볼 수 있듯이 "/run/nvidia" Host path 볼륨을 mount한다. 해당 경로에 driver을 설치하는 것으로 보인다.

Name:                 nvidia-driver-daemonset-fdl8f
Namespace:            gpu-operator-resources
Containers:
  nvidia-driver-ctr:
    Image:         nvcr.io/nvidia/driver:460.73.01-ubuntu20.04
    Command:
      nvidia-driver
    Args:
      init
    Mounts:
      /dev/log from dev-log (rw)
      /etc/containers/oci/hooks.d from config (rw)
      /host-etc/os-release from host-os-release (ro)
      /run/nvidia from run-nvidia (rw)
      /var/log from var-log (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-r548d (ro)
Volumes:
  run-nvidia:
    Type:          HostPath (bare host directory volume)
    Path:          /run/nvidia
    HostPathType:
  var-log:
    Type:          HostPath (bare host directory volume)
    Path:          /var/log
    HostPathType:
  dev-log:
    Type:          HostPath (bare host directory volume)
    Path:          /dev/log
    HostPathType:
  config:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      nvidia-driver
    Optional:  false
  host-os-release:
    Type:          HostPath (bare host directory volume)
    Path:          /etc/os-release
    HostPathType:

해당 설치 과정이 완료되면 nvidia 커널 모듈들이 올라와 있는 것을 확인할 수 있다. 또한 마운트한 /run/nvidia에는 driver에 관련된 파일들이 설치된 것을 확인할 수 있다.

$ lsmod | grep nvidia
nvidia_modeset       1228800  1
nvidia_uvm           1011712  0
nvidia              34123776  50 nvidia_uvm,nvidia_modeset
$ ls /run/nvidia/driver/bin/ | grep nvidia
nvidia-bug-report.sh
nvidia-cuda-mps-control
nvidia-cuda-mps-server
nvidia-debugdump
nvidia-installer
nvidia-ngx-updater
nvidia-persistenced
nvidia-settings
nvidia-smi
nvidia-uninstall
nvidia-xconfig
$ microk8s kubectl logs -n gpu-operator-resources pod/nvidia-driver-daemonset-fdl8f
Creating directory NVIDIA-Linux-x86_64-460.73.01
Verifying archive integrity... OK
Uncompressing NVIDIA Accelerated Graphics Driver for Linux-x86_64 460.73.01...........................
......................................................................................................
중략


    Image:         nvcr.io/nvidia/k8s/container-toolkit:1.4.4-ubuntu18.04
    Mounts:
      /run/nvidia from nvidia-run-path (rw)
      /runtime/config-dir/ from containerd-config (rw)
      /runtime/sock-dir/ from containerd-socket (rw)
      /usr/local/nvidia from nvidia-local (rw)
      /usr/share/containers/oci/hooks.d from crio-hooks (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-5wp4h (ro)
  
Volumes:
  nvidia-run-path:
    Type:          HostPath (bare host directory volume)
    Path:          /run/nvidia
    HostPathType:  DirectoryOrCreate
  run-nvidia-validations:
    Type:          HostPath (bare host directory volume)
    Path:          /run/nvidia/validations
    HostPathType:  DirectoryOrCreate
  driver-install-path:
    Type:          HostPath (bare host directory volume)
    Path:          /run/nvidia/driver
    HostPathType:
  nvidia-local:
    Type:          HostPath (bare host directory volume)
    Path:          /usr/local/nvidia
    HostPathType:
  crio-hooks:
    Type:          HostPath (bare host directory volume)
    Path:          /run/containers/oci/hooks.d
    HostPathType:
  containerd-config:
    Type:          HostPath (bare host directory volume)
    Path:          /var/snap/microk8s/2346/args
    HostPathType:
  containerd-socket:
    Type:          HostPath (bare host directory volume)
    Path:          /var/snap/microk8s/common/run
    HostPathType:

$ ls /usr/local/nvidia/toolkit/ -l
total 4720
lrwxrwxrwx 1 root root      30 Jul 28 05:50 libnvidia-container.so.1 -> ./libnvidia-container.so.1.3.3
-rwxr-xr-x 1 root root  175120 Jul 28 05:50 libnvidia-container.so.1.3.3
-rwxr-xr-x 1 root root     154 Jul 28 05:50 nvidia-container-cli
-rwxr-xr-x 1 root root   43024 Jul 28 05:50 nvidia-container-cli.real
-rwxr-xr-x 1 root root     166 Jul 28 05:50 nvidia-container-runtime
lrwxrwxrwx 1 root root      26 Jul 28 05:50 nvidia-container-runtime-hook -> ./nvidia-container-toolki
t
-rwxr-xr-x 1 root root 2257080 Jul 28 05:50 nvidia-container-runtime.real
-rwxr-xr-x 1 root root     195 Jul 28 05:50 nvidia-container-toolkit
-rwxr-xr-x 1 root root 2335640 Jul 28 05:50 nvidia-container-toolkit.real
  • nvidia-operator-validator

  • nvidia-device-plugin-daemonset

  • nvidia-dcgm-exporter

  • nvidia-mig-manager

  • gpu-feature-discovery

위와 같이 전부 설치되었다면 아래와 같이 cuda 예제를 살펴보도록 하자.

$ cat << EOF | microk8s kubectl create -f -
apiVersion: v1
kind: Pod
metadata:
  name: cuda-vectoradd
spec:
  restartPolicy: OnFailure
  containers:
  - name: cuda-vectoradd
    image: "nvidia/samples:vectoradd-cuda11.2.1"
    resources:
      limits:
         nvidia.com/gpu: 1
EOF

어느 정도 시간이 지난 후 아래와 같이 로그를 살펴보면 성공적으로 실행한 것을 확인할 수 있다.

$ microk8s kubectl logs cuda-vectoradd
[Vector addition of 50000 elements]
Copy input data from the host memory to the CUDA device
CUDA kernel launch with 196 blocks of 256 threads
Copy output data from the CUDA device to the host memory
Test PASSED
Done

Multi node cluster

새로운 노드를 추가하기 위해서 새로운 토큰을 할당받는다. 이 과정은 한 노드에 한 번씩 수행해야 한다.

<Cluster Nonde>
$ microk8s add-node
From the node you wish to join to this cluster, run the following:
microk8s join 10.0.0.250:25000/b123aa2d7b57caddf13e1bdc2fba3c56/f1e71b50a42c


<New Node>
$ microk8s join 10.0.0.250:25000/b123aa2d7b57caddf13e1bdc2fba3c56/f1e71b50a42c
$ microk8s enable openebs
$ microk8s enable dashboard
조회수 295회댓글 0개

관련 게시물

전체 보기