仮想化通信

日本仮想化技術株式会社の公式エンジニアブログ

K3SをNVIDIA Jetson Nanoで実行する

はじめに

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」を参考にして執筆しています。

www.virtualthoughts.co.uk

左は会社から送ってもらったJetson Nanoで、右は私物です。 二台使ってKubernetesクラスターを作ってみました。なんて贅沢。

f:id:virtualtech:20200722181338j:plain

NVIDIA Jetson Nanoのセットアップ

以下のページに従って、Jetson Nanoをセットアップしていきます。 OSは、Ubuntuベースの「Jetson Nano Developer Kit SD Card Image」をイメージ書き込みツールなどを使ってmicroSDに書き込み、Jetson Nanoに取り付けます。

developer.nvidia.com

初回起動時は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