巷ではコンテナが大人気です。一方で、アプリケーションコンテナである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-nspawn
はchroot
と異なり、OSのブート(といってもinit起動以降の部分)が可能になっています。
Ubuntuのコンテナをとりあえず立ち上げてみる
systemd-nspawnはデフォルトではインストールされていないため、systemd-container
パッケージが必要です。
また、起動させたいディストリビューションの入ったルートファイルシステムを作る必要があります。 Ubuntuのルートファイルシステムを作成するには、debootstrap
パッケージも必要となります。
任意のディレクトリにdebootstrap
コマンドを使い、Ubuntuのルートファイルシステムを作成します。ここでは現在開発中の17.10(開発コード:artful)のルートファイルシステムを、ホームディレクトリにartful
という名前で作成します。
コマンドを実行すると、パッケージのダウンロードと展開が始まります。
このままでは、コンテナにログインできるユーザーが存在しません。そのため、一度、ブートなしでコンテナに入ります。 エラーのようなメッセージが表示されますが、特に問題はありません。
コンテナ起動時のメッセージにもありますが、何か不都合が生じた場合はCtrl
を押しながら]
を3回、1秒以内に連打すると、コンテナを強制終了できます。
続いて、管理者用のユーザーを作成し、パスワードを設定します[4]。
コンテナから抜けます。ブートなしの場合は以下で抜けることができます。
続いて、-b
オプションを付けてコマンドを実行し、コンテナを「起動(ブート)」させます。
様々なサービスがコンテナ内のsystemdにより起動させられ、ログインの待受け画面になります。
先ほど作成したユーザーでログインしましょう。ログインできない場合はユーザー・パスワード設定が間違っているかもしれません。 その場合には先述したように、Ctrl
を押しながら]
を1秒以内に3連打してコンテナを強制終了し、手順をやり直してください。
DNSサーバーの設定
ここで、ネットワーク情報を確認します。
ホストで利用できるすべてのIPアドレスがコンテナでも利用できることを確認できるはずです。systemd-nspawn
はオプションを指定しない場合、NICとIPアドレスをホストと共有します。
ただし、このままでは満足にインターネットを利用できません。というのも、ホスト側で利用しているDNSサーバーの情報はコンテナ側には伝わらず、名前解決ができないからです。
17.04以降のUbuntuではsystemd-resolved
がDNSリゾルバーに採用されており、名前解決の設定ファイル/etc/resolv.conf
は自動で管理されています。今回、コンテナで動かしている17.10も同様です。
そのため、/etc/systemd/resolved.conf
にDNSサーバーの情報を記入します。
まずはホスト側で利用しているDNSサーバーの情報を確認します。GUIの接続情報画面を開いて確認もできますが、次のコマンドでも表示できます。
そして、取得した情報をもとに/etc/systemd/resolved.conf
の一部をコメントアウトを外し、以下のように編集します。
その後、systemd-resolved
を再起動します。
これで、名前解決が利用できるようになったので、パッケージをインストールしてみます。
ブートありの場合のコンテナを終了・再起動は、通常のOSのシャットダウンと同じです。しかし、Ubuntuのコンテナはあとで使いますので、起動したままにしておきます。
Fedoraのコンテナを立ち上げる
Fedoraのコンテナも作ってみましょう。
別の端末を起動します。 Fedoraのルートファイルシステムを作るのに必要なyum
をインストールします[5]。
Fedora 26のレポジトリのパッケージをダウンロードして展開し、レポジトリ情報とGPG鍵を配置します。
Fedoraのルートファイルシステムを、ホームディレクトリにfedora-26
というディレクトリに作成します。
あとのユーザー作成とDNS設定の手順はほぼ同じですが、管理者権限を持つユーザーを作成する部分は次のようにしてください。
気をつけなければならない点としては、UbuntuでFedoraのルートファイルシステムを作成する場合、インストールしたパッケージ情報がrpmdbに書き込まれない点です。 ルートファイルシステムを作った時に入れたはずのパッケージも入ってないことになっています。 これでは不便なので、あまりスマートではありませんが、コンテナをブートさせたあとにインストールし直すのが良いでしょう。
fedora-release
もインストールしているので、以後、--releasever
オプションなしでもdnf
が使えます[6]。
コンテナの中のsystemdを操作する
ここまでで、UbuntuとFedoraと2つのディストリビューションのコンテナが起動している状態になりました。 最後に、ホスト側からsystemd関連のコマンドを利用して、これらのコンテナを簡単に操作してみます。
さらに別の端末を立ち上げます。 machinectl
コマンドを利用すると、起動しているコンテナの情報を確認できます。
systemd関連コマンドで末尾がctl
で終わるコマンドの中には-M
オプションを利用できるものがあります。-M
オプションを使うと、systemd-nspawn
で起動したコンテナを操作対象にできます。
次の例では、コンテナのsystemdのジャーナル、システム・サービスの状態表示させています[7]。
-M
で指定しているコンテナの名前は、今回の場合、ルートファイルシステムを入れたディレクトリ名となっています。systemd-nspawn
コマンドも-M
オプションを取ることができ、ここでコンテナの名前を指定できます。
このあたりがsystemd-nspawn
であえてコンテナを動かしていておもしろい部分です[8]。
systemd採用のディストリビューションなら(たぶん)何でも動かせる
今回はUbuntuとFedoraのコンテナ動かす例を取り上げましたが、systemd-nspawn
ではルートファイルシステムが用意できれば、systemdを採用のどのディストリビューションでも(たぶん)動かすことができます。
Ubuntuと同じやり方でDebianを動かしてみたり、Fedoraと同じやり方でCentOSを動かしてみたり、zypper[9]を使ってopenSUSEを動かしてみたり、いろいろ試してみると面白いのではないでしょうか。