2022-12-05 / @syui

arch , docker / arch

archlinuxでsystemd-nspawnを使いcontinerを立ててみた

botに複数の仮想環境を構築する必要があったので、今回はsystemd-nspawnを採用してみることにしました。

結論から言うと、systemd-nspawnはとっつきにくいですが、一度使えるようになっておくと、本格的に便利だと感じました。

ただ、とっつきにくさがすごい。コマンドも複数あって混乱を招くと思われます。

archwikiの最初の説明が以下です。

$ mkdir -p ~/arch
$ sudo pacstrap -c ~/arch base
# -D : chroot
$ sudo systemd-nspawn -D ~/arch
$ passwd
$ logout
# -b : コンテナ起動
$ sudo systemd-nspawn -b -D ~/arch
# -n : ネットワーク
$ sudo systemd-nspawn -b -D ~/arch -n

これは色んな意味で正しいのですが、私の環境では動作しません。

設定したpasswordでloginできない。なお、設定していないと空なのでenterでloginできるはず(たぶん)。ttyのsecurityが働いているからです。

Arch Linux 6.0.11-arch1-1 (pts/1)
arch login:
arch-nspawn login: root
Login incorrect

ここでホストから~/arch/etc/securettyを編集し、ここではpts/1でloginしようとしているため、これを追記します。pts/0ならpts/0ですし、その他ならそのttyを記述してください。

$ sudo vim ~/arch/etc/securetty

さて、loginできたとしましょう。

一旦、poweroffして仮想環境(continer)を落とします。

$ poweroff
$ machinectl list

次に、本来のsystemd-nspawnの一般的な使い方を説明します。

$ machinectl --help

$ sudo mv ~/arch /var/lib/machines/
$ sudo machinectl list-images
$ sudo machinectl start arch
$ sudo machinectl login arch

# vmの削除
$ sudo machinectl remove arch

# vmにshell
# loginはおすすめしません。Ctrl+Dで抜けられません。shellの場合はexitできます。continerはupしたままになります。
$ sudo machinectl shell arch

# vmをdown
$ sudo machinectl poweroff arch
$ sudo machinectl terminate arch

/var/lib/machinesにおいたcontiner image(dir)をmachinectlで呼び出します。

これは、systemctlsystemd-nspawn@archでも同じようなことができます。

# archというcontinerをstart
$ sudo systemctl start systemd-nspawn@arch
$ sudo machinectl start arch

# archというccontinerをPC起動時に立ち上げる
$ sudo systemctl enable systemd-nspawn@arch
$ sudo machinectl enable arch

$ sudo systemctl daemon-reload

machinectl, systemd-nspawn, systemctlのどれを使ってもいいですが、個人的にはmachinectlをおすすめします。しかし、それぞれが使い方に微妙な違いを含んでいます。

machinectlは主にvm操作で、pacstrapはarchの構築、systemctlはホスト環境の構築、systemd-nspawnはdir(chroot)操作です。

正直、わかりづらい。

dockerのほうが遥かにわかりやすいですね。

ですが、archer(archlinuxを普段使いしる人)にとっては、慣れると扱いやすいし、便利そうだと感じています。

# イメージのダウンロード
$ sudo machinectl pull-tar --verify=no http://localhost:8000/arch.tar.gz arch

# アーカイブ
$ sudo machinectl export-tar --format=[gz, bzip2, xz] [コンテナ名] [ファイル名]
# xz でマルチスレッド圧縮をする例 (一番お勧め!)
$ maxz() { machinectl export-tar $1 $1.tar && nice -n 20 xz -z -f -T $(nproc) -vv $1.tar; }
$ maxz gbase
# インポート
$ sudo machinectl import-tar [ファイル名] [コンテナ名]

# docker imgをインポート
$ sudo docker export $(docker create debian:latest) | machinectl import-tar - debian


# hostのnetworkを使う, VirtualEthernetもconfiguredにすると有効
$ networkctl
IDX LINK    TYPE     OPERATIONAL SETUP
  1 lo      loopback carrier     unmanaged
  2 eth0  ether    routable    configured
  3 ve-arch ether    no-carrier  configuring
$ sudo vim /etc/systemd/nspawn/arch.nspawn
[Network]
VirtualEthernet=no
# ssh接続
$ ssh-keygen -f ~/.ssh/test
$ sudo cat ~/.ssh/test.pub >> /var/lib/machines/arch/root/.ssh/authorized_keys

$ sudo machinectl shell arch
$ pacman -S openssh
$ vim /etc/ssh/sshd_config
$ systemctl enable sshd
$ systemctl start ssh
$ exit

$ ssh root@localhost -p xxx -i ~/.ssh/test

bot運用をどうするか

例えば、botに一つの仮想環境をあてがい、その中で使える機能を限定して、1日に1回、もしくは呼び出すごとにresetされるように運用するのがいいかも。

その場合、cronとcloneを駆使してやるとよさそう。

$ sudo machinectl clone arch backup
$ sudo machinectl poweroff arch
$ sudo machinectl remove arch
$ sudo machinectl clone backup arch

ref

https://wiki.archlinux.org/title/systemd-nspawn

https://blog.usaturn.net/contents/2016/manage_spawn_container/

https://blog.n-z.jp/blog/2022-09-27-systemd-nspawn.html