「Systemd-nspawn」の版間の差分

提供: ArchWiki
ナビゲーションに移動 検索に移動
(同期)
(校正(でき・出来))
 
(5人の利用者による、間の183版が非表示)
1行目: 1行目:
 
{{Lowercase title}}
 
{{Lowercase title}}
 
[[Category:仮想化]]
 
[[Category:仮想化]]
  +
[[Category:サンドボックス]]
 
[[en:Systemd-nspawn]]
 
[[en:Systemd-nspawn]]
  +
[[es:Systemd-nspawn]]
 
[[ru:Systemd-nspawn]]
 
[[ru:Systemd-nspawn]]
 
{{Related articles start}}
 
{{Related articles start}}
8行目: 10行目:
 
{{Related|systemd-networkd}}
 
{{Related|systemd-networkd}}
 
{{Related|Docker}}
 
{{Related|Docker}}
{{Related|Lxc-systemd}}
 
 
{{Related articles end}}
 
{{Related articles end}}
   
 
''systemd-nspawn'' は [[chroot]] コマンドに似ていますが、''chroot を強化したもの''です。
 
''systemd-nspawn'' は [[chroot]] コマンドに似ていますが、''chroot を強化したもの''です。
   
''systemd-nspawn'' を使えば軽量な名前空間コンテナでコマンドや OS を実行することができます。ファイルシステム構造だけでなく、プロセスツリーや様々な IPC サブシステム、ホスト・ドメイン名も完全に仮想化するため [[chroot]] よりも強力です。
+
''systemd-nspawn'' を使えば軽量な名前空間コンテナでコマンドや OS を実行することができます。ファイルシステム階層だけでなく、プロセスツリーや様々な IPC サブシステム、ホスト・ドメイン名も完全に仮想化するため [[chroot]] よりも強力です。
   
''systemd-nspawn'' は {{ic|/sys}}, {{ic|/proc/sys}}, {{ic|/sys/fs/selinux}} などのコンテナの様々なカーネルインターフェイスへのアクセスを読み取り専用に制限します。コンテナの中からネットワークインターフェイスやシステムクロックを変更することは出来ません。デバイスノード作成することも不可能。コンテナの中からホスト環境を再起動することはできず、カーネルモジュールロードすること制限され
+
''systemd-nspawn'' は {{ic|/sys}}, {{ic|/proc/sys}}, {{ic|/sys/fs/selinux}} などのコンテナの様々なカーネルインターフェイスへのアクセスを読み取り専用に制限します。コンテナの中からネットワークインターフェイスやシステムクロックを変更することはできません。デバイスノード作成きません。コンテナの中からホスト環境を再起動することはできず、カーネルモジュールロードもできせん
   
仕組みとしては [[Lxc-systemd]] や [[Libvirt]]-lxc と異な、とてシンプルなツールで設定を行います。
+
''systemd-nspawn'' は [[Linux コンテナ]]や [[Libvirt]] りも設定が簡単なツールです。
   
 
== インストール ==
 
== インストール ==
   
''systemd-nspawn'' は {{Pkg|systemd}} に含まれています。
+
''systemd-nspawn'' は systemd の一部であり、{{Pkg|systemd}} に含まれています。
   
 
== サンプル ==
 
== サンプル ==
   
=== コンテナに最小限の Arch Linux ディストリビューションを作成して起動 ===
+
=== コンテナに最小限の Arch Linux を作成して起動 ===
   
まず[[公式リポジトリ]]からパッケージ {{Pkg|arch-install-scripts}} を[[pacman|インストール]]してください。
+
まず {{Pkg|arch-install-scripts}} パッケージを[[pacman|インストール]]してください。
   
そして、お好きな場所にディレクトリを作成してください。例えば: {{ic|$ mkdir ~/''MyContainer''}}。
+
、コンテナを置くためのディレクトリを作成してください。このでは、{{ic|~/''MyContainer''}} を使用します
   
pacstrap を使って最小限の arch システムをコンテナにインストールします。最低限でも {{Grp|base}} グルはインストールする必要があります。
+
そして、''pacstrap'' を使って最小限の arch システムをコンテナにインストールします。最低限でも {{Pkg|base}} パッケはインストールする必要があります。
   
# pacstrap -i -c -d ~/MyContainer base [additional pkgs/groups]
+
# pacstrap -K -c ~/MyContainer base [additional pkgs/groups]
   
