Debian buster 上带有用户命名空间的 libvirt-lxc 容器并不总是可启动

Debian buster 上带有用户命名空间的 libvirt-lxc 容器并不总是可启动

我有一堆 libvirt-lxc 容器,它们的配置我已从 Debian jessie 迁移到新的 Debian buster 主机。我使用重新创建了容器的 rootfs,lxc-create -t debian -- --release buster然后使用我知道可以正常工作的脚本重新映射了 rootfs 的 uid/gid 编号。

容器配置如下:

<domain type='lxc'>
  <name>some-container</name>
  <uuid>1dbc80cf-e287-43cb-97ad-d4bdb662ca43</uuid>
  <title>Some Container</title>
  <memory unit='KiB'>2097152</memory>
  <currentMemory unit='KiB'>2097152</currentMemory>
  <memtune>
    <swap_hard_limit unit='KiB'>2306867</swap_hard_limit>
  </memtune>
  <vcpu placement='static'>1</vcpu>
  <resource>
    <partition>/machine</partition>
  </resource>
  <os>
    <type arch='x86_64'>exe</type>
    <init>/sbin/init</init>
  </os>
  <idmap>
    <uid start='0' target='200000' count='65535'/>
    <gid start='0' target='200000' count='65535'/>
  </idmap>
  <clock offset='utc'/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <devices>
    <emulator>/usr/lib/libvirt/libvirt_lxc</emulator>
    <filesystem type='mount' accessmode='passthrough'>
      <source dir='/var/lib/lxc/some-container/rootfs/'/>
      <target dir='/'/>
    </filesystem>
    <filesystem type='mount' accessmode='passthrough'>
      <source dir='/var/www/some-container/static/'/>
      <target dir='/var/www/some-container/static/'/>
    </filesystem>
    <interface type='bridge'>
      <mac address='52:54:00:a1:98:03'/>
      <source bridge='guests0'/>
      <ip address='192.0.2.3' family='ipv4' prefix='24'/>
      <ip address='2001:db8::3' family='ipv6' prefix='112'/>
      <route family='ipv4' address='0.0.0.0' prefix='0' gateway='192.0.2.1'/>
      <route family='ipv6' address='2000::' prefix='3' gateway='fe80::1'/>
      <target dev='vcontainer0'/>
      <guest dev='eth0'/>
    </interface>
    <console type='pty' tty='/dev/pts/21'>
      <source path='/dev/pts/21'/>
      <target type='lxc' port='0'/>
      <alias name='console0'/>
    </console>
    <hostdev mode='capabilities' type='misc'>
      <source>
        <char>/dev/net/tun</char>
      </source>
    </hostdev>
  </devices>
</domain>

(IP 地址已更改为使用文档/示例 IPv4/IPv6 前缀。)挂载点存在且已准备好。我有大约 15 个类似这样的容器。发生以下事情:

  • 当主机刚刚启动时,我可以执行以下任一操作:

    • 启动一个具有用户命名空间的容器,然后只启动没有用户命名空间的容器
    • 启动一个没有用户命名空间的容器,然后具有用户命名空间的容器

当我virsh -c lxc:/// start some-container在任何其他容器已启动后运行时,libvirt 声称已启动该容器:

# virsh -c lxc:/// start some-container
Domain some-container started

它在virsh -c lxc:/// list输出中也显示为正在运行,但容器的 root UID 下没有进程在运行。运行systemctl restart libvirtd使 libvirt 识别出该容器实际上已死亡,并将其再次标记为shut off正在运行。virsh -c lxc:/// list

查看 libvirt 日志时,我找不到任何有用的信息:

2019-05-09 15:38:38.264+0000: starting up
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin LIBVIRT_DEBUG=4 LIBVIRT_LOG_OUTPUTS=4:stderr /usr/lib/libvirt/libvirt_lxc --name some-container --console 25 --security=apparmor --handshake 52 --veth vnet0
PATH=/bin:/sbin TERM=linux container=lxc-libvirt HOME=/ container_uuid=1dbc80cf-e287-43cb-97ad-d4bdb662ca43 LIBVIRT_LXC_UUID=1dbc80cf-e287-43cb-97ad-d4bdb662ca43 LIBVIRT_LXC_NAME=some-container /sbin/init

(注:我尝试过使用和不使用 apparmor)

我变得非常绝望,将 strace 连接到strace -ff -o somedir/foo -plibvirtd,然后启动一个容器。经过大量挖掘,我发现 libvirt/sbin/init在容器内启动,然后容器很快以状态代码 255 退出。这是在使用 cgroups 执行某些操作后执行 EACCESS 之后的结果:

openat(AT_FDCWD, "/sys/fs/cgroup/systemd/system.slice/libvirtd.service/init.scope/cgroup.procs", O_WRONLY|O_NOCTTY|O_CLOEXEC) = -1 EACCES (Permission denied)
writev(3, [{iov_base="\33[0;1;31m", iov_len=9}, {iov_base="Failed to create /system.slice/l"..., iov_len=91}, {iov_base="\33[0m", iov_len=4}, {iov_base="\n", iov_len=1}], 4) = 105
epoll_ctl(4, EPOLL_CTL_DEL, 5, NULL)    = 0
close(5)                                = 0
close(4)                                = 0
writev(3, [{iov_base="\33[0;1;31m", iov_len=9}, {iov_base="Failed to allocate manager objec"..., iov_len=52}, {iov_base="\33[0m", iov_len=4}, {iov_base="\n", iov_len=1}], 4) = 66
openat(AT_FDCWD, "/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC) = 4
ioctl(4, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(4, TIOCGWINSZ, {ws_row=0, ws_col=0, ws_xpixel=0, ws_ypixel=0}) = 0
writev(4, [{iov_base="[", iov_len=1}, {iov_base="\33[0;1;31m!!!!!!\33[0m", iov_len=19}, {iov_base="] ", iov_len=2}, {iov_base="Failed to allocate manager objec"..., iov_len=34}, {iov_base="\n", iov_len=1}], 5) = 57
close(4)                                = 0
writev(3, [{iov_base="\33[0;1;31m", iov_len=9}, {iov_base="Exiting PID 1...", iov_len=16}, {iov_base="\33[0m", iov_len=4}, {iov_base="\n", iov_len=1}], 4) = 30
exit_group(255)                         = ?
+++ exited with 255 +++

进一步挖掘后,我发现 libvirt 并未为容器创建 Cgroup 命名空间,而且显然它们都尝试使用相同的 cgroup 路径。这样一来,这种行为就说得通了:如果启动的第一个容器是用户命名空间的,它将获得 cgroup 子树的所有权,而其他用户命名空间的容器则无法使用它。非用户命名空间的容器可以简单地接管 cgroup 树,因为它们以 UID 0 运行。

现在的问题是:为什么 cgroup 配置不正确?是 libvirt 错误吗?还是我的系统配置错误?

答案1

我想到了一个想法,尝试<partition/>为每个容器使用单独的 s,以尝试彼此隔离。

当我尝试这样做时,出现了以下错误:

error: internal error: guest failed to start: Failure in libvirt_lxc startup: Failed to create v1 controller cpu for group: No such file or directory

这其实很熟悉。我曾经打开过无效的错误报告因为这。

此错误是由于 libvirt 未正确检测 systemd 而导致的,而 systemd 又systemd-container未安装。修复方法是:

apt install systemd-container

这既解决了原始问题,也解决了我尝试解决的问题。

相关内容