PC에 kubeflow 설치하기 – 2부 kubernetes, nvidia device-plugin 설치하기

swap 비활성화 하기

쿠버네티스(kubernetes)를 설치 하기 위해서 swap을 비활성화 합니다.

$ sudo swapoff -a

그리고 재부팅 하였을때 swap이 다시 활성화되는 것을 막기 위해서, /etc/fstab 에 있는 swap 관련 부분을 주석 처리하거나, 제거해 줍니다.

$ sudo vi /etc/fstab
 
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
/dev/mapper/ubuntu--vg-root /               ext4    errors=remount-ro 0       1
# /boot/efi was on /dev/nvme0n1p1 during installation
UUID=D21A-9B89  /boot/efi       vfat    umask=0077      0       1
# /dev/mapper/ubuntu--vg-swap_1 none            swap    sw              0       0

iptables 설치하기

iptables을 설치하고, 필요에 따라서 iptables tooling을 legacy 모드로 변경합니다.

# ensure legacy binaries are installed
$ sudo apt-get install -y iptables arptables ebtables

# switch to legacy versions
sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
sudo update-alternatives --set arptables /usr/sbin/arptables-legacy
sudo update-alternatives --set ebtables /usr/sbin/ebtables-legacy

kubelet, kubeadm, kubectl 설치하기

쿠버네티스 설치에 필요한 kubelet, kubeadm, kubectl을 설치합니다. 버전을 명시해 주지 않으면, 최선 버전으로 설치됩니다. kubeflow 문서에 따르면 현재 권장하는 쿠버네티스 버전은 1.14 입니다. 1.15 버전도 호환이 되기 때문에, 이 글에서는 1.15.10-00 버전으로 설치 하였습니다.

$ sudo apt-get update && sudo apt-get install -y apt-transport-https curl
$ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
$ cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
$ sudo apt-get update
$ sudo apt-get install -y kubelet=1.15.10-00 kubeadm=1.15.10-00 kubectl=1.15.10-00
$ sudo apt-mark hold kubelet kubeadm kubectl

쿠버네티스 설치하기

kubeadm을 사용해서 쿠버네티스를 설치합니다. 포드 네트워크 애드온을 cilium을 사용할 것이기 때문에 --pod-network-cidr=10.217.0.0/16 옵션을 사용하겠습니다.

다음 명령어를 실행해서 쿠버네티스를 설치합니다.

$ sudo kubeadm init --pod-network-cidr=10.217.0.0/16

설치가 완료되면, kubectl을 사용하기 위해서 관리자 설정 파일을 유저 디렉토리로 복사합니다.

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

쿠버네티스 접속을 테스트 하기 위해서, 다음 명령어를 실행합니다.

$ kubectl cluster-info
Kubernetes master is running at https://192.168.21.36:6443
KubeDNS is running at https://192.168.21.36:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

이제 Cilium을 쿠버네티스에 설치합니다.

$ kubectl create -f https://raw.githubusercontent.com/cilium/cilium/v1.6/install/kubernetes/quick-install.yaml

cilim 포드의 READY가 1/1이 되면, 쿠버네티스 클러스터를 사용할 수 있습니다.

$ kubectl get pods -n kube-system --selector=k8s-app=cilium
NAME           READY   STATUS    RESTARTS   AGE
cilium-k4l5b   1/1     Running   0          70s

Control plane 노드 격리 해제하기

기본적으로 쿠버네티스 클러스터의 컨트롤 플레인(control-plane) 노드에는 보안상의 이유로 노드가 격리되어 있어서, 포드가 스케줄링되지 않습니다. 이 문서에는 1대의 머신만을 사용하기 때문에 노드 격리를 해제하겠습니다.

다음 명령어로 노드 격리를 해제 시킵니다.

$ kubectl taint nodes --all node-role.kubernetes.io/master-
node/mortar untainted

nvidia plugin 설치하기

쿠버네티스에서 GPU를 사용하기 위해서, nvidia k8s-device-plugin 을 설치합니다. 이 문서를 작성하는 시점에서는 1.12가 최신버전이라서 1.12로 설치하겠습니다.

$ kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.12/nvidia-device-plugin.yml

daemonset.extensions/nvidia-device-plugin-daemonset-1.12 created

참고로, 쿠버네티스 1.15 버전을 설치했을 경우에는 문제가 없을 건데, 1.16 버전 이상을 설치 했을 경우, 다음과 같은 에러가 발생할 것입니다. 자세한 사항은 해당 페이지를 참고 바랍니다.

error: unable to recognize "https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.12/nvidia-device-plugin.yml": no matches for kind "DaemonSet" in version "extensions/v1beta1"

쿠버네티스 버전이 올라가면서, Daemonsetextensions/v1beta1 버전을 더 이상 지원하지 않아서 입니다. 버전을 apps/v1 으로 변경하고 selector를 추가한 후, k8s-device-plugin 을 다시 설치합니다.

다음은 변경한 1.17 버전에 맞게 변경한 메니페스트 파일입니다.

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nvidia-device-plugin-daemonset-1.12
  namespace: kube-system
