「Systemd-nspawn」の版間の差分
Kusanaginoturugi (トーク | 投稿記録) |
Kusanaginoturugi (トーク | 投稿記録) (→ヒントとテクニック: add == Configuration ==) |
||
169行目: | 169行目: | ||
* コンテナの起動時間を表示: {{bc|$ systemd-analyze -M MyContainer}} |
* コンテナの起動時間を表示: {{bc|$ systemd-analyze -M MyContainer}} |
||
* リソース利用状況を表示: {{bc|$ systemd-cgtop}} |
* リソース利用状況を表示: {{bc|$ systemd-cgtop}} |
||
+ | |||
+ | == Configuration == |
||
+ | |||
+ | === Per-container settings === |
||
+ | |||
+ | To specify per-container settings and not global overrides, the ''.nspawn'' files can be used. See {{man|5|systemd.nspawn}} for details. |
||
+ | |||
+ | {{Note| |
||
+ | * ''.nspawn'' files may be removed unexpectedly from {{ic|/etc/systemd/nspawn/}} when you run {{ic|machinectl remove}}. [https://github.com/systemd/systemd/issues/15900] |
||
+ | * The interaction of network options specified in the ''.nspawn'' file and on the command line does not work correctly when there is {{ic|1=--settings=override}} (which is specified in the {{ic|systemd-nspawn@.service}} file). [https://github.com/systemd/systemd/issues/12313#issuecomment-681116926] As a workaround, you need to include the option {{ic|1=VirtualEthernet=on}}, even though the service specifies {{ic|1=--network-veth}}. |
||
+ | }} |
||
+ | |||
+ | === Enable container to start at boot === |
||
+ | |||
+ | When using a container frequently, you may want to start it at boot. |
||
+ | |||
+ | First make sure that the {{ic|machines.target}} is [[enabled]]. |
||
+ | |||
+ | Containers discoverable by [[#machinectl|machinectl]] can be enabled or disabled: |
||
+ | |||
+ | $ machinectl enable ''container-name'' |
||
+ | |||
+ | {{Note| |
||
+ | * This has the effect of enabling the {{ic|systemd-nspawn@''container-name''.service}} systemd unit. |
||
+ | * As mentioned in [[#Default systemd-nspawn options]], containers started by ''machinectl'' get a virtual Ethernet interface. To disable private networking, see [[#Use host networking]]. |
||
+ | }} |
||
+ | |||
+ | === Resource control === |
||
+ | |||
+ | You can take advantage of control groups to implement limits and resource management of your containers with {{ic|systemctl set-property}}, see {{man|5|systemd.resource-control}}. For example, you may want to limit the memory amount or CPU usage. To limit the memory consumption of your container to 2 GiB: |
||
+ | |||
+ | # systemctl set-property systemd-nspawn@''container-name''.service MemoryMax=2G |
||
+ | |||
+ | Or to limit the CPU time usage to roughly the equivalent of 2 cores: |
||
+ | |||
+ | # systemctl set-property systemd-nspawn@''container-name''.service CPUQuota=200% |
||
+ | |||
+ | This will create permanent files in {{ic|/etc/systemd/system.control/systemd-nspawn@''container-name''.service.d/}}. |
||
+ | |||
+ | According to the documentation, {{ic|MemoryHigh}} is the preferred method to keep in check memory consumption, but it will not be hard-limited as is the case with {{ic|MemoryMax}}. You can use both options leaving {{ic|MemoryMax}} as the last line of defense. Also take in consideration that you will not limit the number of CPUs the container can see, but you will achieve similar results by limiting how much time the container will get at maximum, relative to the total CPU time. |
||
+ | |||
+ | {{Tip|If you want these changes to be only temporary, you can pass the option {{ic|--runtime}}. You can check their results with ''systemd-cgtop''.}} |
||
+ | |||
+ | === Networking === |
||
+ | |||
+ | ''systemd-nspawn'' containers can use either ''host networking'' or ''private networking'': |
||
+ | |||
+ | * In the host networking mode, the container has full access to the host network. This means that the container will be able to access all network services on the host and packets coming from the container will appear to the outside network as coming from the host (i.e. sharing the same IP address). |
||
+ | * In the private networking mode, the container is disconnected from the host's network. This makes all network interfaces unavailable to the container, with the exception of the loopback device and those explicitly assigned to the container. There is a number of different ways to set up network interfaces for the container: |
||
+ | ** an existing interface can be assigned to the container (e.g. if you have multiple Ethernet devices), |
||
+ | ** a virtual network interface associated with an existing interface (i.e. [[VLAN]] interface) can be created and assigned to the container, |
||
+ | ** a virtual Ethernet link between the host and the container can be created. |
||
+ | : In the latter case the container's network is fully isolated (from the outside network as well as other containers) and it is up to the administrator to configure networking between the host and the containers. This typically involves creating a [[network bridge]] to connect multiple (physical or virtual) interfaces or setting up a [[Wikipedia:Network Address Translation|Network Address Translation]] between multiple interfaces. |
||
+ | |||
+ | The host networking mode is suitable for ''application containers'' which do not run any networking software that would configure the interface assigned to the container. Host networking is the default mode when you run ''systemd-nspawn'' from the shell. |
||
+ | |||
+ | On the other hand, the private networking mode is suitable for ''system containers'' that should be isolated from the host system. The creation of virtual Ethernet links is a very flexible tool allowing to create complex virtual networks. This is the default mode for containers started by ''machinectl'' or {{ic|systemd-nspawn@.service}}. |
||
+ | |||
+ | The following subsections describe common scenarios. See {{man|1|systemd-nspawn|Networking Options}} for details about the available ''systemd-nspawn'' options. |
||
+ | |||
+ | ==== Use host networking ==== |
||
+ | |||
+ | To disable private networking and the creation of a virtual Ethernet link used by containers started with ''machinectl'', add a ''.nspawn'' file with the following option: |
||
+ | |||
+ | {{hc|/etc/systemd/nspawn/''container-name''.nspawn|2= |
||
+ | [Network] |
||
+ | VirtualEthernet=no |
||
+ | }} |
||
+ | |||
+ | This will override the {{ic|-n}}/{{ic|--network-veth}} option used in {{ic|systemd-nspawn@.service}} and the newly started containers will use the host networking mode. |
||
+ | |||
+ | ==== Use a virtual Ethernet link ==== |
||
+ | |||
+ | If a container is started with the {{ic|-n}}/{{ic|--network-veth}} option, ''systemd-nspawn'' will create a virtual Ethernet link between the host and the container. The host side of the link will be available as a network interface named {{ic|ve-''container-name''}}. The container side of the link will be named {{ic|host0}}. Note that this option implies {{ic|--private-network}}. |
||
+ | |||
+ | {{Note| |
||
+ | * If the container name is too long, the interface name will be shortened (e.g. {{ic|ve-long-conKQGh}} instead of {{ic|ve-long-container-name}}) to fit into the [https://stackoverflow.com/a/29398765 15-characters limit]. The full name will be set as the {{ic|altname}} property of the interface (see {{man|8|ip-link}}) and can be still used to reference the interface. |
||
+ | * When examining the interfaces with {{ic|ip link}}, interface names will be shown with a suffix, such as {{ic|ve-''container-name''@if2}} and {{ic|host0@if9}}. The {{ic|@if''N''}} is not actually part of the interface name; instead, {{ic|ip link}} appends this information to indicate which "slot" the virtual Ethernet cable connects to on the other end. |
||
+ | : For example, a host virtual Ethernet interface shown as {{ic|ve-''foo''@if2}} is connected to the container {{ic|''foo''}}, and inside the container to the second network interface – the one shown with index 2 when running {{ic|ip link}} inside the container. Similarly, the interface named {{ic|host0@if9}} in the container is connected to the 9th network interface on the host. |
||
+ | }} |
||
+ | |||
+ | When you start the container, an IP address has to be assigned to both interfaces (on the host and in the container). If you use [[systemd-networkd]] on the host as well as in the container, this is done out-of-the-box: |
||
+ | |||
+ | * the {{ic|/usr/lib/systemd/network/80-container-ve.network}} file on the host matches the {{ic|ve-''container-name''}} interface and starts a DHCP server, which assigns IP addresses to the host interface as well as the container, |
||
+ | * the {{ic|/usr/lib/systemd/network/80-container-host0.network}} file in the container matches the {{ic|host0}} interface and starts a DHCP client, which receives an IP address from the host. |
||
+ | |||
+ | If you do not use [[systemd-networkd]], you can configure static IP addresses or start a DHCP server on the host interface and a DHCP client in the container. See [[Network configuration]] for details. |
||
+ | |||
+ | To give the container access to the outside network, you can configure NAT as described in [[Internet sharing#Enable NAT]]. If you use [[systemd-networkd]], this is done (partially) automatically via the {{ic|1=IPMasquerade=yes}} option in {{ic|/usr/lib/systemd/network/80-container-ve.network}}. However, this issues just one [[iptables]] rule such as |
||
+ | |||
+ | -t nat -A POSTROUTING -s 192.168.163.192/28 -j MASQUERADE |
||
+ | |||
+ | The {{ic|filter}} table has to be configured manually as shown in [[Internet sharing#Enable NAT]]. You can use a wildcard to match all interfaces starting with {{ic|ve-}}: |
||
+ | |||
+ | # iptables -A FORWARD -i ve-+ -o ''internet0'' -j ACCEPT |
||
+ | |||
+ | {{Note|''systemd-networkd'' uses the [https://tldp.org/HOWTO/Querying-libiptc-HOWTO/whatis.html libiptc] library to interact with [[iptables]]. If you use [[nftables]], install the {{Pkg|iptables-nft}} translation layer. See also [https://github.com/systemd/systemd/issues/13307 systemd issue 13307].}} |
||
+ | |||
+ | {{Accuracy|Investigate if/why the following is necessary.}} |
||
+ | |||
+ | Additionally, the rule {{ic|-A FORWARD -i ve-+ -o ''internet0'' -j ACCEPT}} may not work as described in [[Internet sharing#Enable NAT]]. If that is the case, try {{ic|-A FORWARD -i ve-+ -j ACCEPT}}. |
||
+ | |||
+ | ==== Use a network bridge ==== |
||
+ | |||
+ | If you have configured a [[network bridge]] on the host system, you can create a virtual Ethernet link for the container and add its host side to the network bridge. This is done with the {{ic|1=--network-bridge=''bridge-name''}} option. Note that {{ic|--network-bridge}} implies {{ic|--network-veth}}, i.e. the virtual Ethernet link is created automatically. However, the host side of the link will use the {{ic|vb-}} prefix instead of {{ic|ve-}}, so the [[systemd-networkd]] options for starting the DHCP server and IP masquerading will not be applied. |
||
+ | |||
+ | The bridge management is left to the administrator. For example, the bridge can connect virtual interfaces with a physical interface, or it can connect only virtual interfaces of several containers. See [[systemd-networkd#Network bridge with DHCP]] and [[systemd-networkd#Network bridge with static IP addresses]] for example configurations using [[systemd-networkd]]. |
||
+ | |||
+ | There is also a {{ic|1=--network-zone=''zone-name''}} option which is similar to {{ic|--network-bridge}} but the network bridge is managed automatically by ''systemd-nspawn'' and ''systemd-networkd''. The bridge interface named {{ic|vz-''zone-name''}} is automatically created when the first container configured with {{ic|1=--network-zone=''zone-name''}} is started, and is automatically removed when the last container configured with {{ic|1=--network-zone=''zone-name''}} exits. Hence, this option makes it easy to place multiple related containers on a common virtual network. Note that {{ic|vz-*}} interfaces are managed by [[systemd-networkd]] same way as {{ic|ve-*}} interfaces using the options from the {{ic|/usr/lib/systemd/network/80-container-vz.network}} file. |
||
+ | |||
+ | ==== Use a "macvlan" or "ipvlan" interface ==== |
||
+ | |||
+ | Instead of creating a virtual Ethernet link (whose host side may or may not be added to a bridge), you can create a virtual interface on an existing physical interface (i.e. [[VLAN]] interface) and add it to the container. The virtual interface will be bridged with the underlying host interface and thus the container will be exposed to the outside network, which allows it to obtain a distinct IP address via DHCP from the same LAN as the host is connected to. |
||
+ | |||
+ | ''systemd-nspawn'' offers 2 options: |
||
+ | |||
+ | * {{ic|1=--network-macvlan=''interface''}} – the virtual interface will have a different MAC address than the underlying physical {{ic|''interface''}} and will be named {{ic|mv-''interface''}}. |
||
+ | * {{ic|1=--network-ipvlan=''interface''}} – the virtual interface will have the same MAC address as the underlying physical {{ic|''interface''}} and will be named {{ic|iv-''interface''}}. |
||
+ | |||
+ | Both options imply {{ic|--private-network}}. |
||
+ | |||
+ | ==== Use an existing interface ==== |
||
+ | |||
+ | If the host system has multiple physical network interfaces, you can use the {{ic|1=--network-interface=''interface''}} to assign {{ic|''interface''}} to the container (and make it unavailable to the host while the container is started). Note that {{ic|--network-interface}} implies {{ic|--private-network}}. |
||
+ | |||
+ | {{Note|Passing wireless network interfaces to ''systemd-nspawn'' containers is currently not supported. [https://github.com/systemd/systemd/issues/7873]}} |
||
+ | |||
+ | === Port mapping === |
||
+ | |||
+ | When private networking is enabled, individual ports on the host can be mapped to ports on the container using the {{ic|-p}}/{{ic|--port}} option or by using the {{ic|Port}} setting in an ''.nspawn'' file. This is done by issuing [[iptables]] rules to the {{ic|nat}} table, but the {{ic|FORWARD}} chain in the {{ic|filter}} table needs to be configured manually as shown in [[#Use a virtual Ethernet link]]. |
||
+ | |||
+ | For example, to map a TCP port 8000 on the host to the TCP port 80 in the container: |
||
+ | |||
+ | {{hc|/etc/systemd/nspawn/''container-name''.nspawn|2= |
||
+ | [Network] |
||
+ | Port=tcp:8000:80 |
||
+ | }} |
||
+ | |||
+ | {{Note| |
||
+ | * ''systemd-nspawn'' explicitly excludes the {{ic|loopback}} interface when mapping ports. Hence, for the example above, {{ic|localhost:8000}} connects to the host and not to the container. Only connections to other interfaces are subjected to port mapping. See [https://github.com/systemd/systemd/issues/6106] for details. |
||
+ | * Port mapping works only for IPv4 connections. [https://github.com/systemd/systemd/issues/10254] |
||
+ | }} |
||
+ | |||
+ | === Domain name resolution === |
||
+ | |||
+ | [[Domain name resolution]] in the container can be configured by the {{ic|--resolv-conf}} option of ''systemd-nspawn'' or the corresponding option {{ic|1=ResolvConf=}} for the ''.nspawn'' files. There are many possible values which are described in {{man|1|systemd-nspawn|Integration Options}}. |
||
+ | |||
+ | The default value is {{ic|auto}}, which means that: |
||
+ | |||
+ | * If {{ic|--private-network}} is enabled, the {{ic|/etc/resolv.conf}} is left as it is in the container. |
||
+ | * Otherwise, if [[systemd-resolved]] is running on the host, its stub {{ic|resolv.conf}} file is copied or bind-mounted into the container. |
||
+ | * Otherwise, the {{ic|/etc/resolv.conf}} file is copied or bind-mounted from the host to the container. |
||
+ | |||
+ | In the last two cases, the file is copied, if the container root is writeable, and bind-mounted if it is read-only. |
||
== ヒントとテクニック == |
== ヒントとテクニック == |
2020年9月18日 (金) 15:21時点における版
systemd-nspawn は chroot コマンドに似ていますが、chroot を強化したものです。
systemd-nspawn を使えば軽量な名前空間コンテナでコマンドや OS を実行することができます。ファイルシステム構造だけでなく、プロセスツリーや様々な IPC サブシステム、ホスト・ドメイン名も完全に仮想化するため chroot よりも強力です。
systemd-nspawn は /sys
, /proc/sys
, /sys/fs/selinux
などのコンテナの様々なカーネルインターフェイスへのアクセスを読み取り専用に制限します。コンテナの中からネットワークインターフェイスやシステムクロックを変更することは出来ません。デバイスノードを作成することも不可能です。コンテナの中からホスト環境を再起動することはできず、カーネルモジュールをロードすることも制限されます。
仕組みとしては Lxc-systemd や Libvirt-lxc と異なり、とてもシンプルなツールで設定を行います。
目次
インストール
systemd-nspawn は systemd に含まれています。
サンプル
コンテナに最小限の Arch Linux ディストリビューションを作成して起動
まず arch-install-scripts パッケージをインストールしてください。
そして、お好きな場所にディレクトリを作成してください。例えば: $ mkdir ~/MyContainer
。
pacstrap を使って最小限の arch システムをコンテナにインストールします。最低限でも base グループはインストールする必要があります。
# pacstrap -c ~/MyContainer base [additional pkgs/groups]
インストールが完了したら、コンテナに chroot し、root パスワードを設定します。
# systemd-nspawn -D ~/MyContainer # passwd # logout
最後に、コンテナを起動します。
# systemd-nspawn -b -D ~/MyContainer
(-b
はシェルを実行する代わりにコンテナを起動します (つまり PID=1 として systemd
を実行)。-D
にはコンテナのルートディレクトリにするディレクトリを指定します):
コンテナが開始したら、設定したパスワードを使って "root" でログインしてください。
コンテナの電源を切りたいときはコンテナの中から poweroff
を実行することで出来ます。ホストからは、machinectl ツールでコンテナを制御できます。
Debian や Ubuntu 環境の作成
debootstrap と debian-archive-keyring か ubuntu-keyring のどちらか (インストールしたい方のディストリのキーリング) をインストールしてください。
後は簡単に Debian や Ubuntu 環境をセットアップできます:
# cd /var/lib/machines # debootstrap <codename> myContainer <repository-url>
Debian の場合、コードネームとして指定するのは "stable" や "testing" などのローリングの名前か "stretch" や "sid" などのリリース名になります。Ubuntu の場合、"xenial" や "zesty" などのコードネームを使ってください。コードネームの完全なリストは /usr/share/debootstrap/scripts
にあります。Debian イメージの場合は "repository-url" には http://deb.debian.org/debian/
などを指定します。Ubuntu のイメージの場合は "repository-url" は http://archive.ubuntu.com/ubuntu/
などとなります。
Arch と違って、Debian や Ubuntu は最初のログイン時にパスワードが要ることになっています。root のパスワードを設定するために、'-b' オプションを付けずにログインしてからパスワードを設定してください:
# systemd-nspawn -D myContainer # passwd # logout
上記のコマンドで上手く行かない場合、コンテナを起動してから以下のコマンドを使ってみてください:
# systemd-nspawn -b -D myContainer #Starts the container # machinectl shell root@myContainer /bin/bash #Get a root bash shell # passwd # logout
パッケージのビルドおよびテスト
使用例については、他のディストリビューションのパッケージの作成 を参照してください。
プライベートユーザーの作成 (非特権コンテナ)
systemd-nspawn は非特権コンテナをサポートしていますが、コンテナは root で起動する必要があります。
非特権コンテナを使うときは systemd-nspawn に全てを決めさせるのが一番簡単です:
# systemd-nspawn -UD myContainer # passwd # logout # systemd-nspawn -bUD myContainer
上記のコマンドで systemd-nspawn はディレクトリの所有者が使われているかどうか確認して、使われていない場合は所有者をベースとしてそれを上回る 65536 の ID が使われます。一方で UID/GID が使用中の場合はランダムに 524288 - 1878982656 の範囲から 65536 の ID を選択します。
コンテナの UID/GID を手動で指定することも可能です:
# systemd-nspawn -D myContainer --private-users=1354956800:65536 --private-users-chown # passwd # logout # systemd-nspawn -bUD myContainer
コンテナの起動時に --private-users=1354956800:65536
と --private-users-chown
を使うこともできますが、無駄に複雑なので、ID を割り当てた後に -U
を使うようにしてください。
マシンのブート時にコンテナを起動する
コンテナを頻繁に使用する場合、ブート時に systemd でコンテナを起動できます。まず systemd
ターゲットの machines.target
を有効化してください:
# systemctl enable machines.target
それから以下を実行してください:
# mv ~/MyContainer /var/lib/machines/MyContainer # systemctl enable systemd-nspawn@MyContainer.service # systemctl start systemd-nspawn@MyContainer.service
control group の中身を表示したい場合は、$ systemd-cgls
を実行してください。
管理
使用例は他のディストリビューションのパッケージの作成を参照。
machinectl
コンテナの管理は原則 $ machinectl
コマンドで行います。このサービスを使って仮想マシンやコンテナの状態を確認したり操作します。オプションの詳細なリストは machinectl(1)
を参照してください。
例:
- 実行中のコンテナに新しいシェルを起動:
$ machinectl login MyContainer
- コンテナの詳細情報を表示:
$ machinectl status MyContainer
- コンテナを再起動:
$ machinectl reboot MyContainer
- コンテナを電源オフ:
$ machinectl poweroff MyContainer
- イメージをダウンロード:
# machinectl pull-tar URL name
systemd ツールチェイン
systemd のコアツールチェインは多くがコンテナでも使えるようにアップデートされています。コンテナの名前を引数とする -M, --machine=
オプションをツールに付けるだけです。
例:
- 特定のマシンの journal ログを表示:
$ journalctl -M MyContainer
- control group の中身を表示:
$ systemd-cgls -M MyContainer
- コンテナの起動時間を表示:
$ systemd-analyze -M MyContainer
- リソース利用状況を表示:
$ systemd-cgtop
Configuration
Per-container settings
To specify per-container settings and not global overrides, the .nspawn files can be used. See systemd.nspawn(5) for details.
Enable container to start at boot
When using a container frequently, you may want to start it at boot.
First make sure that the machines.target
is enabled.
Containers discoverable by machinectl can be enabled or disabled:
$ machinectl enable container-name
Resource control
You can take advantage of control groups to implement limits and resource management of your containers with systemctl set-property
, see systemd.resource-control(5). For example, you may want to limit the memory amount or CPU usage. To limit the memory consumption of your container to 2 GiB:
# systemctl set-property systemd-nspawn@container-name.service MemoryMax=2G
Or to limit the CPU time usage to roughly the equivalent of 2 cores:
# systemctl set-property systemd-nspawn@container-name.service CPUQuota=200%
This will create permanent files in /etc/systemd/system.control/systemd-nspawn@container-name.service.d/
.
According to the documentation, MemoryHigh
is the preferred method to keep in check memory consumption, but it will not be hard-limited as is the case with MemoryMax
. You can use both options leaving MemoryMax
as the last line of defense. Also take in consideration that you will not limit the number of CPUs the container can see, but you will achieve similar results by limiting how much time the container will get at maximum, relative to the total CPU time.
Networking
systemd-nspawn containers can use either host networking or private networking:
- In the host networking mode, the container has full access to the host network. This means that the container will be able to access all network services on the host and packets coming from the container will appear to the outside network as coming from the host (i.e. sharing the same IP address).
- In the private networking mode, the container is disconnected from the host's network. This makes all network interfaces unavailable to the container, with the exception of the loopback device and those explicitly assigned to the container. There is a number of different ways to set up network interfaces for the container:
- an existing interface can be assigned to the container (e.g. if you have multiple Ethernet devices),
- a virtual network interface associated with an existing interface (i.e. VLAN interface) can be created and assigned to the container,
- a virtual Ethernet link between the host and the container can be created.
- In the latter case the container's network is fully isolated (from the outside network as well as other containers) and it is up to the administrator to configure networking between the host and the containers. This typically involves creating a network bridge to connect multiple (physical or virtual) interfaces or setting up a Network Address Translation between multiple interfaces.
The host networking mode is suitable for application containers which do not run any networking software that would configure the interface assigned to the container. Host networking is the default mode when you run systemd-nspawn from the shell.
On the other hand, the private networking mode is suitable for system containers that should be isolated from the host system. The creation of virtual Ethernet links is a very flexible tool allowing to create complex virtual networks. This is the default mode for containers started by machinectl or systemd-nspawn@.service
.
The following subsections describe common scenarios. See systemd-nspawn(1) § Networking Options for details about the available systemd-nspawn options.
Use host networking
To disable private networking and the creation of a virtual Ethernet link used by containers started with machinectl, add a .nspawn file with the following option:
/etc/systemd/nspawn/container-name.nspawn
[Network] VirtualEthernet=no
This will override the -n
/--network-veth
option used in systemd-nspawn@.service
and the newly started containers will use the host networking mode.
Use a virtual Ethernet link
If a container is started with the -n
/--network-veth
option, systemd-nspawn will create a virtual Ethernet link between the host and the container. The host side of the link will be available as a network interface named ve-container-name
. The container side of the link will be named host0
. Note that this option implies --private-network
.
When you start the container, an IP address has to be assigned to both interfaces (on the host and in the container). If you use systemd-networkd on the host as well as in the container, this is done out-of-the-box:
- the
/usr/lib/systemd/network/80-container-ve.network
file on the host matches theve-container-name
interface and starts a DHCP server, which assigns IP addresses to the host interface as well as the container, - the
/usr/lib/systemd/network/80-container-host0.network
file in the container matches thehost0
interface and starts a DHCP client, which receives an IP address from the host.
If you do not use systemd-networkd, you can configure static IP addresses or start a DHCP server on the host interface and a DHCP client in the container. See Network configuration for details.
To give the container access to the outside network, you can configure NAT as described in Internet sharing#Enable NAT. If you use systemd-networkd, this is done (partially) automatically via the IPMasquerade=yes
option in /usr/lib/systemd/network/80-container-ve.network
. However, this issues just one iptables rule such as
-t nat -A POSTROUTING -s 192.168.163.192/28 -j MASQUERADE
The filter
table has to be configured manually as shown in Internet sharing#Enable NAT. You can use a wildcard to match all interfaces starting with ve-
:
# iptables -A FORWARD -i ve-+ -o internet0 -j ACCEPT
Additionally, the rule -A FORWARD -i ve-+ -o internet0 -j ACCEPT
may not work as described in Internet sharing#Enable NAT. If that is the case, try -A FORWARD -i ve-+ -j ACCEPT
.
Use a network bridge
If you have configured a network bridge on the host system, you can create a virtual Ethernet link for the container and add its host side to the network bridge. This is done with the --network-bridge=bridge-name
option. Note that --network-bridge
implies --network-veth
, i.e. the virtual Ethernet link is created automatically. However, the host side of the link will use the vb-
prefix instead of ve-
, so the systemd-networkd options for starting the DHCP server and IP masquerading will not be applied.
The bridge management is left to the administrator. For example, the bridge can connect virtual interfaces with a physical interface, or it can connect only virtual interfaces of several containers. See systemd-networkd#Network bridge with DHCP and systemd-networkd#Network bridge with static IP addresses for example configurations using systemd-networkd.
There is also a --network-zone=zone-name
option which is similar to --network-bridge
but the network bridge is managed automatically by systemd-nspawn and systemd-networkd. The bridge interface named vz-zone-name
is automatically created when the first container configured with --network-zone=zone-name
is started, and is automatically removed when the last container configured with --network-zone=zone-name
exits. Hence, this option makes it easy to place multiple related containers on a common virtual network. Note that vz-*
interfaces are managed by systemd-networkd same way as ve-*
interfaces using the options from the /usr/lib/systemd/network/80-container-vz.network
file.
Use a "macvlan" or "ipvlan" interface
Instead of creating a virtual Ethernet link (whose host side may or may not be added to a bridge), you can create a virtual interface on an existing physical interface (i.e. VLAN interface) and add it to the container. The virtual interface will be bridged with the underlying host interface and thus the container will be exposed to the outside network, which allows it to obtain a distinct IP address via DHCP from the same LAN as the host is connected to.
systemd-nspawn offers 2 options:
--network-macvlan=interface
– the virtual interface will have a different MAC address than the underlying physicalinterface
and will be namedmv-interface
.--network-ipvlan=interface
– the virtual interface will have the same MAC address as the underlying physicalinterface
and will be namediv-interface
.
Both options imply --private-network
.
Use an existing interface
If the host system has multiple physical network interfaces, you can use the --network-interface=interface
to assign interface
to the container (and make it unavailable to the host while the container is started). Note that --network-interface
implies --private-network
.
Port mapping
When private networking is enabled, individual ports on the host can be mapped to ports on the container using the -p
/--port
option or by using the Port
setting in an .nspawn file. This is done by issuing iptables rules to the nat
table, but the FORWARD
chain in the filter
table needs to be configured manually as shown in #Use a virtual Ethernet link.
For example, to map a TCP port 8000 on the host to the TCP port 80 in the container:
/etc/systemd/nspawn/container-name.nspawn
[Network] Port=tcp:8000:80
Domain name resolution
Domain name resolution in the container can be configured by the --resolv-conf
option of systemd-nspawn or the corresponding option ResolvConf=
for the .nspawn files. There are many possible values which are described in systemd-nspawn(1) § Integration Options.
The default value is auto
, which means that:
- If
--private-network
is enabled, the/etc/resolv.conf
is left as it is in the container. - Otherwise, if systemd-resolved is running on the host, its stub
resolv.conf
file is copied or bind-mounted into the container. - Otherwise, the
/etc/resolv.conf
file is copied or bind-mounted from the host to the container.
In the last two cases, the file is copied, if the container root is writeable, and bind-mounted if it is read-only.
ヒントとテクニック
X 環境
新しいコンテナで X アプリケーションを動かす必要がある場合は Xhost を見て下さい。
外部の X サーバーにコンテナのセッションを接続するには DISPLAY
環境変数を設定する必要があります。
X は必要なファイルを /tmp
ディレクトリに保存します。コンテナから全てを表示させるには、/tmp
ディレクトリのファイルにアクセスできるようにしなくてはなりません。コンテナを起動するときに --bind=/tmp/.X11-unix:/tmp/.X11-unix
オプションを追加してください。
nspawn コンテナの中で Firefox を実行
Firefox 設定#nspawn コンテナの中で Firefox を実行を見て下さい。
ホストのファイルシステムにアクセス
例えばホストとコンテナの両方が 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-networkd を使用して DNS に systemd-resolved
を使用する、インターネットに接続できる最も簡単な設定:
# systemctl enable --now systemd-networkd systemd-resolved # ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf # let systemd-resolved manage /etc/resolv.conf
上記の設定を使うには -n
スイッチを使って systemd-nspawn
を実行して、ホストに仮想イーサネットリンクを作成する必要があります。
systemd-resolved
を使わないでコンテナの /etc/resolv.conf
を手動で編集して DNS サーバーの IP アドレスを追加することも可能です。
基本的な systemd-networkd のホストとコンテナの .network
ファイルは https://github.com/systemd/systemd/tree/master/network にあります。
もっと複雑なネットワークを設定する方法は、systemd-networkd#コンテナでの使用方法を見て下さい。
nsswitch.conf
ホストからコンテナへの接続を楽にするために、コンテナの名前のローカル DNS 解決を有効にすることができます。/etc/nsswitch.conf
の hosts:
セクションに mymachines
を追加してください:
hosts: files mymachines dns myhostname
こうすると、ホスト上でホストネーム foo
の DNS ルックアップで /etc/hosts
が参照され、それからローカルコンテナの名前、上流の DNS などが参照されます。
ホストのネットワークを使用
machinectl start MyContainer
で起動したコンテナによって使用されるプライベートネットワークを無効化するには systemctl edit systemd-nspawn@.service
を実行して systemd-nspawn@.service
サービスファイルの設定を編集してください。--network-veth
パラメータを削除するように ExecStart=
オプションを設定します:
/etc/systemd/system/systemd-nspawn@.service.d/override.conf
[Service] ExecStart= ExecStart=/usr/bin/systemd-nspawn --quiet --keep-unit --boot --link-journal=try-guest --machine=%I
次に起動したコンテナはホストのネットワークを使用するようになります。
仮想イーサネットインターフェイス
コンテナを systemd-nspawn ... -n
で起動した場合、systemd は自動的にホストとコンテナに仮想イーサネットインターフェイスを作成して、仮想イーサネットケーブルで接続します。
コンテナの名前が foo
ならば、仮想イーサネットインターフェイスのホストにおける名前は ve-foo
になり、コンテナではどんな場合でも名前は host0
です。
ip link
でインターフェイスを確認すると、インターフェイスの名前には ve-foo@if2
や host0@if9
のように接尾辞が付きます。@ifN
は実際はインターフェイスの名前には含まれていません。仮想イーサネットケーブルが他の端末に接続されていることを示すために ip link
によって情報が加えられています。
例えば、ホストの仮想イーサネットインターフェイス ve-foo@if2
がコンテナ foo
に接続、コンテナの中の2番目のネットワークインターフェイスに接続する場合、コンテナの中から ip link
を実行するとインデックス 2 が付きます。同じように、コンテナの host0@if9
という名前のインターフェイスはホストの9番目のインターフェイスに接続します。
ネットワークブリッジを使用
ローカルネットワークの物理マシンのようにコンテナに IP アドレスを割り当てるためにホスト環境にネットワークブリッジを設定している場合 (詳しくは systemd-networkd#2つの別々な IP で DHCP を使うや systemd-networkd#固定 IP ネットワークを参照)、--network-bridge=br0
オプションを使って systemd-nspawn から利用することができます。
systemd を使っていない環境で動作させる
Init#systemd-nspawn を見て下さい。
コンテナごとに設定を指定する
全体設定を上書きすることなく各コンテナの設定を指定したい場合 (例: どれかひとつのコンテナにディレクトリをバインドする場合)、.nspawn
ファイルを使うことで設定できます [8]。systemd.nspawn(5) を見てください [9]。
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 サブボリュームはすぐに削除されます。
トラブルシューティング
root ログインが失敗する
(machinectl login <name>
を使用して) ログインしようとしたときに以下のエラーが表示される場合:
arch-nspawn login: root Login incorrect
そして journalctl
が以下のように表示する場合:
pam_securetty(login:auth): access denied: tty 'pts/0' is not secure !
コンテナのファイルシステム上にある /etc/securetty
のターミナル名のリストに pts/0
を追加してください。詳しくは [10] を参照。また、コンテナの /etc/securetty
を削除して root で全ての tty にログインできるようにするという方法もあります。[11] を見てください。
コンテナのパッケージをアップグレードできない
ときどきコンテナの特定のパッケージがアップグレードできなくなることがあります。filesystem などが特にそうです。原因は /sys
が読み取り専用でマウントされていることにあります。mount -o remount,rw -t sysfs sysfs /sys
を実行してディレクトリを読み書き可能で再マウントしてから、アップグレードを行なって、コンテナを再起動してください。