この文書について
この文書は、連載記事「LXC 1.0: Blog post series」の一つである以下の記事を翻訳したものです。連載の目次や注意点はこちらを参照してください。
この文書のライセンスは原文と同じく、Creative Commons BY-NC-SA 2.5のもとに提供されています。
非特権コンテナーについて
非特権コンテナーのサポートは、個人的にはLXC 1.0のもっとも重要な新機能の一つです。
以前の記事で、たとえ名前空間を分離していたとしても、コンテナーの中のUID 0は、コンテナーの外のUID 0と同じであり、procなりsysなり他のシステムコールなりを経由してあらゆるホストリソースにアクセスできたり、コンテナーの外に出てホストの管理者に昇格することもできるので、LXCは安全ではないと考えるべきである、と伝えたことを覚えているかもしれません。
ユーザー名前空間はそのためにデザインされ、実装されました。数年に渡る熟慮と、上流のカーネルに対して必要な数百ものパッチのゆっくりとした提供が行われました。そしてついに3.12で、完全なシステムコンテナーをユーザー権限で起動できるようになったのです。
ユーザー名前空間はどのように動作するのでしょうか? えっと、簡単に言うと、システム上でそれを利用可能な個々のユーザーは、使用していないUIDとGIDの領域、理想的には65536個全部が割り当てられます。ユーザーは、二つの標準的なツールである newuidmap
と newgidmap
を使って、割り当てられたUIDやGIDをユーザー名前空間内の仮想的なUIDやGIDにマッピングした上で、そのUIDやGIDを使うことができます。
つまり、下記のような設定を行ったコンテナーを作ることができるのです:
lxc.id_map = u 0 100000 65536
lxc.id_map = g 0 100000 65536
上記は、コンテナーにそれぞれ一つずつのUIDマップとGIDマップを定義しています。この定義は、コンテナー内部の0から65536までのUID/GIDを、ホスト上の100000から165536までのそれにマッピングすることを意味します。
これを許可するために、システムレベルでユーザーをその領域に割り当てる必要があります(訳注: stgraber
は記事の著者のアカウント名):
stgraber@castiana:~$ grep stgraber /etc/sub* 2>/dev/null
/etc/subgid:stgraber:100000:65536
/etc/subuid:stgraber:100000:65536
すべてのツールがこの非特権コンテナーを理解できるように、LXCは更新されました。標準的なパスも、非特権用のものがそれぞれ用意されています;
-
/etc/lxc/lxc.conf
=>~/.config/lxc/lxc.conf
-
/etc/lxc/default.conf
=>~/.config/lxc/default.conf
-
/var/lib/lxc
=>~/.local/share/lxc
-
/var/lib/lxcsnaps
=>~/.local/share/lxcsnaps
-
/var/cache/lxc
=>~/.cache/lxc
UID 0となり、その名前空間に関連するいくつかのリソースに対して管理者権限を持てるような、新しいユーザー名前空間を作成できたとしても、もちろんそのユーザーに、ホストに対するそれ以上の権限を与えることはありません。
そのような例の一つが、ホスト上でネットワークデバイスを作成したり、ブリッジ設定を変更することです。これを回避するために、「 lxc-user-nic
」と呼ばれるツールを作成しました。これはLXC 1.0で唯一SETUIDされたバイナリで、一つのシンプルなタスクをこなします。設定ファイルを解析し、その内容に基づいて、ユーザー用のネットワークデバイスを作成し、ブリッジします。悪用を避けるために、ユーザーが要求しブリッジに追加できるデバイスの数を制限することも可能です。
次の例は、私の /etc/lxc/lxc-usernet
ファイルです:
stgraber veth lxcbr0 10
これは、「 stgraber
」ユーザーが10個までのvethタイプのデバイスを作成し、 lxcbr0
という名前のブリッジに追加できることを許可しています。
カーネルの中のユーザー名前空間によって提供されるものと、setuidツールによって、多くのディストリビューションを非特権で実行するために必要なツールが揃いました。
必要なもの
ここで説明するすべての例と操作方法は、Ubuntu 14.04(コードネーム:trusty)の最新の状態でなら完全に動作するでしょう。リリース前のUbuntuなので、普段使用しているコンピューターをアップグレードするよりは、仮想マシン上で実行するか、スペアマシンを使うと良いかもしれません。
最新のものが必要な理由は、非特権コンテナーを動かすためにはおよそ次のものが必要だからです:
- カーネル:3.13といくつかの(Ubuntuのカーネルでは適用されている)パッチ
- カーネル上でユーザー名前空間が有効化されていること
- subuid/subgidをサポートする
shadow
の最新版 - すべてのコントローラーでユーザー単位のcgroupを使えること(数週間前に有効化しました)
- Per-user cgroups on all controllers (which I turned on a couple of weeks ago)
- LXC 1.0の(二日前にリリースされた)ベータ2かそれ以上
- loginuidパッチが適用されたバージョンのPAM、まだリリースはされていません
これらの必要事項は、二日前のUbuntuの開発版でようやくすべてが揃うようになりました。
作成済みのLXCコンテナー
ユーザー名前空間にはいくつかの明らかな制約があります。例えば、ユーザー名前空間内において、ブロックデバイスやキャラクターデバイスを作成するための mknod
の使用をユーザーに許可することはできません。これを許してしまうと、ホスト上のあらゆるアクセスを許してしまうからです。いくつかのファイルシステムに関する制約もあります。例えば、ブロックデバイスへのアクセスが許されていたとしても、ループバックマウントや、extパーティションのマウントは許可できません。
これらの制約は、日々の使用において必ずしも世界の終わりを意味するものではありません。大きな問題となりうるのは、debootstrap
や yum
といった通常これらの制限された操作を行う必要があり、失敗した場合はうまくいかないようなツールを使う必要がある、コンテナーの初回のブートストラップ時です。
いくつかのテンプレートは動作するように修正したり、制約をバイパスするような修正済の fakeroot
を使うことで回避すれば対応可能です。しかしながら、LXCプロジェクトの目標は、ユーザーにディストリビューションの開発者になってもらうことではありません。もっと簡単な解決方法を用意しました。
私は新しい「download」という名前のテンプレートを作成しました。これはルートファイルシステムを作成・設定する代わりに、主要なテンプレートについて毎日事前作成・設定されたルートファイルシステムを提供するサーバーに接続します。
これらのイメージは、私のホームネットワーク上の数台のマシン(いくつかの強力なx86ビルダーと、クアッドコアのARMボード)を使用したJenkisサーバーで作成しています。ビルドプロセスはすごく真っ正直で、基本的なchrootを作成したあと、gitリポジトリのmasterブランチのcurrentをダウンロード・ビルドし、リリースとアーキテクチャに合わせて標準的なテンプレートが実行され、その結果作成されたルートファイルシステムは圧縮され、基本的な設定やメタデータ(有効期限やテンプレートファイルなど)が保存され、それらがメインサーバーに送られ、GPGキーで署名され、Webサーバーで公開されます。
クライアント側はサーバーにHTTPSでアクセスし(ドメインはDNSSECが有効で、IPv6経由でもアクセスできます)、すべての利用可能なイメージの署名されたインデックスを取得し、要求されたディストリビューション、リリース、アーキテクチャの組み合わせをサポートしているかどうかを確認し、サポートしているならルートファイルシステムとメタデータのアーカイブを取得し、署名を検証し、ローカルキャッシュに保存するだけのシンプルなテンプレートです。その後に作成されるあらゆるコンテナーは、キャッシュの有効期限が切れるまではそのキャッシュを使い、切れたら新しいコピーをサーバーから取得します。
現在のイメージリストは次のとおりです(--listを渡せば取得できます):
---
DIST RELEASE ARCH VARIANT BUILD
---
debian wheezy amd64 default 20140116_22:43
debian wheezy armel default 20140116_22:43
debian wheezy armhf default 20140116_22:43
debian wheezy i386 default 20140116_22:43
debian jessie amd64 default 20140116_22:43
debian jessie armel default 20140116_22:43
debian jessie armhf default 20140116_22:43
debian jessie i386 default 20140116_22:43
debian sid amd64 default 20140116_22:43
debian sid armel default 20140116_22:43
debian sid armhf default 20140116_22:43
debian sid i386 default 20140116_22:43
oracle 6.5 amd64 default 20140117_11:41
oracle 6.5 i386 default 20140117_11:41
plamo 5.x amd64 default 20140116_21:37
plamo 5.x i386 default 20140116_21:37
ubuntu lucid amd64 default 20140117_03:50
ubuntu lucid i386 default 20140117_03:50
ubuntu precise amd64 default 20140117_03:50
ubuntu precise armel default 20140117_03:50
ubuntu precise armhf default 20140117_03:50
ubuntu precise i386 default 20140117_03:50
ubuntu quantal amd64 default 20140117_03:50
ubuntu quantal armel default 20140117_03:50
ubuntu quantal armhf default 20140117_03:50
ubuntu quantal i386 default 20140117_03:50
ubuntu raring amd64 default 20140117_03:50
ubuntu raring armhf default 20140117_03:50
ubuntu raring i386 default 20140117_03:50
ubuntu saucy amd64 default 20140117_03:50
ubuntu saucy armhf default 20140117_03:50
ubuntu saucy i386 default 20140117_03:50
ubuntu trusty amd64 default 20140117_03:50
ubuntu trusty armhf default 20140117_03:50
ubuntu trusty i386 default 20140117_03:50
このテンプレートはPOSIX互換のシェルと wget
が動作するあらゆるシステム上で動くように注意深く作成しています。GPGは推奨されていますが、持っていなければ(あなたの責任において)無効化することは可能です。
同じテンプレートを、個人のサーバーに対しても使うことができます。中央に配置するようなテンプレートを作成すればエンタープライズ向けのデプロイで便利でしょうし、この有効期限のメカニズムを使ってすべてのホストから自動的に最新に保つように取得できれば良いだろうと考えています。
このテンプレートは非特権コンテナーの制約を回避するようにデザインされていますが、システムコンテナーに対しても同じように使えます。例えば非特権コンテナーをサポートしていないシステムであっても、次コマンドは実行できます。
lxc-create -t download -n p1 -- -d ubuntu -r trusty -a amd64
これにより、amd64版のUbuntu 14.04の最新ビルドが動作する新しいコンテナーを取得できます。
非特権のLXCを使用する
そうですね、実際に始めてみましょうか。既に伝えているとおり、すべての作業はごく最近のUbuntu 14.04(trusty)でのみ確認しています。デイリービルドイメージを取得し、仮想マシン上で起動してください。
必要なパッケージをインストールします:
sudo apt-get update
sudo apt-get dist-upgrade
sudo apt-get install lxc systemd-services uidmap
新しいcgroupマネージャーがUbuntuに取り込まれるまでの簡単な回避策として、下記の設定を /etc/init/lxc-unpriv-cgroup.conf
に記述します:
start on starting systemd-logind and started cgroup-lite
script
set +e
echo 1 > /sys/fs/cgroup/memory/memory.use_hierarchy
for entry in /sys/fs/cgroup/*/cgroup.clone_children; do
echo 1 > $entry
done
exit 0
end script
これはlogindが、LXCが要求する use_hierarchy
と clone_children
を設定しないために必要です。
これらのcgroup設定を正しく反映するために、一度マシンを再起動します。
あなた自身を、UITとGIDのグループに割り当てます:
sudo usermod --add-subuids 100000-165536 $USER
sudo usermod --add-subgids 100000-165536 $USER
~/.config/lxc/default.conf
に次の設定を行います:
lxc.network.type = veth
lxc.network.link = lxcbr0
lxc.network.flags = up
lxc.network.hwaddr = 00:16:3e:xx:xx:xx
lxc.id_map = u 0 100000 65536
lxc.id_map = g 0 100000 65536
さらに /etc/lxc/lxc-usernet
に次の設定を追加します:
<あなたのユーザー名> veth lxcbr0 10
これで必要な作業は完了です。それでは最初の非特権コンテナーを作成しましょう:
lxc-create -t download -n p1 -- -d ubuntu -r trusty -a amd64
ダウンロードテンプレートが次のようなメッセージを出力するはずです:
Setting up the GPG keyring
Downloading the image index
Downloading the rootfs
Downloading the metadata
The image cache is now ready
Unpacking the rootfs
---
You just created an Ubuntu container (release=trusty, arch=amd64).
The default username/password is: ubuntu / ubuntu
To gain root privileges, please use sudo.
これで最初のコンテナーの作成は成功したはずです。起動すると次のようになるはずです:
So looks like your first container was created successfully, now let’s see if it starts:
ubuntu@trusty-daily:~$ lxc-start -n p1 -d
ubuntu@trusty-daily:~$ lxc-ls --fancy
NAME STATE IPV4 IPV6 AUTOSTART
------------------------------------------
p1 RUNNING UNKNOWN UNKNOWN NO
「起動中」の状態になりました! この時点で、 lxc-console
コマンドでコンソールに入ったり、ARPテーブル( arp -n
)にあるIPアドレスを探すことでSSHを使うことができます。
上記の出力を見たとき、コンテナーのIPアドレスが表示されていないことに気づいたでしょう。これは、残念なことに現在のLXCが非特権コンテナーの名前空間にアタッチできないことが理由です。同じ理由で、 lxc-info
のいくつかのフィールドは空になり、 lxc-attach
は使用できません。しかしながら、近い将来にこの問題を解決できるような手段を模索中です。
カーネル内のジョブコントロールやPAMにもいくつかの問題があり、デタッチしない lxc-start
は、コンソールの表示がおかしくなり、 sudo
はおそらく失敗するでしょう。SSHもいくつかのディストリビューションでは失敗するかもしれません。これを解決するパッチはアップストリームに送信済みですが、それを適用したとしてもすべての問題を解決できるわけではないようですし、まだリリースしていません。
非特権コンテナーに対してはもっとたくさんの改善を、来月の1.0リリースまでに行う予定です。ただし、非特権コンテナーに割り当て可能なすべての作業量を予測できているわけではないので、もっと大掛かりな改善やもっと興味深い使用方法のためのより良いものが残っているかもしれません。