🍃

mmdebstrapを使ってJetson NanoへUbuntu 20.04環境を最小クリーンインストールする

2021/12/18に公開

概要

Jetson NanoのOSをubuntu 20.04以降へ更新するのはけっこう大変です。JetPack(ubuntu 18.04)をベースにアップデートすることはできますが、実際にやってみると時間がかかるうえ途中でダイアログを出して止まったりするので手間もかかります。依存関係をきちんと把握して対処しないと、netplanなどのOSの基本的なコンポーネントが削除されてネットにつながらないシステムが出来上がったりします。

今回、Jetson Nano用にミニマルな構成のubuntu 20.04環境をクリーンインストールすることができましたので、その作業手順をご紹介します。最小構成なら10〜20分程度でインストールが終わりますので、かなりの時短ができると思います。ミニマルなシステムをベースにして必要なコンポーネントをビルドアップする方が、かえって環境構築が簡単だと実感されるかも知れません。

作業の流れ

作業の流れは次のとおりです。

  1. Jetson NanoをJetPackで起動する
  2. USBカードリーダ経由で別のmicroSDカードへ最小構成のubuntuをインストールする
    2.1. mmdebstrapを使ってubuntuを展開する
    2.1. chrootで入ってJetson Linux Driver Package (L4T)を追加する
  3. 必要に応じて開発環境やGUIデスクトップ環境などを追加する

これでシンプルなubuntu 20.04環境が出来上がります。

準備

用意するもの

Jetson Nano、microSDカード2枚、USBカードリーダ
SDカード2枚とUSBカードリーダを使用します。本記事では2枚のSDカードを区別するために、それぞれ親SD、子SDと呼ぶことにします。

  • Jetson Nano
  • microSDカード2枚
    • 親SD:JetPackホスト用のmicroSD
    • 子SD:ubuntu 20.04のインストールターゲットとなるmicroSD
  • microSDカード用のUSBカードリーダ

JetPackのインストール(親SD、子SDとも)

親SD、子SDの両方にJetPackをインストールして、それぞれ一旦Jetson Nanoを起動して設定を終わらせておきます。子SDは後ほどパーティション1の中身を削除することになりますが、microSDカード上にはOSパーティション以外にも固有のパーティションが複数ありますので、それらを作成しておくためにこの作業が必要です。

クリーンインストール開始

Jetson Nanoの起動

準備を済ませた親SDでJetson Nanoを起動して、まずはJetPack自身のOSパッケージのアップデートを行います。

JetPack親SD
sudo apt update
sudo apt upgrade
sudo shutdown -r now

子SDのマウント

USBカードリーダをJetson NanoのUSBポートへ接続して、子SDのデバイスとパーティションを探します。パーティション1〜14が存在するsdデバイスが該当するmicroSDカードです。

JetPack親SD
ls /dev/sd*
ls /dev/sd*の出力例
/dev/sda  /dev/sdc  /dev/sdd1   /dev/sdd11  /dev/sdd13  /dev/sdd2  /dev/sdd4  /dev/sdd6  /dev/sdd8
/dev/sdb  /dev/sdd  /dev/sdd10  /dev/sdd12  /dev/sdd14  /dev/sdd3  /dev/sdd5  /dev/sdd7  /dev/sdd9

ここではsddが該当するmicroSDカードです。パーティション1を/mntへマウントします。

JetPack親SD
sudo mount /dev/sdd1 /mnt

マウントしたパーティション(子SDのパーティション1)の中身をすべて削除します。

