Jetson Orin Nano を Kubernetes のノードにした
前回の続き。
containerd の設定
CRI のデフォルトランタイムを以下を参考に nvidia
に変更。
$ sudo mkdir -p /etc/containerd
$ sudo curl -o /etc/containerd/config.toml https://raw.githubusercontent.com/NVIDIA/cloud-native-stack/master/playbooks/config.toml
$ sudo systemctl restart containerd
Kernel のリビルド
下記の記事によると、前世代のJetson NanoをKubernetesのノードにするためにはカーネルのリビルドが必要になるらしい。(どうでもいいけどKubernetesに関連する記事を検索すると高確率で同僚の記事がヒットするのが面白い。)
Jetson Orin Nano 上で確認したところ、最低限の設定はされていそう。
$ zcat /proc/config.gz | grep CONFIG_IP_NF_TARGET_REDIRECT
CONFIG_IP_NF_TARGET_REDIRECT=m
$ zcat /proc/config.gz | grep CONFIG_CGROUP_HUGETLB
CONFIG_CGROUP_HUGETLB=y
どちらにしろ、CSIでISCSIを有効化するためには以下を設定しないといけないのでどちらにしろカーネルビルドをやってみることにする。
$ zcat /proc/config.gz | grep ISCSI
# CONFIG_ISCSI_IBFT is not set
# CONFIG_SCSI_ISCSI_ATTRS is not set
# CONFIG_ISCSI_TCP is not set
# CONFIG_ISCSI_BOOT_SYSFS is not set
# CONFIG_SCSI_CXGB3_ISCSI is not set
# CONFIG_SCSI_CXGB4_ISCSI is not set
# CONFIG_SCSI_BNX2_ISCSI is not set
# CONFIG_BE2ISCSI is not set
# CONFIG_SCSI_QLA_ISCSI is not set
コンパイル準備
とりあえず公式ドキュメントでカーネルコンパイルの方法を確認。
以下からカーネルのソースを入手。
$ curl -LO https://developer.nvidia.com/downloads/embedded/l4t/r35_release_v3.1/sources/public_sources.tbz2
$ tar -xjf public_sources.tbz2
カーネルのソースコードを解凍。
$ cd Linux_for_Tegra/source/public
$ tar -xjf kernel_src.tbz2
$ cd kernel/kernel-5.10/
現状の .config
を入手して make nconfig
で設定。
Jetson で iSCSI デバイスを使うための設定は以下の情報を参考にした。
$ zcat /proc/config.gz > .config.org
$ cp .config.org .config
$ make nconfig
こんな感じ。
$ diff -u .config.org .config
--- .config.org 2023-04-29 13:15:52.741355433 +0900
+++ .config 2023-04-29 15:33:25.786778247 +0900
@@ -2,10 +2,10 @@
# Automatically generated file; DO NOT EDIT.
# Linux/arm64 5.10.104 Kernel Configuration
#
-CONFIG_CC_VERSION_TEXT="aarch64-buildroot-linux-gnu-gcc.br_real (Buildroot 2020.08) 9.3.0"
+CONFIG_CC_VERSION_TEXT="gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0"
CONFIG_CC_IS_GCC=y
-CONFIG_GCC_VERSION=90300
-CONFIG_LD_VERSION=233010000
+CONFIG_GCC_VERSION=90400
+CONFIG_LD_VERSION=234000000
CONFIG_CLANG_VERSION=0
CONFIG_LLD_VERSION=0
CONFIG_CC_CAN_LINK=y
@@ -445,6 +445,7 @@
CONFIG_CC_HAS_BRANCH_PROT_PAC_RET=y
CONFIG_CC_HAS_SIGN_RETURN_ADDRESS=y
CONFIG_AS_HAS_PAC=y
+CONFIG_AS_HAS_CFI_NEGATE_RA_STATE=y
# end of ARMv8.3 architectural features
#
@@ -807,10 +808,6 @@
# end of GCOV-based kernel profiling
CONFIG_HAVE_GCC_PLUGINS=y
-CONFIG_GCC_PLUGINS=y
-# CONFIG_GCC_PLUGIN_CYC_COMPLEXITY is not set
-# CONFIG_GCC_PLUGIN_LATENT_ENTROPY is not set
-# CONFIG_GCC_PLUGIN_RANDSTRUCT is not set
# end of General architecture-dependent options
CONFIG_RT_MUTEXES=y
@@ -1134,6 +1131,7 @@
#
CONFIG_NETFILTER_XT_MARK=m
CONFIG_NETFILTER_XT_CONNMARK=m
+# CONFIG_NETFILTER_XT_SET is not set
#
# Xtables targets
@@ -1216,7 +1214,24 @@
CONFIG_NETFILTER_XT_MATCH_U32=m
# end of Core Netfilter Configuration
-# CONFIG_IP_SET is not set
+CONFIG_IP_SET=m
+CONFIG_IP_SET_MAX=256
+CONFIG_IP_SET_BITMAP_IP=m
+CONFIG_IP_SET_BITMAP_IPMAC=m
+CONFIG_IP_SET_BITMAP_PORT=m
+CONFIG_IP_SET_HASH_IP=m
+CONFIG_IP_SET_HASH_IPMARK=m
+CONFIG_IP_SET_HASH_IPPORT=m
+CONFIG_IP_SET_HASH_IPPORTIP=m
+CONFIG_IP_SET_HASH_IPPORTNET=m
+CONFIG_IP_SET_HASH_IPMAC=m
+CONFIG_IP_SET_HASH_MAC=m
+CONFIG_IP_SET_HASH_NETPORTNET=m
+CONFIG_IP_SET_HASH_NET=m
+CONFIG_IP_SET_HASH_NETNET=m
+CONFIG_IP_SET_HASH_NETPORT=m
+CONFIG_IP_SET_HASH_NETIFACE=m
+CONFIG_IP_SET_LIST_SET=m
CONFIG_IP_VS=m
# CONFIG_IP_VS_IPV6 is not set
# CONFIG_IP_VS_DEBUG is not set
@@ -1439,6 +1454,7 @@
# CONFIG_NET_EMATCH_META is not set
# CONFIG_NET_EMATCH_TEXT is not set
# CONFIG_NET_EMATCH_CANID is not set
+# CONFIG_NET_EMATCH_IPSET is not set
# CONFIG_NET_EMATCH_IPT is not set
CONFIG_NET_CLS_ACT=y
CONFIG_NET_ACT_POLICE=m
@@ -2166,15 +2182,18 @@
# CONFIG_CHR_DEV_SG is not set
# CONFIG_CHR_DEV_SCH is not set
# CONFIG_SCSI_CONSTANTS is not set
+CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_LOGGING=y
# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_SCAN_ASYNC=y
#
# SCSI Transports
#
# CONFIG_SCSI_SPI_ATTRS is not set
# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
+CONFIG_SCSI_ISCSI_ATTRS=m
CONFIG_SCSI_SAS_ATTRS=m
CONFIG_SCSI_SAS_LIBSAS=m
CONFIG_SCSI_SAS_ATA=y
@@ -2183,12 +2202,12 @@
# end of SCSI Transports
CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_ISCSI_BOOT_SYSFS is not set
-# CONFIG_SCSI_CXGB3_ISCSI is not set
-# CONFIG_SCSI_CXGB4_ISCSI is not set
-# CONFIG_SCSI_BNX2_ISCSI is not set
-# CONFIG_BE2ISCSI is not set
+CONFIG_ISCSI_TCP=m
+CONFIG_ISCSI_BOOT_SYSFS=m
+CONFIG_SCSI_CXGB3_ISCSI=m
+CONFIG_SCSI_CXGB4_ISCSI=m
+CONFIG_SCSI_BNX2_ISCSI=m
+CONFIG_BE2ISCSI=m
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_HPSA is not set
# CONFIG_SCSI_3W_9XXX is not set
@@ -2243,6 +2262,8 @@
# CONFIG_SCSI_PM8001 is not set
# CONFIG_SCSI_VIRTIO is not set
# CONFIG_SCSI_DH is not set
+CONFIG_SCSI_DH=y
+CONFIG_SCSI_DH_ALUA=y
# end of SCSI device support
CONFIG_HAVE_PATA_PLATFORM=y
@@ -2350,22 +2371,38 @@
CONFIG_BLK_DEV_DM_BUILTIN=y
CONFIG_BLK_DEV_DM=y
# CONFIG_DM_DEBUG is not set
+CONFIG_DM_DEBUG=y
+CONFIG_DM_BIO_PRISON=y
+CONFIG_DM_PERSISTENT_DATA=y
CONFIG_DM_BUFIO=y
# CONFIG_DM_DEBUG_BLOCK_MANAGER_LOCKING is not set
# CONFIG_DM_UNSTRIPED is not set
CONFIG_DM_CRYPT=y
# CONFIG_DM_SNAPSHOT is not set
+CONFIG_DM_SNAPSHOT=y
# CONFIG_DM_THIN_PROVISIONING is not set
+CONFIG_DM_THIN_PROVISIONING=y
# CONFIG_DM_CACHE is not set
+CONFIG_DM_CACHE=y
+CONFIG_DM_CACHE_SMQ=y
# CONFIG_DM_WRITECACHE is not set
# CONFIG_DM_EBS is not set
# CONFIG_DM_ERA is not set
+CONFIG_DM_ERA=y
# CONFIG_DM_CLONE is not set
# CONFIG_DM_MIRROR is not set
+CONFIG_DM_MIRROR=y
+CONFIG_DM_LOG_USERSPACE=y
# CONFIG_DM_RAID is not set
+CONFIG_DM_RAID=y
# CONFIG_DM_ZERO is not set
+CONFIG_DM_ZERO=y
# CONFIG_DM_MULTIPATH is not set
+CONFIG_DM_MULTIPATH=y
+CONFIG_DM_MULTIPATH_QL=y
+CONFIG_DM_MULTIPATH_ST=y
# CONFIG_DM_DELAY is not set
+CONFIG_DM_DELAY=y
# CONFIG_DM_DUST is not set
# CONFIG_DM_INIT is not set
CONFIG_DM_UEVENT=y
@@ -2374,7 +2411,10 @@
CONFIG_DM_VERITY_VERIFY_ROOTHASH_SIG=y
# CONFIG_DM_VERITY_FEC is not set
# CONFIG_DM_SWITCH is not set
+CONFIG_DM_SWITCH=y
# CONFIG_DM_LOG_WRITES is not set
+CONFIG_DM_LOG_WRITES=y
+CONFIG_DM_ZONED=y
# CONFIG_DM_INTEGRITY is not set
# CONFIG_TARGET_CORE is not set
# CONFIG_FUSION is not set
@@ -2508,6 +2548,7 @@
CONFIG_CHELSIO_T3=m
CONFIG_CHELSIO_T4=m
CONFIG_CHELSIO_T4VF=m
+CONFIG_CHELSIO_LIB=m
CONFIG_CHELSIO_INLINE_CRYPTO=y
CONFIG_NET_VENDOR_CISCO=y
CONFIG_ENIC=m
@@ -7586,7 +7627,6 @@
CONFIG_TEGRA_HV_PM_CTL=y
CONFIG_TEGRA_HV_MANAGER=y
CONFIG_TEGRA_VIRTUALIZATION=y
-CONFIG_TEGRA_NVLINK=y
# end of Device Drivers
#
@@ -7925,10 +7965,6 @@
# Memory initialization
#
CONFIG_INIT_STACK_NONE=y
-# CONFIG_GCC_PLUGIN_STRUCTLEAK_USER is not set
-# CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF is not set
-# CONFIG_GCC_PLUGIN_STRUCTLEAK_BYREF_ALL is not set
-# CONFIG_GCC_PLUGIN_STACKLEAK is not set
# CONFIG_INIT_ON_ALLOC_DEFAULT_ON is not set
# CONFIG_INIT_ON_FREE_DEFAULT_ON is not set
# end of Memory initialization
コンパイル
準備ができたのでコンパイル。数時間かかるそうなので放置。
$ make prepare
$ make modules_prepare
$ make -j5 Image
$ make -j5 modules
カーネルのインストール
インストールして再起動。
$ sudo cp /boot/Image /boot/Image.org
$ sudo cp arch/arm64/boot/Image /boot/Image
$ sudo make modules_install
$ sudo reboot
カーネルがついさっきビルドしたものに変わっていることを確認。
$ uname -a
Linux uribo 5.10.104 #2 SMP PREEMPT Sat Apr 29 14:42:12 JST 2023 aarch64 aarch64 aarch64 GNU/Linux
Kubernetes へ Join
自分は kubeadm
を使ってないので適時 kubelet をインストールし systemd などの設定を手作業でやったが、普通は kubeadm join
で大丈夫と思われる。
✦ ➜ k get node uribo -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
uribo Ready <none> 63s v1.24.6 192.168.1.152 <none> Ubuntu 20.04.5 LTS 5.10.104 containerd://1.6.12
無事、Kubernetesにノードとして追加された。
ちなみに、メモリも少ないので kubelet の設定で Swap を有効化しておいた。
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
...
(snip)
...
failSwapOn: false
featureGates:
NodeSwap: true
nvidia device plugin のインストール
下記の記事に従って、device plugin をインストールする。
containerdはすでに設定しており、nvidia-container-toolkit
もインストール済みのため、/etc/docker/daemon.json
を少し編集して、
{
"default-runtime": "nvidia",
"runtimes": {
"nvidia": {
"path": "/usr/bin/nvidia-container-runtime",
"runtimeArgs": []
}
}
}
マニフェストをapplyするのみ。
$ kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.14.0/nvidia-device-plugin.yml
動作確認
devicequery を実行。
✦ ➜ cat <<EOF | k apply -f -
apiVersion: v1
kind: Pod
metadata:
name: devicequery
spec:
restartPolicy: Never
containers:
- name: nvidia
image: xift/jetson_devicequery:r32.5.0
command: [ "./deviceQuery" ]
resources:
limits:
nvidia.com/gpu: 1
nodeSelector:
kubernetes.io/hostname: "uribo"
tolerations:
- effect: NoSchedule
key: nvidia.com/gpu
operator: Exists
EOF
✦ ➜ k get pod devicequery
NAME READY STATUS RESTARTS AGE
devicequery 0/1 Completed 0 11s
✦ ➜ k logs devicequery
./deviceQuery Starting...
CUDA Device Query (Runtime API) version (CUDART static linking)
Detected 1 CUDA Capable device(s)
Device 0: "Orin"
CUDA Driver Version / Runtime Version 11.4 / 10.2
CUDA Capability Major/Minor version number: 8.7
Total amount of global memory: 6480 MBytes (6794899456 bytes)
MapSMtoCores for SM 8.7 is undefined. Default to use 64 Cores/SM
MapSMtoCores for SM 8.7 is undefined. Default to use 64 Cores/SM
( 8) Multiprocessors, ( 64) CUDA Cores/MP: 512 CUDA Cores
GPU Max Clock rate: 624 MHz (0.62 GHz)
Memory Clock rate: 624 Mhz
Memory Bus Width: 64-bit
L2 Cache Size: 2097152 bytes
Maximum Texture Dimension Size (x,y,z) 1D=(131072), 2D=(131072, 65536), 3D=(16384, 16384, 16384)
Maximum Layered 1D Texture Size, (num) layers 1D=(32768), 2048 layers
Maximum Layered 2D Texture Size, (num) layers 2D=(32768, 32768), 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: 65536
Warp size: 32
Maximum number of threads per multiprocessor: 1536
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 2 copy engine(s)
Run time limit on kernels: No
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: Yes
Supports Cooperative Kernel Launch: Yes
Supports MultiDevice Co-op Kernel Launch: Yes
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 = 11.4, CUDA Runtime Version = 10.2, NumDevs = 1
Result = PASS
どうやら動いてるらしいが、色々クセがあってなんか使いづらい。。
ホストの CUDA 関連ライブラリがPodにインストールされていない
nvidia-container-runtimeは /etc/nvidia-container-runtime/host-files-for-container.d/
にある csv を参照して、ホストのライブラリその他をコンテナにマウントしてくれるらしい。
しかし、JetPack 5.1からはなぜか l4t.csv
のみが存在し、今まであったはずの cuda.csv
や cudnn.csv
が見当たらない。
$ ls -la /etc/nvidia-container-runtime/host-files-for-container.d/
total 24
drwxr-xr-x 2 root root 4096 Mar 20 12:01 .
drwxr-xr-x 3 root root 4096 Apr 29 18:15 ..
-rw-r--r-- 1 root root 16370 Mar 20 00:14 l4t.csv
下記のフォーラムを見ると、コンテナ内に自分でインストールする必要があるらしい。
ただ、コンテナごとにインストールするのが面倒だったので、結局 hostPath
でマウントすることにした。
volumes:
- name: cuda
hostPath:
path: /usr/local/cuda-11.4
- name: cudnn
hostPath:
path: /usr/lib/aarch64-linux-gnu/libcudnn.so.8
コンテナのユーザがrootじゃないとGPUを利用できない
コンテナ内でPyTorchをインストールして一般ユーザでGPUが利用できるかチェックしたところ、以下のエラー。
➜ python3 -c "import torch; print(torch.cuda.is_available())"
NvRmMemInitNvmap failed with Permission denied
549: Memory Manager Not supported
****NvRmMemInit failed**** error type: 196626
*** NvRmMemInit failed NvRmMemConstructor
/home/yuanying/src/github.com/yuanying/uribo/.venv/lib/python3.8/site-packages/torch/cuda/__init__.py:107: UserWarning: CUDA initialization: Unexpected error from cudaGetDeviceCount(). Did you run some cuda functions before calling NumCudaDevices() that might have already set an error? Error 801: operation not supported (Triggered internally at /opt/pytorch/pytorch/c10/cuda/CUDAFunctions.cpp:109.)
return torch._C._cuda_getDeviceCount() > 0
False
Permission denied
とは何のPermissionかわからなかったが、/dev/nvhost*
を確認したところ、一般ユーザがGPUを使うためにはvideo
グループに属していないといけないようだった。
ということで、Dockerfile
で作成した一般ユーザを video
グループに追加したらうまく動くようになった。
RUN useradd -G video -g 50 -m -s /bin/bash -u 501 "$USER"
ただ、gpu-operatorで作成した環境だと、/dev/nvhost*
は誰でも読み書きできるようになっていたため、色々謎がある。