如何使用 --uidmap/gidmap 和 --net-host 选项正确运行具有 containerd 的 ctr 的容器



我正在运行一个具有ctr的容器,然后使用用户名称空间将容器内的用户(根)映射到主机上的另一个用户,我想使主机网络可用于容器。为此,我使用--net-host选项。基于一个非常简单的测试容器

$ cat Dockerfile
FROM alpine
ENTRYPOINT ["/bin/sh"]

我试着用

sudo ctr run -rm --uidmap "0:1000:999" --gidmap "0:1000:999" --net-host docker.io/library/test:latest test

给出如下错误

ctr: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused "rootfs_linux.go:58: mounting \"sysfs\" to rootfs \"/run/containerd/io.containerd.runtime.v2.task/default/test/rootfs\" at \"/sys\" caused \"operation not permitted\""": unknown

如果我

  1. 删除--net-host标志或
  2. 删除--uidmap/--gidmap参数

我尝试将主机为uid=1000的用户添加到netdev组,但仍然出现相同的错误。我可能需要使用网络名称空间吗?

编辑:

同时发现这是runc内部的问题。如果我通过向config.json

添加以下内容来使用用户名称空间
"linux": {
"uidMappings": [
{
"containerID": 0,
"hostID": 1000,
"size": 999
}
],
"gidMappings": [
{
"containerID": 0,
"hostID": 1000,
"size": 999
}
],

not使用网络命名空间,这意味着省略进入

{
"type": "network"
},

"namespaces"部分,我从runc得到以下错误:

$ sudo runc run test
WARN[0000] exit status 1
ERRO[0000] container_linux.go:349: starting container process caused "process_linux.go:449: container init caused "rootfs_linux.go:58: mounting \"sysfs\" to rootfs \"/vagrant/test/rootfs\" at \"/sys\" caused \"operation not permitted\"""
container_linux.go:349: starting container process caused "process_linux.go:449: container init caused "rootfs_linux.go:58: mounting \"sysfs\" to rootfs \"/vagrant/test/rootfs\" at \"/sys\" caused \"operation not permitted\"""

终于在runc中找到了这个问题的答案。它基本上是内核中的一个限制,即不拥有网络名称空间的用户没有CAP_SYS_ADMIN功能,没有sysfs功能就不能挂载CC_14。由于容器中的根用户映射到的主机上的用户没有创建主机网络命名空间,因此那里没有CAP_SYS_ADMIN

runc问题的讨论中,我现在确实看到了以下选项:

  1. 移除sysfs的安装。

    runc使用的config.json中,删除"mounts"中的以下部分:

    {
    "destination": "/sys",
    "type": "sysfs",
    "source": "sysfs",
    "options": [
    "nosuid",
    "noexec",
    "nodev",
    "ro"
    ]
    },
    

    在我的情况下,我也无法挂载/etc/resolv.conf。通过删除这两个,容器运行良好,并具有主机网络访问。

  2. 设置从主机网络命名空间到容器网络空间的桥接(参见这里和slirp4netns)。

  3. 使用docker或podman,如果可能的话,它们似乎使用slirp4netns来实现此目的。有一个老的moby问题也可能会很有趣。

最新更新