Ubuntu Weekly Recipe

第491回いまから「あえて」systemdのコンテナ機能を使ってみる

巷ではコンテナが大人気です。一方で、アプリケーションコンテナであるDockerとDockerコンテナをオーケストレーションするKubernetes。もう一方で、システムコンテナであるLXCとそれを便利に使うためのLXD

本連載でもこれらの技術のいくつかは何度か取り上げられています。

ところで、Ubuntuではバージョン15.04よりinitとしてsystemdが採用されていますが、実は、このsystemdにもコンテナを動かす機能があります。

そこで今回は、上に挙げたような「有名ドコロ」のコンテナ技術がアツい中、あえてsystemd-nspawnというコマンドを使い、systemdに備わっているコンテナ機能をとりあえず簡単に使う方法を紹介します。

強化版chroot

UNIX オペレーティングシステムには本来のルートディレクトリと論理的に分離し、ユーザーやプロセスにあたかもルートディレクトリの中にいるかのように見せかける、chrootというコマンドがあります。

chrootのよくある利用方法としては次のようなものがあります。

  • システムで動作しているサービスを隔離し、万が一、これが侵入者に乗っ取られた場合でも、システム全体が脅威に晒されることを防ぐ
  • FTPサーバーなどのリモートユーザーがアクセスできる領域を制限する
  • Linuxディストリビューションのインストールで利用する ※1

chrootの歴史は古いですが、中に何かを閉じ込めて安全に利用するという点では、ある意味、コンテナであると言えます。

今回紹介するsystemd-nspawnはこのchrootの強化版です[2]⁠。

systemdのコンテナ機能はLinuxカーネルの機能である名前空間を主に利用しています。この機能を使えば、例えば「この名前空間ではPIDが1のプロセスはA。また別の名前空間では別のB」と名前空間同士を隔離させることができます。また、隔離の対象とできる名前空間には複数あります[3]⁠。

systemd-nspawnは複数の種類がある名前空間をまとめて取り扱い、適切に隔離し、コンテナを利用するためのコマンドと考えるよいでしょう(nspawnは"Namespace Spawn"を意味していると考えるのが妥当でしょう⁠⁠。 つまり、コンテナを起動させるシステム(以下、ホスト)の名前空間とは別にコンテナ用の名前空間を立ち上げ、コンテナの中をホストから厳格に隔離します。

そのため、systemd-nspawnchrootと異なり、OSのブート(といってもinit起動以降の部分)が可能になっています。

Ubuntuのコンテナをとりあえず立ち上げてみる

systemd-nspawnはデフォルトではインストールされていないため、systemd-containerパッケージが必要です。

また、起動させたいディストリビューションの入ったルートファイルシステムを作る必要があります。 Ubuntuのルートファイルシステムを作成するには、debootstrapパッケージも必要となります。

host$ sudo apt install -y systemd-container debootstrap

任意のディレクトリにdebootstrapコマンドを使い、Ubuntuのルートファイルシステムを作成します。ここでは現在開発中の17.10(開発コード:artful)のルートファイルシステムを、ホームディレクトリにartfulという名前で作成します。

host$ sudo debootstrap artful ~/artful

コマンドを実行すると、パッケージのダウンロードと展開が始まります。

I: Retrieving InRelease 
I: Checking Release signature
I: Valid Release signature (key id 790BC7277767219C42C86F933B4FE6ACC0B21F32)
I: Retrieving Packages 
I: Validating Packages 
I: Resolving dependencies of required packages...
I: Resolving dependencies of base packages...
(中略)
I: Base system installed successfully.

このままでは、コンテナにログインできるユーザーが存在しません。そのため、一度、ブートなしでコンテナに入ります。 エラーのようなメッセージが表示されますが、特に問題はありません。

host$ sudo systemd-nspawn -D ~/artful
Spawning container artful on /home/popo/artful.
Press ^] three times within 1s to kill container.
host's /etc/localtime is not a symlink, not updating container timezone.
-bash: cannot set terminal process group (-1): Inappropriate ioctl for device
-bash: no job control in this shell
mesg: ttyname failed: No such device

コンテナ起動時のメッセージにもありますが、何か不都合が生じた場合はCtrlを押しながら]を3回、1秒以内に連打すると、コンテナを強制終了できます。

続いて、管理者用のユーザーを作成し、パスワードを設定します[4]⁠。

artful# useradd admin -G sudo -m # 管理者ユーザーの作成
artful# passwd admin             # パスワードの設定
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully

コンテナから抜けます。ブートなしの場合は以下で抜けることができます。

artful# exit
logout
Container artful exited successfully.

続いて、-bオプションを付けてコマンドを実行し、コンテナを「起動(ブート⁠⁠」させます。

host$ sudo systemd-nspawn -b -D ~/artful

様々なサービスがコンテナ内のsystemdにより起動させられ、ログインの待受け画面になります。

Ubuntu Artful Aardvark (development branch) ubuntu console

ubuntu login:

先ほど作成したユーザーでログインしましょう。ログインできない場合はユーザー・パスワード設定が間違っているかもしれません。 その場合には先述したように、Ctrlを押しながら]を1秒以内に3連打してコンテナを強制終了し、手順をやり直してください。

DNSサーバーの設定

ここで、ネットワーク情報を確認します。

artful$ ip addr show

ホストで利用できるすべてのIPアドレスがコンテナでも利用できることを確認できるはずです。systemd-nspawnはオプションを指定しない場合、NICとIPアドレスをホストと共有します。

