systemd_nspawn

chroot

本題に入る前に、理解しておきたい点がある。 Linuxに於いて、プロセスはルートディレクトリを属性の1つとして持つ。 それは普通、プロセス内で/から始まる絶対パスの解釈に使われ、通常はシステムのルートディレクトリ(/)が設定されている。 chroot()システムコールはルートディレクトリを指定したパスに変更する。 これにより、アクセス可能なファイル等を制限出来る。

systemd-nspawn

systemd-nspawnchrootの強化版と解釈出来る。 chrootと異なる点として、systemd-nspawnは ファイルシステムの階層やプロセスツリー、各種IPC、ホスト名やドメイン等も完全に仮想化、隔離する。 名前空間を隔離し、軽量なコンテナとして扱える。

また、systemd-nspawnを用いるモチベーションの1つとして、systemdを用いるLinuxディストリビューションなら何も考えず使えるという点がある。

Dockerとの違い

再現されたディストリビューションのディレクトリツリー内で出来ることは何でもできる。 Dockerはアプリケーション単位でコンテナを構築するのに対し、systemd-nspawnはコンテナに1つのLinuxシステムを構成する。 コンテナ内で複数のアプリケーションを普通のLinux環境同様に起動できるVM型の仮想化に近い環境を構築できる。

はじめる

筆者が普段使っているUbuntuをホストとし、そこにsystemd-nspawnを用いてコンテナ環境を作る。

環境

Linux karkador 5.0.0-37-generic #40~18.04.1-Ubuntu SMP Thu Nov 14 12:06:39 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

準備

コンテナ上で必要なファイルを用意するためにdebootstrapを用いる。 debootstrapとは、Ubuntuのベースとなっているディストリビューションであるdebianの最小限のディレクトリツリーを構成する為のツール。今回はこれでUbuntu用のものを用意する。 今回は/var/lib/machines/ubuntuという名前でコンテナ用のディレクトリを用意し、そこへファイルをインストールする。

# debootstrap --arch=$(dpkg --print-architecture) $(lsb_release -cs) /var/lib/machines/ubuntu http://archive.ubuntu.com/ubuntu

これでコンテナに必要なファイルは作られた

コンテナに入る

# systemd-nspawn -D /path/to/container

これで用意した環境のルートシェルに入れる。とりあえずpasswdでパスワードの設定だけして抜ける。 コンテナから出るにはCtrl ]]]で良い。

# systemd-nspawn -b -D /var/lib/machines/ubuntu

コンテナをブートする。即ち、コンテナ内でinitを起動する。 見慣れたUbuntuのブート画面の後、ログインシェルが立ち上がる。 ここまで来ればもう普段通りの事は大体できる。 抜け方は同じ。

# systemctl start systemd-nspawn@ubuntu

でコンテナが起動される。 自動起動等の操作は他と同様、enable|disableで行う。

コンテナの操作

systemd-nspawnコマンドには多数のオプションがある。 例えば最初の-Dは指定したディレクトリをコンテナのファイルシステムのルートとするオプション。 また、systemd-nspawn以外にコンテナの操作に便利なコマンドがある。

--syscall-filter

コンテナ内で発行されるシステムコールのルールを変えられる。 例えばreadを許可しない時は --syscall-filter="~read" で出来る(尚、readを許可しないと実行も出来ない)

指定するシステムコールに関する詳細はsystemd-analyze syscall-filterで確認出来る。(グループ単位での指定等)

machinectl

systemctl start systemd-nspawn@hostname で起動されているコンテナは、machinectlコマンドで操作できる。 machinectl listで起動中のコンテナのリストを表示、 machinectl list-images/var/lib/machinesにあるコンテナのイメージのリストを表示する。 また、自動起動の操作もmachinectl enable|disableで行える。

machinectlは、コンテナ周りのsystemctlの操作とsystemd-nspawnをまとめたようなコマンドで大抵の操作はこれで行える。

コンテナのネットワーク

デフォルトではホストとネットワークを共有している。 またsystemd-networkdをコンテナ、ホストに設定すると仮想イーサネットリンクやブリッジ、ポートフォワーディングなど、幅広いネットワーク設定が可能になる。

まとめ

Dockerとは異なる点も多く、使い方も全く別のコンテナ技術として面白いものだと思う。