LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術

第16回 Linuxカーネルのコンテナ機能 [6] ─ユーザ名前空間

この記事を読むのに必要な時間:およそ 7 分

複数のIDのマッピング

ここまでの例では,UID/GID=1000/1000の一般ユーザであるubuntuユーザのIDのみを,新たに作成したユーザ名前空間にマッピングしていましたので,マッピングファイルに書き込む3つの数値のうち,⁠範囲」を表す値を1にしていました。

この場合,一般ユーザであるubuntuユーザでマッピングファイルへの書き込みができました。自身で起動したプロセスに対する操作ですので権限があるためです。

マッピングファイルに書き込む値の「範囲」を表す数値を2以上にすれば,複数のIDに対してマッピングできます。しかしその場合は親の名前空間でroot権限が必要になります。なぜなら自身のUID/GID以外のIDと名前空間内のIDのマッピングを行うことになるからです。自身のID以外のマッピングが自由にできるのは問題がありますよね。

コンテナを使う場合,通常はコンテナ内で複数のユーザを使う必要があることが多いでしょう。一般ユーザでコンテナを起動する際にもroot権限でマッピングを書き込む必要があるということになると,利便性が大きく損なわれます。

このような一般ユーザでのコンテナの利用の際のマッピングの問題を解決するために,DebianとUbuntuではshadowを拡張し,あるユーザが自由に使える「サブID」を定義できるようになりました。Plamoでもこの拡張されたshadowを採用しています。

この「サブID」はUID,GIDそれぞれに定義でき,管理者があらかじめ定義しておきます。丁度,ユーザ作成時にそのユーザがどのグループに属するかを定義するのと同じようなものですね。

この「サブID」を定義するにはusermodコマンドの-vオプション(サブUID)-wオプション(サブGID)を使います。

たとえば,testユーザにUID/GID共に200000から65536個の使用を許可する場合,以下のように実行します。

# usermod -v 200000-265535 -w 200000-265535 test

この定義は/etc/subuid/etc/subgidに保存されます。

# grep test /etc/subuid
test:200000:65536
# grep test /etc/subgid
test:200000:65536

ちなみにUbuntuではインストール時に作成したubuntuユーザに対して,デフォルトで100000から65536個のサブUID/GIDが割り当てられていました。

この状態で新たにユーザを追加すると,以下のようにその後の使われていない範囲から65536個割り当たるようになっているようです。

※)
Ubuntu 14.04 LTS と 14.10 で確認
$ sudo adduser test
Adding user `test' ...
Adding new group `test' (1001) ...
Adding new user `test' (1001) with group `test' ...
Creating home directory `/home/test' ...
Copying files from `/etc/skel' ...
Enter new UNIX password: 
Retype new UNIX password: 
    : (略)
$ grep test /etc/subuid
test:165536:65536
$ grep test /etc/subgid
test:165536:65536

このサブUIDとサブGIDを使ってマッピングを作成するには,uidmapパッケージが必要です。

$ sudo apt-get install uidmap
$ ls -l /usr/bin/new?idmap
-rwsr-xr-x 1 root root 33688 Jul 18 23:29 /usr/bin/newgidmap
-rwsr-xr-x 1 root root 33688 Jul 18 23:29 /usr/bin/newuidmap

インストールすると,以上のようにsetuidされたnewuidmapコマンドとnewgidmapコマンドがインストールされます。

では,newuidmapコマンドを使って複数のIDをユーザ名前空間に対してマッピングしてみましょう。

ここでは実験のためにデフォルトで定義されているサブUID以外にさらに定義を追加します。

$ sudo usermod -v 1000-1001 ubuntu
$ cat /etc/subuid
ubuntu:100000:65536
ubuntu:1000:2

1000と1001の2つがubuntuユーザで使えるようになりました。

新しいユーザ名前空間で起動しているPID=1777のシェルに対してマッピングを定義します。名前空間内のUID=0と1を名前空間外のUID=1000と1001にそれぞれマッピングします。

