LXDでネストした非特権コンテナを試してみた

はじめに

https://twitter.com/ten_forward/status/844107303099932676

https://twitter.com/ten_forward/status/844142416282054658

というツイートを受けて自分でもLXDでネストした非特権コンテナを試してみました。 環境はUbuntu 16.04です。 lxdのバージョンは2.0.9です。

$ uname -a
Linux bai1b7faf04 4.4.0-53-generic #74-Ubuntu SMP Fri Dec 2 15:59:10 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
$ lxd --version
2.0.9

subuidとsubgidファイルを編集しつつ作成

まずは Nested containers in LXD | Ubuntu Insights に従って /etc/subuid/etc/subgid を編集しつつ試しました。

一段ネストして lxc launch images:ubuntu/xenial c2 するところで、

error: Get https://images.linuxcontainers.org/streams/v1/index.json: x509: failed to load system roots and no roots provided

というエラーが出ました。 これは 失敗: Alpine 3.5.1上でLXD 2.8を使おうと試行錯誤した - Qiita の「トラブルシューティング」にあるように ca-certificatesopenssl をインストールしたら解消しました。

その後3段目まで無事作れました。そこで調子に乗って4段目も作ってみると、なんと作れてしまいました。 しかも lxc launch の際に -c security.nesting=true を指定してなかったような気がします。

Nested containers in LXD | Ubuntu Insights の記事にあった uid の話は関係なかったのでしょうか。

subuidとsubgidファイルを元に戻して再度実験

$ lxc launch images:ubuntu/xenial c1
Creating c1
Starting c1
$ lxc exec c1 bash
root@c1:~#
root@c1:~# apt update && apt install -y lxd ca-certificates openssl
root@c1:~# lxd init
# 質問やダイアログは全てEnterキーで進む
root@c1:~# su - ubuntu
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

ubuntu@c1:~$ lxc list
Generating a client certificate. This may take a minute...
If this is your first time using LXD, you should also run: sudo lxd init
To start your first container, try: lxc launch ubuntu:16.04

+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+
ubuntu@c1:~$ lxc launch images:ubuntu/xenial c2
Creating c2
Starting c2
error: Error calling 'lxd forkstart c2 /var/lib/lxd/containers /var/log/lxd/c2/lxc.conf': err='exit status 1'
  lxc 20170321123841.200 ERROR lxc_utils - utils.c:safe_mount:1751 - Permission denied - Failed to mount proc onto /usr/lib/x86_64-linux-gnu/lxc/proc
  lxc 20170321123841.200 ERROR lxc_conf - conf.c:lxc_mount_auto_mounts:801 - Permission denied - error mounting proc on /usr/lib/x86_64-linux-gnu/lxc/proc flags 14
  lxc 20170321123841.200 ERROR lxc_conf - conf.c:lxc_setup:3859 - failed to setup the automatic mounts for 'c2'
  lxc 20170321123841.200 ERROR lxc_start - start.c:do_start:811 - Failed to setup container "c2".
  lxc 20170321123841.200 ERROR lxc_sync - sync.c:__sync_wait:57 - An error occurred in another process (expected sequence number 3)
  lxc 20170321123841.239 ERROR lxc_start - start.c:__lxc_start:1346 - Failed to spawn container "c2".
  lxc 20170321123841.801 ERROR lxc_conf - conf.c:run_buffer:405 - Script exited with status 1.
  lxc 20170321123841.801 ERROR lxc_start - start.c:lxc_fini:546 - Failed to run lxc.hook.post-stop for container "c2".

Try `lxc info --show-log local:c2` for more info

1段目のみsecurity.nestingはつけて再実験

$ lxc launch images:ubuntu/xenial c1 -c security.nesting=true
Creating c1
Starting c1
$ lxc exec c1 bash
root@c1:~# apt update && apt install -y lxd ca-certificates openssl
root@c1:~# lxd init
# 質問やダイアログは全てEnterキーで進む
root@c1:~# su - ubuntu
ubuntu@c1:~$ lxc list
Generating a client certificate. This may take a minute...
If this is your first time using LXD, you should also run: sudo lxd init
To start your first container, try: lxc launch ubuntu:16.04

