userns 容器启动失败,如何查找原因?

0xC*_*22L 8 ubuntu lxc userns

在 Ubuntu 14.04 上使用以下命令行创建用户(非特权)LXC 容器时:

lxc-create -n test1 -t download -- -d $(lsb_release -si|tr 'A-Z' 'a-z') -r $(lsb_release -sc) -a $(dpkg --print-architecture)
Run Code Online (Sandbox Code Playgroud)

并且(不涉及创建的配置文件)然后尝试使用以下命令启动它:

lxc-start -n test1 -l DEBUG
Run Code Online (Sandbox Code Playgroud)

它失败。日志文件显示我:

lxc-start 1420149317.700 INFO     lxc_start_ui - using rcfile /home/user/.local/share/lxc/test1/config
lxc-start 1420149317.700 INFO     lxc_utils - XDG_RUNTIME_DIR isn't set in the environment.
lxc-start 1420149317.701 INFO     lxc_confile - read uid map: type u nsid 0 hostid 100000 range 65536
lxc-start 1420149317.701 INFO     lxc_confile - read uid map: type g nsid 0 hostid 100000 range 65536
lxc-start 1420149317.701 WARN     lxc_log - lxc_log_init called with log already initialized
lxc-start 1420149317.701 INFO     lxc_lsm - LSM security driver AppArmor
lxc-start 1420149317.701 INFO     lxc_utils - XDG_RUNTIME_DIR isn't set in the environment.
lxc-start 1420149317.702 DEBUG    lxc_conf - allocated pty '/dev/pts/2' (5/6)
lxc-start 1420149317.702 DEBUG    lxc_conf - allocated pty '/dev/pts/7' (7/8)
lxc-start 1420149317.702 DEBUG    lxc_conf - allocated pty '/dev/pts/8' (9/10)
lxc-start 1420149317.702 DEBUG    lxc_conf - allocated pty '/dev/pts/10' (11/12)
lxc-start 1420149317.702 INFO     lxc_conf - tty's configured
lxc-start 1420149317.702 DEBUG    lxc_start - sigchild handler set
lxc-start 1420149317.702 DEBUG    lxc_console - opening /dev/tty for console peer
lxc-start 1420149317.702 DEBUG    lxc_console - using '/dev/tty' as console
lxc-start 1420149317.702 DEBUG    lxc_console - 14946 got SIGWINCH fd 17
lxc-start 1420149317.702 DEBUG    lxc_console - set winsz dstfd:14 cols:118 rows:61
lxc-start 1420149317.905 INFO     lxc_start - 'test1' is initialized
lxc-start 1420149317.906 DEBUG    lxc_start - Not dropping cap_sys_boot or watching utmp
lxc-start 1420149317.906 INFO     lxc_start - Cloning a new user namespace
lxc-start 1420149317.906 INFO     lxc_cgroup - cgroup driver cgmanager initing for test1
lxc-start 1420149317.907 ERROR    lxc_cgmanager - call to cgmanager_create_sync failed: invalid request
lxc-start 1420149317.907 ERROR    lxc_cgmanager - Failed to create hugetlb:test1
lxc-start 1420149317.907 ERROR    lxc_cgmanager - Error creating cgroup hugetlb:test1
lxc-start 1420149317.907 INFO     lxc_cgmanager - cgroup removal attempt: hugetlb:test1 did not exist
lxc-start 1420149317.908 INFO     lxc_cgmanager - cgroup removal attempt: perf_event:test1 did not exist
lxc-start 1420149317.908 INFO     lxc_cgmanager - cgroup removal attempt: blkio:test1 did not exist
lxc-start 1420149317.908 INFO     lxc_cgmanager - cgroup removal attempt: freezer:test1 did not exist
lxc-start 1420149317.909 INFO     lxc_cgmanager - cgroup removal attempt: devices:test1 did not exist
lxc-start 1420149317.909 INFO     lxc_cgmanager - cgroup removal attempt: memory:test1 did not exist
lxc-start 1420149317.909 INFO     lxc_cgmanager - cgroup removal attempt: cpuacct:test1 did not exist
lxc-start 1420149317.909 INFO     lxc_cgmanager - cgroup removal attempt: cpu:test1 did not exist
lxc-start 1420149317.910 INFO     lxc_cgmanager - cgroup removal attempt: cpuset:test1 did not exist
lxc-start 1420149317.910 INFO     lxc_cgmanager - cgroup removal attempt: name=systemd:test1 did not exist
lxc-start 1420149317.910 ERROR    lxc_start - failed creating cgroups
lxc-start 1420149317.910 INFO     lxc_utils - XDG_RUNTIME_DIR isn't set in the environment.
lxc-start 1420149317.910 ERROR    lxc_start - failed to spawn 'test1'
lxc-start 1420149317.910 INFO     lxc_utils - XDG_RUNTIME_DIR isn't set in the environment.
lxc-start 1420149317.910 INFO     lxc_utils - XDG_RUNTIME_DIR isn't set in the environment.
lxc-start 1420149317.910 ERROR    lxc_start_ui - The container failed to start.
lxc-start 1420149317.910 ERROR    lxc_start_ui - Additional information can be obtained by setting the --logfile and --logpriority options.
Run Code Online (Sandbox Code Playgroud)