spec:
  updateStrategy:
    type: RollingUpdate
  selector:
    matchLabels:
      name: nvidia-device-plugin-ds
  template:
    metadata:
      # 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.  This annotation works in tandem with the toleration below.
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ""
      labels:
        name: nvidia-device-plugin-ds
    spec:
      tolerations:
      # Allow this pod to be rescheduled while the node is in "critical add-ons only" mode.
      # This, along with the annotation above marks this pod as a critical add-on.
      - key: CriticalAddonsOnly
        operator: Exists
      - key: nvidia.com/gpu
        operator: Exists
        effect: NoSchedule
      containers:
      - image: nvidia/k8s-device-plugin:1.11
        name: nvidia-device-plugin-ctr
        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
EOF

device-plugin 포드가 정상적으로 작동했는지 확인해 봅니다.

$ kubectl -n kube-system get pod -l name=nvidia-device-plugin-ds
NAME                                        READY   STATUS    RESTARTS   AGE
nvidia-device-plugin-daemonset-1.12-4kt95   1/1     Running   0          24s

$ kubectl -n kube-system logs  -l name=nvidia-device-plugin-ds
2020/02/09 09:05:10 Loading NVML
2020/02/09 09:05:10 Fetching devices.
2020/02/09 09:05:10 Starting FS watcher.
2020/02/09 09:05:10 Starting OS watcher.
2020/02/09 09:05:10 Starting to serve on /var/lib/kubelet/device-plugins/nvidia.sock
2020/02/09 09:05:10 Registered device plugin with Kubelet

GPU 테스트 하기

다음은 텐서플로를 이용해서, GPU를 테스트 해 보는 예제입니다. 단순한 테스트이기 때문에 무시하고 넘어가도 됩니다.

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: tf-gpu-jupyter
  name: tf-gpu-jupyter
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tf-gpu-jupyter
  template:
    metadata:
      labels:
        app: tf-gpu-jupyter
    spec:
      containers:
      - image: tensorflow/tensorflow:2.1.0-gpu-py3-jupyter
        imagePullPolicy: IfNotPresent
        name: tf-gpu-jupyter
        ports:
        - containerPort: 8888
          protocol: TCP
        resources:
          limits:
            nvidia.com/gpu: "1"
EOF

tf-gpu-jupyter 라는 이름을 가진 GPU를 사용할 수 있는 텐서플로 주피터(jupyter)를 생성하였습니다. 포드가 정상적으로 작동했는지 확인해 봅니다.

$ kubectl get pod -l app=tf-gpu-jupyter
NAME                              READY   STATUS    RESTARTS   AGE
tf-gpu-jupyter-66f89b64cd-vrllc   1/1     Running   0          5m58s

주피터 접속에 필요한 토큰 정보를 얻기 위해서 로그를 조회해 보겠습니다.

$ kubectl logs -l app=tf-gpu-jupyter
[I 09:15:25.009 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 09:15:25.012 NotebookApp] 
    
    To access the notebook, open this file in a browser:
        file:///root/.local/share/jupyter/runtime/nbserver-1-open.html
    Or copy and paste one of these URLs:
        http://tf-gpu-jupyter-66f89b64cd-vrllc:8888/?token=6527214998b8d895f6f14a8901a39ba6d8420c43e68f6919
     or http://127.0.0.1:8888/?token=6527214998b8d895f6f14a8901a39ba6d8420c43e68f6919
[I 09:17:20.916 NotebookApp] 302 GET / (127.0.0.1) 0.53ms
[I 09:17:20.926 NotebookApp] 302 GET /tree? (127.0.0.1) 0.65ms

포드에 접속하기 위해서 port-forward를 사용하겠습니다.

$ kubectl port-forward pod/tf-gpu-jupyter-66f89b64cd-vrllc 8888:8888
Forwarding from 127.0.0.1:8888 -> 8888
Forwarding from [::1]:8888 -> 8888

kubectl delete deployment tf-gpu-jupyter
deployment.apps "tf-gpu-jupyter" deleted

포트 포워드가 활성화 되면, 브라우저에서 주피터 주소를 입력합니다. 포드 로그에서 봤던 주소를 입력하면 됩니다. 이 예제에서 주소는 http://127.0.0.1:8888/?token=6527214998b8d895f6f14a8901a39ba6d8420c43e68f6919 입니다.

정상적으로 접속이 되면, 다음과 같은 화면을 보실 수 있습니다.

사용 가능한 GPU 갯수를 확인하겠습니다. 파이썬3 노트북을 생성한 후, 다음 코드를 입력합니다.

from __future__ import absolute_import, division, print_function, unicode_literals

import tensorflow as tf
print("Num GPUs Available: ", len(tf.config.experimental.list_physical_devices('GPU')))

코드를 실행하면 다음과 같이 사용 가능한 GPU 개수가 출력될 것입니다.

확인을 다 했으면, 브라우저를 종료하고, 자원 낭비를 막기 위해서 디플로이먼트를 삭제하도록 하겠습니다. 우리의 GPU는 소중하니까요.

$ kubectl delete deploy tf-gpu-jupyter

참고

  • https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
  • https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/
  • https://github.com/NVIDIA/k8s-device-plugin
  • https://hub.docker.com/r/tensorflow/tensorflow/
  • https://www.tensorflow.org/guide/gpu

“PC에 kubeflow 설치하기 – 2부 kubernetes, nvidia device-plugin 설치하기”에 대한 한개의 댓글

  1. 안녕하세요? 아직 설치를 진행하지는 못했지만 글주제가 너무 좋은 것 같습니다. 좋은 정보 감사합니다.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다