如何使用 cgroup v2 从容器中获取 docker 容器 ID

How to get docker container ID from within the container with cgroup v2

由于 Docker 从引擎版本 20.10 开始支持 cgroup v2,它将自动在启用了 cgroups v2 的发行版上使用它。从容器中获取唯一容器 ID 的已知解决方案不再有效。

/ # cat /proc/self/cgroup
0::/

/ # cat /proc/1/cpuset
/

在 Debian 11 上尝试 docker v20.10.8 alpine:latest。

cgroup v1 的工作解决方案: How can I get Docker Linux container information from within the container itself?

如 docker 参考中所述,对于 cgroup v2,容器 ID 在文件系统中的以下位置仍然可见,但无法从容器本身访问。

/sys/fs/cgroup/memory/docker/<longid>/ on cgroup v1, cgroupfs driver
/sys/fs/cgroup/memory/system.slice/docker-<longid>.scope/ on cgroup v1, systemd driver
/sys/fs/cgroup/docker/<longid/> on cgroup v2, cgroupfs driver
/sys/fs/cgroup/system.slice/docker-<longid>.scope/ on cgroup v2, systemd driver

https://docs.docker.com/config/containers/runmetrics/#find-the-cgroup-for-a-given-container

编辑 1/2021-09-01:

一种解决方法是 运行 带有选项 --cgroupns host 的容器。但这需要控制容器的创建。

$ docker run -it --cgroupns host alpine cat /proc/self/cgroup
0::/system.slice/docker-09ec67119d38768dbf7994d81c325e2267214428a3c2e581c81557e3650863d8.scope

$ docker run -it alpine cat /proc/self/cgroup
0::/

问题:

有什么方法可以从内部获取唯一的容器 ID? (无需依赖容器主机名或必须使用 docker api 来获取 id)

我在尝试从 cgroup 获取容器标识时遇到了同样的问题。

但是还有另一种方法可以达到同样的目的。 Docker 容器依赖于 OverlayFS 存储驱动,每个容器都会分配一个唯一的目录,该目录映射到写入容器文件的虚拟文件系统。

root@container:~# cat /proc/self/mountinfo | grep -i overlay

767 553 0:187 / / rw,relatime master:167 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/ZTHS22AHCPD2HJEY6UIKIO3BHY:/var/lib/docker/overlay2/l/4P6QELQ6532G5362S5VVTA7Y7K,upperdir=/var/lib/docker/overlay2/76c8877e95fa589df1fb97bf831ec221df130fdfb8f1f1cb8166bd99bebf51de/diff,workdir=/var/lib/docker/overlay2/76c8877e95fa589df1fb97bf831ec221df130fdfb8f1f1cb8166bd99bebf51de/work

如上所示命令结果,upperdir=/var/lib/docker/overlay2/76c8877e95fa589df1fb97bf831ec221df130fdfb8f1f1cb8166bd99bebf51de/diff位于主机中,它只服务于分配给它的一个容器。

请注意,OverlayFS 可以替换为实现存储驱动程序规范的任何驱动程序,但upperdir信息保持相同的结构。

确保必须在容器内做出决定,因为如果在主机上部署了 LXC,主机会显示 OverlayFS 挂载信息。

这似乎无需查询 cgroup 且无需使用主机名的值即可工作,主机名有时未设置为容器 ID 的值,例如在具有 docker 执行程序的 gitlab 运行程序中。

OVERLAY_ID=`cat /proc/self/mountinfo | grep -i overlay | sed -n "s/.\+upperdir\=\(.\+\)\/diff.\+//p"`
CONTAINER_ID=`docker inspect -f $'{{.ID}}\t{{.Name}}\t{{.GraphDriver.Data.MergedDir}}' $(docker ps -aq) | grep $OVERLAY_ID | sed -n "s/\t\+.\+//p"`
echo $CONTAINER_ID

感谢@soxfmr 和这个

--cgroupns host 修复有效,但如果您不控制容器的创建则不可用。此外,此 docker run 选项在 API 或 docker 撰写 (https://github.com/compose-spec/compose-spec/issues/148) 中不可用。

但是...好消息 - 容器 ID 仍然通过 /proc/self/mountinfo:

公开
678 655 254:1 /docker/containers/7a0144cee1256c539fab790199527b7051aff1b603ebcf7ed3fd436440ef3b3a/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/vda1 rw
679 655 254:1 /docker/containers/7a0144cee1256c539fab790199527b7051aff1b603ebcf7ed3fd436440ef3b3a/hostname /etc/hostname rw,relatime - ext4 /dev/vda1 rw
680 655 254:1 /docker/containers/7a0144cee1256c539fab790199527b7051aff1b603ebcf7ed3fd436440ef3b3a/hosts /etc/hosts rw,relatime - ext4 /dev/vda1 rw

这里有一个 Python 片段可以解析它:

with open( '/proc/self/mountinfo' ) as file:
    line = file.readline().strip()    
    while line:
        if '/docker/containers/' in line:
            containerID = line.split('/docker/containers/')[-1]     # Take only text to the right
            containerID = containerID.split('/')[0]                 # Take only text to the left
            break
        line = file.readline().strip()

归功于 richgriswold:https://community.toradex.com/t/python-nullresource-error-when-running-torizoncore-builder-build/15240/4