{{Tip|{{ic|-i}} オプションはパッケージ選択の自動確認を無効にします。コンテナ上に Linux カーネルをインストールする必要はないため、パッケージリストの選択から[[Pacman#使方|削除]]することができます。}}
+
{{Tip|{{Pkg|base}} パッケージは、{{Pkg|linux}} カーネルパッケージに依存せず、コンテナにも対応しています。}}
  +
{{Note|''pacstrap'' が利用できない異なるオペレーティングシステムから作成する場合、[[既存の Linux からインストール#方法 A: ブートストラップイメージを使う (推奨)|bootstrap tarball]] をコンテナイメージとして使用することができます。pacman キーリングはコンテナ内で初期化する必要があります。詳細は [[既存の Linux からインストール#pacman キーリングの初期化]] を参照してください。}}
   
  +
インストールが完了したら、コンテナに chroot し、root パスワードを設定します。
{{Note|{{Grp|base}} グループに含まれている {{Pkg|linux}} は {{Pkg|linux-firmware}} パッケージを必要としていますがコンテナを実行するのに必要というわけではなく、{{ic|systemd-nspawn}} で起動を行うときに {{ic|systemd-tmpfiles-setup.service}} に問題を発生させることがあります。コンテナを作成するとき {{Grp|base}} グループをインストールすることは可能ですが、その場合 {{ic|# pacstrap -i -c -d ~/MyContainer base --ignore linux [additional pkgs/groups]}} として {{Pkg|linux}} パッケージやその依存パッケージは除外してください。{{ic|--ignore}} フラグは {{Pkg|pacman}} に渡されます。詳しくは {{Bug|46591}} を参照。}}
 
  +
# systemd-nspawn -D ~/MyContainer
  +
# passwd
  +
# logout
   
  +
{{Tip|Setting root password is optional. You can get a root shell in a booted container directly without having to log in by running {{ic|machinectl shell root@MyContainer}}. See [[#machinectl]].}}
インストールが完了したら、コンテナを起動してください ({{ic|-b}} はシェルを実行する代わりにコンテナを起動します (つまり PID=1 として {{ic|systemd}} を実行)。{{ic|-D}} にはコンテナのルートディレクトリにするディレクトリを指定します。{{ic|-n}} はホストとコンテナ間のプライベートネットワークを設定します):
 
# systemd-nspawn -b -D ~/MyContainer -n
 
   
  +
最後に、コンテナを起動します。
これで終わりです。空のパスワードを使って "root" でログインしてください。
 
   
  +
# systemd-nspawn -b -D ~/MyContainer
コンテナの電源を切りたいときはコンテナの中から {{ic|poweroff}} を実行することで出来ます。ホストからは、[[#machinectl|machinectl]] ツールでコンテナを制御できます。
 
   
{{Note|コンテナの中からセッションを終了するに {{ic|Ctrl}} を押ながら {{ic|]}} を素早く3回押してくださいUS キーボード以外の場合は {{ic|]}} の代わり {{ic|%}} 使用します。}}
+
{{ic|-b}} オプションはシェル実行する代わりコンテナを起動します (つまり PID=1 と {{ic|systemd}} を実行)。{{ic|-D}} にはコンテナルートディレクトリするディレクトリ指定します。
   
  +
コンテナが開始したら、設定したパスワードを使って "root" でログインしてください。
==== x86_64 環境で Arch Linux i686 をブートストラップ ====
 
   
  +
{{Note|"Login incorrect" でログインが失敗する場合、問題は、{{ic|securetty}} TTY デバイスのホワイトリストである可能性があります。[[#root ログインが失敗する]] をご確認ください。}}
サブディレクトリの中に i686 の最小限の Arch Linux をインストールして [[chroot]] や[[:カテゴリ:仮想化|仮想化]]するかわりに systemd-nspawn コンテナとして使うことができます。i686 環境で {{ic|PKGBUILD}} のコンパイルをテストしたい場合などに有用です。{{ic|pacman.conf}} で {{ic|multilib}} リポジトリが有効になっていないことを確認してください。
 
   
  +
コンテナの電源を切りたいときはコンテナの中から {{ic|poweroff}} を実行することでできます。ホストからは、[[#machinectl|machinectl]] ツールでコンテナを制御できます。
# pacman_conf=/tmp/pacman.conf # this is pacman.conf without multilib
 
# mkdir /mnt/i686-archlinux
 
# linux32 pacstrap -C "$pacman_conf" -di /mnt/i686-archlinux base base-devel
 
   
  +
{{Note|コンテナの中からセッションを終了するには {{ic|Ctrl}} を押しながら {{ic|]}} を素早く3回押してください。US キーボード以外の場合は {{ic|]}} の代わりに {{ic|%}} を使用します。}}
{{ic|base}} グループの {{ic|linux}} の選択は解除してかまいません。作成されるブートストラップディレクトリは実機や仮想マシン上で実行するわけではないためです。
 
 
作成された i686 の Arch Linux の systemd-nspawn インスタンスを起動するには、以下のコマンドを実行:
 
 
# linux32 systemd-nspawn -D /mnt/i686-archlinux
 
   
 
=== Debian や Ubuntu 環境の作成 ===
 
=== Debian や Ubuntu 環境の作成 ===
   
{{Pkg|debootstrap}}, {{Aur|gnupg1}} と {{Aur|debian-archive-keyring}} か {{Aur|ubuntu-keyring}} のどちらか (インストールしたい方のディストリのキーリング) をインストールしてください。
+
{{Pkg|debootstrap}} と {{Pkg|debian-archive-keyring}} か {{Pkg|ubuntu-keyring}} のどちらか (インストールしたい方のディストリのキーリング) をインストールしてください。
   
{{Note|systemd-nspawn を使用するにはコンテナ内の OS で systemd PID 1 として動作ている必要があります。Ubuntu 15.04 以前は、そのまで動作せず、upstart から systemd への移行必須です。}}
+
{{Note|systemd-nspawn はコンテナ内のオペレーティングシステムが systemd init を使用し (PID 1 として動作する)、systemd-nspawn がコンテナにインストールされている必要があります。この要件は、コンテナ環境に systemd-container パッケージをインストールすることで満たされます。systemd-container パッケージ dbus に依存しますがdbus dbus-broker パッケージコンテナシステムにインストールされていることを確認してください。}}
   
 
後は簡単に Debian や Ubuntu 環境をセットアップできます:
 
後は簡単に Debian や Ubuntu 環境をセットアップできます:
   
 
# cd /var/lib/machines
 
# cd /var/lib/machines
# debootstrap <codename> myContainer <repository>
+
# debootstrap --include=dbus-broker,systemd-container --components=main,universe ''codename'' ''container-name'' ''repository-url''
   
Debian の場合、コードネームとして指定するのは "stable" や "testing" などのローリングの名前か "stretch" や "sid" などのリリース名になります。Ubuntu の場合、"wily" や "hardy" などのコードネームを使ってください。完全なリストは {{ic|/usr/share/debootstrap/scripts}} にあります。
+
Debian の場合、コードネームとして指定するのは "stable" や "testing" などのローリングの名前か "stretch" や "sid" などのリリース名になります。Ubuntu の場合、"xenial" や "zesty" などのコードネームを使ってください。コードネームの完全なリストは {{ic|/usr/share/debootstrap/scripts}} にあります。Debian イメージの場合は "repository-url" には https://deb.debian.org/debian/ などを指定します。Ubuntu のイメージの場合は "repository-url" は http://archive.ubuntu.com/ubuntu/ などとなります。
   
Arch と違って、Debian や Ubuntu は最初のログイン時にパスワードが要ることになってい。root のパスワードを設定するために、'-b' オプションを付けずにログインしてからパスワードを設定してください:
+
Arch と同様に、Debian や Ubuntu はパスワードなしでログインすることはできせん。root のパスワードを設定するために、'-b' オプションを付けずにログインしてからパスワードを設定してください:
   
  +
# cd /var/lib/machines
 
# systemd-nspawn -D myContainer
 
# systemd-nspawn -D myContainer
 
# passwd
 
# passwd
 
# logout
 
# logout
   
  +
=== Fedora または AlmaLinux 環境の作成 ===
=== マシンのブート時にコンテナを起動する ===
 
   
  +
{{Pkg|dnf}} をインストールし、必要な Fedora リポジトリを追加するために {{ic|/etc/dnf/dnf.conf}} ファイルを編集します。
コンテナを頻繁に使用する場合、ブート時に systemd でコンテナを起動できます。まず {{ic|systemd}} ターゲットの {{ic|machines.target}} を有効化してください:
 
   
  +
{{hc|/etc/dnf/dnf.conf|output=<nowiki>
# systemctl enable machines.target
 
  +
[fedora]
  +
name=Fedora $releasever - $basearch
  +
metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch
  +
gpgkey=https://getfedora.org/static/fedora.gpg
   
  +
[updates]
それから以下を実行してください:
 
  +
name=Fedora $releasever - $basearch - Updates
  +
metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-f$releasever&arch=$basearch
  +
gpgkey=https://getfedora.org/static/fedora.gpg</nowiki>
  +
}}
   
  +
''fedora.gpg'' ファイルには最新の Fedora リリース用の gpg キーが含まれています https://getfedora.org/security/ 。Fedora 37 の最小コンテナを設定するには:
# mv ~/MyContainer /var/lib/machines/MyContainer
 
# systemctl enable systemd-nspawn@MyContainer.service
 
# systemctl start systemd-nspawn@MyContainer.service
 
   
  +
# cd /var/lib/machines
{{Note|{{ic|systemd-nspawn@.service}} は nspawn コンテナが {{ic|/var/lib/machines}} にあることを想定したテンプレートユニットです。}}
 
  +
# mkdir ''container-name''
  +
# dnf --releasever=37 --best --setopt=install_weak_deps=False --repo=fedora --repo=updates --installroot=/var/lib/machines/''container-name'' install dhcp-client dnf fedora-release glibc glibc-langpack-en iputils less ncurses passwd systemd systemd-networkd systemd-resolved util-linux vim-default-editor
   
  +
{{note|異なる Fedora リリースをインストールしたい場合は、異なるリリースが [https://docs.fedoraproject.org/en-US/fedora-server/containerization/systemd-nspawn-setup/#_2_1_creating_a_container_directory_tree 独自のパッケージ要件] を持つことを考慮してください。
{{Tip|
 
  +
* {{Pkg|systemd}} v229 から {{ic|/var/lib/machines}} のコンテナにシンボリックリンクを張ることはできなくなっています。[https://github.com/systemd/systemd/issues/2001] を参照。
 
  +
btrfs ファイルシステムを使用している場合は、ディレクトリを作成する代わりにサブボリュームを作成してください。
* ''systemd-nspawn'' サービスは次のコマンドを実行します: {{ic|<nowiki>/usr/bin/systemd-nspawn --quiet --keep-unit --boot --link-journal=guest --directory=/var/lib/machines/%i</nowiki>}}。ディスクイメージファイルを使用したりコンテナに [[SELinux]] セキュリティを設定するために、コンテナのディレクトリから {{ic|/var/lib/container/MyCoantainer}} にシンボリックリンクが貼られていない場合、このファイルを修正してオプションを追加する必要があります。コンテナのネットワーク設定を分離させたい場合、[[systemd-networkd]] を参照してください。さらに詳しいブートオプションの情報は {{ic|systemd-nspawn(1)}} に載っています。
 
* {{ic|systemd-nspawn@.service}} を無効にすると、{{ic|# systemd-nspawn -bD /path/to/container}} を実行して手動でコンテナを起動することができます。コンテナにログインした後は、{{ic|# systemctl poweroff}} を実行すればシャットダウンします。
 
 
}}
 
}}
   
  +
AlmaLinux のようなエンタープライズ Linux 派生物は、デフォルトで三つのリポジトリが有効になっています。''BaseOS'' は、すべてのインストールの基盤となるコアセットを含み、''AppStream'' は追加アプリケーション、言語パッケージなどを含み、''Extras'' は RHEL に含まれないパッケージを含んでいます。したがって、最小限のコンテナには {{ic|/etc/dnf/dnf.conf}} に BaseOS リポジトリのみを追加する必要があります。
[[cgroups|control group]] の中身を表示したい場合は、{{ic|$ systemd-cgls}} を実行してください。
 
  +
  +
{{hc|/etc/dnf/dnf.conf|output=<nowiki>
  +
[baseos]
  +
name=AlmaLinux $releasever - BaseOS
  +
mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/baseos
  +
gpgkey=https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux-$releasever</nowiki>
  +
}}
  +
  +
AlmaLinux 9 の最小コンテナを作成するには:
  +
  +
# dnf --repo=baseos --releasever=9 --best --installroot=/var/lib/machines/''container-name'' --setopt=install_weak_deps=False install almalinux-release dhcp-client dnf glibc-langpack-en iproute iputils less passwd systemd vim-minimal
  +
  +
これにより、AlmaLinux 9 の最新マイナーバージョンがインストールされますが、特定のポイントリリースをインストールすることもできますが、その場合は ''gpgpkey'' エントリを手動で ''RPM-GPG-KEY-AlmaLinux-9'' を指すように変更する必要があります。
  +
  +
Arch、Fedora、AlmaLinux のように、root パスワードを設定しない限り、root としてログインすることは許可されません。root パスワードを設定するには、{{ic|-b}} オプションなしで ''systemd-nspawn'' を実行してください:
  +
  +
# systemd-nspawn -D /var/lib/machines/''container-name'' passwd
  +
  +
=== パッケージのビルドおよびテスト ===
  +
  +
使用例については、[[他のディストリビューションのパッケージの作成]] を参照してください。
   
 
== 管理 ==
 
== 管理 ==
   
  +
{{ic|/var/lib/machines/}} にあるコンテナは、''machinectl'' コマンドによって制御することができます。内部的には {{ic|systemd-nspawn@.service}} ユニットのインスタンスを制御しています。{{ic|/var/lib/machines/}} のサブディレクトリはコンテナ名に対応しています。
使用例は[[他のディストリビューションのパッケージの作成]]を参照。
 
  +
  +
{{Note|なんらかの理由でコンテナを {{ic|/var/lib/machines/}} に移動できない場合、シンボリックリンクが使えます。{{man|1|machinectl|FILES AND DIRECTORIES}} を参照してください。}}
  +
  +
=== systemd-nspawn オプションのデフォルト値 ===
  +
  +
''machinectl'' や {{ic|systemd-nspawn@.service}} 経由で起動されたコンテナは ''systemd-nspawn'' コマンドで起動されたコンテナとはオプションの既定値が異なることを理解することが重要です。サービスが使用する追加オプションは以下の通りです。
  +
* {{ic|-b}}/{{ic|--boot}} – マネージドコンテナは自動的に init プログラムを検索し、PID 1 として起動します。
  +
* {{ic|--network-veth}} つまり {{ic|--private-network}} – マネージドコンテナは仮想ネットワークインターフェースを取得し、ホストネットワークから切り離されます。詳細は、[[#ネットワーキング]] を参照してください。
  +
* {{ic|-U}} – カーネルがサポートしている場合、マネージドコンテナはデフォルトで user_namespaces(7) 機能を使用します。詳細は、[[#非特権コンテナ]] を参照してください。
  +
* {{ic|1=--link-journal=try-guest}}
  +
この動作は、コンテナごとの設定ファイルでオーバーライドすることができます。
  +
詳細は、[[#設定]] を参照してください。
   
 
=== machinectl ===
 
=== machinectl ===
111行目: 150行目:
 
{{Note|''machinectl'' ツールを使うには [[systemd]] と {{Pkg|dbus}} がコンテナにインストールされている必要があります。詳しくは [https://github.com/systemd/systemd/issues/685] を参照。}}
 
{{Note|''machinectl'' ツールを使うには [[systemd]] と {{Pkg|dbus}} がコンテナにインストールされている必要があります。詳しくは [https://github.com/systemd/systemd/issues/685] を参照。}}
   
コンテナの管理原則 {{ic|$ machinectl}} コマンドで行います。このサービスを使って仮想マシンやコンテナの状態を確認したり操作します。オプションの詳細なリストは {{ic|machinectl(1)}} を参照してください
+
コンテナはコマンドで管理できます。例えば、コンテナを起動するには、次ようにします。
   
  +
$ machinectl start ''container-name''
例:
 
  +
  +
{{Note|''machinectl'' は、コンテナ名が有効な[[ホスト名]]であるように、ASCII 文字、数字、ハイフンのみで構成されていることを要求します。例えば、コンテナ名にアンダースコアが含まれている場合、それは単に認識されず、 {{ic|machinectl start container_name}} を実行すると、エラー {{ic|Invalid machine name container_name}} となります。詳しくは[https://github.com/systemd/systemd/issues/11765]と[https://github.com/systemd/systemd/commit/d65652f1f21a4b0c59711320f34266c635393c89]を参照してください。}}
  +
  +
同様に、{{ic|poweroff}}, {{ic|reboot}}, {{ic|status}}, {{ic|show}} などのサブコマンドがあります。詳細な説明については、{{man|1|machinectl|Machine Commands}} を参照してください。
  +
  +
{{Tip|電源オフと再起動の操作は、{{ic|poweroff}} と {{ic|reboot}} コマンドを使用してコンテナ内から実行することができます。}}
  +
  +
その他の一般的なコマンドは以下の通りです:
  +
  +
* {{ic|machinectl list}} – 現在実行中のコンテナの一覧を表示する
  +
* {{ic|machinectl login container-name}} - 実行中のコンテナに新しいシェルを起動
  +
* {{ic|machinectl shell ''[username@]container-name''}} – コンテナで対話的なシェルセッションを開きます(コンテナ内のログインプロセスを経ずにユーザープロセスが即座に呼びだす)。
  +
* {{ic|machinectl enable container-name}} または {{ic|machinectl disable container-name}} - コンテナを有効または無効にして、起動時に開始します。詳細については、[[#PC起動時にコンテナを自動で開始する]] を参照してください。
   
  +
''machinectl'' にはコンテナ(または仮想マシン)イメージとイメージ転送を管理するためのサブコマンドもあります。詳細については、{{man|1|machinectl|Image Commands}} および、{{man|1|machinectl|Image Transfer Commands}} を参照してください。2023Q1 時点で、{{man|1|machinectl|EXAMPLES}} にある最初の 3 つの例はイメージ転送コマンドを示しています。{{man|1|machinectl|FILES AND DIRECTORIES}} では、適切なイメージをどこで見つけるかについて説明しています。
* 実行中のコンテナに新しいシェルを起動: {{bc|$ machinectl login MyContainer}}
 
* コンテナの詳細情報を表示: {{bc|$ machinectl status MyContainer}}
 
* コンテナを再起動: {{bc|$ machinectl reboot MyContainer}}
 
* コンテナを電源オフ: {{bc|$ machinectl poweroff MyContainer}}
 
:{{Tip|電源オフや再起動は ''systemctl'' の {{ic|reboot}} や {{ic|poweroff}} コマンドをコンテナのセッションの中から実行することでも可能です。}}
 
* イメージをダウンロード: {{bc|# machinectl pull-tar ''URL'' ''name''}}
 
   
 
=== systemd ツールチェイン ===
 
=== systemd ツールチェイン ===
133行目: 180行目:
 
* リソース利用状況を表示: {{bc|$ systemd-cgtop}}
 
* リソース利用状況を表示: {{bc|$ systemd-cgtop}}
   
== Tips and tricks ==
+
== 設定 ==
  +
  +
=== コンテナ毎の設定 ===
  +
  +
グローバル設定のオーバーライドではなく、コンテナ毎の設定を指定するには、''.nspawn'' ファイルを使用できます。詳細については、 {{man|5|systemd.nspawn}} を参照してください。
  +
  +
{{Note|
  +
* ''.nspawn'' ファイルは、{{ic|machinectl remove}} を実行した時に、{{ic|/etc/systemd/nspawn/}} から予期せずに削除される場合があります。
  +
* {{ic|systemd-nspawn@.service}} ファイルで指定されている、{{ic|1=--settings=override}} がある場合、''.nspawn'' ファイルで指定されているネットワークオプションとコマンドラインオプションの相互作用で正しく動作しません。回避策としてサービスが {{ic|1=--network-veth}} を指定している場合でも、{{ic|1=VirtualEthernet=on}} オプションを含める必要があります。
  +
}}
  +
  +
=== PC起動時にコンテナを自動で開始する ===
  +
  +
コンテナを頻繁に使用する場合は、PC起動時に開始することをおすすめします。
  +
  +
まず、{{ic|machines.target}} が[[systemd#ユニットを使う|有効]]になっている事を確認します。
  +
[[#machinectl|machinectl]] で検出可能なコンテナは、有効または無効にできます:
  +
  +
$ machinectl enable ''container-name''
  +
  +
{{Note|
  +
* まず {{ic|systemd-nspawn@''container-name''.service}} ユニットを有効にする効果があります。
  +
* [[#systemd-nspawn オプションのデフォルト値]] で説明されているように、''machinectl'' と入力し開始されたコンテナは仮想 Ethernet インタフェースを取得します。プライベートネットワークを無効にするには、 [[#ホストネットワークを使う]] を参照してください。
  +
}}
  +
  +
=== リソース制御 ===
  +
  +
{{ic|systemctl set-property}} でコンテナの制限やリソース管理を実装するために、コントロールグループを利用することができます。{{man|5|systemd.resource-control}} を参照してください。例えば、メモリ容量やCPU使用率を制限できます。コンテナのメモリ消費を2GiBに制限するには:
  +
  +
# systemctl set-property systemd-nspawn@''container-name''.service MemoryMax=2G
  +
  +
または、CPU時間の使用量をだいたい2コア分に制限したい場合:
  +
  +
# systemctl set-property systemd-nspawn@''container-name''.service CPUQuota=200%
  +
  +
これにより以下の永続ファイルが作成されます。
  +
{{ic|/etc/systemd/system.control/systemd-nspawn@''container-name''.service.d/}}.
  +
  +
ドキュメントによると、{{ic|MemoryHigh}} はメモリ消費をチェックするための推奨される方法ですが、{{ic|MemoryMax}} のように厳密に制限されることはありません。{{ic|MemoryMax}} を最終防衛戦として残して、両方のオプションを使用できます。また、コンテナが認識できるCPUの数を制限しないことも考慮に入れてください。ただし、CPU時間合計に対して、コンテナが最大で取得する時間を制限することで、同様の結果が得られます。
  +
  +
{{Tip|これらの変更を一時的なものにしたい場合は、{{ic|--runtime}} オプションを渡すことができます。その結果は、''systemd-cgtop'' で確認できます。}}
  +
  +
=== ネットワーキング ===
  +
  +
''systemd-nspawn'' コンテナは、''ホストネットワーク'' または ''プライベートネットワーク''のいずれかを使用できます。
  +
* ホストネットワークモードでは、コンテナはホストネットワークへのフルアクセスが可能です。これは、コンテナがホスト上のすべてのネットワークサービスにアクセスできるようになり、コンテナからのパケットがホストのパケットとして外部ネットワークに表示される事を意味します(つまり、同じIPアドレスを共有します)。
  +
* プライベートネットワークモードでは、コンテナはホストのネットワークから切断されています。これにより、ループバックデバイスとコンテナに明示的に割り当てられたものを除いて、すべてのネットワークインターフェイスがコンテナを使用できなくなります。コンテナのネットワークインターフェイスを設定するには、いくつかの方法があります。
  +
** 既存のインターフェイスをコンテナに割り当てることができます(たとえば、複数のイーサネットデバイスがある場合)。
  +
** 既存のインターフェース(つまり、[[VLAN]]インターフェース)に関連付けられた仮想ネットワークインターフェースを作成して、コンテナーに割り当てることができます。
  +
** ホストとコンテナの間に仮想イーサネットリンクを作成できます。
  +
: 後者の場合、コンテナのネットワークは、(外部ネットワークや他のコンテナから) 完全に分離されており、ホストとコンテナ間のネットワークを構成するのは管理者の責任です。これには通常、複数の(物理または仮想)インターフェイスを接続するための [[ネットワークブリッジ]] の作成、または複数のインターフェイス間の [[wikipedia:ja:ネットワークアドレス変換|ネットワークアドレス変換]] の設定が含まれます。
  +
  +
ホストネットワーキングモードは、コンテナに割り当てられたインターフェースを構成するネットワーキングソフトウェアを実行しない ''アプリケーションコンテナ'' に適しています。ホストネットワーキングは、シェルから ''systemd-nspawn'' を実行するときのデフォルトのモードです。
  +
  +
一方、プライベート・ネットワーキング・モードは、ホスト・システムから隔離されている必要がある ''システムコンテナ'' に適しています。仮想イーサネットリンクの作成は、複雑な仮想ネットワークの作成を可能にする非常に柔軟なツールです。これは ''machinectl'' や {{ic|systemd-nspawn@.service}} によって起動されたコンテナのデフォルトモードです。
  +
  +
次のサブセクションでは、一般的なシナリオについて説明します。使用可能な ''systemd-nspawn'' のオプションの詳細については、{{man|1|systemd-nspawn|Networking Options}} を参照してください。
  +
  +
==== ホストネットワークを使う ====
  +
  +
プライベートネットワークを無効にし、''machinectl'' で開始されたコンテナで使用される仮想イーサネットリンクを作成するには、次のオプションを指定して、''.nspawn'' ファイルを追加します:
  +
  +
{{hc|/etc/systemd/nspawn/''container-name''.nspawn|2=
  +
[Network]
  +
VirtualEthernet=no
  +
}}
  +
  +
これにより、{{ic|systemd-nspawn@.service}} の {{ic|-n}}/{{ic|--network-veth}} オプションが上書きされ、新しく開始されたコンテナはホストネットワークモードを使用します。
  +
  +
==== 仮想イーサネットリンクを使用する ====
  +
  +
コンテナが、{{ic|-n}}/{{ic|--network-veth}} オプションで起動された場合、''systemd-nspawn'' はホストとコンテナの間に仮想イーサネットリンクを作成します。リンクのホスト側は、{{ic|ve-''container-name''}} という名前のネットワークインターフェイスとして利用可能になります。リンクのコンテナ側は、{{ic|hosts0}} という名前になります。このオプションは、{{ic|--private-network}} を意味することに注意してください。
  +
  +
{{Note|
  +
* コンテナ名が長すぎる場合、インターフェイス名は、[https://stackoverflow.com/a/29398765 15文字制限] に収まるように短縮されます(例: {{ic|ve-long-container-name}} の代わりに {{ic|ve-long-conKQGh}})。フルネームはインターフェイスの {{ic|altname}} プロパティとして設定され({{man|8|ip-link}}を参照)、インターフェイスの参照に使用できます。
  +
  +
* {{ic|ip link}} でインターフェイスを調べる場合、インターフェイス名は、{{ic|ve-''container-name''@if2}} や {{ic|host0@if9}} のようにサフィックスを付けて表示されます。{{ic|@if''N''}} は実際にはインターフェイス名の一部ではありません。その代わりに、{{ic|ip link}} はこの情報を追加して、仮想イーサネットケーブルが相手側のどの ''slot'' に接続しているかを示します
  +
: 例えば、{{ic|ve-''foo''@if2}} とし表示されているホスト仮想イーサネットインターフェイスはコンテナ {{ic|''foo''}} に接続され、コンテナ内で {{ic|ip link}} を実行しているときに、index 2 で示されている 2 番目のネットワークインタフェースに接続されています。同様に、コンテナ内の {{ic|host0@if9}} という名前のインターフェイスは、ホスト上の 9 番目のネットワークインターフェイス接続されています。}}
  +
  +
コンテナを起動する際には、ホストとコンテナの両方のインターフェイスにIPアドレスを割り当てなければなりません。ホストとコンテナの両方で [[systemd-networkd]] を使用している場合、初期状態で実行されます:
  +
  +
* ホスト上の {{ic|/usr/lib/systemd/network/80-container-ve.network}} ファイルは {{ic|ve-container-name}} インターフェイスと一致し、DHCP サーバーを起動します。DHCP サーバーは、IP アドレスをホストインターフェイスとコンテナーに割り当てます。
  +
* {{ic|/usr/lib/systemd/network/80-container-host0.network}} コンテナ内のファイルは {{ic|host0}} インターフェイスと一致し、ホストから IP アドレスを受信する DHCP クライアントを起動します。
  +
  +
[[systemd-networkd]] を使用しない場合は、静的IPアドレスを設定するか、ホストインターフェイスで、DHCP サーバを起動し、コンテナで DHCP クライアントを起動できます。詳細については、[[ネットワーク設定]] を参照してください。
  +
  +
コンテナに外部ネットワークへのアクセスを許可するには、[[インターネット共有#NAT の有効化]] の説明に従って NAT を設定します。[[systemd-networkd]] を使用する場合、これは、{{ic|/usr/lib/systemd/network/80-container-ve.network}} ファイルの {{ic|1=IPMasquerade=yes}} オプションを介して(部分的に)自動的に行われます。ただし、これは次のような [[iptables]] ルールのみを発行します。
  +
  +
-t nat -A POSTROUTING -s 192.168.163.192/28 -j MASQUERADE
  +
  +
{{ic|filter}} テーブルは、[[インターネット共有#NAT の有効化]]のように手動で設定する必要があります。ワイルドカードを使用して、{{ic|ve-}} で始まるすべてのインターフェイスに一致させることができます:
  +
  +
# iptables -A FORWARD -i ve-+ -o ''internet0'' -j ACCEPT
  +
  +
{{Note|''systemd-networkd'' は、[https://tldp.org/HOWTO/Querying-libiptc-HOWTO/whatis.html libiptc] ライブラリを使用して、[[iptables]] と対話します。 [[nftables]] を使用する場合は、{{Pkg|iptables-nft}} 変換レイヤーをインストールします。[https://github.com/systemd/systemd/issues/13307 systemd issue 13307] も参照してください。}}
  +
  +
さらに、DHCP サーバー(''systemd-networkd'' によって運用される)への着信接続用に {{ic|ve-+}} インターフェースの UDP ポート 67 を開く必要があります:
  +
  +
# iptables -A INPUT -i ve-+ -p udp -m udp --dport 67 -j ACCEPT
  +
  +
==== ネットワークブリッジを使用する ====
  +
  +
ホストシステムに[[ネットワークブリッジ]]を構成している場合は、コンテナの仮想イーサネットリンクを作成し、そのホスト側をネットワークブリッジに追加できます。 これは、{{ic|1=--network-bridge=''bridge-name''}} オプションを使用して実行されます。{{ic|--network-bridge}} は {{ic|--network-veth}} を意味することに注意してください。つまり、仮想イーサネットリンクは自動的に作成されます。 ただし、リンクのホスト側は {{ic|ve-}} ではなく {{ic|vb-}} プリフィックスを使用するため、DHCP サーバーと IP マスカレードを起動するための systemd-networkd オプションは適用されません。
  +
  +
ブリッジの管理は管理者に任されています。例えば、ブリッジは物理インターフェースと仮想インターフェースを接続したり、複数のコンテナの仮想インターフェースのみを接続したりすることができます。[[systemd-networkd]] を使用した設定例については、[[systemd-networkd#Network bridge with DHCP]] と [[systemd-networkd#Network bridge with static IP addresses]] を参照してください。
  +
  +
また、{{ic|1=--network-zone=zone-name}} オプションは {{ic|--network-bridge}} と似ていますが、ネットワークブリッジは ''systemd-nspawn'' と ''systemd-networkd'' によって自動的に管理されます。{{ic|vz-zone-name}} という名前のブリッジインターフェースは、{{ic|1=--network-zone=zone-name}} を設定した最初のコンテナが起動したときに自動的に作成され、{{ic|1=--network-zone=zone-name}} を設定した最後のコンテナが終了したときに自動的に削除されます。したがって、このオプションを使用すると、複数の関連するコンテナを共通の仮想ネットワーク上に簡単に配置することができます。{{ic|vz-*}} インターフェースは、{{ic|/usr/lib/systemd/network/80-container-vz.network}} ファイルのオプションを使って、{{ic|ve-*}} インターフェースと同じように [[systemd-networkd]] によって管理されることに注意してください。
  +
  +
==== 「macvlan」または「ipvlan」インターフェースを使用する ====
  +
  +
仮想イーサネットリンク(ホスト側がブリッジに追加される場合とされない場合があります)を作成する代わりに、既存の物理インターフェイス(つまり、[[VLAN]] インターフェイス)上に仮想インターフェイスを作成し、それをコンテナに追加できます。仮想インターフェイスは、基盤となるホストインターフェイスとブリッジされるため、コンテナは外部ネットワークに公開されます。これにより、ホストが接続されているのと同じ LAN から DHCP を介して個別の IP アドレスを取得できます。
  +
  +
''systemd-nspawn'' には2つのオプションがあります:
  +
  +
* {{ic|1=--network-macvlan=''interface''}} – 仮想インターフェイスは、基盤となる物理インターフェイスとは異なるMACアドレスを持ち、{{ic|mv-''interface''}} という名前が付けられます。
  +
  +
* {{ic|1=--network-ipvlan=''interface''}} – 仮想インターフェイスは、基礎となる物理インターフェイスと同じMACアドレスを持ち、{{ic|iv-''interface''}} と名付けられます。
  +
  +
どちらのオプションも {{ic|--private-network}} を意味します。
  +
  +
{{Note|ホストがコンテナと通信できるようにするために、ホストに macvlan または ipvlan インターフェースを作成し、それをコンテナが使用している同じ物理インターフェースに接続し、その上でネットワーク接続を設定してください。仮想インターフェース名が ''systemd-nspawn'' によって作成された仮想インターフェースと衝突しないことを確認してください。''systemd-networkd'' を使用した例については、[[systemd-networkd#MACVLAN bridge]] を参照してください。}}
  +
  +
==== 既存のインターフェイスを使用する ====
  +
  +
ホストシステムに複数の物理ネットワークインターフェイスがある場合は、 {{ic|1=--network-interface=''interface''}} を使用してコンテナにインターフェイスを割り当てることができます(コンテナが起動している間はホストからは利用できないようにします)。{{ic|--network-interface}} は{{ic|--private-network}} を意味することに注意してください。
  +
  +
{{Note|''systemd-nspawn'' コンテナにワイヤレスネットワークインターフェイスを渡すことは現在サポートされていません。[https://github.com/systemd/systemd/issues/7873]}}
  +
  +
=== ポートマッピング ===
  +
  +
プライベートネットワークが有効になっている場合、ホストの個々のポートは、{{ic|-p}}/{{ic|--port}} オプションを使用するか、または ''.nspawn'' ファイルの {{ic|Port}} 設定を使用してコンテナのポートにマッピングすることができます。たとえば、ホストの TCP ポート 8000 をコンテナの TCP ポート 80 にマッピングするには:
  +
  +
{{hc|/etc/systemd/nspawn/''container-name''.nspawn|2=
  +
[Network]
  +
Port=tcp:8000:80
  +
}}
  +
  +
これは、{{ic|nat}} テーブルに [[iptables]] ルールを発行することで機能しますが、{{ic|filter}} テーブルの {{ic|FORWARD}} チェインは、[[#仮想イーサネットリンクを使用する]]に示されているように手動で設定する必要があります。さらに、[[シンプルなステートフルファイアウォール]]に従った場合、ホストの {{ic|''wan_interface''}} で転送されたポートへの新しい接続を許可するには、次のコマンドを実行してください:
  +
  +
# iptables -A FORWARD -i ''wan_interface'' -o ve-+ -p tcp --syn --dport 8000 -m conntrack --ctstate NEW -j ACCEPT
  +
  +
{{Note|
  +
* ''systemd-nspawn'' は、ポートをマッピングする際に {{ic|loopback}} インターフェイスを明示的に除外します。したがって、上記の例では、{{ic|localhost:8000}} はホストに接続し、コンテナには接続しません。他のインターフェイスへの接続のみがポートマッピングの対象となります。詳細は、[https://github.com/systemd/systemd/issues/6106] を参照してください。
  +
* ポートマッピングは IPv4 接続に対してのみ機能します。 [https://github.com/systemd/systemd/issues/10254]
  +
}}
  +
  +
=== ドメイン名前解決 ===
  +
  +
コンテナ内の [[ドメイン名前解決]] は ''systemd-nspawn'' の {{ic|--resolv-conf}} オプションか、''.nspawn'' ファイルの {{ic|1=ResolvConf=}} オプションで設定できます。{{man|1|systemd-nspawn|統合オプション}} に多くの値が記述されています。
  +
  +
デフォルト値は {{ic|auto}} で以下の事を意味します:
  +
  +
* {{ic|--private-network}} が有効になっている場合、{{ic|/etc/resolv.conf}} はコンテナ内のまま残ります。
  +
* あるいは、ホストで [[systemd-resolved]] が実行されている場合、そのスタブ {{ic|resolv.conf}} ファイルがコンテナにコピーまたはバインドマウントされます。
  +
* それ以外の場合、{{ic|/etc/resolv.conf}} ファイルはホストからコンテナにコピーされるか、バインドマウントされます。
  +
  +
最後の2つのケースでは、コンテナルートが書き込み可能な場合はファイルがコピーされ、読み取り専用の場合はバインドマウントされます。
  +
  +
ホスト上で [[systemd-resolved]] が実行される 2 番目のケースでは、コンテナがホストからのスタブ symlink ファイル {{ic|/etc/resolv.conf}} を使用できるように ''systemd-nspawn'' がコンテナ内でも実行されることを期待します。そうでない場合、デフォルト値の {{ic|auto}} はもはや機能しませんので、{{ic|replace-*}} オプションのいずれかを使ってシンボリックリンクを置き換える必要があります。
  +
  +
== ヒントとテクニック ==
  +
  +
=== シェル/init 以外のコマンドを実行する ===
  +
  +
{{man|1|systemd-nspawn|Execution Options}} より。
  +
  +
:"'' [オプション] --as-pid2 [呼び出し] シェルまたは指定されたプログラムを、PID 1(init)ではなくプロセス ID(PID)2 として使用します。[...] PID 1として正しく実行されるように変更されていない限り、コンテナ内で任意のコマンドを呼び出すにはこのモードを使用することが推奨されます。言い換えれば、このスイッチは、コマンドが init やシェルの実装を参照している場合を除き、ほとんどすべてのコマンドに使用すべきです。[...] このオプションは {{ic|--boot}} と組み合わせることはできません。
  +
  +
=== 非特権コンテナ ===
  +
  +
''systemd-nspawn'' は非特権コンテナをサポートしますが、コンテナは root として起動する必要があります。
  +
  +
{{Note|この機能には {{man|7|user_namespaces}} が必要です。詳細については、[[Linux Containers#非特権コンテナのサポートを有効化 (任意)]] を参照してください。}}
  +
  +
これを行う最も簡単な方法は、{{ic|-U}} オプションを使用して ''systemd-nspawn'' が自動的に未使用の UIDs/GIDs の範囲を選択させることです:
  +
  +
# systemd-nspawn -bUD ~/MyContainer
  +
  +
カーネルがユーザー名前空間をサポートしている場合、{{ic|-U}} オプションは {{ic|1=--private-users=pick --private-users-chown}} と同等です。これはコンテナの開始時にコンテナ内のファイルとディレクトリが選択された範囲のプライベート UIDs/GIDs に変更される事を意味します。詳細は、
  +
{{man|1|systemd-nspawn|User Namespacing Options}} を参照してください。
  +
  +
{{Note|コンテナの UID/GID の範囲を手動で指定することもできますが、これが役立つことはほとんどありません。}}
  +
  +
プライベート UID/GID の範囲を持つコンテナを起動したら、パーミッションエラーを避けるために、そのコンテナを使い続ける必要があります。あるいは、{{ic|--private-users-chown}} (または {{ic|-U}}) のファイルシステムへの影響を元に戻すには、0で始まるIDの範囲を指定します:
  +
  +
# systemd-nspawn -D ~/MyContainer --private-users=0 --private-users-chown
   
 
=== X 環境 ===
 
=== X 環境 ===
143行目: 375行目:
 
X は必要なファイルを {{ic|/tmp}} ディレクトリに保存します。コンテナから全てを表示させるには、{{ic|/tmp}} ディレクトリのファイルにアクセスできるようにしなくてはなりません。コンテナを起動するときに {{ic|--bind<nowiki>=</nowiki>/tmp/.X11-unix:/tmp/.X11-unix}} オプションを追加してください。
 
X は必要なファイルを {{ic|/tmp}} ディレクトリに保存します。コンテナから全てを表示させるには、{{ic|/tmp}} ディレクトリのファイルにアクセスできるようにしなくてはなりません。コンテナを起動するときに {{ic|--bind<nowiki>=</nowiki>/tmp/.X11-unix:/tmp/.X11-unix}} オプションを追加してください。
   
  +
{{Note|systemd バージョン 235 には [https://github.com/systemd/systemd/issues/7093 バグ] が存在し、{{ic|/tmp/.X11-unix}} がファイルシステムから消失することがあります。問題を回避するには {{ic|/tmp/.X11-unix}} を読み取り専用でバインドしてください: {{ic|--bind-ro<nowiki>=</nowiki>/tmp/.X11-unix/X0}}。{{ic|/run/user/1000}} もバインドしている場合は明示的に {{ic|/run/user/1000/bus}} を読み取り専用でバインドすることで dbus ソケットが削除されないように保護することができます。}}
=== nspawn コンテナの中で Firefox を実行 ===
 
   
  +
==== xhost の回避 ====
[[Firefox 設定#nspawn コンテナの中で Firefox を実行]]を見て下さい。
 
   
  +
{{ic|xhost}} は、Xサーバに対してかなり粗いアクセス権しか与えません。​{{ic|$XAUTHORITY}} ファイルを使用すると、より詳細なアクセス制御が可能になります。​残念ながら、コンテナ内の{{ic|$XAUTHORITY}} ファイルにアクセスできるようにしただけではうまくいきません。{{ic|$XAUTHORITY}} ファイルはホスト固有のものですが、コンテナは別のホストです。​stackoverflowを参考にした以下のトリックを使えば、Xサーバがコンテナ内で実行されているXアプリケーションから、{{ic|$XAUTHORITY}} ファイルを受け入れるようにすることができます:
=== ホストのファイルシステムにアクセス ===
 
   
  +
$ XAUTH=/tmp/container_xauth
例えばホストとコンテナの両方が Arch Linux で、pacman のキャッシュを共有するには:
 
  +
$ xauth nextract - "$DISPLAY" | sed -e 's/^..../ffff/' | xauth -f "$XAUTH" nmerge -
  +
# systemd-nspawn -D myContainer --bind=/tmp/.X11-unix --bind="$XAUTH" -E DISPLAY="$DISPLAY" -E XAUTHORITY="$XAUTH" --as-pid2 /usr/bin/xeyes
   
  +
上記の2行目では、接続ファミリーを ""FamilyWild""(値{{ic|65535}}) に設定しているため、エントリはすべての表示に一致します。​詳細は{{man|7|Xsecurity}} を参照。
# systemd-nspawn --bind=/var/cache/pacman/pkg
 
  +
  +
==== X nesting/Xephyr を使用====
  +
  +
X アプリケーションを実行し、共有 X デスクトップのリスクを回避するもう1つの簡単な方法は、X nesting を使用することです。
  +
ここでの利点は、コンテナ内アプリケーションと非コンテナアプリケーションの間の相互作用を完全に回避し、異なる [[デスクトップ環境]] または [[ウィンドウマネージャ]] を実行できることです。 欠点はパフォーマンスの低下と [[Xephyr]] を使用した場合のハードウェアアクセラレーションの欠如です。
  +
  +
Xephyr をコンテナの外で起動するには以下の方法があります。
  +
  +
# Xephyr :1 -resizeable
  +
  +
その後、以下のオプションでコンテナを起動します。
  +
  +
--setenv=DISPLAY=:1 --bind-ro<nowiki>=</nowiki>/tmp/.X11-unix/X1
  +
  +
他のバインドは必要ありません。
  +
  +
状況によっては、コンテナ内で {{ic|1=DISPLAY=:1}} を手動で設定する必要があるかもしれません(主に {{ic|-b}} と併用する場合)
  +
  +
==== Firefox を起動する ====
  +
  +
PID 1 として実行するには
  +
  +
# systemd-nspawn --setenv=DISPLAY=:0 \
  +
--setenv=XAUTHORITY=~/.Xauthority \
  +
--bind-ro=$HOME/.Xauthority:/root/.Xauthority \
  +
--bind=/tmp/.X11-unix \
  +
-D ~/containers/firefox \
  +
firefox
   
  +
{{Note|そのため、firefox は root ユーザーとして実行されますが、[[#非特権コンテナ]]を使用していない場合には独自のリスクが伴います。その場合、まずコンテナ内で[[ユーザーとグループ#ユーザーを追加する例|ユーザーを追加]]し、その後 ''systemd-nspawn'' の呼び出しで {{ic|--user <username>}} オプションを追加することができます。}}
詳しくは {{ic|man systemd-nspawn}} の {{ic|--bind}} と {{ic|--bind-ro}} を参照してください。
 
   
  +
あるいは、コンテナを起動して、例えば、[[systemd-networkd]] に仮想ネットワークインターフェイスを設定することもできます。
=== ネットワーク ===
 
   
  +
# systemd-nspawn --bind-ro=$HOME/.Xauthority:/root/.Xauthority \
ネットワーク管理に [[systemd-networkd]] を使用して DNS に {{ic|systemd-resolved}} を使用する、インターネットに接続できる最も簡単な設定:
 
  +
--bind=/tmp/.X11-unix \
  +
-D ~/containers/firefox \
  +
--network-veth -b
   
  +
コンテナが起動したら、次のようにXorgバイナリを実行します:
# systemctl enable --now systemd-networkd systemd-resolved
 
# ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf # let systemd-resolved manage /etc/resolv.conf
 
   
  +
# systemd-run -M firefox --setenv=DISPLAY=:0 firefox
上記の設定を使うには {{ic|-n}} スイッチを使って {{ic|systemd-nspawn}} を実行して、ホストに仮想イーサネットリンクを作成する必要があります。
 
   
  +
==== 3D グラフィックスアクセラレーション ====
{{ic|systemd-resolved}} を使わないでコンテナの {{ic|/etc/resolv.conf}} を手動で編集して DNS サーバーの IP アドレスを追加することも可能です。
 
   
  +
3Dグラフィックスアクセラレーションを有効にするためには、''.nspawn'' ファイルに以下の行を追加して、マウント {{ic|/dev/dri}} をコンテナにバインドする必要があるかもしれません。
基本的な [[systemd-networkd]] のホストとコンテナの {{ic|.network}} ファイルは https://github.com/systemd/systemd/tree/master/network にあります。
 
   
  +
Bind=/dev/dri
もっと複雑なネットワークを設定する方法は、[[systemd-networkd#コンテナでの使用方法]]を見て下さい。
 
   
  +
この方法は [https://web.archive.org/web/20190925003151/https://patrickskiba.com/sysytemd-nspawn/2019/03/21/graphical-applications-in-systemd-nspawn.html patrickskiba.com] から引用しました。これにより、以下の問題が解決されます。
==== nsswitch.conf ====
 
   
  +
libGL error: MESA-LOADER: failed to retrieve device information
ホストからコンテナへの接続を楽にするために、コンテナの名前のローカル DNS 解決を有効にすることができます。{{ic|/etc/nsswitch.conf}} の {{ic|hosts:}} セクションに {{ic|mymachines}} を追加してください:
 
  +
libGL error: Version 4 or later of flush extension not found
  +
libGL error: failed to load driver: i915
   
  +
{{ic|glxinfo}} または {{ic|glxgears}} を実行して、有効になっているか確認してください。
hosts: files mymachines dns myhostname
 
   
  +
===== NVIDIA GPUs =====
こうすると、ホスト上でホストネーム {{ic|foo}} の DNS ルックアップで {{ic|/etc/hosts}} が参照され、それからローカルコンテナの名前、上流の DNS などが参照されます。
 
   
  +
コンテナ上にホストと同じバージョンの NVIDIA ドライバをインストールできない場合、ドライバライブラリファイルもバインドする必要がある場合があります。ホスト上で {{ic|pacman -Ql nvidia-utils}} を実行すると、含まれている全てのファイルを確認することができます。全てをコピーする必要はありません。以下の systemd override ファイルは、コンテナを {{ic|machinectl start ''container-name''}} で実行する際に必要なファイルを全てバインドします。
==== ホストのネットワークを使用 ====
 
   
  +
{{Accuracy|No reason to bind from {{ic|/usr/lib/}} into {{ic|/usr/lib/x86_64-linux-gnu/}}.}}
{{ic|machinectl start MyContainer}} で起動したコンテナによって使用されるプライベートネットワークを無効化するには {{ic|systemctl edit systemd-nspawn@.service}} を実行して {{ic|systemd-nspawn@.service}} サービスファイルの設定を編集してください。{{ic|--network-veth}} パラメータを削除するように {{ic|1=ExecStart=}} オプションを設定します:
 
   
{{hc|/etc/systemd/system/systemd-nspawn@.service.d/override.conf|<nowiki>
+
{{hc|/etc/systemd/system/systemd-nspawn@.service.d/nvidia-gpu.conf|2=
 
[Service]
 
[Service]
 
ExecStart=
 
ExecStart=
ExecStart=/usr/bin/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --machine=%I
+
ExecStart=systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --machine=%i \
  +
--bind=/dev/dri \
</nowiki>}}
 
  +
--bind=/dev/shm \
  +
--bind=/dev/nvidia0 \
  +
--bind=/dev/nvidiactl \
  +
--bind=/dev/nvidia-modeset \
  +
--bind=/usr/bin/nvidia-bug-report.sh:/usr/bin/nvidia-bug-report.sh \
  +
--bind=/usr/bin/nvidia-cuda-mps-control:/usr/bin/nvidia-cuda-mps-control \
  +
--bind=/usr/bin/nvidia-cuda-mps-server:/usr/bin/nvidia-cuda-mps-server \
  +
--bind=/usr/bin/nvidia-debugdump:/usr/bin/nvidia-debugdump \
  +
--bind=/usr/bin/nvidia-modprobe:/usr/bin/nvidia-modprobe \
  +
--bind=/usr/bin/nvidia-ngx-updater:/usr/bin/nvidia-ngx-updater \
  +
--bind=/usr/bin/nvidia-persistenced:/usr/bin/nvidia-persistenced \
  +
--bind=/usr/bin/nvidia-powerd:/usr/bin/nvidia-powerd \
  +
--bind=/usr/bin/nvidia-sleep.sh:/usr/bin/nvidia-sleep.sh \
  +
--bind=/usr/bin/nvidia-smi:/usr/bin/nvidia-smi \
  +
--bind=/usr/bin/nvidia-xconfig:/usr/bin/nvidia-xconfig \
  +
--bind=/usr/lib/gbm/nvidia-drm_gbm.so:/usr/lib/x86_64-linux-gnu/gbm/nvidia-drm_gbm.so \
  +
--bind=/usr/lib/libEGL_nvidia.so:/usr/lib/x86_64-linux-gnu/libEGL_nvidia.so \
  +
--bind=/usr/lib/libGLESv1_CM_nvidia.so:/usr/lib/x86_64-linux-gnu/libGLESv1_CM_nvidia.so \
  +
--bind=/usr/lib/libGLESv2_nvidia.so:/usr/lib/x86_64-linux-gnu/libGLESv2_nvidia.so \
  +
--bind=/usr/lib/libGLX_nvidia.so:/usr/lib/x86_64-linux-gnu/libGLX_nvidia.so \
  +
--bind=/usr/lib/libcuda.so:/usr/lib/x86_64-linux-gnu/libcuda.so \
  +
--bind=/usr/lib/libnvcuvid.so:/usr/lib/x86_64-linux-gnu/libnvcuvid.so \
  +
--bind=/usr/lib/libnvidia-allocator.so:/usr/lib/x86_64-linux-gnu/libnvidia-allocator.so \
  +
--bind=/usr/lib/libnvidia-cfg.so:/usr/lib/x86_64-linux-gnu/libnvidia-cfg.so \
  +
--bind=/usr/lib/libnvidia-egl-gbm.so:/usr/lib/x86_64-linux-gnu/libnvidia-egl-gbm.so \
  +
--bind=/usr/lib/libnvidia-eglcore.so:/usr/lib/x86_64-linux-gnu/libnvidia-eglcore.so \
  +
--bind=/usr/lib/libnvidia-encode.so:/usr/lib/x86_64-linux-gnu/libnvidia-encode.so \
  +
--bind=/usr/lib/libnvidia-fbc.so:/usr/lib/x86_64-linux-gnu/libnvidia-fbc.so \
  +
--bind=/usr/lib/libnvidia-glcore.so:/usr/lib/x86_64-linux-gnu/libnvidia-glcore.so \
  +
--bind=/usr/lib/libnvidia-glsi.so:/usr/lib/x86_64-linux-gnu/libnvidia-glsi.so \
  +
--bind=/usr/lib/libnvidia-glvkspirv.so:/usr/lib/x86_64-linux-gnu/libnvidia-glvkspirv.so \
  +
--bind=/usr/lib/libnvidia-ml.so:/usr/lib/x86_64-linux-gnu/libnvidia-ml.so \
  +
--bind=/usr/lib/libnvidia-ngx.so:/usr/lib/x86_64-linux-gnu/libnvidia-ngx.so \
  +
--bind=/usr/lib/libnvidia-opticalflow.so:/usr/lib/x86_64-linux-gnu/libnvidia-opticalflow.so \
  +
--bind=/usr/lib/libnvidia-ptxjitcompiler.so:/usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so \
  +
--bind=/usr/lib/libnvidia-rtcore.so:/usr/lib/x86_64-linux-gnu/libnvidia-rtcore.so \
  +
--bind=/usr/lib/libnvidia-tls.so:/usr/lib/x86_64-linux-gnu/libnvidia-tls.so \
  +
--bind=/usr/lib/libnvidia-vulkan-producer.so:/usr/lib/x86_64-linux-gnu/libnvidia-vulkan-producer.so \
  +
--bind=/usr/lib/libnvoptix.so:/usr/lib/x86_64-linux-gnu/libnvoptix.so \
  +
--bind=/usr/lib/modprobe.d/nvidia-utils.conf:/usr/lib/x86_64-linux-gnu/modprobe.d/nvidia-utils.conf \
  +
--bind=/usr/lib/nvidia/wine/_nvngx.dll:/usr/lib/x86_64-linux-gnu/nvidia/wine/_nvngx.dll \
  +
--bind=/usr/lib/nvidia/wine/nvngx.dll:/usr/lib/x86_64-linux-gnu/nvidia/wine/nvngx.dll \
  +
--bind=/usr/lib/nvidia/xorg/libglxserver_nvidia.so:/usr/lib/x86_64-linux-gnu/nvidia/xorg/libglxserver_nvidia.so \
  +
--bind=/usr/lib/vdpau/libvdpau_nvidia.so:/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_nvidia.so \
  +
--bind=/usr/lib/xorg/modules/drivers/nvidia_drv.so:/usr/lib/x86_64-linux-gnu/xorg/modules/drivers/nvidia_drv.so \
  +
--bind=/usr/share/X11/xorg.conf.d/10-nvidia-drm-outputclass.conf:/usr/share/X11/xorg.conf.d/10-nvidia-drm-outputclass.conf \
  +
--bind=/usr/share/dbus-1/system.d/nvidia-dbus.conf:/usr/share/dbus-1/system.d/nvidia-dbus.conf \
  +
--bind=/usr/share/egl/egl_external_platform.d/15_nvidia_gbm.json:/usr/share/egl/egl_external_platform.d/15_nvidia_gbm.json \
  +
--bind=/usr/share/glvnd/egl_vendor.d/10_nvidia.json:/usr/share/glvnd/egl_vendor.d/10_nvidia.json \
  +
--bind=/usr/share/licenses/nvidia-utils/LICENSE:/usr/share/licenses/nvidia-utils/LICENSE \
  +
--bind=/usr/share/vulkan/icd.d/nvidia_icd.json:/usr/share/vulkan/icd.d/nvidia_icd.json \
  +
--bind=/usr/share/vulkan/implicit_layer.d/nvidia_layers.json:/usr/share/vulkan/implicit_layer.d/nvidia_layers.json \
  +
DeviceAllow=/dev/dri rw
  +
DeviceAllow=/dev/shm rw
  +
DeviceAllow=/dev/nvidia0 rw
  +
DeviceAllow=/dev/nvidiactl rw
  +
DeviceAllow=/dev/nvidia-modeset rw
  +
}}
   
  +
{{Note|ホスト上で NVIDIA ドライバをアップグレードするたびに、コンテナを再起動する必要があり、ライブラリを更新するためにコンテナ内で {{ic|ldconfig}} を実行する必要がある場合があります。}}
次に起動したコンテナはホストのネットワークを使用するようになります。
 
   
==== 仮想イーサネッインターイス ====
+
=== ホスルシステムにアクセス ===
   
  +
例えばホストとコンテナの両方が Arch Linux で、pacman のキャッシュを共有するには:
コンテナを {{ic|systemd-nspawn ... -n}} で起動した場合、systemd は自動的にホストとコンテナに仮想イーサネットインターフェイスを作成して、仮想イーサネットケーブルで接続します。
 
   
  +
# systemd-nspawn --bind=/var/cache/pacman/pkg
コンテナの名前が {{ic|foo}} ならば、仮想イーサネットインターフェイスのホストにおける名前は {{ic|ve-foo}} になり、コンテナではどんな場合でも名前は {{ic|host0}} です。
 
   
  +
詳しくは {{man|1|systemd-nspawn}} の {{ic|--bind}} と {{ic|--bind-ro}} を参照してください。
{{ic|ip link}} でインターフェイスを確認すると、インターフェイスの名前には {{ic|ve-foo@if2}} や {{ic|host0@if9}} のように接尾辞が付きます。{{ic|@ifN}} は実際はインターフェイスの名前には含まれていません。仮想イーサネットケーブルが他の端末に接続されていることを示すために {{ic|ip link}} によって情報が加えられています。
 
  +
  +
ファイルを使ってコンテナごとにバインドを設定することもできます:
  +
  +
{{hc|/etc/systemd/nspawn/''my-container''.nspawn|<nowiki>
  +
[Files]
  +
Bind=/var/cache/pacman/pkg
  +
</nowiki>}}
   
  +
[[#コンテナごとに設定を指定する]]を参照。
例えば、ホストの仮想イーサネットインターフェイス {{ic|ve-foo@if2}} がコンテナ {{ic|foo}} に接続、コンテナの中の2番目のネットワークインターフェイスに接続する場合、コンテナの中から {{ic|ip link}} を実行するとインデックス 2 が付きます。同じように、コンテナの {{ic|host0@if9}} という名前のインターフェイスはホストの9番目のインターフェイスに接続します。
 
   
 
=== systemd を使っていない環境で動作させる ===
 
=== systemd を使っていない環境で動作させる ===
227行目: 558行目:
   
 
コンテナの電源を切ると、作成された btrfs サブボリュームはすぐに削除されます。
 
コンテナの電源を切ると、作成された btrfs サブボリュームはすぐに削除されます。
  +
  +
=== system-nspawn で docker を実行 ===
  +
  +
[[Docker]] 20.10 以降、''cgroups v2'' を有効にした非特権 ''systemd-nspawn'' コンテナ内で Docker コンテナを実行することが可能になりました(Arch Linux ではデフォルト)。これにより、cgroups やユーザー名前空間を無効にすることなくセキュリティ対策を損なうことなく行えます。これを行うには、{{ic|/etc/systemd/nspawn/myContainer.nspawn}} を編集し(存在しない場合は作成)、以下の設定を追加します。
  +
  +
{{hc|/etc/systemd/nspawn/myContainer.nspawn|<nowiki>
  +
[Exec]
  +
SystemCallFilter=add_key keyctl bpf
  +
</nowiki>}}
  +
  +
その後、コンテナ内で Docker はそのまま機能するはずです。
  +
  +
{{Note|上記の設定では、コンテナに ''add_key''、''keyctl''、および ''bpf'' といった名前空間化されていないシステムコールを公開しています。これはユーザー名前空間を完全に無効にする以前の方法と比較するとセキュリティリスクは大幅に低いものの、依然としてセキュリティリスクになり得ます。}}
  +
  +
''overlayfs'' はユーザー名前空間と互換性がなく、デフォルトでは ''systemd-nspawn'' 内で使用できません。そのため、Docker は非効率な ''vfs'' をストレージドライバーとして使用することになります。これはコンテナを開始するたびにイメージのコピーを作成します。これを回避するためには、ストレージドライバーとして ''fuse-overlayfs'' を使用する必要があります。これを行うためには、まずコンテナに ''fuse'' を公開する必要があります:
  +
  +
{{hc|/etc/systemd/nspawn/myContainer.nspawn|<nowiki>
  +
[Files]
  +
Bind=/dev/fuse
  +
</nowiki>}}
  +
  +
そして、コンテナがデバイスノードを読み書きできるように設定します:
  +
  +
# systemctl set-property systemd-nspawn@myContainer DeviceAllow='/dev/fuse rwm'
  +
  +
最後に、コンテナ内に {{Pkg|fuse-overlayfs}} パッケージをインストールします。すべての設定を有効にするには、コンテナを再起動する必要があります。
   
 
== トラブルシューティング ==
 
== トラブルシューティング ==
236行目: 593行目:
 
Login incorrect
 
Login incorrect
   
そして {{ic|journalctl}} が以下のように表示する場合:
+
そして、コンテナの [[journal]] が以下のように表示する場合:
   
 
pam_securetty(login:auth): access denied: tty 'pts/0' is not secure !
 
pam_securetty(login:auth): access denied: tty 'pts/0' is not secure !
   
  +
{{Accuracy|Files in {{ic|/usr/lib}} should not be edited by users, the change in {{ic|/usr/lib/tmpfiles.d/arch.conf}} will be lost when {{pkg|filesystem}} is upgraded.}}
コンテナのファイルシステム上にある {{ic|/etc/securetty}} のターミナル名のリストに {{ic|pts/0}} を追加してください。詳しくは [http://unix.stackexchange.com/questions/41840/effect-of-entries-in-etc-securetty/41939#41939] を参照。また、コンテナの {{ic|/etc/securetty}} を削除して root で全ての tty にログインできるようにするという方法もあります。[https://github.com/systemd/systemd/issues/852] を見てください。
 
   
  +
'''コンテナ'''ファイルシステム上の、{{ic|/etc/securetty}}[https://unix.stackexchange.com/questions/41840/effect-of-entries-in-etc-securetty/41939#41939] と {{ic|/usr/share/factory/etc/securetty}} を削除するか、'''コンテナ'''ファイイルシステム上の {{ic|/etc/securetty}} に必要な pty 端末デバイス({{ic|pts/0}} のような)を追加します。変更は、次の起動時に上書きされるため、{{ic|/etc/securetty}} のエントリを削除する必要があります。{{Bug|63236}} を参照。削除を選択した場合は、{{ic|/etc/pacman.conf}} の [[pacman#Skip files from being installed to system|NoExtract]] にそれらを追加し、再インストールされないようにします。{{Bug|45903}} を参照してください。
=== コンテナのパッケージをアップグレードできない ===
 
   
  +
=== execv(...) failed: Permission denied ===
ときどきコンテナの特定のパッケージがアップグレードできなくなることがあります。{{Pkg|filesystem}} などが特にそうです。原因は {{ic|/sys}} が読み取り専用でマウントされていることにあります。{{ic|mount -o remount,rw -t sysfs sysfs /sys}} を実行してディレクトリを読み書き可能で再マウントしてから、アップグレードを行なって、コンテナを再起動してください。
 
  +
  +
{{ic|systemd-nspawn -bD ''/path/to/container''}} によってコンテナを起動 (またはコンテナ内で何かを実行) しようとすると、以下のようなエラーが発生します:
  +
  +
execv(/usr/lib/systemd/systemd, /lib/systemd/systemd, /sbin/init) failed: Permission denied
  +
  +
問題のファイル (例えば {{ic|/lib/systemd/systemd}}) のパーミッションが正しくても、コンテナが保存されているファイルシステムを非rootユーザーとしてマウントした結果である可能性があります。例えば、[[fstab]] に {{ic|noauto,user,...}} というオプションを指定して手動でディスクをマウントした場合、''systemd-nspawn'' は rootが所有するファイルであっても実行は許可しません。
  +
  +
=== TERM の端末タイプが間違っている (色が壊れている) ===
  +
  +
{{ic|machinectl login}} でコンテナにログインすると、コンテナ内の端末の色とキーストロークが壊れることがあります。これは、{{ic|TERM}} 環境変数の端末タイプが正しくないことが原因である可能性があります。環境変数はホストのシェルから継承されませんが、明示的に設定されていない限り、systemd ({{ic|vt220}}) で固定されたデフォルトに戻ります。設定するには、コンテナ内の {{ic|container-getty@.service}} サービス用のオーバーレイを作成して、{{ic|machinectl login}} の login getty を起動し、ログインしているホスト端末と一致する値を {{ic|TERM}} に設定してください。
  +
  +
{{hc|/etc/systemd/system/container-getty@.service.d/term.conf|2=
  +
[Service]
  +
Environment=TERM=xterm-256color
  +
}}
  +
  +
もしくは、{{ic|machinectl shell}} を使用してください。端末から {{ic|TERM}} 環境変数を適切に継承します。
  +
  +
=== コンテナ内へのNFS共有のマウント ===
  +
  +
現時点(2019年6月)では利用できません。
   
 
== 参照 ==
 
== 参照 ==
   
  +
* [[Getty#Nspawn コンソール|自動コンソールログイン]]
* [http://www.freedesktop.org/software/systemd/man/machinectl.html machinectl man ページ]
 
* [http://www.freedesktop.org/software/systemd/man/systemd-nspawn.html systemd-nspawn man ページ]
+
* [https://lwn.net/Articles/572957/ Creating containers with systemd-nspawn]
* [http://lwn.net/Articles/572957/ Creating containers with systemd-nspawn]
+
* [https://www.youtube.com/results?search_query=systemd-nspawn&aq=f Presentation by Lennart Poettering on systemd-nspawn]
* [https://www.youtube.com/results?search_query=systemd-nspawn&aq=f Lennart Pottering による systemd-nspawn のプレゼンテーション]
+
* [https://dabase.com/e/12009/ Running Firefox in a systemd-nspawn container]
  +
* [https://web.archive.org/web/20190925003151/https://patrickskiba.com/sysytemd-nspawn/2019/03/21/graphical-applications-in-systemd-nspawn.html Graphical applications in systemd-nspawn]
* [http://dabase.com/e/12009/ Running Firefox in a systemd-nspawn container]
 
  +
  +
{{TranslationStatus|Systemd-nspawn|2024/4/18|798804}}

2024年7月10日 (水) 20:16時点における最新版

関連記事

systemd-nspawnchroot コマンドに似ていますが、chroot を強化したものです。

systemd-nspawn を使えば軽量な名前空間コンテナでコマンドや OS を実行することができます。ファイルシステム階層だけでなく、プロセスツリーや様々な IPC サブシステム、ホスト・ドメイン名も完全に仮想化するため chroot よりも強力です。

systemd-nspawn/sys, /proc/sys, /sys/fs/selinux などのコンテナの様々なカーネルインターフェイスへのアクセスを読み取り専用に制限します。コンテナの中からネットワークインターフェイスやシステムクロックを変更することはできません。デバイスノードの作成はできません。コンテナの中からホスト環境を再起動することはできず、カーネルモジュールのロードもできません。

systemd-nspawnLinux コンテナLibvirt よりも設定が簡単なツールです。

目次

インストール

systemd-nspawn は systemd の一部であり、systemd に含まれています。

サンプル

コンテナに最小限の Arch Linux を作成して起動

まず arch-install-scripts パッケージをインストールしてください。

次に、コンテナを置くためのディレクトリを作成してください。この例では、~/MyContainer を使用します。

そして、pacstrap を使って最小限の arch システムをコンテナにインストールします。最低限でも base パッケージはインストールする必要があります。

# pacstrap -K -c ~/MyContainer base [additional pkgs/groups]
ヒント: base パッケージは、linux カーネルパッケージに依存せず、コンテナにも対応しています。
ノート: pacstrap が利用できない異なるオペレーティングシステムから作成する場合、bootstrap tarball をコンテナイメージとして使用することができます。pacman キーリングはコンテナ内で初期化する必要があります。詳細は 既存の Linux からインストール#pacman キーリングの初期化 を参照してください。

インストールが完了したら、コンテナに chroot し、root パスワードを設定します。

# systemd-nspawn -D ~/MyContainer
# passwd
# logout
ヒント: Setting root password is optional. You can get a root shell in a booted container directly without having to log in by running machinectl shell root@MyContainer. See #machinectl.

最後に、コンテナを起動します。

# systemd-nspawn -b -D ~/MyContainer

-b オプションはシェルを実行する代わりにコンテナを起動します (つまり PID=1 として systemd を実行)。-D にはコンテナのルートディレクトリにするディレクトリを指定します。

コンテナが開始したら、設定したパスワードを使って "root" でログインしてください。

ノート: "Login incorrect" でログインが失敗する場合、問題は、securetty TTY デバイスのホワイトリストである可能性があります。#root ログインが失敗する をご確認ください。

コンテナの電源を切りたいときはコンテナの中から poweroff を実行することでできます。ホストからは、machinectl ツールでコンテナを制御できます。

ノート: コンテナの中からセッションを終了するには Ctrl を押しながら ] を素早く3回押してください。US キーボード以外の場合は ] の代わりに % を使用します。

Debian や Ubuntu 環境の作成

debootstrapdebian-archive-keyringubuntu-keyring のどちらか (インストールしたい方のディストリのキーリング) をインストールしてください。

ノート: systemd-nspawn はコンテナ内のオペレーティングシステムが systemd init を使用し (PID 1 として動作する)、systemd-nspawn がコンテナにインストールされている必要があります。この要件は、コンテナ環境に systemd-container パッケージをインストールすることで満たされます。systemd-container パッケージは dbus に依存しますが、dbus または dbus-broker パッケージがコンテナシステムにインストールされていることを確認してください。

後は簡単に Debian や Ubuntu 環境をセットアップできます:

# cd /var/lib/machines
# debootstrap --include=dbus-broker,systemd-container --components=main,universe codename container-name repository-url

Debian の場合、コードネームとして指定するのは "stable" や "testing" などのローリングの名前か "stretch" や "sid" などのリリース名になります。Ubuntu の場合、"xenial" や "zesty" などのコードネームを使ってください。コードネームの完全なリストは /usr/share/debootstrap/scripts にあります。Debian イメージの場合は "repository-url" には https://deb.debian.org/debian/ などを指定します。Ubuntu のイメージの場合は "repository-url" は http://archive.ubuntu.com/ubuntu/ などとなります。

Arch と同様に、Debian や Ubuntu ではパスワードなしでログインすることはできません。root のパスワードを設定するために、'-b' オプションを付けずにログインしてからパスワードを設定してください:

# cd /var/lib/machines
# systemd-nspawn -D myContainer
# passwd
# logout

Fedora または AlmaLinux 環境の作成

dnf をインストールし、必要な Fedora リポジトリを追加するために /etc/dnf/dnf.conf ファイルを編集します。

/etc/dnf/dnf.conf
[fedora]                                                                                            
name=Fedora $releasever - $basearch
metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch
gpgkey=https://getfedora.org/static/fedora.gpg

[updates]                                                                                           
name=Fedora $releasever - $basearch - Updates
metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-f$releasever&arch=$basearch
gpgkey=https://getfedora.org/static/fedora.gpg

fedora.gpg ファイルには最新の Fedora リリース用の gpg キーが含まれています https://getfedora.org/security/ 。Fedora 37 の最小コンテナを設定するには:

# cd /var/lib/machines
# mkdir container-name
# dnf --releasever=37 --best --setopt=install_weak_deps=False --repo=fedora --repo=updates --installroot=/var/lib/machines/container-name install dhcp-client dnf fedora-release glibc glibc-langpack-en iputils less ncurses passwd systemd systemd-networkd systemd-resolved util-linux vim-default-editor
ノート: 異なる Fedora リリースをインストールしたい場合は、異なるリリースが 独自のパッケージ要件 を持つことを考慮してください。

btrfs ファイルシステムを使用している場合は、ディレクトリを作成する代わりにサブボリュームを作成してください。

AlmaLinux のようなエンタープライズ Linux 派生物は、デフォルトで三つのリポジトリが有効になっています。BaseOS は、すべてのインストールの基盤となるコアセットを含み、AppStream は追加アプリケーション、言語パッケージなどを含み、Extras は RHEL に含まれないパッケージを含んでいます。したがって、最小限のコンテナには /etc/dnf/dnf.conf に BaseOS リポジトリのみを追加する必要があります。

/etc/dnf/dnf.conf
[baseos]                                                                                            
name=AlmaLinux $releasever - BaseOS                                          
mirrorlist=https://mirrors.almalinux.org/mirrorlist/$releasever/baseos       
gpgkey=https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux-$releasever

AlmaLinux 9 の最小コンテナを作成するには:

# dnf --repo=baseos --releasever=9 --best --installroot=/var/lib/machines/container-name --setopt=install_weak_deps=False install almalinux-release dhcp-client dnf glibc-langpack-en iproute iputils less passwd systemd vim-minimal

これにより、AlmaLinux 9 の最新マイナーバージョンがインストールされますが、特定のポイントリリースをインストールすることもできますが、その場合は gpgpkey エントリを手動で RPM-GPG-KEY-AlmaLinux-9 を指すように変更する必要があります。

Arch、Fedora、AlmaLinux のように、root パスワードを設定しない限り、root としてログインすることは許可されません。root パスワードを設定するには、-b オプションなしで systemd-nspawn を実行してください:

# systemd-nspawn -D /var/lib/machines/container-name passwd

パッケージのビルドおよびテスト

使用例については、他のディストリビューションのパッケージの作成 を参照してください。

管理

/var/lib/machines/ にあるコンテナは、machinectl コマンドによって制御することができます。内部的には systemd-nspawn@.service ユニットのインスタンスを制御しています。/var/lib/machines/ のサブディレクトリはコンテナ名に対応しています。

ノート: なんらかの理由でコンテナを /var/lib/machines/ に移動できない場合、シンボリックリンクが使えます。machinectl(1) § FILES AND DIRECTORIES を参照してください。

systemd-nspawn オプションのデフォルト値

machinectlsystemd-nspawn@.service 経由で起動されたコンテナは systemd-nspawn コマンドで起動されたコンテナとはオプションの既定値が異なることを理解することが重要です。サービスが使用する追加オプションは以下の通りです。

  • -b/--boot – マネージドコンテナは自動的に init プログラムを検索し、PID 1 として起動します。
  • --network-veth つまり --private-network – マネージドコンテナは仮想ネットワークインターフェースを取得し、ホストネットワークから切り離されます。詳細は、#ネットワーキング を参照してください。
  • -U – カーネルがサポートしている場合、マネージドコンテナはデフォルトで user_namespaces(7) 機能を使用します。詳細は、#非特権コンテナ を参照してください。
  • --link-journal=try-guest

この動作は、コンテナごとの設定ファイルでオーバーライドすることができます。 詳細は、#設定 を参照してください。

machinectl

ノート: machinectl ツールを使うには systemddbus がコンテナにインストールされている必要があります。詳しくは [1] を参照。

コンテナはコマンドで管理できます。例えば、コンテナを起動するには、次のようにします。

$ machinectl start container-name
ノート: machinectl は、コンテナ名が有効なホスト名であるように、ASCII 文字、数字、ハイフンのみで構成されていることを要求します。例えば、コンテナ名にアンダースコアが含まれている場合、それは単に認識されず、 machinectl start container_name を実行すると、エラー Invalid machine name container_name となります。詳しくは[2][3]を参照してください。

同様に、poweroff, reboot, status, show などのサブコマンドがあります。詳細な説明については、machinectl(1) § Machine Commands を参照してください。

ヒント: 電源オフと再起動の操作は、poweroffreboot コマンドを使用してコンテナ内から実行することができます。

その他の一般的なコマンドは以下の通りです:

  • machinectl list – 現在実行中のコンテナの一覧を表示する
  • machinectl login container-name - 実行中のコンテナに新しいシェルを起動
  • machinectl shell [username@]container-name – コンテナで対話的なシェルセッションを開きます(コンテナ内のログインプロセスを経ずにユーザープロセスが即座に呼びだす)。
  • machinectl enable container-name または machinectl disable container-name - コンテナを有効または無効にして、起動時に開始します。詳細については、#PC起動時にコンテナを自動で開始する を参照してください。

machinectl にはコンテナ(または仮想マシン)イメージとイメージ転送を管理するためのサブコマンドもあります。詳細については、machinectl(1) § Image Commands および、machinectl(1) § Image Transfer Commands を参照してください。2023Q1 時点で、machinectl(1) § EXAMPLES にある最初の 3 つの例はイメージ転送コマンドを示しています。machinectl(1) § FILES AND DIRECTORIES では、適切なイメージをどこで見つけるかについて説明しています。

systemd ツールチェイン

systemd のコアツールチェインは多くがコンテナでも使えるようにアップデートされています。コンテナの名前を引数とする -M, --machine= オプションをツールに付けるだけです。

例:

  • 特定のマシンの journal ログを表示:
    $ journalctl -M MyContainer
  • control group の中身を表示:
    $ systemd-cgls -M MyContainer
  • コンテナの起動時間を表示:
    $ systemd-analyze -M MyContainer
  • リソース利用状況を表示:
    $ systemd-cgtop

設定

コンテナ毎の設定

グローバル設定のオーバーライドではなく、コンテナ毎の設定を指定するには、.nspawn ファイルを使用できます。詳細については、 systemd.nspawn(5) を参照してください。

ノート:
  • .nspawn ファイルは、machinectl remove を実行した時に、/etc/systemd/nspawn/ から予期せずに削除される場合があります。
  • systemd-nspawn@.service ファイルで指定されている、--settings=override がある場合、.nspawn ファイルで指定されているネットワークオプションとコマンドラインオプションの相互作用で正しく動作しません。回避策としてサービスが --network-veth を指定している場合でも、VirtualEthernet=on オプションを含める必要があります。

PC起動時にコンテナを自動で開始する

コンテナを頻繁に使用する場合は、PC起動時に開始することをおすすめします。

まず、machines.target有効になっている事を確認します。 machinectl で検出可能なコンテナは、有効または無効にできます:

$ machinectl enable container-name
ノート:

リソース制御

systemctl set-property でコンテナの制限やリソース管理を実装するために、コントロールグループを利用することができます。systemd.resource-control(5) を参照してください。例えば、メモリ容量やCPU使用率を制限できます。コンテナのメモリ消費を2GiBに制限するには:

# systemctl set-property systemd-nspawn@container-name.service MemoryMax=2G

または、CPU時間の使用量をだいたい2コア分に制限したい場合:

# systemctl set-property systemd-nspawn@container-name.service CPUQuota=200%

これにより以下の永続ファイルが作成されます。 /etc/systemd/system.control/systemd-nspawn@container-name.service.d/.

ドキュメントによると、MemoryHigh はメモリ消費をチェックするための推奨される方法ですが、MemoryMax のように厳密に制限されることはありません。MemoryMax を最終防衛戦として残して、両方のオプションを使用できます。また、コンテナが認識できるCPUの数を制限しないことも考慮に入れてください。ただし、CPU時間合計に対して、コンテナが最大で取得する時間を制限することで、同様の結果が得られます。

ヒント: これらの変更を一時的なものにしたい場合は、--runtime オプションを渡すことができます。その結果は、systemd-cgtop で確認できます。

ネットワーキング

systemd-nspawn コンテナは、ホストネットワーク または プライベートネットワークのいずれかを使用できます。

  • ホストネットワークモードでは、コンテナはホストネットワークへのフルアクセスが可能です。これは、コンテナがホスト上のすべてのネットワークサービスにアクセスできるようになり、コンテナからのパケットがホストのパケットとして外部ネットワークに表示される事を意味します(つまり、同じIPアドレスを共有します)。
  • プライベートネットワークモードでは、コンテナはホストのネットワークから切断されています。これにより、ループバックデバイスとコンテナに明示的に割り当てられたものを除いて、すべてのネットワークインターフェイスがコンテナを使用できなくなります。コンテナのネットワークインターフェイスを設定するには、いくつかの方法があります。
    • 既存のインターフェイスをコンテナに割り当てることができます(たとえば、複数のイーサネットデバイスがある場合)。
    • 既存のインターフェース(つまり、VLANインターフェース)に関連付けられた仮想ネットワークインターフェースを作成して、コンテナーに割り当てることができます。
    • ホストとコンテナの間に仮想イーサネットリンクを作成できます。
後者の場合、コンテナのネットワークは、(外部ネットワークや他のコンテナから) 完全に分離されており、ホストとコンテナ間のネットワークを構成するのは管理者の責任です。これには通常、複数の(物理または仮想)インターフェイスを接続するための ネットワークブリッジ の作成、または複数のインターフェイス間の ネットワークアドレス変換 の設定が含まれます。

ホストネットワーキングモードは、コンテナに割り当てられたインターフェースを構成するネットワーキングソフトウェアを実行しない アプリケーションコンテナ に適しています。ホストネットワーキングは、シェルから systemd-nspawn を実行するときのデフォルトのモードです。

一方、プライベート・ネットワーキング・モードは、ホスト・システムから隔離されている必要がある システムコンテナ に適しています。仮想イーサネットリンクの作成は、複雑な仮想ネットワークの作成を可能にする非常に柔軟なツールです。これは machinectlsystemd-nspawn@.service によって起動されたコンテナのデフォルトモードです。

次のサブセクションでは、一般的なシナリオについて説明します。使用可能な systemd-nspawn のオプションの詳細については、systemd-nspawn(1) § Networking Options を参照してください。

ホストネットワークを使う

プライベートネットワークを無効にし、machinectl で開始されたコンテナで使用される仮想イーサネットリンクを作成するには、次のオプションを指定して、.nspawn ファイルを追加します:

/etc/systemd/nspawn/container-name.nspawn
[Network]
VirtualEthernet=no

これにより、systemd-nspawn@.service-n/--network-veth オプションが上書きされ、新しく開始されたコンテナはホストネットワークモードを使用します。

仮想イーサネットリンクを使用する

コンテナが、-n/--network-veth オプションで起動された場合、systemd-nspawn はホストとコンテナの間に仮想イーサネットリンクを作成します。リンクのホスト側は、ve-container-name という名前のネットワークインターフェイスとして利用可能になります。リンクのコンテナ側は、hosts0 という名前になります。このオプションは、--private-network を意味することに注意してください。

ノート:
  • コンテナ名が長すぎる場合、インターフェイス名は、15文字制限 に収まるように短縮されます(例: ve-long-container-name の代わりに ve-long-conKQGh)。フルネームはインターフェイスの altname プロパティとして設定され(ip-link(8)を参照)、インターフェイスの参照に使用できます。
  • ip link でインターフェイスを調べる場合、インターフェイス名は、ve-container-name@if2host0@if9 のようにサフィックスを付けて表示されます。@ifN は実際にはインターフェイス名の一部ではありません。その代わりに、ip link はこの情報を追加して、仮想イーサネットケーブルが相手側のどの slot に接続しているかを示します
例えば、ve-foo@if2 とし表示されているホスト仮想イーサネットインターフェイスはコンテナ foo に接続され、コンテナ内で ip link を実行しているときに、index 2 で示されている 2 番目のネットワークインタフェースに接続されています。同様に、コンテナ内の host0@if9 という名前のインターフェイスは、ホスト上の 9 番目のネットワークインターフェイス接続されています。

コンテナを起動する際には、ホストとコンテナの両方のインターフェイスにIPアドレスを割り当てなければなりません。ホストとコンテナの両方で systemd-networkd を使用している場合、初期状態で実行されます:

  • ホスト上の /usr/lib/systemd/network/80-container-ve.network ファイルは ve-container-name インターフェイスと一致し、DHCP サーバーを起動します。DHCP サーバーは、IP アドレスをホストインターフェイスとコンテナーに割り当てます。
  • /usr/lib/systemd/network/80-container-host0.network コンテナ内のファイルは host0 インターフェイスと一致し、ホストから IP アドレスを受信する DHCP クライアントを起動します。

systemd-networkd を使用しない場合は、静的IPアドレスを設定するか、ホストインターフェイスで、DHCP サーバを起動し、コンテナで DHCP クライアントを起動できます。詳細については、ネットワーク設定 を参照してください。

コンテナに外部ネットワークへのアクセスを許可するには、インターネット共有#NAT の有効化 の説明に従って NAT を設定します。systemd-networkd を使用する場合、これは、/usr/lib/systemd/network/80-container-ve.network ファイルの IPMasquerade=yes オプションを介して(部分的に)自動的に行われます。ただし、これは次のような iptables ルールのみを発行します。

-t nat -A POSTROUTING -s 192.168.163.192/28 -j MASQUERADE

filter テーブルは、インターネット共有#NAT の有効化のように手動で設定する必要があります。ワイルドカードを使用して、ve- で始まるすべてのインターフェイスに一致させることができます:

# iptables -A FORWARD -i ve-+ -o internet0 -j ACCEPT
ノート: systemd-networkd は、libiptc ライブラリを使用して、iptables と対話します。 nftables を使用する場合は、iptables-nft 変換レイヤーをインストールします。systemd issue 13307 も参照してください。

さらに、DHCP サーバー(systemd-networkd によって運用される)への着信接続用に ve-+ インターフェースの UDP ポート 67 を開く必要があります:

# iptables -A INPUT -i ve-+ -p udp -m udp --dport 67 -j ACCEPT

ネットワークブリッジを使用する

ホストシステムにネットワークブリッジを構成している場合は、コンテナの仮想イーサネットリンクを作成し、そのホスト側をネットワークブリッジに追加できます。 これは、--network-bridge=bridge-name オプションを使用して実行されます。--network-bridge--network-veth を意味することに注意してください。つまり、仮想イーサネットリンクは自動的に作成されます。 ただし、リンクのホスト側は ve- ではなく vb- プリフィックスを使用するため、DHCP サーバーと IP マスカレードを起動するための systemd-networkd オプションは適用されません。

ブリッジの管理は管理者に任されています。例えば、ブリッジは物理インターフェースと仮想インターフェースを接続したり、複数のコンテナの仮想インターフェースのみを接続したりすることができます。systemd-networkd を使用した設定例については、systemd-networkd#Network bridge with DHCPsystemd-networkd#Network bridge with static IP addresses を参照してください。

また、--network-zone=zone-name オプションは --network-bridge と似ていますが、ネットワークブリッジは systemd-nspawnsystemd-networkd によって自動的に管理されます。vz-zone-name という名前のブリッジインターフェースは、--network-zone=zone-name を設定した最初のコンテナが起動したときに自動的に作成され、--network-zone=zone-name を設定した最後のコンテナが終了したときに自動的に削除されます。したがって、このオプションを使用すると、複数の関連するコンテナを共通の仮想ネットワーク上に簡単に配置することができます。vz-* インターフェースは、/usr/lib/systemd/network/80-container-vz.network ファイルのオプションを使って、ve-* インターフェースと同じように systemd-networkd によって管理されることに注意してください。

「macvlan」または「ipvlan」インターフェースを使用する

仮想イーサネットリンク(ホスト側がブリッジに追加される場合とされない場合があります)を作成する代わりに、既存の物理インターフェイス(つまり、VLAN インターフェイス)上に仮想インターフェイスを作成し、それをコンテナに追加できます。仮想インターフェイスは、基盤となるホストインターフェイスとブリッジされるため、コンテナは外部ネットワークに公開されます。これにより、ホストが接続されているのと同じ LAN から DHCP を介して個別の IP アドレスを取得できます。

systemd-nspawn には2つのオプションがあります:

  • --network-macvlan=interface – 仮想インターフェイスは、基盤となる物理インターフェイスとは異なるMACアドレスを持ち、mv-interface という名前が付けられます。
  • --network-ipvlan=interface – 仮想インターフェイスは、基礎となる物理インターフェイスと同じMACアドレスを持ち、iv-interface と名付けられます。

どちらのオプションも --private-network を意味します。

ノート: ホストがコンテナと通信できるようにするために、ホストに macvlan または ipvlan インターフェースを作成し、それをコンテナが使用している同じ物理インターフェースに接続し、その上でネットワーク接続を設定してください。仮想インターフェース名が systemd-nspawn によって作成された仮想インターフェースと衝突しないことを確認してください。systemd-networkd を使用した例については、systemd-networkd#MACVLAN bridge を参照してください。

既存のインターフェイスを使用する

ホストシステムに複数の物理ネットワークインターフェイスがある場合は、 --network-interface=interface を使用してコンテナにインターフェイスを割り当てることができます(コンテナが起動している間はホストからは利用できないようにします)。--network-interface--private-network を意味することに注意してください。

ノート: systemd-nspawn コンテナにワイヤレスネットワークインターフェイスを渡すことは現在サポートされていません。[4]

ポートマッピング

プライベートネットワークが有効になっている場合、ホストの個々のポートは、-p/--port オプションを使用するか、または .nspawn ファイルの Port 設定を使用してコンテナのポートにマッピングすることができます。たとえば、ホストの TCP ポート 8000 をコンテナの TCP ポート 80 にマッピングするには:

/etc/systemd/nspawn/container-name.nspawn
[Network]
Port=tcp:8000:80

これは、nat テーブルに iptables ルールを発行することで機能しますが、filter テーブルの FORWARD チェインは、#仮想イーサネットリンクを使用するに示されているように手動で設定する必要があります。さらに、シンプルなステートフルファイアウォールに従った場合、ホストの wan_interface で転送されたポートへの新しい接続を許可するには、次のコマンドを実行してください:

# iptables -A FORWARD -i wan_interface -o ve-+ -p tcp --syn --dport 8000 -m conntrack --ctstate NEW -j ACCEPT
ノート:
  • systemd-nspawn は、ポートをマッピングする際に loopback インターフェイスを明示的に除外します。したがって、上記の例では、localhost:8000 はホストに接続し、コンテナには接続しません。他のインターフェイスへの接続のみがポートマッピングの対象となります。詳細は、[5] を参照してください。
  • ポートマッピングは IPv4 接続に対してのみ機能します。 [6]

ドメイン名前解決

コンテナ内の ドメイン名前解決systemd-nspawn--resolv-conf オプションか、.nspawn ファイルの ResolvConf= オプションで設定できます。systemd-nspawn(1) § 統合オプション に多くの値が記述されています。

デフォルト値は auto で以下の事を意味します:

  • --private-network が有効になっている場合、/etc/resolv.conf はコンテナ内のまま残ります。
  • あるいは、ホストで systemd-resolved が実行されている場合、そのスタブ resolv.conf ファイルがコンテナにコピーまたはバインドマウントされます。
  • それ以外の場合、/etc/resolv.conf ファイルはホストからコンテナにコピーされるか、バインドマウントされます。

最後の2つのケースでは、コンテナルートが書き込み可能な場合はファイルがコピーされ、読み取り専用の場合はバインドマウントされます。

ホスト上で systemd-resolved が実行される 2 番目のケースでは、コンテナがホストからのスタブ symlink ファイル /etc/resolv.conf を使用できるように systemd-nspawn がコンテナ内でも実行されることを期待します。そうでない場合、デフォルト値の auto はもはや機能しませんので、replace-* オプションのいずれかを使ってシンボリックリンクを置き換える必要があります。

ヒントとテクニック

シェル/init 以外のコマンドを実行する

systemd-nspawn(1) § Execution Options より。

" [オプション] --as-pid2 [呼び出し] シェルまたは指定されたプログラムを、PID 1(init)ではなくプロセス ID(PID)2 として使用します。[...] PID 1として正しく実行されるように変更されていない限り、コンテナ内で任意のコマンドを呼び出すにはこのモードを使用することが推奨されます。言い換えれば、このスイッチは、コマンドが init やシェルの実装を参照している場合を除き、ほとんどすべてのコマンドに使用すべきです。[...] このオプションは --boot と組み合わせることはできません。

非特権コンテナ

systemd-nspawn は非特権コンテナをサポートしますが、コンテナは root として起動する必要があります。

ノート: この機能には user_namespaces(7) が必要です。詳細については、Linux Containers#非特権コンテナのサポートを有効化 (任意) を参照してください。

これを行う最も簡単な方法は、-U オプションを使用して systemd-nspawn が自動的に未使用の UIDs/GIDs の範囲を選択させることです:

# systemd-nspawn -bUD ~/MyContainer

カーネルがユーザー名前空間をサポートしている場合、-U オプションは --private-users=pick --private-users-chown と同等です。これはコンテナの開始時にコンテナ内のファイルとディレクトリが選択された範囲のプライベート UIDs/GIDs に変更される事を意味します。詳細は、 systemd-nspawn(1) § User Namespacing Options を参照してください。

ノート: コンテナの UID/GID の範囲を手動で指定することもできますが、これが役立つことはほとんどありません。

プライベート UID/GID の範囲を持つコンテナを起動したら、パーミッションエラーを避けるために、そのコンテナを使い続ける必要があります。あるいは、--private-users-chown (または -U) のファイルシステムへの影響を元に戻すには、0で始まるIDの範囲を指定します:

# systemd-nspawn -D ~/MyContainer --private-users=0 --private-users-chown

X 環境

新しいコンテナで X アプリケーションを動かす必要がある場合は Xhost を見て下さい。

外部の X サーバーにコンテナのセッションを接続するには DISPLAY 環境変数を設定する必要があります。

X は必要なファイルを /tmp ディレクトリに保存します。コンテナから全てを表示させるには、/tmp ディレクトリのファイルにアクセスできるようにしなくてはなりません。コンテナを起動するときに --bind=/tmp/.X11-unix:/tmp/.X11-unix オプションを追加してください。

ノート: systemd バージョン 235 には バグ が存在し、/tmp/.X11-unix がファイルシステムから消失することがあります。問題を回避するには /tmp/.X11-unix を読み取り専用でバインドしてください: --bind-ro=/tmp/.X11-unix/X0/run/user/1000 もバインドしている場合は明示的に /run/user/1000/bus を読み取り専用でバインドすることで dbus ソケットが削除されないように保護することができます。

xhost の回避

xhost は、Xサーバに対してかなり粗いアクセス権しか与えません。​$XAUTHORITY ファイルを使用すると、より詳細なアクセス制御が可能になります。​残念ながら、コンテナ内の$XAUTHORITY ファイルにアクセスできるようにしただけではうまくいきません。$XAUTHORITY ファイルはホスト固有のものですが、コンテナは別のホストです。​stackoverflowを参考にした以下のトリックを使えば、Xサーバがコンテナ内で実行されているXアプリケーションから、$XAUTHORITY ファイルを受け入れるようにすることができます:

$ XAUTH=/tmp/container_xauth
$ xauth nextract - "$DISPLAY" | sed -e 's/^..../ffff/' | xauth -f "$XAUTH" nmerge -
# systemd-nspawn -D myContainer --bind=/tmp/.X11-unix --bind="$XAUTH" -E DISPLAY="$DISPLAY" -E XAUTHORITY="$XAUTH" --as-pid2 /usr/bin/xeyes

上記の2行目では、接続ファミリーを ""FamilyWild""(値65535) に設定しているため、エントリはすべての表示に一致します。​詳細はXsecurity(7) を参照。

X nesting/Xephyr を使用

X アプリケーションを実行し、共有 X デスクトップのリスクを回避するもう1つの簡単な方法は、X nesting を使用することです。 ここでの利点は、コンテナ内アプリケーションと非コンテナアプリケーションの間の相互作用を完全に回避し、異なる デスクトップ環境 または ウィンドウマネージャ を実行できることです。 欠点はパフォーマンスの低下と Xephyr を使用した場合のハードウェアアクセラレーションの欠如です。

Xephyr をコンテナの外で起動するには以下の方法があります。

# Xephyr :1 -resizeable

その後、以下のオプションでコンテナを起動します。

--setenv=DISPLAY=:1 --bind-ro=/tmp/.X11-unix/X1

他のバインドは必要ありません。

状況によっては、コンテナ内で DISPLAY=:1 を手動で設定する必要があるかもしれません(主に -b と併用する場合)

Firefox を起動する

PID 1 として実行するには

 # systemd-nspawn --setenv=DISPLAY=:0 \
              --setenv=XAUTHORITY=~/.Xauthority \
              --bind-ro=$HOME/.Xauthority:/root/.Xauthority \
              --bind=/tmp/.X11-unix \
              -D ~/containers/firefox \
              firefox
ノート: そのため、firefox は root ユーザーとして実行されますが、#非特権コンテナを使用していない場合には独自のリスクが伴います。その場合、まずコンテナ内でユーザーを追加し、その後 systemd-nspawn の呼び出しで --user <username> オプションを追加することができます。

あるいは、コンテナを起動して、例えば、systemd-networkd に仮想ネットワークインターフェイスを設定することもできます。

# systemd-nspawn --bind-ro=$HOME/.Xauthority:/root/.Xauthority \
              --bind=/tmp/.X11-unix \
              -D ~/containers/firefox \
              --network-veth -b

コンテナが起動したら、次のようにXorgバイナリを実行します:

# systemd-run -M firefox --setenv=DISPLAY=:0 firefox

3D グラフィックスアクセラレーション

3Dグラフィックスアクセラレーションを有効にするためには、.nspawn ファイルに以下の行を追加して、マウント /dev/dri をコンテナにバインドする必要があるかもしれません。

Bind=/dev/dri

この方法は patrickskiba.com から引用しました。これにより、以下の問題が解決されます。

libGL error: MESA-LOADER: failed to retrieve device information
libGL error: Version 4 or later of flush extension not found
libGL error: failed to load driver: i915

glxinfo または glxgears を実行して、有効になっているか確認してください。

NVIDIA GPUs

コンテナ上にホストと同じバージョンの NVIDIA ドライバをインストールできない場合、ドライバライブラリファイルもバインドする必要がある場合があります。ホスト上で pacman -Ql nvidia-utils を実行すると、含まれている全てのファイルを確認することができます。全てをコピーする必要はありません。以下の systemd override ファイルは、コンテナを machinectl start container-name で実行する際に必要なファイルを全てバインドします。

この記事またはセクションの正確性には問題があります。
理由: No reason to bind from /usr/lib/ into /usr/lib/x86_64-linux-gnu/. (議論: トーク:Systemd-nspawn#)
/etc/systemd/system/systemd-nspawn@.service.d/nvidia-gpu.conf
[Service]
ExecStart=
ExecStart=systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --machine=%i \
--bind=/dev/dri \
--bind=/dev/shm \
--bind=/dev/nvidia0 \
--bind=/dev/nvidiactl \
--bind=/dev/nvidia-modeset \
--bind=/usr/bin/nvidia-bug-report.sh:/usr/bin/nvidia-bug-report.sh \
--bind=/usr/bin/nvidia-cuda-mps-control:/usr/bin/nvidia-cuda-mps-control \
--bind=/usr/bin/nvidia-cuda-mps-server:/usr/bin/nvidia-cuda-mps-server \
--bind=/usr/bin/nvidia-debugdump:/usr/bin/nvidia-debugdump \
--bind=/usr/bin/nvidia-modprobe:/usr/bin/nvidia-modprobe \
--bind=/usr/bin/nvidia-ngx-updater:/usr/bin/nvidia-ngx-updater \
--bind=/usr/bin/nvidia-persistenced:/usr/bin/nvidia-persistenced \
--bind=/usr/bin/nvidia-powerd:/usr/bin/nvidia-powerd \
--bind=/usr/bin/nvidia-sleep.sh:/usr/bin/nvidia-sleep.sh \
--bind=/usr/bin/nvidia-smi:/usr/bin/nvidia-smi \
--bind=/usr/bin/nvidia-xconfig:/usr/bin/nvidia-xconfig \
--bind=/usr/lib/gbm/nvidia-drm_gbm.so:/usr/lib/x86_64-linux-gnu/gbm/nvidia-drm_gbm.so \
--bind=/usr/lib/libEGL_nvidia.so:/usr/lib/x86_64-linux-gnu/libEGL_nvidia.so \
--bind=/usr/lib/libGLESv1_CM_nvidia.so:/usr/lib/x86_64-linux-gnu/libGLESv1_CM_nvidia.so \
--bind=/usr/lib/libGLESv2_nvidia.so:/usr/lib/x86_64-linux-gnu/libGLESv2_nvidia.so \
--bind=/usr/lib/libGLX_nvidia.so:/usr/lib/x86_64-linux-gnu/libGLX_nvidia.so \
--bind=/usr/lib/libcuda.so:/usr/lib/x86_64-linux-gnu/libcuda.so \
--bind=/usr/lib/libnvcuvid.so:/usr/lib/x86_64-linux-gnu/libnvcuvid.so \
--bind=/usr/lib/libnvidia-allocator.so:/usr/lib/x86_64-linux-gnu/libnvidia-allocator.so \
--bind=/usr/lib/libnvidia-cfg.so:/usr/lib/x86_64-linux-gnu/libnvidia-cfg.so \
--bind=/usr/lib/libnvidia-egl-gbm.so:/usr/lib/x86_64-linux-gnu/libnvidia-egl-gbm.so \
--bind=/usr/lib/libnvidia-eglcore.so:/usr/lib/x86_64-linux-gnu/libnvidia-eglcore.so \
--bind=/usr/lib/libnvidia-encode.so:/usr/lib/x86_64-linux-gnu/libnvidia-encode.so \
--bind=/usr/lib/libnvidia-fbc.so:/usr/lib/x86_64-linux-gnu/libnvidia-fbc.so \
--bind=/usr/lib/libnvidia-glcore.so:/usr/lib/x86_64-linux-gnu/libnvidia-glcore.so \
--bind=/usr/lib/libnvidia-glsi.so:/usr/lib/x86_64-linux-gnu/libnvidia-glsi.so \
--bind=/usr/lib/libnvidia-glvkspirv.so:/usr/lib/x86_64-linux-gnu/libnvidia-glvkspirv.so \
--bind=/usr/lib/libnvidia-ml.so:/usr/lib/x86_64-linux-gnu/libnvidia-ml.so \
--bind=/usr/lib/libnvidia-ngx.so:/usr/lib/x86_64-linux-gnu/libnvidia-ngx.so \
--bind=/usr/lib/libnvidia-opticalflow.so:/usr/lib/x86_64-linux-gnu/libnvidia-opticalflow.so \
--bind=/usr/lib/libnvidia-ptxjitcompiler.so:/usr/lib/x86_64-linux-gnu/libnvidia-ptxjitcompiler.so \
--bind=/usr/lib/libnvidia-rtcore.so:/usr/lib/x86_64-linux-gnu/libnvidia-rtcore.so \
--bind=/usr/lib/libnvidia-tls.so:/usr/lib/x86_64-linux-gnu/libnvidia-tls.so \
--bind=/usr/lib/libnvidia-vulkan-producer.so:/usr/lib/x86_64-linux-gnu/libnvidia-vulkan-producer.so \
--bind=/usr/lib/libnvoptix.so:/usr/lib/x86_64-linux-gnu/libnvoptix.so \
--bind=/usr/lib/modprobe.d/nvidia-utils.conf:/usr/lib/x86_64-linux-gnu/modprobe.d/nvidia-utils.conf \
--bind=/usr/lib/nvidia/wine/_nvngx.dll:/usr/lib/x86_64-linux-gnu/nvidia/wine/_nvngx.dll \
--bind=/usr/lib/nvidia/wine/nvngx.dll:/usr/lib/x86_64-linux-gnu/nvidia/wine/nvngx.dll \
--bind=/usr/lib/nvidia/xorg/libglxserver_nvidia.so:/usr/lib/x86_64-linux-gnu/nvidia/xorg/libglxserver_nvidia.so \
--bind=/usr/lib/vdpau/libvdpau_nvidia.so:/usr/lib/x86_64-linux-gnu/vdpau/libvdpau_nvidia.so \
--bind=/usr/lib/xorg/modules/drivers/nvidia_drv.so:/usr/lib/x86_64-linux-gnu/xorg/modules/drivers/nvidia_drv.so \
--bind=/usr/share/X11/xorg.conf.d/10-nvidia-drm-outputclass.conf:/usr/share/X11/xorg.conf.d/10-nvidia-drm-outputclass.conf \
--bind=/usr/share/dbus-1/system.d/nvidia-dbus.conf:/usr/share/dbus-1/system.d/nvidia-dbus.conf \
--bind=/usr/share/egl/egl_external_platform.d/15_nvidia_gbm.json:/usr/share/egl/egl_external_platform.d/15_nvidia_gbm.json \
--bind=/usr/share/glvnd/egl_vendor.d/10_nvidia.json:/usr/share/glvnd/egl_vendor.d/10_nvidia.json \
--bind=/usr/share/licenses/nvidia-utils/LICENSE:/usr/share/licenses/nvidia-utils/LICENSE \
--bind=/usr/share/vulkan/icd.d/nvidia_icd.json:/usr/share/vulkan/icd.d/nvidia_icd.json \
--bind=/usr/share/vulkan/implicit_layer.d/nvidia_layers.json:/usr/share/vulkan/implicit_layer.d/nvidia_layers.json \
DeviceAllow=/dev/dri rw
DeviceAllow=/dev/shm rw
DeviceAllow=/dev/nvidia0 rw
DeviceAllow=/dev/nvidiactl rw
DeviceAllow=/dev/nvidia-modeset rw
ノート: ホスト上で NVIDIA ドライバをアップグレードするたびに、コンテナを再起動する必要があり、ライブラリを更新するためにコンテナ内で ldconfig を実行する必要がある場合があります。

ホストのファイルシステムにアクセス

例えばホストとコンテナの両方が Arch Linux で、pacman のキャッシュを共有するには:

# systemd-nspawn --bind=/var/cache/pacman/pkg

詳しくは systemd-nspawn(1)--bind--bind-ro を参照してください。

ファイルを使ってコンテナごとにバインドを設定することもできます:

/etc/systemd/nspawn/my-container.nspawn
[Files]
Bind=/var/cache/pacman/pkg

#コンテナごとに設定を指定するを参照。

systemd を使っていない環境で動作させる

Init#systemd-nspawn を見て下さい。

Btrfs のサブボリュームをコンテナのルートとして使う

Btrfs サブボリュームをコンテナのルートのテンプレートとして使うには、--template フラグを使用します。サブボリュームのスナップショットを使ってコンテナのルートディレクトリが生成されます。

ノート: 指定されたテンプレートのパスがサブボリュームのルートでなかった場合、ツリー全体がコピーされます。その場合、非常に時間がかかります。

例えば、/.snapshots/403/snapshot に存在するスナップショットを使うには:

# systemd-nspawn --template=/.snapshots/403/snapshots -b -D my-container

my-container は作成するコンテナのディレクトリの名前に置き換えてください。電源を切っても、新しく作成されたサブボリュームは消えません。

コンテナの一時的な Btrfs スナップショットを使う

--ephemeral-x フラグを使ってコンテナの一時的な btrfs スナップショットを作成してコンテナのルートとして利用できます。コンテナの実行中に変更が加えられても保存されません。例:

# systemd-nspawn -D my-container -xb

my-container はシステムに存在する既存のコンテナのディレクトリに置き換えてください。例えば / が btrfs のサブボリュームだった場合、以下のコマンドで実行中のホスト環境の一時的なコンテナを作成することができます:

# systemd-nspawn -D / -xb 

コンテナの電源を切ると、作成された btrfs サブボリュームはすぐに削除されます。

system-nspawn で docker を実行

Docker 20.10 以降、cgroups v2 を有効にした非特権 systemd-nspawn コンテナ内で Docker コンテナを実行することが可能になりました(Arch Linux ではデフォルト)。これにより、cgroups やユーザー名前空間を無効にすることなくセキュリティ対策を損なうことなく行えます。これを行うには、/etc/systemd/nspawn/myContainer.nspawn を編集し(存在しない場合は作成)、以下の設定を追加します。

/etc/systemd/nspawn/myContainer.nspawn
[Exec]
SystemCallFilter=add_key keyctl bpf

その後、コンテナ内で Docker はそのまま機能するはずです。

ノート: 上記の設定では、コンテナに add_keykeyctl、および bpf といった名前空間化されていないシステムコールを公開しています。これはユーザー名前空間を完全に無効にする以前の方法と比較するとセキュリティリスクは大幅に低いものの、依然としてセキュリティリスクになり得ます。

overlayfs はユーザー名前空間と互換性がなく、デフォルトでは systemd-nspawn 内で使用できません。そのため、Docker は非効率な vfs をストレージドライバーとして使用することになります。これはコンテナを開始するたびにイメージのコピーを作成します。これを回避するためには、ストレージドライバーとして fuse-overlayfs を使用する必要があります。これを行うためには、まずコンテナに fuse を公開する必要があります:

/etc/systemd/nspawn/myContainer.nspawn
[Files]
Bind=/dev/fuse

そして、コンテナがデバイスノードを読み書きできるように設定します:

# systemctl set-property systemd-nspawn@myContainer DeviceAllow='/dev/fuse rwm'

最後に、コンテナ内に fuse-overlayfs パッケージをインストールします。すべての設定を有効にするには、コンテナを再起動する必要があります。

トラブルシューティング

root ログインが失敗する

(machinectl login <name> を使用して) ログインしようとしたときに以下のエラーが表示される場合:

arch-nspawn login: root
Login incorrect

そして、コンテナの journal が以下のように表示する場合:

pam_securetty(login:auth): access denied: tty 'pts/0' is not secure !
この記事またはセクションの正確性には問題があります。
理由: Files in /usr/lib should not be edited by users, the change in /usr/lib/tmpfiles.d/arch.conf will be lost when filesystem is upgraded. (議論: トーク:Systemd-nspawn#)

コンテナファイルシステム上の、/etc/securetty[7]/usr/share/factory/etc/securetty を削除するか、コンテナファイイルシステム上の /etc/securetty に必要な pty 端末デバイス(pts/0 のような)を追加します。変更は、次の起動時に上書きされるため、/etc/securetty のエントリを削除する必要があります。FS#63236 を参照。削除を選択した場合は、/etc/pacman.confNoExtract にそれらを追加し、再インストールされないようにします。FS#45903 を参照してください。

execv(...) failed: Permission denied

systemd-nspawn -bD /path/to/container によってコンテナを起動 (またはコンテナ内で何かを実行) しようとすると、以下のようなエラーが発生します:

execv(/usr/lib/systemd/systemd, /lib/systemd/systemd, /sbin/init) failed: Permission denied

問題のファイル (例えば /lib/systemd/systemd) のパーミッションが正しくても、コンテナが保存されているファイルシステムを非rootユーザーとしてマウントした結果である可能性があります。例えば、fstabnoauto,user,... というオプションを指定して手動でディスクをマウントした場合、systemd-nspawn は rootが所有するファイルであっても実行は許可しません。

TERM の端末タイプが間違っている (色が壊れている)

machinectl login でコンテナにログインすると、コンテナ内の端末の色とキーストロークが壊れることがあります。これは、TERM 環境変数の端末タイプが正しくないことが原因である可能性があります。環境変数はホストのシェルから継承されませんが、明示的に設定されていない限り、systemd (vt220) で固定されたデフォルトに戻ります。設定するには、コンテナ内の container-getty@.service サービス用のオーバーレイを作成して、machinectl login の login getty を起動し、ログインしているホスト端末と一致する値を TERM に設定してください。

/etc/systemd/system/container-getty@.service.d/term.conf
[Service]
Environment=TERM=xterm-256color

もしくは、machinectl shell を使用してください。端末から TERM 環境変数を適切に継承します。

コンテナ内へのNFS共有のマウント

現時点(2019年6月)では利用できません。

参照

翻訳ステータス: このページは en:Systemd-nspawn の翻訳バージョンです。最後の翻訳日は 2024/4/18 です。もし英語版に 変更 があれば、翻訳の同期を手伝うことができます。