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"
쿠버네티스 버전이 올라가면서, Daemonset
의 extensions/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
안녕하세요? 아직 설치를 진행하지는 못했지만 글주제가 너무 좋은 것 같습니다. 좋은 정보 감사합니다.