$ newuidmap 1777 0 1000 2
$ cat /proc/1777/uid_map 
         0       1000          2

newuidmapコマンドには,以上のように「⁠⁠PID⁠⁠名前空間内の最初のUID⁠⁠名前空間外の最初のUID⁠⁠範囲⁠⁠」の順で引数を与えて実行します。uid_mapgid_mapファイルと似ていますね。

それではユーザ名前空間内で実効UIDを1に変えてみましょう。

$ echo $$
1777
$ whoami
root
$ python
Python 2.7.8 (default, Oct 20 2014, 15:05:19) 
[GCC 4.9.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.seteuid(1)
>>> os.getpid()
1800

以上のようにPythonを起動し,seteuidしてみました。Pythonのpid=1800ですので,親の名前空間であるホストOS上からこのプロセスの状態を確認してみましょう。

$ ls -ld /proc/1800
dr-xr-xr-x 9 1001 ubuntu 0 Dec  1 20:13 /proc/1800
$ grep '[U|G]id' /proc/1800/status
Uid:    1000    1001    1000    1001
Gid:    1000    1000    1000    1000

以上のように実効UID=1001で実行されているのがわかります。

LXCでは,一般ユーザでコンテナを作成したり起動したりする際に,ユーザ名前空間を作成し,このnewuidmapnewgidmapコマンドを使って,マッピングの範囲を指定し,コンテナの操作を行っています。

まとめ

今回は一般ユーザでコンテナを操作する際に使うLinuxカーネルの機能であるユーザ名前空間について説明しました。

次回はUbuntu上での一般ユーザでのコンテナの操作について説明したいと思います。

最近のLXC関連の動き

この記事の原稿を書いている間にLXC 1.0.7がリリースされました(12月5日⁠⁠。1.1.0リリースの話もメーリングリスト上で話題にのぼるようになってきました。原稿執筆時点で1.1.0.alpha3というバージョンになっています。2015年早々に1.1.0をリリースしたいようですが,最新のsystemdへの対応など,結構大きなテーマが残っているのでスケジュール通りに進むかどうかはわかりません。

これまでLXC関連のプロジェクトはLXCとcgroupを管理するためのCGManagerの2つでしたが,11月の初めにはLXDというプロジェクトがアナウンスされました

当初は文書だけでコードはない状態でしたが,その後急速に開発が進み,とりあえず動作する状態になっているようです。LXDはliblxcのGoバインディングを使って開発されており,最近の流行に乗っているような感じがしますね。今後が楽しみです。

また,プロジェクトが増えたのに合わせて,LXCのメンテナであるStéphane Graber氏が,ウェブサイトのリニューアルに着手しました。サイトのコンテンツはGithubで管理されており英語以外の言語のコンテンツも簡単に追加できることを考えて作られています。

この新しいサイトも12月の初めには正式に公開されました。URLは変わっていません。

英語のコンテンツはまだとりあえず揃えただけという感が強いですが一通りのコンテンツが揃いました。日本語の翻訳もとりあえず私が一通り行い,公開が済んでいます。

言語独自のコンテンツを追加することも特に問題なさそうですので,この連載へのリンクを早速公式ページの日本語コンテンツに追加しておきました。日本独自の役に立つのコンテンツを充実させていくこともできると思います。

誰でもGitHub上でforkして変更や追加を行ってプルリクエストを送れますので,興味のある方は是非ご参加いただければと思います。日本語訳はまだまだ改良の余地があると思っていますので,品質の向上に協力いただける方もお待ちいたしております。

著者プロフィール

加藤泰文(かとうやすふみ)

2009年頃にLinuxカーネルのcgroup機能に興味を持って以来,Linuxのコンテナ関連の最新情報を追っかけたり,コンテナの勉強会を開いたりして勉強しています。英語力のない自分用にLXCのmanページを日本語訳していたところ,あっさり本家にマージされてしまい,それ以来日本語訳のパッチを送り続けています。

Plamo Linuxメンテナ

Twitter:@ten_forward
技術系のブログ:http://tenforward.hatenablog.com/