JetPack親SD
sudo rm -rf /mnt/*

作業用コンテナのセットアップとmmdebstrapの実行

mmdebstrapはシステム環境構築ツールです。比較的新しいツールなので、ubuntuでは19.04以降で使用できます。JetPackのOSはubuntu 18.04であるためmmdebstrapコマンドがありません。今回はLXD/LXCを使ってJetPack上にubuntu 20.04の作業用コンテナを立ち上げて、そこでmmdebstrapを使用します。

JetPack親SD
sudo apt install -y lxd
sudo lxd init --auto
lxc launch ubuntu:20.04 mm

コンテナ名は短くmmとしました。続いて、ホストの/mntをコンテナの/mntにマウントします。その後、設定反映のためにコンテナを再起動してからコンテナに入ります。

JetPack親SD
lxc config device add mm mnt disk source=/mnt path=mnt
lxc config set mm security.privileged true
lxc config set mm security.nesting true
lxc restart mm
lxc exec mm -- /bin/bash

mmdebstrapをインストールします。

コンテナ
apt update
apt upgrade -y
apt install -y mmdebstrap

mmdebstrapを使ってubuntu 20.04 (名称focal) を/mntへインストールします。

コンテナ
mmdebstrap --components="main restricted universe multiverse" focal /mnt http://ports.ubuntu.com/ubuntu-ports

進捗を眺めながらインストールが終わるのを待ちます。数分程度です。

I: automatically chosen mode: root
I: chroot architecture arm64 is equal to the host's architecture
I: running apt-get update...
done
I: downloading packages with apt...
done
I: extracting archives...
done
I: installing packages...
done
I: downloading apt...
done
I: installing apt...
done
I: installing remaining packages inside the chroot...
done
I: cleaning package lists and apt cache...
done
done

USB2接続の場合、4分程度で終わりました。そのうち2/3以上はI/O waitに費やされているようです。

real    4m1.236s
user    0m54.472s
sys     0m16.680s

終わったらexitしてコンテナから抜けます。

コンテナ
exit

コンテナの役目はここまでです。

ubuntu 20.04環境の初期設定

親SDのJetPackからファイル3つをubuntu 20.04環境へコピーします。これらは後ほどL4Tをインストールする際に参照されます。

JetPack親SD
sudo cp -i /etc/nv_boot_control.conf /mnt/etc/
sudo cp -i /etc/apt/sources.list.d/nvidia-l4t-apt-source.list /mnt/etc/apt/sources.list.d/
sudo cp -r -i /boot/extlinux /mnt/boot/

このタイミングで子SDの/etc/apt/sources.listファイル(親SDからは/mnt/etc/apt/sources.listとして見える)を次のように編集しておきます。

/mnt/etc/apt/sources.list
deb http://ports.ubuntu.com/ubuntu-ports focal main restricted universe multiverse
deb http://ports.ubuntu.com/ubuntu-ports focal-updates main restricted universe multiverse
deb http://ports.ubuntu.com/ubuntu-ports focal-security main restricted universe multiverse
deb http://ports.ubuntu.com/ubuntu-ports focal-backports main restricted universe multiverse

必要なデバイスをmountしたうえで、chrootでubuntu 20.04環境へ入ります。

JetPack親SD
sudo mount -t proc none /mnt/proc
sudo mount -t devtmpfs none /mnt/dev
sudo mount -t sysfs none /mnt/sys
sudo chroot /mnt /bin/su

以降はchroot内での作業が続きます。

初期設定をおこないます。

chroot内
cd
echo "/dev/root / ext4 defaults 0 1" >> /etc/fstab
echo "child" > /etc/hostname
echo "Asia/Tokyo" > /etc/timezone
cp /usr/share/zoneinfo/Japan /etc/localtime
locale-gen ja_JP.UTF-8
echo -e "network:\n  version: 2\n  ethernets:\n    eth0:\n      dhcp4: yes" > /etc/netplan/01-dhcp.yaml

ユーザを作成します。(ここではユーザ名をfooとしています)

chroot内
adduser foo
usermod -aG sudo foo

L4Tのインストール準備

aptにNVIDIAのキーを登録します。初回のapt updateではエラーが出ますがキーを登録すれば消えますので問題ありません。

chroot内
apt update
apt install -y gnupg
apt-key adv --fetch-key http://repo.download.nvidia.com/jetson/jetson-ota-public.asc
apt update

L4Tが依存するlibffi6パッケージをubuntu 18.04用のリポジトリから取得してインストールします。(問題なくインストールできます)

chroot内
apt install -y wget
wget http://ports.ubuntu.com/pool/main/libf/libffi/libffi6_3.2.1-8_arm64.deb
apt install -y ./libffi6_*_arm64.deb 

後ほどI2Cを通してJetson Nano本体のブートローダを書き換えますので、あらかじめi2c-toolsをインストールしておきます。

chroot内
apt install -y i2c-tools

L4Tのインストール

最初にnvidia-l4t-apt-sourceをインストールします。既存ファイルを上書きさせます。

chroot内
apt -o Dpkg::Options::="--force-confnew" install -y nvidia-l4t-apt-source

続いてnvidia-l4t-initをインストールします。/etc/systemd/sleep.confファイルがsystemdパッケージとバッティングしますので上書きインストールします。

chroot内
apt -o Dpkg::Options::="--force-overwrite" install -y nvidia-l4t-init

L4TのBSPコンポーネントグループをインストールします。

chroot内
apt install -y \
  jetson-gpio-common \
  nvidia-l4t-3d-core \
  nvidia-l4t-apt-source \
  nvidia-l4t-bootloader \
  nvidia-l4t-camera \
  nvidia-l4t-configs \
  nvidia-l4t-core \
  nvidia-l4t-cuda \
  nvidia-l4t-firmware \
  nvidia-l4t-graphics-demos \
  nvidia-l4t-gstreamer \
  nvidia-l4t-init \
  nvidia-l4t-initrd \
  nvidia-l4t-jetson-io \
  nvidia-l4t-jetson-multimedia-api \
  nvidia-l4t-kernel \
  nvidia-l4t-kernel-dtbs \
  nvidia-l4t-kernel-headers \
  nvidia-l4t-multimedia \
  nvidia-l4t-multimedia-utils \
  nvidia-l4t-oem-config \
  nvidia-l4t-tools \
  nvidia-l4t-wayland \
  nvidia-l4t-weston \
  nvidia-l4t-x11 \
  nvidia-l4t-xusb-firmware \
  python-jetson-gpio \
  python3-jetson-gpio

Tegra用のDRM (Direct Rendering Manager)を入れておきます。

chroot内
apt install -y libdrm-tegra0

インストール作業の終了

chrootを抜けてJetson Nanoをシャットダウンします。

chroot内
exit
JetPack親SD
sudo shutdown -h now

作成したUbuntu 20.04の起動とパッケージの追加

作成した子SDをJetson Nanoへ装着して起動します。最小インストールのシンプルなCLIのubuntuが起動します。

アクセス権の追加

最初に、ユーザに対してシステムリソースやデバイスへのアクセス権を付与します。

# ログファイル
sudo usermod -aG adm $USER
# GPU、オーディオ
sudo usermod -aG video $USER
sudo usermod -aG audio $USER
# 外部機器, I/O端子, ほか
sudo usermod -aG cdrom $USER
sudo usermod -aG plugdev $USER
sudo usermod -aG gpio $USER
sudo usermod -aG i2c $USER
sudo usermod -aG dip $USER
sudo usermod -aG lpadmin $USER

Timezoneの設定

システムのTimezoneも設定しておきましょう。

sudo timedatectl set-timezone Asia/Tokyo

swapの追加

デフォルトのswapはzramを使った2GBですので、すぐに足りなくなってしまいます。ファイルシステム上にスワップファイルを6GBほど確保して追加しておきます。

sudo fallocate -l 6g /swapfile
sudo mkswap /swapfile
sudo chmod 0600 /swapfile
sudo sh -c "echo /swapfile none swap defaults 0 0 >>/etc/fstab"
sudo swapon -p 1 /swapfile

追加パッケージのインストール

用途に応じて必要なパッケージを追加インストールします。参考までに次のパッケージのインストール方法を以下に記します。

  • 言語パック
  • 日本語キーボードの設定
  • openssh-server
  • nvidia-container
  • CUDA および cuDNN
  • VisionWorks
  • VPI および nvidia-opencv
  • gputools
  • uff-converter-tf
  • nsight-systems-cli
  • deepstream
  • graphsurgeon-tf
  • cuda-minimal-build
  • cuda-gdb-src
  • TensorRT
  • デスクトップ環境
    • Unity
    • GNOME3
    • KDE
    • LXQt
    • XFce
    • MATE
    • Cinnamon
    • Budgie
    • UKUI

言語パック

sudo apt install -y language-pack-ja language-pack-en

日本語キーボードの設定

sudo dpkg-reconfigure keyboard-configuration

次の順に設定します。

  • Generic 105-key (Intl) PC
  • Japanese

openssh-server

sudo apt install -y openssh-server

nvidia-container

sudo apt install -y nvidia-container

CUDA および cuDNN

sudo apt install -y nvidia-cuda nvidia-cudnn8

Computer vision (VisionWorks)

sudo apt install -y nvidia-visionworks

Computer vision (VPI) および nvidia-opencv

依存関係がキツイので不足するコンポーネントをubuntu 18.04から取得します。libopencv-devがubuntu 20.04とバッティングしますのでnvidiaのパッケージバージョンを指定したうえholdマークを付けます。その際にubuntu 20.04由来のopencv関連のパッケージが多数不要となりautoremove対象となります。

wget \
  http://ports.ubuntu.com/pool/main/libv/libvpx/libvpx5_1.7.0-3ubuntu0.18.04.1_arm64.deb \
  http://ports.ubuntu.com/pool/universe/f/ffmpeg/libavcodec57_3.4.8-0ubuntu0.2_arm64.deb \
  http://ports.ubuntu.com/pool/universe/f/ffmpeg/libavformat57_3.4.8-0ubuntu0.2_arm64.deb \
  http://ports.ubuntu.com/pool/universe/f/ffmpeg/libavutil55_3.4.8-0ubuntu0.2_arm64.deb \
  http://ports.ubuntu.com/pool/universe/f/ffmpeg/libswresample2_3.4.8-0ubuntu0.2_arm64.deb \
  http://ports.ubuntu.com/pool/universe/f/ffmpeg/libswscale4_3.4.8-0ubuntu0.2_arm64.deb \
  http://ports.ubuntu.com/pool/universe/x/x264/libx264-152_0.152.2854+gite9a5903-2_arm64.deb \
  http://ports.ubuntu.com/pool/universe/x/x265/libx265-146_2.6-3_arm64.deb

sudo apt install -y \
  ./libvpx5_*_arm64.deb \
  ./libavcodec57_*_arm64.deb \
  ./libavformat57_*_arm64.deb \
  ./libavutil55_*_arm64.deb \
  ./libswresample2_*_arm64.deb \
  ./libswscale4_*_arm64.deb \
  ./libx264-152_*_arm64.deb \
  ./libx265-146_*_arm64.deb

sudo apt install -y --allow-downgrades --allow-change-held-packages \
  nvidia-opencv \
  libopencv \
  libopencv-dev=4.1.1-2-gd5a58aa75 \
  libopencv-python \
  libopencv-samples \
  opencv-licenses

sudo apt-mark hold libopencv-dev

sudo apt install -y \
  libnvvpi1 \
  vpi1-demos \
  vpi1-dev \
  vpi1-samples \
  python-vpi1
以下のパッケージが自動でインストールされましたが、もう必要とされていません:
  gdal-data ibverbs-providers javascript-common libaec0 libarmadillo9
  libarpack2 libavcodec-dev libavformat-dev libavresample-dev libavresample4
  libavutil-dev libcaf-openmpi-3 libcfitsio8 libcharls2
  libcoarrays-openmpi-dev libdap25 libdapclient6v5 libdc1394-22-dev
  libepsilon1 libevent-2.1-7 libevent-core-2.1-7 libevent-dev
  libevent-extra-2.1-7 libevent-openssl-2.1-7 libevent-pthreads-2.1-7
  libexif-dev libexif-doc libexif12 libfreexl1 libfyba0 libgd3 libgdal26
  libgdcm-dev libgdcm3.0 libgeos-3.8.0 libgeos-c1v5 libgeotiff5 libgif7
  libgl2ps1.4 libgphoto2-6 libgphoto2-dev libgphoto2-l10n libgphoto2-port12
  libhdf4-0-alt libhdf5-103 libhdf5-openmpi-103 libhwloc-dev libhwloc-plugins
  libhwloc15 libibverbs-dev libibverbs1 libilmbase-dev libjbig-dev libjpeg-dev
  libjpeg-turbo8-dev libjpeg8-dev libjs-jquery libkmlbase1 libkmldom1
  libkmlengine1 liblept5 liblzma-dev libminizip1 libmysqlclient21
  libnetcdf-c++4 libnetcdf15 libnl-3-200 libnl-3-dev libnl-route-3-200
  libnl-route-3-dev libnspr4 libnss3 libnuma-dev libodbc1 libogdi4.1
  libopencv-calib3d4.2 libopencv-contrib4.2 libopencv-core4.2 libopencv-dnn4.2
  libopencv-features2d4.2 libopencv-flann4.2 libopencv-highgui4.2
  libopencv-imgcodecs4.2 libopencv-imgproc4.2 libopencv-ml4.2
  libopencv-objdetect4.2 libopencv-photo4.2 libopencv-shape4.2
  libopencv-stitching4.2 libopencv-superres4.2 libopencv-video4.2
  libopencv-videoio4.2 libopencv-videostab4.2 libopencv-viz4.2
  libopencv4.2-java libopencv4.2-jni libopenexr-dev libopenmpi-dev libopenmpi3
  libpciaccess0 libpmix2 libpng-dev libpng-tools libpoppler97 libpq5 libproj15
  libprotobuf17 libqhull7 libraw1394-dev libraw1394-tools libsocket++1
  libspatialite7 libsuperlu5 libswresample-dev libswscale-dev libsz2
  libtbb-dev libtesseract4 libtiff-dev libtiffxx5 liburiparser1 libvtk6.3
  libxerces-c3.2 libxnvctrl0 mysql-common odbcinst odbcinst1debian2
  openmpi-bin openmpi-common poppler-data proj-bin proj-data

gputools

sudo apt install -y nvidia-l4t-gputools

uff-converter-tf

sudo apt install -y uff-converter-tf

nsight-systems-cli

sudo apt install -y nsight-systems-cli-2021.2.3

deepstream

sudo apt install -y deepstream-6.0

graphsurgeon-tf

sudo apt install -y graphsurgeon-tf

cuda-minimal-build

sudo apt install -y cuda-minimal-build-10-2

cuda-gdb-src

sudo apt install -y cuda-gdb-src-10-2

TensorRT (非推奨)

wget http://ports.ubuntu.com/pool/main/p/python3.6/python3.6_3.6.9-1~18.04ubuntu1.6_arm64.deb
wget http://ports.ubuntu.com/pool/main/p/python3.6/python3.6-minimal_3.6.9-1~18.04ubuntu1.6_arm64.deb
wget http://ports.ubuntu.com/pool/main/p/python3.6/libpython3.6-stdlib_3.6.9-1~18.04ubuntu1.6_arm64.deb
wget http://ports.ubuntu.com/pool/main/p/python3.6/libpython3.6-minimal_3.6.9-1~18.04ubuntu1.6_arm64.deb
wget http://ports.ubuntu.com/pool/main/r/readline/libreadline7_7.0-3_arm64.deb
wget http://ports.ubuntu.com/pool/main/p/python3-defaults/python3_3.6.7-1~18.04_arm64.deb
wget http://ports.ubuntu.com/pool/main/p/python3-defaults/python3-minimal_3.6.7-1~18.04_arm64.deb
wget http://ports.ubuntu.com/pool/main/p/python3-defaults/libpython3-stdlib_3.6.7-1~18.04_arm64.deb

sudo apt install -y --allow-downgrades \
  ./python3_*_arm64.deb \
  ./python3-minimal_*_arm64.deb \
  ./libpython3-stdlib_*_arm64.deb \
  ./python3.6_*_arm64.deb \
  ./python3.6-minimal_*_arm64.deb \
  ./libpython3.6-stdlib_*_arm64.deb \
  ./libpython3.6-minimal_*_arm64.deb \
  ./libreadline7_*_arm64.deb

sudo apt install -y nvidia-tensorrt python3-libnvinfer python3-libnvinfer-dev
sudo apt-mark hold nvidia-tensorrt python3-libnvinfer python3-libnvinfer-dev

デスクトップ環境

デスクトップ環境を利用するためにはGPUとオーディオデバイスへのアクセス権が必要です。

sudo usermod -aG video $USER
sudo usermod -aG audio $USER

また、使用するディスプレイマネージャに応じてアクセス権を設定してください。

# gdm
sudo usermod -aG video gdm
sudo usermod -aG gdm $USER
# lightdm
sudo usermod -aG video lightdm
sudo usermod -aG lightdm $USER
# sddm
sudo usermod -aG video sddm
sudo usermod -aG sddm $USER

Unity

sudo apt install -y ubuntu-unity-desktop
sudo usermod -aG video $USER
sudo usermod -aG audio $USER
sudo usermod -aG video lightdm
sudo usermod -aG lightdm $USER

GNOME3

sudo apt install -y ubuntu-desktop
sudo usermod -aG video $USER
sudo usermod -aG audio $USER
sudo usermod -aG video gdm
sudo usermod -aG gdm $USER

KDE

sudo apt install -y kubuntu-desktop
sudo usermod -aG video $USER
sudo usermod -aG audio $USER
sudo usermod -aG video sddm
sudo usermod -aG sddm $USER

SDDMが使えない場合はlightdmで代替できます。

LXQt

sudo apt install -y lubuntu-desktop
sudo usermod -aG video $USER
sudo usermod -aG audio $USER
sudo usermod -aG video sddm
sudo usermod -aG sddm $USER

SDDMが使えない場合はlightdmで代替できます。GPUリソースをあまり使わないようなので動作が軽いです。

Xfce

sudo apt install -y xubuntu-desktop
sudo usermod -aG video $USER
sudo usermod -aG audio $USER
sudo usermod -aG video lightdm
sudo usermod -aG lightdm $USER

ログイン画面lightdmのテーマlightdm-gtk-greeterがインストールされますがミニキーボードのNumLk制御との相性がよくありませんでした。同様の環境の方へはlightdm-gtk-greeterのアンインストールをおすすめします。

MATE

sudo apt install -y ubuntu-mate-desktop
sudo usermod -aG video $USER
sudo usermod -aG audio $USER
sudo usermod -aG video lightdm
sudo usermod -aG lightdm $USER

GPUリソースをあまり使わないようです。

Cinnamon

sudo apt install -y cinnamon-desktop-environment
sudo usermod -aG video $USER
sudo usermod -aG audio $USER
sudo usermod -aG video lightdm
sudo usermod -aG lightdm $USER

Budgie

sudo apt install -y ubuntu-budgie-desktop
sudo usermod -aG video $USER
sudo usermod -aG audio $USER
sudo usermod -aG video lightdm
sudo usermod -aG lightdm $USER

nvpmodel_indicator.pyがパネル上で大きな顔をしますので対応が必要です。

UKUI

sudo apt install -y ubuntukylin-desktop
sudo usermod -aG video $USER
sudo usermod -aG audio $USER
sudo usermod -aG video lightdm
sudo usermod -aG lightdm $USER

Jetson NanoのGPUに対して画面エフェクトが多めです。

まとめ

mmdebstrapで作成したブートストラップ環境にL4Tを追加することで、Jetson Nano用のUbuntu 20.04の最小クリーンインストールを行うことができます。必要に応じてコンポーネントを追加することにより、フットプリントが小さくて実用的なファイルシステムが作成できます。

本稿の手順でubuntu 21.10環境のインストールも可能でした。

https://zenn.dev/marbocub/articles/cfb2b4b3ba605d

GitHubで編集を提案

Discussion