kubernetes(k8s)を使って,ラボのWorkStation環境を再構成したので備忘録として残します.
はじめに
私の所属するラボでは,以前からk8sでGPUを管理していましたが,UbuntuのバージョンやCUDAバージョンが古くなって動作も不安定担ってきたことから,全て初期化して再設定しました.なんとか素人の私と後輩たちでも構成できたのでk8sに詳しい方なら余裕な内容となってしまうと思います.しかし,同様の記事が少なくて手こずったため紹介しようと思います.
WS-Masterの準備
事前に以下の準備をします.
- Ubuntu 20.04 LTS をインストール
ポートの開放
使用するポートを事前に開放します.
$ sudo ufw enable $ sudo ufw status 状態: アクティブ
以下のコマンドで開放するポートを設定.
$ sudo ufw allow 53 $ sudo ufw allow 6443 $ sudo ufw allow 2379:2380/tcp $ sudo ufw allow 8285 $ sudo ufw allow 8472 $ sudo ufw allow 9153 $ sudo ufw allow 10250:10252/tcp $ sudo reboot
確認.
sudo ufw status 状態: アクティブ To Action From -- ------ ---- 22 ALLOW Anywhere 22/tcp ALLOW Anywhere 53 ALLOW Anywhere 6443 ALLOW Anywhere 2379:2380/tcp ALLOW Anywhere 8285 ALLOW Anywhere 8472 ALLOW Anywhere 9153 ALLOW Anywhere 10250:10252/tcp ALLOW Anywhere 22 (v6) ALLOW Anywhere (v6) 22/tcp (v6) ALLOW Anywhere (v6) 53 (v6) ALLOW Anywhere (v6) 6443 (v6) ALLOW Anywhere (v6) 2379:2380/tcp (v6) ALLOW Anywhere (v6) 8285 (v6) ALLOW Anywhere (v6) 8472 (v6) ALLOW Anywhere (v6) 9153 (v6) ALLOW Anywhere (v6) 10250:10252/tcp (v6) ALLOW Anywhere (v6)
Swap領域のオフ
swap領域が有るとk8sが動作しないので,オフにします.
$ sudo vim /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). # /swapfile none swap sw 0 0
/swapもしくは/swapfileと表記のある行をコメントアウトします.
$ sudo reboot
Dockerの設定
Dockerのインストール
Dockerはk8sで動作するバージョンに指定があるため,公式を参考にインストールします.
CRIのインストール | Kubernetes
HTTPS越しのリポジトリの使用をaptに許可するために、パッケージをインストールします.
$ sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common gnupg2
Docker公式のGPG鍵を追加します.
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
Dockerのaptレポジトリを追加します.
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
Docker CEをインストールします.
Docker-ceがver.19代でなければ動作しなかったはずです.
$ sudo apt-get update && sudo apt-get install -y containerd.io=1.2.13-2 docker-ce=5:19.03.11~3-0~ubuntu-$(lsb_release -cs) docker-ce-cli=5:19.03.11~3-0~ubuntu-$(lsb_release -cs)
デーモンをセットアップ
以下を記載.
$ sudo vim /etc/docker/daemon.json { "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2" }
service.dの作成.
$ sudo mkdir -p /etc/systemd/system/docker.service.d
dockerを再起動
$ sudo gpasswd -a $USER docker $ sudo systemctl daemon-reload $ sudo systemctl restart docker $ sudo systemctl enable docker
情報を確認します. $ docker version Client: Docker Engine - Community Version: 19.03.11 API version: 1.40 Go version: go1.13.10 Git commit: 42e35e61f3 Built: Mon Jun 1 09:12:34 2020 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.11 API version: 1.40 (minimum version 1.12) Go version: go1.13.10 Git commit: 42e35e61f3 Built: Mon Jun 1 09:11:07 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.2.13 GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429 nvidia: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683
k8sのインストールと設定
kubeadm, kubectl, kubeletのインストール
こちら(Ubuntu 20.04LTSにkubernetes環境をkubeadmで構築する手順 | Snow System)のサイトを参考にインストールします.
$ sudo apt-get update && sudo apt-get install -y apt-transport-https $ curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - $ sudo apt-add-repository "deb http://apt.kubernetes.io/ kubernetes-xenial main" $ sudo apt update $ sudo apt install -y kubeadm kubelet kubectl
クラスターを作成
kubernetesクラスタを初期化します.
$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16 $ mkdir -p $HOME/.kube $ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config $ sudo chown $(id -u):$(id -g) $HOME/.kube/config
発行されたトークンをWorkerに共有します.
中断や失敗した場合,一時ファイルが残るのでリセットが必要です.
$ sudo kubeadm reset
一般ユーザへのkubectlコマンド開放をします.
$ sudo vim /etc/profile # 以下を追記 export KUBECONFIG=/etc/kubernetes/admin.conf
$ sudo chmod 644 /etc/kubernetes/admin.conf
flannelのインストール
$ sudo sysctl net.bridge.bridge-nf-call-iptables=1 $ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
kubernetes Device Pluginの有効化
$ sudo vim /etc/default/kubelet
/etc/default/kubelet
KUBELET_EXTRA_ARGS=--feature-gates=DevicePlugins=true
$ sudo systemctl daemon-reload $ sudo systemctl restart kubelet
k8s-device-plugin
以下の公式ドキュメントを参考にインストールします.
GitHub - NVIDIA/k8s-device-plugin: NVIDIA device plugin for Kubernetes
$ kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.10.0/nvidia-device-plugin.yml
次に,ワーカーノードを設定します.
WS-Workerの準備
事前に以下の準備をします.
ポートの開放
使用するポートを事前に開放します.
$ sudo ufw enable $ sudo ufw status 状態: アクティブ
以下のコマンドで開放するポートを設定します.
$ sudo ufw allow 53 $ sudo ufw allow 8285 $ sudo ufw allow 8472 $ sudo ufw allow 9153 $ sudo ufw allow 10250 $ sudo ufw allow 30000:32767/tcp $ sudo reboot
確認.
sudo ufw status Status: active To Action From -- ------ ---- 22 ALLOW Anywhere 10250 ALLOW Anywhere 53 ALLOW Anywhere 8285 ALLOW Anywhere 8472 ALLOW Anywhere 9153 ALLOW Anywhere 30000:32767/tcp ALLOW Anywhere 22 (v6) ALLOW Anywhere (v6) 10250 (v6) ALLOW Anywhere (v6) 53 (v6) ALLOW Anywhere (v6) 8285 (v6) ALLOW Anywhere (v6) 8472 (v6) ALLOW Anywhere (v6) 9153 (v6) ALLOW Anywhere (v6) 30000:32767/tcp (v6) ALLOW Anywhere (v6)
Swap領域のオフ
WS-Masterと同様の手順で.
Dockerの設定
WS-Masterと同様の手順で.
nvidia-docker2のインストール
DockerからGPUを使用するためのソフトウェアであるnvidia-docker2をインストールします.
これはk8s-device-pluginで使用されるため,k8s-device-pluginのインストラクションに従ってインストールします.
GitHub - NVIDIA/k8s-device-plugin: NVIDIA device plugin for Kubernetes
$ 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-docker2 $ sudo systemctl restart docker
/etc/docker/daemon.jsonに追記します.
$ sudo vim /etc/docker/daemon.json
{ "default-runtime": "nvidia", "runtimes": { "nvidia": { "path": "/usr/bin/nvidia-container-runtime", "runtimeArgs": [] } }, "exec-opts": ["native.cgroupdriver=systemd"], "log-driver": "json-file", "log-opts": { "max-size": "100m" }, "storage-driver": "overlay2" }
dockerを再起動します.
$ sudo pkill -SIGHUP dockerd $ sudo systemctl daemon-reload $ sudo systemctl restart docker
情報を確認します.
$ sudo nvidia-docker version NVIDIA Docker: 2.8.0 Client: Docker Engine - Community Version: 19.03.11 API version: 1.40 Go version: go1.13.10 Git commit: 42e35e61f3 Built: Mon Jun 1 09:12:22 2020 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.11 API version: 1.40 (minimum version 1.12) Go version: go1.13.10 Git commit: 42e35e61f3 Built: Mon Jun 1 09:10:54 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.2.13 GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429 nvidia: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683
dockerイメージからGPUが確認できるか確認します.
Docker Hubではnvidia/cudaのような暗黙のlatestタグがduplicatedになったため,nvidia/cuda:11.4.3-runtime-ubuntu20.04のように正しく指定する必要があります.
$ sudo docker run --rm nvidia/cuda:11.4.3-runtime-ubuntu20.04 nvidia-smi
k8sのインストールと設定
kubeadm, kubectl, kubeletのインストール
WS-Masterと同様の手順で.
クラスターに参加
WS-Masterで発行されたトークンを使用してクラスターに参加します.
$ sudo kubeadm join [IPアドレス]:6443 --token [Token] --discovery-token-ca-cert-hash [Token Hash]
エラーが起きてjoinできないときはresetをします.
途中でキャンセルした場合も一時ファイルが残るのでリセットが必要です.
$ sudo kubeadm reset
ここまでがWS-Workerでの作業となります.
Master側で確認
設定情報を確認します.
$ kubectl get nodes NAME STATUS ROLES AGE VERSION workstation-01 Ready compute 4d v1.23.1 workstation-02 Ready compute 3d21h v1.23.1 workstation-03 Ready compute 4d13h v1.23.1 workstation-04 Ready compute 4d17h v1.23.1 ws-master Ready control-plane,master 4d17h v1.23.1
workstation-01等のワーカーノードに設定したPCのホスト名が見えており,STATUSがReadyになっていると大丈夫です.
最後に,構成したクラスターの設定をWS-Masterでします.
WS-Master でクラスターの設定
node role, accelerator(GPUセレクタ)の設定
ワーカーノードに役割を付与します.
ワーカーノードのRoleをCompute(計算用)に設定
$ kubectl label nodes [worker hostname] node-role.kubernetes.io/compute=true
搭載GPUでノード選択可能に(GPU名をラベルとして設定).
gpu nameの例: nvidia-geforce-gtx1080ti, nvidia-tesla-v100
$ kubectl label nodes [worker hostname] accelerator=(gpu name) # 例えば, $ kubectl label nodes workstation-01 accelerator=nvidia-geforce-rtx2080ti
$ kubectl describe nodes # role, acceleratorの確認(詳細)
Podの作成
ここは一般的なk8sの使い方に近くなるため,簡単に書きます.
WS-Masterに自身のユーザーを作成し,ログインします.
ネームスペースを作成します.
$ kubectl create ns haruka # haruka 部分を適当なユーザー名に変更
test.yml を作成します.
test.yml
apiVersion: v1 kind: Pod metadata: name: haruka-test-2080ti # `kubectl get pod` で表示される名前 spec: containers: - name: haruka-pytorch-container # 表示先が無い名前 image: "nvidia/cuda:11.4.3-runtime-ubuntu20.04" # 使用するdocker image resources: limits: nvidia.com/gpu: 1 # 使用するGPU枚数 command: ["sh", "-c", "tail -f /dev/null",] # Pod生成後,すぐ実行されるコマンド workingDir: /home/haruka # Podの中に入ると最初にいる場所 restartPolicy: OnFailure nodeSelector: # 使用するGPUの設定.記述がない場合は自動で割当られる accelerator: nvidia-geforce-rtx2080ti #accelerator: nvidia-titan-rtx #accelerator: nvidia-geforce-gtx1080
test.yml をapplyし,ポッドを作成します.
$ kubectl apply -n haruka -f test.yml
以下のコマンドでステータスが確認でき,RunningになるとPodの作成の成功を示します.ちなみに,PendingだとGPUリソースの空きを待っている状態です.
$ kubectl get pods -n haruka NAME READY STATUS RESTARTS AGE haruka-test-2080ti 1/1 Running 1 (4d ago) 4d19h
以下のコマンドでPodに入ります.
$ kubectl exec -it -n haruka haruka-test-2080ti /bin/bash root@haruka-test-2080ti:/home/haruka# root@haruka-test-2080ti:/home/haruka# nvidia-smi Mon Jan 17 09:17:42 2022 +-----------------------------------------------------------------------------+ | NVIDIA-SMI 495.29.05 Driver Version: 495.29.05 CUDA Version: 11.5 | |-------------------------------+----------------------+----------------------+ | 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 NVIDIA GeForce ... On | 00000000:86:00.0 Off | N/A | | 27% 22C P8 19W / 250W | 1MiB / 11019MiB | 0% Default | | | | N/A | +-------------------------------+----------------------+----------------------+
以下のコマンドでPodを削除します.
$ kubectl delete pod -n haruka haruka-test-2080ti pod "haruka-test-2080ti" deleted
GPUリソースの空きを確認する便利コマンドを作成
kubectl describe nodesではリソースの空きが確認し辛いため,確認用のシェルスクリプトを作成します.
$ sudo mkdir /usr/local/command
以下のスクリプトを/usr/local/command/に配置します.
$ sudo vim /usr/local/command/showgpus
/usr/local/command/showgpus
var1=($(kubectl describe nodes | tr -d '\000' | sed -n -e '/^Name/,/Roles/p' -e '/^Capacity/,/Allocatable/p' -e '/^Allocated resources/,/Events/p' | grep -e Name -e nvidia.com | perl -pe 's/\n//' | perl -pe 's/Name:/\n/g' | sed 's/nvidia.com\/gpu:\?//g' | sed '1s/^/Node Available(GPUs) Used(GPUs)/' | sed 's/$/ 0 0 0/' | awk '{print $1, $2, $3}' | column -t)) var2=($(kubectl describe nodes | grep -e accelerator= | sed -e "s/.*accelerator=//")) var3=($(kubectl describe nodes | grep -e Hostname: | sed -e "s/.*Hostname:\s*//")) printf "|%-15s|%-30s|%-9s|\n" "Node" "GPU" "Used" for i in `seq 0 $((${#var2[@]}-1))` do printf "|%-15s|%-30s|%4d/%-4d|\n" ${var3[$i]} ${var2[$i]} ${var1[$((5+3*$i))]} ${var1[$((4+3*$i))]} done
実行できるようにします.
$ sudo chmod 777 /usr/local/command/showgpus
$ sudo vim /etc/profile #末尾に以下を追記 export PATH=$PATH:/usr/local/command
実行結果は以下のようになります.
$ showgpus |Node |GPU |Used | |workstation-01 |nvidia-rtx-a5000 | 0/2 | |workstation-02 |nvidia-titan-rtx | 0/2 | |workstation-03 |nvidia-geforce-rtx2080ti | 0/2 | |workstation-04 |nvidia-geforce-rtx2080ti | 1/4 |
おわりに
お疲れさまでした.これで,複数人でGPUを利用する研究室で自動でGPUリソースが割り振られる環境が整いました.
準備に少し手間がかかりましたが,他人の学習を誤って止める危険がなくなりました.
素人には辛かったです...
もし非常に役に立ちましたら,haruka | OFUSE (オフセ)