ただし、このままでは満足にインターネットを利用できません。というのも、ホスト側で利用しているDNSサーバーの情報はコンテナ側には伝わらず、名前解決ができないからです。

17.04以降のUbuntuではsystemd-resolvedがDNSリゾルバーに採用されており、名前解決の設定ファイル/etc/resolv.confは自動で管理されています。今回、コンテナで動かしている17.10も同様です。

そのため、/etc/systemd/resolved.confにDNSサーバーの情報を記入します。

まずはホスト側で利用しているDNSサーバーの情報を確認します。GUIの接続情報画面を開いて確認もできますが、次のコマンドでも表示できます。

host$ systemd-resolve --status|grep "DNS Servers: " # Ubuntu 17.04以降
host$ nmcli con show (接続名) |grep "IP4.DNS"        # Ubuntu 16.04 LTS Desktop版の場合
host$ grep nameserver /etc/resolv.conf              # Ubuntu 16.04 LTS Server版のように、/etc/resolv.confでDNSサーバーを指定している場合

そして、取得した情報をもとに/etc/systemd/resolved.confの一部をコメントアウトを外し、以下のように編集します。

[Resolve]
DNS=(ホストで利用しているDNSサーバーのIPアドレス)

その後、systemd-resolvedを再起動します。

artful$ sudo systemctl restart systemd-resolved

これで、名前解決が利用できるようになったので、パッケージをインストールしてみます。

artful$ sudo apt install -y vim bash-completion

ブートありの場合のコンテナを終了・再起動は、通常のOSのシャットダウンと同じです。しかし、Ubuntuのコンテナはあとで使いますので、起動したままにしておきます。

artful$ sudo poweroff # 終了
artful$ sudo reboot   # 再起動

Fedoraのコンテナを立ち上げる

Fedoraのコンテナも作ってみましょう。

別の端末を起動します。 Fedoraのルートファイルシステムを作るのに必要なyumをインストールします[5]⁠。

host$ sudo apt install yum

Fedora 26のレポジトリのパッケージをダウンロードして展開し、レポジトリ情報とGPG鍵を配置します。

host$ wget http://ftp.riken.jp/Linux/fedora/releases/26/Everything/x86_64/os/Packages/f/fedora-repos-26-1.noarch.rpm
host$ rpm2cpio fedora-repos-26-1.noarch.rpm | cpio -id
host$ sudo cp etc/yum.repos.d/* /etc/yum/repos.d/
host$ sudo cp -R etc/pki/ /etc/

Fedoraのルートファイルシステムを、ホームディレクトリにfedora-26というディレクトリに作成します。

host$ sudo yum -y --releasever=26 --installroot=$HOME/fedora-26 install systemd passwd dnf vim iproute sudo

あとのユーザー作成とDNS設定の手順はほぼ同じですが、管理者権限を持つユーザーを作成する部分は次のようにしてください。

fedora-26# useradd admin -G wheel -m         # sudoグループではなくwheelグループを指定する
fedora-26# passwd admin

気をつけなければならない点としては、UbuntuでFedoraのルートファイルシステムを作成する場合、インストールしたパッケージ情報がrpmdbに書き込まれない点です。 ルートファイルシステムを作った時に入れたはずのパッケージも入ってないことになっています。 これでは不便なので、あまりスマートではありませんが、コンテナをブートさせたあとにインストールし直すのが良いでしょう。

fedora-26$ sudo dnf -y --releasever=26 install systemd passwd dnf vim iproute sudo fedora-release

fedora-releaseもインストールしているので、以後、--releaseverオプションなしでもdnfが使えます[6]⁠。

コンテナの中のsystemdを操作する

ここまでで、UbuntuとFedoraと2つのディストリビューションのコンテナが起動している状態になりました。 最後に、ホスト側からsystemd関連のコマンドを利用して、これらのコンテナを簡単に操作してみます。

さらに別の端末を立ち上げます。 machinectlコマンドを利用すると、起動しているコンテナの情報を確認できます。

host$ machinectl
MACHINE   CLASS     SERVICE        OS     VERSION ADDRESSES
artful    container systemd-nspawn ubuntu 17.10   -
fedora-26 container systemd-nspawn fedora 26      -

2 machines listed.

systemd関連コマンドで末尾がctlで終わるコマンドの中には-Mオプションを利用できるものがあります。-Mオプションを使うと、systemd-nspawnで起動したコンテナを操作対象にできます。

次の例では、コンテナのsystemdのジャーナル、システム・サービスの状態表示させています[7]⁠。

host$ sudo journalctl -M artful
host$ sudo systemctl status -M artful

-Mで指定しているコンテナの名前は、今回の場合、ルートファイルシステムを入れたディレクトリ名となっています。systemd-nspawnコマンドも-Mオプションを取ることができ、ここでコンテナの名前を指定できます。

このあたりがsystemd-nspawnあえてコンテナを動かしていておもしろい部分です[8]⁠。

systemd採用のディストリビューションなら(たぶん)何でも動かせる

今回はUbuntuとFedoraのコンテナ動かす例を取り上げましたが、systemd-nspawnではルートファイルシステムが用意できれば、systemdを採用のどのディストリビューションでも(たぶん)動かすことができます。

Ubuntuと同じやり方でDebianを動かしてみたり、Fedoraと同じやり方でCentOSを動かしてみたり、zypper[9]を使ってopenSUSEを動かしてみたり、いろいろ試してみると面白いのではないでしょうか。

おすすめ記事

記事・ニュース一覧