+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+
ubuntu@c1:~$ lxc launch images:ubuntu/xenial c2
Creating c2
Starting c2
ubuntu@c1:~$ lxc exec c2 bash
root@c2:~# apt update && apt install -y lxd ca-certificates openssl
...(略)...
Setting up apparmor (2.10.95-0ubuntu2.5) ...
update-rc.d: warning: start and stop actions are no longer supported; falling back to defaults
Skipping profile in /etc/apparmor.d/disable: usr.sbin.rsyslogd
/sbin/apparmor_parser: Unable to replace "/sbin/dhclient".  Permission denied; attempted to load a profile while confined?
Skipping profile in /etc/apparmor.d/disable: usr.sbin.rsyslogd
/sbin/apparmor_parser: Unable to replace "/sbin/dhclient".  Permission denied; attempted to load a profile while confined?
sh: echo: I/O error
sh: echo: I/O error
sh: echo: I/O error
sh: echo: I/O error
sh: echo: I/O error
sh: echo: I/O error
diff: /var/lib/apparmor/profiles/.apparmor.md5sums: No such file or directory
Setting up rsync (3.1.1-3ubuntu1) ...
Setting up lxd-client (2.0.9-0ubuntu1~16.04.2) ...
Setting up libfuse2:amd64 (2.9.4-1ubuntu3.1) ...
Setting up lxcfs (2.0.6-0ubuntu1~16.04.1) ...
Setting up squashfs-tools (1:4.3-3ubuntu2) ...
Setting up uidmap (1:4.2-3.1ubuntu5) ...
Setting up xz-utils (5.1.1alpha+20120614-2ubuntu2) ...
update-alternatives: using /usr/bin/xz to provide /usr/bin/lzma (lzma) in auto mode
Setting up openssl (1.0.2g-1ubuntu4.6) ...
Setting up ca-certificates (20160104ubuntu1) ...
Setting up libcap-ng0:amd64 (0.7.7-1) ...
Setting up dbus (1.10.6-1ubuntu3.3) ...
Setting up dns-root-data (2015052300+h+1) ...
Setting up liblxc1 (2.0.7-0ubuntu1~16.04.2) ...
Setting up lxd (2.0.9-0ubuntu1~16.04.2) ...
apparmor_parser: Unable to replace "/usr/lib/lxd/lxd-bridge-proxy".  Permission denied; attempted to load a profile while confined?

The default LXD bridge, lxdbr0, comes unconfigured by default.
Only limited HTTP connectivity through a PROXY will be available.
To go through the initial LXD configuration, run: lxd init

Setting up lxc-common (2.0.7-0ubuntu1~16.04.2) ...
apparmor.service is not active, cannot reload.
invoke-rc.d: initscript apparmor, action "reload" failed.
apparmor_parser: Unable to replace "/usr/bin/lxc-start".  Permission denied; attempted to load a profile while confined?

2段目もsecurity.nestingをつけて再実験

root@c2:~# exit
ubuntu@c1:~$ lxc delete -f c2
ubuntu@c1:~$ lxc launch images:ubuntu/xenial c2 -c security.nesting=true
ubuntu@c1:~$ lxc exec c2 bash
root@c2:~# apt update && apt install -y lxd ca-certificates openssl

同じエラーが出ました。 とりあえず無視して続けてみました。

root@c2:~# lxd init
# 質問やダイアログは全てEnterキーで進む
ubuntu@c2:~$ lxc launch images:ubuntu/xenial c3
ubuntu@c2:~$ lxc exec c3 bash

ホストでプロセスを確認して見ました。

$ ps auxww | grep 'lxc exec c[1-3]'
hnakamur 10810  0.0  0.1 217644 16368 pts/25   Sl+  21:45   0:00 lxc exec c1 bash
101000   19687  0.0  0.0 208436 14836 pts/13   Sl+  21:54   0:00 lxc exec c2 bash
101000   26461  0.0  0.0 202800  8952 pts/1    Sl+  23:21   0:00 lxc exec c3 bash

1段目のみsecurity.nestingをつけて一からやり直し