现在我在这里看到两个错误,后者可能是前者的结果,即:

lxc_start - 创建 cgroup 失败

但是,我看到/sys/fs/cgroup安装:

$ mount|grep cgr
none on /sys/fs/cgroup type tmpfs (rw)
Run Code Online (Sandbox Code Playgroud)

cgmanager已安装:

$ dpkg -l|awk '$1 ~ /^ii$/ && /cgmanager/ {print $2 " " $3 " " $4}'
cgmanager 0.24-0ubuntu7 amd64
libcgmanager0:amd64 0.24-0ubuntu7 amd64
Run Code Online (Sandbox Code Playgroud)

注意:我的主机默认仍为upstart.

如果有任何疑问,内核支持cgroups

$ grep CGROUP /boot/config-$(uname -r)
CONFIG_CGROUPS=y
# CONFIG_CGROUP_DEBUG is not set
CONFIG_CGROUP_FREEZER=y
CONFIG_CGROUP_DEVICE=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_HUGETLB=y
CONFIG_CGROUP_PERF=y
CONFIG_CGROUP_SCHED=y
CONFIG_BLK_CGROUP=y
# CONFIG_DEBUG_BLK_CGROUP is not set
CONFIG_NET_CLS_CGROUP=m
CONFIG_NETPRIO_CGROUP=m
Run Code Online (Sandbox Code Playgroud)

注意:我的主机默认仍为upstart.

0xC*_*22L 7

结果,出人意料的是,这是一个 Ubuntu 特有的东西。


原因

问题:尽管内核已cgroups启用(检查grep CGROUP /boot/config-$(uname -r))并cgmanager正在运行,但没有特定于我的用户的 cgroup。您可以通过以下方式检查:

$ cat /proc/self/cgroup
11:hugetlb:/
10:perf_event:/
9:blkio:/
8:冷冻室:/
7:设备:/
6:记忆:/
5:cpuacct:/
4:CPU:/
3:name=systemd:/
2:cpuset:/

如果在每一行中都给出了您的 UID,那就没问题,但是如果没有定义 cgroup,则每行的第二个冒号后只会有一个斜杠。

我的问题特定于启动非特权容器。我可以很好地启动特权容器。

原来我的问题与邮件列表上的这个线程lxc-users密切相关。

补救

在 Ubuntu 14.04 上upstart是默认的,而不是systemd. 因此systemd,默认情况下不会安装将安装在基于发行版的某些组件。

cgmanager为了解决我的问题中显示的错误,我还必须安装两个软件包:cgroup-binlibpam-systemd. 坦率地说,我不是 100% 肯定前者是严格需要的,因此您可以尝试将其省略并在此处发表评论。

