はじめに
NVIDIA SDK Manager dockerを使用し、以下3点をインストールする方法を紹介します。
・L4TのLinux Kernelに変更を加えビルドした.img
ファイル(カスタムイメージと呼びます)
・Jetsonから読み取ったカスタムイメージ
・Jetson SDK Components
セットアップ環境の前提
ホストコンピュータは下記の記事でセットアップしたものを使用します。
カスタムイメージのインストール準備
カスタムイメージは、L4T Driver Package に含まれる flash.sh
を使用しJetsonにインストールしますが、flash.sh
はSDK Managerのプログラムを利用します。過去のバージョンのSDK ManagerはSDK ManagerをインストールするPC(ホストコンピュータと呼びます)のビデオドライバーやCUDAのバージョンをアップデートしなければならない仕様だったことが私のトラウマ(笑)になっており、ホストコンピュータに直接SDK Managerをインストールしたくありません。よって、SDK Manager Dockerを使用します。
SDK Manager Docker
SDK ManagerのDockerイメージはNVIDIAから配布されていますが、flash.sh
を使用するにはひと手間が必要です。
まず、公式からDockerイメージをダウンロードします。注意点は次のとおりです。
- 古いSDK Managerはユーザ認証に失敗するため、新しいバージョンをダウンロードします
- イメージのUbuntuバージョンは、インストールするLinux KernelとJetPackのインストールに対応したものを選択します(ダウンロードページに対応表があります)
ホストコンピュータにDockerイメージをロードします。
.tar.gz
のファイル名は、ダウンロードしたものに置き換えます。
docker load -i ~/Downloads/sdkmanager-2.1.0.11660-Ubuntu_18.04_docker.tar.gz
SDK Managerは、インストールファイルをビルドする際、Jetsonハードウェアの仮想化にQEMUを使用します。しかし、Jetsonのアーキテクチャであるaarch64のプロファイルがSDK Manager Dockerになく、プロファイルをイメージに加えます。また、ホストコンピュータがプロキシを経由してインターネットへ接続する環境下にあり、JetPackをダウンロードするためにプロキシサーバの設定を加えます。これらにDocker composeを使用します。
以下のファイルを準備します。
docker_sdkmanager
├── Dockerfile.sdk
├── build_sdk.sh
├── container_bind
│ ├── qemu-aarch64
│ └── setup_sdk.sh
└── docker-compose.yaml
sdkmanager:2.1.0.11660-Ubuntu_18.04
はダウンロードしたイメージファイルに変更します。
FROM sdkmanager:2.1.0.11660-Ubuntu_18.04
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG L4T_WORKDIR
ARG CONTAINER_BIND
ENV http_proxy ${HTTP_PROXY}
ENV https_proxy ${HTTPS_PROXY}
ENV L4T_WORKDIR ${L4T_WORKDIR}
ENV CONTAINER_BIND ${CONTAINER_BIND}
RUN sudo touch /etc/apt/apt.conf.d/90proxy && \
sudo echo 'Acquire::http::proxy "'${http_proxy}'";' | sudo tee -a /etc/apt/apt.conf.d/90proxy > /dev/null && \
sudo echo 'Acquire::https::proxy "'${https_proxy}'";' | sudo tee -a /etc/apt/apt.conf.d/90proxy > /dev/null && \
sudo echo 'Acquire::ftp::proxy "'${http_proxy}'";' | sudo tee -a /etc/apt/apt.conf.d/90proxy > /dev/null && \
sudo echo 'Acquire::socks::proxy "'${http_proxy}'";' | sudo tee -a /etc/apt/apt.conf.d/90proxy > /dev/null
RUN sudo apt-get update -y
RUN sudo apt-get install -y --no-install-recommends \
qemu-user-static \
binfmt-support \
binutils \
wget
RUN wget https://github.com/qemu/qemu/raw/master/scripts/qemu-binfmt-conf.sh
RUN chmod +x qemu-binfmt-conf.sh
RUN sudo ./qemu-binfmt-conf.sh --qemu-path /usr/bin --qemu-suffix -static --debian
ENTRYPOINT []
公式のDockerイメージは ENTRYPOINTに sdkmanager --cli
が指定されていますが、flash.sh
なども使用するためENTRYPOINTを無しにします。
#!/bin/bash
docker-compose build \
--build-arg HTTP_PROXY=${http_proxy} \
--build-arg HTTPS_PROXY=${https_proxy} \
using_jetpack
docker-compose run --name using_jetpack_${USER} using_jetpack /bin/bash -c '${CONTAINER_BIND}/setup_sdk.sh'
docker container commit using_jetpack_${USER} jetpack_setup
docker container rm using_jetpack_${USER}
package qemu-user-static
interpreter /usr/bin/qemu-aarch64-static
flags: OC
offset 0
magic \x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00
mask \xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff
#!/bin/bash
sudo mkdir -p ${L4T_WORKDIR}
sudo chown nvidia:root ${L4T_WORKDIR}
sudo cp "${CONTAINER_BIND}/qemu-aarch64" /usr/share/binfmts/
sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
sudo update-binfmts --enable qemu-aarch64
version: "3.7"
services:
using_jetpack:
image: jetpack_setup
privileged: true
build:
context: ./
dockerfile: ./Dockerfile.sdk
args:
- HTTP_PROXY=${http_proxy}
- HTTPS_PROXY=${https_proxy}
- L4T_WORKDIR=/tmp/nvidia/sdkm_downloads
- CONTAINER_BIND=/var/container_bind
volumes:
- type: bind
source: /dev
target: /dev
- type: bind
source: /dev/bus/usb
target: /dev/bus/usb
- type: bind
source: /media/${USER}
target: /media/nvidia:slave
- type: volume
source: jetpack_temporary
target: /tmp/nvidia
- type: bind
source: ./container_bind
target: /var/container_bind
network_mode: host
volumes:
jetpack_temporary:
Dockerイメージをビルドします。
chmod +x build_sdk.sh ./container_bind/setup_sdk.sh
./build_sdk.sh
JetPack Components
通常、SDK Managerを実行すると、NVIDIAサイトのログインを要求されます。これは、JetPack Componentsをダウンロードするためですが、一度ダウンロードしてしまえば使い回しができ、インストールする度にログインする必要がありません。よって、JetPack Componentsをダウンロードしておきます。ダウンロード先はDockerボリュームを指定するため、ダウンロードファイルはDockerコンテナを停止しても残存します。リフレッシュしたい場合は、Dockerボリュームを削除するだけです。
JETPACK_VERSION='4.5.1'
TARGET_HARDWARE='JETSON_XAVIER_NX'
docker-compose run --rm using_jetpack sdkmanager \
--cli \
--action downloadonly \
--download-folder /tmp/nvidia/sdkm_downloads \
--archived-versions \
--login-type devzone \
--product Jetson \
--target-os Linux \
--version ${JETPACK_VERSION} \
--target ${TARGET_HARDWARE} \
--flash skip \
--license accept \
--stay-logged-in false \
--collect-usage-data disable \
--exit-on-finish
-
この時点で、SDK ManagerからJetsonにJetPackをインストールする環境が整います。L4TのLinux Kernelを含めたJetPackをフルインストールする場合は、リカバリーモードでJetsonを起動し、USBケーブルでJetsonとホストコンピュータを接続し、以下のコマンドを実行します
docker-compose run --rm using_jetpack sdkmanager \ --cli \ --action install \ --check-for-updates false \ --login-type offline \ --download-folder /tmp/nvidia/sdkm_downloads \ --archived-versions \ --product Jetson \ --target-os Linux \ --version ${JETPACK_VERSION} \ --target ${TARGET_HARDWARE} \ --flash all \ --license accept \ --stay-logged-in false \ --collect-usage-data disable \ --exit-on-finish
-
SDK Managerのオプションは頻繁に変わるため、オプションは公式で調べます
https://docs.nvidia.com/sdk-manager/archives/index.html
バージョンを選択 >
Install with the Command Line
>General Arguments
-
SDK Managerは基本的に最新バージョンと1つ前のJetPackに対応していますが、
--archived-versions
オプションを加える事で過去のバージョンも利用可能になります
L4T Driver Package & Sample RootFs
公式からL4T Driver PackageとSample RootFsをダウンロードします。
以下のファイルを準備します。
-
Tegra186_Linux_R32.5.1_aarch64.tbz2
はダウンロードしたL4T Driver Packageに置き換えます -
Tegra_Linux_Sample-Root-Filesystem_R32.5.1_aarch64.tbz2
はダウンロードしたSample RootFsに置き換えます -
docker-compose.yaml
はusing_flash
サービスを追記します
docker_sdkmanager
├── Dockerfile.l4t
├── Dockerfile.sdk
├── build_l4t.sh
├── build_sdk.sh
├── container_bind
│ ├── Tegra186_Linux_R32.5.1_aarch64.tbz2
│ ├── Tegra_Linux_Sample-Root-Filesystem_R32.5.1_aarch64.tbz2
│ ├── qemu-aarch64
│ ├── setup_l4t.sh
│ └── setup_sdk.sh
└── docker-compose.yaml
FROM jetpack_setup
ARG L4T_DRIVERS
ARG L4T_SAMPLE_ROOTFS
ARG L4T_BOARD
ARG L4T_PARTITION
ENV L4T_DRIVERS ${L4T_DRIVERS}
ENV L4T_SAMPLE_ROOTFS ${L4T_SAMPLE_ROOTFS}
ENV L4T_BOARD ${L4T_BOARD}
ENV L4T_PARTITION ${L4T_PARTITION}
ENTRYPOINT []
#!/bin/bash
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]; then
echo "Error: Missing arguments."
echo "Usage: $0 <l4t_drivers> <l4t_sample_rootfs> <board> <partition>"
echo "Example(Product Module): $0 'Tegra186_Linux_R32.5.1_aarch64.tbz2' 'Tegra_Linux_Sample-Root-Filesystem_R32.5.1_aarch64.tbz2' 'jetson-xavier-nx-devkit-emmc' 'mmcblk0p1'"
echo "Example(Devkit): $0 'Tegra186_Linux_R32.5.1_aarch64.tbz2' 'Tegra_Linux_Sample-Root-Filesystem_R32.5.1_aarch64.tbz2' 'jetson-xavier-nx-devkit' 'mmcblk0p1'"
exit 1
fi
docker-compose build \
--build-arg L4T_DRIVERS=$1 \
--build-arg L4T_SAMPLE_ROOTFS=$2 \
--build-arg L4T_BOARD=$3 \
--build-arg L4T_PARTITION=$4 \
using_flash
docker-compose run --name using_flash_${USER} using_flash /bin/bash -c '${CONTAINER_BIND}/setup_l4t.sh'
docker container commit using_flash_${USER} l4t_setup
docker container rm using_flash_${USER}
#!/bin/bash
echo -n 'unpack l4t drivers and sample rootfs ...'
sudo tar xpf "${CONTAINER_BIND}/${L4T_DRIVERS}" -C "${L4T_WORKDIR}/"
echo -n ' doing ...'
sudo tar xpf "${CONTAINER_BIND}/${L4T_SAMPLE_ROOTFS}" -C "${L4T_WORKDIR}/Linux_for_Tegra/rootfs/"
echo ' done'
cd ${L4T_WORKDIR}/Linux_for_Tegra
sudo ./apply_binaries.sh
sudo ./flash.sh --no-flash ${L4T_BOARD} ${L4T_PARTITION}
version: "3.7"
services:
using_jetpack:
image: jetpack_setup
privileged: true
build:
context: ./
dockerfile: ./Dockerfile.sdk
args:
- HTTP_PROXY=${http_proxy}
- HTTPS_PROXY=${https_proxy}
- L4T_WORKDIR=/tmp/nvidia/sdkm_downloads
- CONTAINER_BIND=/var/container_bind
volumes:
- type: bind
source: /dev
target: /dev
- type: bind
source: /dev/bus/usb
target: /dev/bus/usb
- type: bind
source: /media/${USER}
target: /media/nvidia:slave
- type: volume
source: jetpack_temporary
target: /tmp/nvidia
- type: bind
source: ./container_bind
target: /var/container_bind
network_mode: host
using_flash:
image: l4t_setup
privileged: true
build:
context: ./
dockerfile: ./Dockerfile.l4t
args:
- L4T_DRIVERS
- L4T_SAMPLE_ROOTFS
- L4T_BOARD
- L4T_PARTITION
volumes:
- type: bind
source: /dev
target: /dev
- type: bind
source: /dev/bus/usb
target: /dev/bus/usb
- type: bind
source: /media/${USER}
target: /media/nvidia:slave
- type: volume
source: jetpack_temporary
target: /tmp/nvidia
- type: bind
source: ./container_bind
target: /var/container_bind
network_mode: host
volumes:
jetpack_temporary:
Dockerイメージをビルドします。
chmod +x build_l4t.sh ./container_bind/setup_l4t.sh
./build_l4t.sh 'Tegra186_Linux_R32.5.1_aarch64.tbz2' 'Tegra_Linux_Sample-Root-Filesystem_R32.5.1_aarch64.tbz2' 'jetson-xavier-nx-devkit' 'mmcblk0p1'
これで、NVIDIA公式のL4Tをインストールする準備が整いました。あとは、手を加えたL4Tの .img
や、Jetsonから読み取った .img
ファイルに置き換えます。.img
や L4T Driver Packageなどは、Dockerコンテナから参照できる /tmp/nvidia/Linux_for_Tegra
にあります。例えば、custom.img
に置き換える場合は次のように実行します。JetPack Components同様、Jetsonにインストールするファイルや custom.img
はDockerボリュームに保存されるため、Dockerコンテナを停止しても残存します。
docker-compose run --rm using_flash /bin/bash -c 'cd "${L4T_WORKDIR}/Linux_for_Tegra" && sudo cp "${CONTAINER_BIND}/custom.img" ./bootloader/system.img'
L4T_WORKDIR
等の変数はビルドの際Dockerイメージに組み込んでいます。
L4T インストール
リカバリーモードでJetsonを起動し、JetsonとホストコンピュータをUSBケーブルで接続し、flash.sh
を実行します。
docker-compose run --rm using_flash /bin/bash -c 'cd "${L4T_WORKDIR}/Linux_for_Tegra" && sudo ./flash.sh ${L4T_BOARD} ${L4T_PARTITION}'
Jetson SDK Components インストール
Jetson SDK ComponentsはJetPack Componentsの一部であり、Deep Learningや画像処理などGPGPUの恩恵を受けられる計算においてJetsonのリソースを効率よく使用するためのコンポーネントや、Jetson上の開発を支援するツール等がパッケージされたものです。flash.sh
は、L4TをJetsonにインストールするスクリプトであり、Jetson SDK Componentsを使用する場合別途インストールしなければなりません。ただし、Jetsonから読み取った .img
をインストールした場合は、読み取る前にインストールしたJetson SDK Componentsなどのパッケージが含まれています。
docker-compose run --rm using_jetpack sdkmanager \
--cli \
--action install \
--check-for-updates false \
--login-type offline \
--download-folder /tmp/nvidia/sdkm_downloads \
--archived-versions \
--product Jetson \
--target-os Linux \
--version ${JETPACK_VERSION} \
--deselect 'Jetson OS' \
--select 'Jetson SDK Components' \
--target ${TARGET_HARDWARE} \
--flash all \
--license accept \
--stay-logged-in false \
--collect-usage-data disable \
--exit-on-finish
おまけ Jetsonからsystem.imgを読み取る方法
JetsonのメインストレージであるeMMC/SD-Cardなどは、bootloaderやDeviceTree、APP等のパーティションがあり、ここではルートファイルシステムが記憶されているAPPパーティションのみを読み取ります。
リカバリーモードでJetsonを起動し、USBケーブルでJetsonとホストコンピュータを接続し、flash.sh
を実行します。
docker-compose run --rm using_flash /bin/bash -c 'cd "${L4T_WORKDIR}/Linux_for_Tegra" && sudo ./flash.sh -r -k APP -G custom.img ${L4T_BOARD} ${L4T_PARTITION}'
参考文献