はじめに
K3Sは、Rancher Labsによって開発されている軽量のKubernetesディストリビューションです。コンピューティングリソースが制限されるエッジコンピューティングのユースケースに最適です。x86_64、ARMv7、およびARM64アーキテクチャをサポートしているのが特徴です。
NVIDIA Jetson Nanoは、64ビットクアッドコアARM CPUと4GBのLPDDR4メモリーに128コアのNVIDIA GPUが実装されたARMボードです。
今回はこれらを使ってKubernetes GPUクラスターを構築してみたいと思います。 ちなみにJetsonシリーズであればNanoでなくても同様に動くと思います。
なお、今回の内容は以下のブログ「K3S and Nvidia Jetson Nano」を参考にして執筆しています。
左は会社から送ってもらったJetson Nanoで、右は私物です。 二台使ってKubernetesクラスターを作ってみました。なんて贅沢。
NVIDIA Jetson Nanoのセットアップ
以下のページに従って、Jetson Nanoをセットアップしていきます。 OSは、Ubuntuベースの「Jetson Nano Developer Kit SD Card Image」をイメージ書き込みツールなどを使ってmicroSDに書き込み、Jetson Nanoに取り付けます。
初回起動時はUbuntu Desktopのセットアップを行うため、モニター、マウス、キーボードを接続します。 セットアップ後、固定IPアドレスの割り当てやシステムのアップデートなどを行います。
デフォルトDockerランタイムの設定変更
Jetson Nano Developer Kit SD Card Imageには必要なソフトウェアがほとんど含まれています。 DockerやNVIDIA Container Toolkit(旧称 NVIDIA Docker)も同様です。
次のようにランタイム nvidiaを指定して実行すると、GPU利用可能なDockerコンテナーを実行できます。
~$ sudo docker run -it --runtime nvidia jitteam/devicequery
これはデフォルトのランタイムを定義することで省略可能になります。設定変更後、Dockerサービスを再起動します。
~$ sudo docker info | grep Runtime Runtimes: nvidia runc Default Runtime: runc ~$ sudo vi /etc/docker/daemon.json { "default-runtime": "nvidia", <-追記 "runtimes": { "nvidia": { "path": "nvidia-container-runtime", "runtimeArgs": [] } } } ~$ sudo systemctl restart docker ~$ sudo docker info | grep Runtime Runtimes: nvidia runc Default Runtime: nvidia
k3sのセットアップ
K3sはデフォルトではk3sバンドルのcontainerdを利用します。次のようにオプションを指定することで、インストール済みのDockerをコンテナランタイムとして使うことができます。
~$ curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--docker" sh -s -
クラスターの状態を確認するには次のように行います。k3sはkubectlバイナリーも展開するため、k3sを省略しても実行可能です。 次のように一台目のノードが表示されます。
~$ sudo k3s kubectl get no NAME STATUS ROLES AGE VERSION jetson1 Ready master 36s v1.18.6+k3s1
ノードを追加するために一台目のノード(master)でトークンキーを確認します。 二台目以降では一台目と同様のオプションとAPIアドレス、トークンキーを指定して実行します。
ytooyama@jetson1:~$ sudo cat /var/lib/rancher/k3s/server/node-token K10dd486d5f8f07b16240f251013522767fd3086033dede585ddf5195bedd6d3af3::server:694354eaf5cc4d8df811f9fb47af75b9 ytooyama@jetson2:~$ curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--docker" K3S_URL=https://192.168.1.73:6443 K3S_TOKEN=K10dd486d5f8f07b16240f251013522767fd3086033dede585ddf5195bedd6d3af3::server:694354eaf5cc4d8df811f9fb47af75b9 sh - ytooyama@jetson1:~$ sudo k3s kubectl get no NAME STATUS ROLES AGE VERSION jetson1 Ready master 4m2s v1.18.6+k3s1 jetson2 Ready <none> 45s v1.18.6+k3s1
イメージを事前にダウンロード
k3s経由で実行すると時間がかかるので、事前に必要なイメージをDockerコマンドを使ってPullしておきます。
ytooyama@jetson1:~$ docker image pull jitteam/devicequery ytooyama@jetson2:~$ docker image pull jitteam/devicequery
Kubernetes PodでGPUコンテナーを実行
Kubernetes Podを作成して、GPUコンテナーを実行する環境が整いました。テストのために既存のdevicequeryイメージを使ってコンテナーアプリケーションを実行してみます。GPUが認識されていれば次のようにGPUの情報を出力できるはずです。
~$ sudo kubectl run -i -t nvidia --image=jitteam/devicequery --restart=Never ./deviceQuery Starting... CUDA Device Query (Runtime API) version (CUDART static linking) Detected 1 CUDA Capable device(s) Device 0: "NVIDIA Tegra X1" CUDA Driver Version / Runtime Version 10.2 / 10.0 CUDA Capability Major/Minor version number: 5.3 Total amount of global memory: 3964 MBytes (4156780544 bytes) ( 1) Multiprocessors, (128) CUDA Cores/MP: 128 CUDA Cores GPU Max Clock rate: 922 MHz (0.92 GHz) Memory Clock rate: 13 Mhz Memory Bus Width: 64-bit L2 Cache Size: 262144 bytes Maximum Texture Dimension Size (x,y,z) 1D=(65536), 2D=(65536, 65536), 3D=(4096, 4096, 4096) Maximum Layered 1D Texture Size, (num) layers 1D=(16384), 2048 layers Maximum Layered 2D Texture Size, (num) layers 2D=(16384, 16384), 2048 layers Total amount of constant memory: 65536 bytes Total amount of shared memory per block: 49152 bytes Total number of registers available per block: 32768 Warp size: 32 Maximum number of threads per multiprocessor: 2048 Maximum number of threads per block: 1024 Max dimension size of a thread block (x,y,z): (1024, 1024, 64) Max dimension size of a grid size (x,y,z): (2147483647, 65535, 65535) Maximum memory pitch: 2147483647 bytes Texture alignment: 512 bytes Concurrent copy and kernel execution: Yes with 1 copy engine(s) Run time limit on kernels: Yes Integrated GPU sharing Host Memory: Yes Support host page-locked memory mapping: Yes Alignment requirement for Surfaces: Yes Device has ECC support: Disabled Device supports Unified Addressing (UVA): Yes Device supports Compute Preemption: No Supports Cooperative Kernel Launch: No Supports MultiDevice Co-op Kernel Launch: No Device PCI Domain ID / Bus ID / location ID: 0 / 0 / 0 Compute Mode: < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) > deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 10.2, CUDA Runtime Version = 10.0, NumDevs = 1 Result = PASS
追記
NVIDIA NGCに、様々なGPUコンテナーイメージが提供されています。
おわりに...ちょっと愚痴
k3sやっぱり便利ですね。
今回JetsonでKubernetesを動かすのに、「Jetson Nano Developer KitはUbuntuベースだからmicrok8sをsnapイメージでセットアップしてadd-nodeしてクラスター化してGPUアドオンを追加したらいけるんじゃないか」と思っていました。実際にやってみたらGPUアドオンがaarch64では動かないらしく、探していたらいいガイドを見つけたというそんな感じです。
参考にしたサイトはシングルのKubernetesをk3sで動かしていたので、本記事ではノード追加する手順を追加しています。二台目以降は同じ方法で追加できるので、もう少し規模の大きいクラスターをk3sで作るときもおそらく、役立つと思います。
バージョン関連
いざ試そうと思ったら動かないということがあると大変なので、動作確認したバージョンを最後に列挙します。
- Ubuntu 18.04.4 aarch64 (Jetson Nano Developer Kit)
- Linux 4.9.140-tegra
- Docker 19.03.6
- k3s v1.18.6+k3s1