$ lxc delete -f c1
$ lxc launch images:ubuntu/xenial c1 -c security.nesting=true
$ lxc exec c1 bash
root@c1:~# apt update && apt install -y lxd ca-certificates openssl
root@c1:~# lxd init
# 質問やダイアログは全てEnterキーで進む
root@c1:~# su - ubuntu
ubuntu@c1:~$ lxc launch images:ubuntu/xenial c2
ubuntu@c1:~$ lxc exec c2 bash
root@c2:~# apt update && apt install -y lxd ca-certificates openssl
...(略)...
Skipping profile in /etc/apparmor.d/disable: usr.sbin.rsyslogd
/sbin/apparmor_parser: Unable to replace "/sbin/dhclient".  Permission denied; attempted to load a profile while confined?
Skipping profile in /etc/apparmor.d/disable: usr.sbin.rsyslogd
/sbin/apparmor_parser: Unable to replace "/sbin/dhclient".  Permission denied; attempted to load a profile while confined?
sh: echo: I/O error
sh: echo: I/O error
sh: echo: I/O error
sh: echo: I/O error
sh: echo: I/O error
sh: echo: I/O error
diff: /var/lib/apparmor/profiles/.apparmor.md5sums: No such file or directory
Setting up rsync (3.1.1-3ubuntu1) ...
Setting up lxd-client (2.0.9-0ubuntu1~16.04.2) ...
Setting up libfuse2:amd64 (2.9.4-1ubuntu3.1) ...
Setting up lxcfs (2.0.6-0ubuntu1~16.04.1) ...
Setting up squashfs-tools (1:4.3-3ubuntu2) ...
Setting up uidmap (1:4.2-3.1ubuntu5) ...
Setting up xz-utils (5.1.1alpha+20120614-2ubuntu2) ...
update-alternatives: using /usr/bin/xz to provide /usr/bin/lzma (lzma) in auto mode
Setting up openssl (1.0.2g-1ubuntu4.6) ...
Setting up ca-certificates (20160104ubuntu1) ...
Setting up libcap-ng0:amd64 (0.7.7-1) ...
Setting up dbus (1.10.6-1ubuntu3.3) ...
Setting up dns-root-data (2015052300+h+1) ...
Setting up liblxc1 (2.0.7-0ubuntu1~16.04.2) ...
Setting up lxd (2.0.9-0ubuntu1~16.04.2) ...
apparmor_parser: Unable to replace "/usr/lib/lxd/lxd-bridge-proxy".  Permission denied; attempted to load a profile while confined?

The default LXD bridge, lxdbr0, comes unconfigured by default.
Only limited HTTP connectivity through a PROXY will be available.
To go through the initial LXD configuration, run: lxd init

Setting up lxc-common (2.0.7-0ubuntu1~16.04.2) ...
apparmor.service is not active, cannot reload.
invoke-rc.d: initscript apparmor, action "reload" failed.
apparmor_parser: Unable to replace "/usr/bin/lxc-start".  Permission denied; attempted to load a profile while confined?
Processing triggers for libc-bin (2.23-0ubuntu6) ...
Processing triggers for systemd (229-4ubuntu16) ...
Processing triggers for ureadahead (0.100.0-19) ...
Processing triggers for ca-certificates (20160104ubuntu1) ...
Updating certificates in /etc/ssl/certs...
173 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
root@c2:~#
root@c2:~# lxd init
# 質問やダイアログは全てEnterキーで進む
...(略)...
apparmor_parser: Unable to replace "/usr/lib/lxd/lxd-bridge-proxy".  Permission denied; attempted to load a profile while confined?
LXD has been successfully configured.
root@c2:~#
root@c2:~# su - ubuntu
ubuntu@c2:~$ lxc launch images:ubuntu/xenial c3
ubuntu@c2:~$ lxc exec c3 bash

ホストでプロセスを確認。

$ ps auxww | grep 'lxc exec c[1-3]'
101000    3380  0.0  0.0 141844 13336 pts/17   Sl+  23:36   0:00 lxc exec c2 bash
101000    3692  0.0  0.0 207380 12304 pts/1    Sl+  23:37   0:00 lxc exec c3 bash
hnakamur 27103  0.0  0.0 152108 14228 pts/25   Sl+  23:27   0:00 lxc exec c1 bash

apparmor_parser: Unable to replace "ファイル名". Permission denied; attempted to load a profile while confined? のエラーが気になりますが、とりあえずネストして非特権コンテナが動いているっぽいです。