前回は一般ユーザでコンテナを起動する際に利用するカーネルのユーザ名前空間について紹介しました。
今回はそのユーザ名前空間を使って実現している、
一般ユーザでコンテナを利用できるディストリビューション
第16回でユーザ名前空間で複数のIDのマッピングを行うためにshadowに導入された
一般ユーザでLXCコンテナを利用する場合は、
Ubuntu 14.
筆者は、
一般ユーザでコンテナを利用する場合のOSでの準備
一般ユーザでLXCコンテナを利用する場合は、
Ubuntu 14.
$ cat /etc/subuid /etc/subgid ubuntu:100000:65536 ubuntu:100000:65536
この例はubuntu
というユーザをインストール時に追加したときに設定され
たサブIDです。100000から65536個のIDがubuntu
で使えるように設定されています。
これとは別の範囲をサブIDとして設定したい場合や、usermod
コマンドを使います。
$ sudo usermod -v 200000-265535 -w 200000-265535 user
-v
はUIDのサブIDを、-w
はGIDのサブIDの範囲を設定します。
UbuntuのLXCパッケージ使用時の各種パス
一般ユーザでLXCを使ってコンテナを利用する際の設定ファイルなどの場所について第8回で示したのと同様の表を使って紹介しましょう。
ファイル/ |
root権限の時 | 一般ユーザの時 |
---|---|---|
システム設定ファイル | /etc/ |
~/.config/ |
コンテナのデフォルト設定ファイル | /etc/ |
~/.config/ |
テンプレートファイルの置き場所 | /usr/ |
(root権限の場合と同じ) |
コンテナ作成時のキャッシュの置き場所 | /var/ |
~/.cache/ |
コンテナの保存場所 | /var/ |
~/.local/ |
ログファイルの出力場所 | /var/ |
~/.local/ |
一般ユーザが使うネットワークインターフェースの設定ファイル | (なし) | /etc/ |
root権限の場合のパスは各ディストリビューションのコンパイル時のオプションに依存します。一方で一般ユーザの場合は、
テンプレートファイルに関しては、
一般ユーザでコンテナを利用する場合のLXCの設定
ネットワークインターフェースの設定
第16回で説明したように、
現時点では一般ユーザ権限で起動したコンテナと外部の通信をする際は第6回で説明したvethインターフェースを使う必要があります。
コンテナがこのvethインターフェースを使って外部と通信するためには、
一般ユーザでこの特権が必要な操作をするために、lxc-user-nic
というプログラムを使用します。
$ ls -l /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic -rwsr-xr-x 1 root root 34888 Sep 30 17:13 /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
このlxc-user-nic
はUbuntuでは/usr/
にインストールされています
このプログラムは、/etc/
というファイルを参照して、
lxc-usernet
ファイルは以下のような書式で1行に1ユーザの設定を記述します。
(ユーザ名) (インターフェースのタイプ) (接続するブリッジ) (作成できるインターフェースの数)
たとえば、ubuntu
ユーザがvethインターフェースを10個まで作成でき、lxcbr0
に接続する場合は以下のようになります。
ubuntu veth lxcbr0 10
現時点ではインターフェースのタイプはveth以外は指定できません。
各ユーザのLXCの設定ファイル
それでは一般ユーザでコンテナを起動するためのLXCの準備をしていきましょう。
第14回でも簡単に方法に触れていますが、
まずは設定ファイルを置くディレクトリがない場合は作成しましょう。
$ mkdir -p ~/.config/lxc
Ubuntuではシステム設定ファイルであるlxc.
はデフォルトでは使われていません。コンテナイメージが置かれる場所を変えたいなど、~/.config/
ファイルを作成して設定を書いておきましょう。設定についてはman lxc.
をご覧ください。
次はコンテナのデフォルト設定ファイルであるdefault.
です。これはLXCパッケージをインストールしたときに作成されますので、
$ cp /etc/lxc/default.conf ~/.config/lxc/default.conf $ vi ~/.config/lxc/default.conf
ここで追加する設定は/etc/
、/etc/
で行ったようなユーザ名前空間を使うときのマッピング情報です。この設定はlxc.
です。
この設定は4つのフィールドから成っています。最初から順に以下のようになります。
- uidのマッピングの場合は"u"、
gidのマッピングの場合は"g"の一文字 - あとの3つは第16回で紹介した
/proc/[PID]/uid_
とmap /proc/[PID]/gid_
と同じ書式map
たとえばUIDをマッピングする場合で、
lxc.id_map = u 0 100000 65536
となります。
GIDにも同様のマッピングをすると、~/.config/
は以下のようになります。
# /etc/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
コンテナの作成
一般ユーザのコンテナイメージと設定ファイルは、~/.local/
にコンテナ名のディレクトリを作成してそのディレクトリ以下に置かれます。
このディレクトリ(~/.local/
)がない場合はコンテナ作成時に自動的に作成されますので、
一般ユーザ権限の場合は、
lxc-ubuntu
、lxc-centos
などの各ディストリビューション用のテンプレートは使えません。これは、
一般ユーザでコンテナを作成する場合もrootで実行する場合と同じようにlxc-create
を使います。使い方もrootで実行する場合と同じです。
$ lxc-create -n ct01 -t download -- -d ubuntu -r trusty -a amd64 Using image from local cache Unpacking the rootfs --- You just created an Ubuntu container (release=trusty, arch=amd64, variant=default) To enable sshd, run: apt-get install openssh-server For security reason, container images ship without user accounts and without a root password. Use lxc-attach or chroot directly into the rootfs to set a root password or create user accounts.
以上はUbuntu Trusty
作成されたコンテナディレクトリを確認しておきましょう。
$ ls -F ~/.local/share/lxc ct01/ $ ls -F ~/.local/share/lxc/ct01 config rootfs/
以上のようにroot権限で/var/
以下に作成されたコンテナと同様に作成されています。
設定ファイルは以下のようになっています。
$ cat ~/.local/share/lxc/ct01/config :(略) # Distribution configuration lxc.include = /usr/share/lxc/config/ubuntu.common.conf lxc.include = /usr/share/lxc/config/ubuntu.userns.conf lxc.arch = x86_64 # Container specific configuration lxc.id_map = u 0 100000 65536 lxc.id_map = g 0 100000 65536 lxc.rootfs = /home/ubuntu/.local/share/lxc/ct01/rootfs lxc.utsname = ct01 # Network configuration lxc.network.type = veth lxc.network.flags = up lxc.network.link = lxcbr0 lxc.network.hwaddr = 00:16:3e:9f:c4:5a
root権限で作成したコンテナと一般ユーザで作成したコンテナの違いはubuntu.
をincludeしている部分です。これは一般ユーザでコンテナを作成する際に使用する共通の設定をまとめたファイルで、
$ ls /usr/share/lxc/config/*.userns.conf /usr/share/lxc/config/centos.userns.conf /usr/share/lxc/config/debian.userns.conf /usr/share/lxc/config/fedora.userns.conf /usr/share/lxc/config/gentoo.userns.conf /usr/share/lxc/config/oracle.userns.conf /usr/share/lxc/config/plamo.userns.conf /usr/share/lxc/config/ubuntu-cloud.userns.conf /usr/share/lxc/config/ubuntu.userns.conf
たとえばubuntuの場合以下のような内容です。デバイスファイルを作成するなどのユーザ名前空間内では実行できない処理の代わりに、
$ cat /usr/share/lxc/config/ubuntu.userns.conf # CAP_SYS_ADMIN in init-user-ns is required for cgroup.devices lxc.cgroup.devices.deny = lxc.cgroup.devices.allow = # We can't move bind-mounts, so don't use /dev/lxc/ lxc.devttydir = # Extra bind-mounts for userns lxc.mount.entry = /dev/console dev/console none bind,create=file 0 0 lxc.mount.entry = /dev/full dev/full none bind,create=file 0 0 lxc.mount.entry = /dev/null dev/null none bind,create=file 0 0 lxc.mount.entry = /dev/random dev/random none bind,create=file 0 0 lxc.mount.entry = /dev/tty dev/tty none bind,create=file 0 0 lxc.mount.entry = /dev/urandom dev/urandom none bind,create=file 0 0 lxc.mount.entry = /dev/zero dev/zero none bind,create=file 0 0 # Extra fstab entries as mountall can't mount those by itself lxc.mount.entry = /sys/firmware/efi/efivars sys/firmware/efi/efivars none bind,optional 0 0 lxc.mount.entry = /proc/sys/fs/binfmt_misc proc/sys/fs/binfmt_misc none bind,optional 0 0 # Default seccomp policy is not needed for unprivileged containers, and # non-root users cannot use seccmp without NNP anyway. lxc.seccomp =
一般ユーザでのコンテナの起動
一般ユーザでコンテナを起動するには、
Ubuntu 14.04 LTS の場合
Ubuntu 14.lxc-create
でコンテナが作成できれば、lxc-start
でコンテナを起動できます。
あとでcgroupの制限が有効になっているのかを確認するために、ct01
の設定ファイルにcgroupの設定を足しておきます。以下のような2行を追加しました。
$ grep cgroup .local/share/lxc/ct01/config lxc.cgroup.cpu.shares = 1000 lxc.cgroup.memory.limit_in_bytes = 512m
それでは起動しましょう。
$ lxc-ls -f NAME STATE IPV4 IPV6 AUTOSTART ------------------------------------ ct01 STOPPED - - NO $ lxc-start -n ct01 -d $ lxc-ls -f NAME STATE IPV4 IPV6 AUTOSTART ------------------------------------------ ct01 RUNNING 10.0.3.218 - NO
無事実行できましたね。このようにUbuntuだと簡単に一般ユーザ権限でコンテナが実行できます。
この起動したコンテナできちんとcgroupを使ったリソース制限が効いているか確認するために、
CGManagerは新しいマウント名前空間を作成してその中でcgroupfsをマウントしますので、
$ sudo ./nsenter -t `pgrep cgmanager` --mount -- \ > ls -F /run/cgmanager/fs/cpu/user/1000.user/3.session cgroup.clone_children cpu.cfs_period_us cpu.stat tasks cgroup.event_control cpu.cfs_quota_us ct01/ cgroup.procs cpu.shares notify_on_release
ご覧のようにcgmanagerが作成したマウント名前空間内の/run/
以下にct01
というディレクトリがあります。1000.
や3.
はログインユーザやログインセッションによって変化します。
Ubuntu 14.systemd-logind
によりユーザのログインセッション用のcgroupが/sys/
以下に作成されます。CGManagerはそのグループをそのまま使っているようです。
$ ls -ld /sys/fs/cgroup/systemd/user/1000.user/3.session/ (ホストOSの名前空間で実行) drwxr-xr-x 3 ubuntu ubuntu 0 Jan 6 17:01 /sys/fs/cgroup/systemd/user/1000.user/3.session/
では、ct01
用のcgroupで反映されているか確認してみましょう。
$ sudo ./nsenter -t `pgrep cgmanager` --mount -- \ > cat /run/cgmanager/fs/cpu/user/1000.user/3.session/ct01/cpu.shares 1000 $ sudo ./nsenter -t `pgrep cgmanager` --mount -- \ > cat /run/cgmanager/fs/memory/user/1000.user/3.session/ct01/memory.limit_in_bytes 536870912
確かに先に設定した通りの値になっています。
以上のように一般ユーザで作成したコンテナがきちんと起動し、
作成されたコンテナは先に述べたようにアクセスできるユーザやパスワードの設定がされていませんので、lxc-attach
コマンドを使って設定したり、
一般ユーザで操作可能なcgroup
Plamo Linuxや、
$ cat /etc/rc.d/init.d/cgroups-mount-user
#!/bin/sh
# mount cgroup filesystems per subsystem for user name space
USERNS="taro hanako"
start() {
echo 1 > /sys/fs/cgroup/memory/memory.use_hierarchy
for c in /sys/fs/cgroup/* ; do
echo 1 > $c/cgroup.clone_children
for u in $USERNS ; do
mkdir -p $c/$u
chown -R $u $c/$u
if [ ${c##*/} == cpuset ] ; then
echo 0 > $c/$u/cpuset.cpus
echo 0 > $c/$u/cpuset.mems
fi
done
done
}
stop() {
:
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|restart}"
exit 1
;;
esac
このスクリプトは
- memoryサブシステムで階層構造が使えるように設定する
- cpusetサブシステムで親のcgroupの設定を子に引き継ぐように設定する
- ユーザ名のcgroupを作成し、
chownする - cpusetサブシステムが使えるようにcpuset.
cpusとcpuset. memsに初期値を入れる
という操作を指定したユーザごとに実行しています。
ユーザ用のcgroupが準備できたら、lxc-start
を実行するシェルで以下のように実行し、tasks
に登録します。
$ for d in /sys/fs/cgroup/*/${USER} > do > echo $$ > $d/tasks > done
これで準備ができたのでコンテナを開始します。
$ lxc-ls -f NAME STATE IPV4 IPV6 GROUPS AUTOSTART ------------------------------------------------ ct01 STOPPED - - - NO $ lxc-start -n ubuntu01 $ lxc-ls -f NAME STATE IPV4 IPV6 GROUPS AUTOSTART -------------------------------------------------------- ct01 RUNNING 10.0.100.188 - - NO
まとめ
今回は一般ユーザでコンテナを作成し、
Ubuntuだと各ユーザのサブIDを設定し、
一般ユーザによるコンテナの話題は今回で終わりです。次回からは、