安装软件包并重新启动后,您应该会id -u在输出中看到您的 UID(此处为 1000):

$ cat /proc/self/cgroup
11:hugetlb:/user/1000.user/1.session
10:perf_event:/user/1000.user/1.session
9:blkio:/user/1000.user/1.session
8:freezer:/user/1000.user/1.session
7:devices:/user/1000.user/1.session
6:内存:/user/1000.user/1.session
5:cpuacct:/user/1000.user/1.session
4:cpu:/user/1000.user/1.session
3:name=systemd:/user/1000.user/1.session
2:cpuset:/user/1000.user/1.session

之后,尝试启动来宾容器时的错误变为(为简洁起见修剪):

lxc-start 1420160065.383 INFO lxc_cgroup - cgroup 驱动 cgmanager 为 test1 初始化
lxc-start 1420160065.419 错误 lxc_start - 未能创建配置的网络
lxc-start 1420160065.446 错误 lxc_start - 无法生成“test1”
lxc-start 1420160065.451 错误 lxc_start_ui - 容器无法启动。

所以仍然没有成功,但我们更近了一步。

上面链接的lxc-users线程指出/etc/systemd/logind.conf没有提到三个控制器:net_cls,net_priodebug。对我来说,只有最后一个不见了。但是,更改后您必须重新登录,因为更改会在创建登录会话后生效。

LXC 的一位作者的这篇博文给出了下一步:

您的用户,虽然它可以创建新的用户命名空间,其中 uid 0 并且将对绑定到该命名空间的资源具有 root 的一些特权,但显然不会被授予对主机的任何额外特权。

其中一件事是在主机上创建新的网络设备或更改网桥配置。为了解决这个问题,我们编写了一个名为“lxc-user-nic”的工具,它是 LXC 1.0 唯一的 SETUID 二进制部分,它执行一个简单的任务。它解析一个配置文件,并根据其内容为用户创建网络设备并桥接它们。为防止滥用,您可以限制用户可以请求的设备数量以及可以添加的网桥。

一个例子是我自己的 /etc/lxc/lxc-usernet 文件:

stgraber veth lxcbr0 10
Run Code Online (Sandbox Code Playgroud)

这声明用户“stgraber”最多可以创建 10 个 veth 类型的设备并将其添加到名为 lxcbr0 的网桥。

在内核中用户命名空间提供的内容和 setuid 工具之间,我们拥有运行大多数非特权发行版所需的一切。

如果您的用户有sudo权限并且您正在使用 Bash,请使用以下命令:

echo "$(whoami) veth lxcbr0 10"|sudo tee -a /etc/lxc/lxc-usernet
Run Code Online (Sandbox Code Playgroud)

并确保类型 ( veth) 与容器配置中的类型匹配,并且网桥 ( lxcbr0) 已配置并启动。

现在我们得到另一组错误:

lxc-start 1420192192.775 INFO lxc_start - 克隆一个新的用户命名空间
lxc-start 1420192192.775 INFO lxc_cgroup - cgroup 驱动 cgmanager 为 test1 初始化
lxc-start 1420192192.923 注意 lxc_start - 在新用户命名空间中切换到 gid/uid 0
lxc-start 1420192192.923 错误 lxc_start - 权限被拒绝 - 无法访问 /home/user。请授予它“x”访问权限,或为容器根添加 ACL。
lxc-start 1420192192.923 错误 lxc_sync - 无效的序列号 1。预期为 2
lxc-start 1420192192.954 错误 lxc_start - 无法生成“test1”
lxc-start 1420192192.959 错误 lxc_start_ui - 容器无法启动。

太棒了,可以修复。与第一个线程相同的主角的另一个lxc-users线程铺平了道路。

现在必须进行快速测试sudo chmod -R o+X $HOME,但 ACL 在这里也是一个可行的选择。天啊。