使用Docker时,文件属于subuid/subgid导致的问题

33次阅读
没有评论

问题描述

在使用Docker时,希望确保所有与项目一起工作的人和自动化进程使用相同的工具版本和环境,这些工具需要在主机文件系统上进行操作。
用户使用了一个类似于以下的包装/代理脚本来运行工具:

docker run -ti --rm \
  -v $PWD:/workdir \
  -v $HOME/.ssh:/root/.ssh \
  dockerizedxyz "$@"

这个方法运行得很好,但是…

解决方案

请注意以下操作注意版本差异及修改前做好备份。

方案1

显然,如果只使用上述方法,那么容器内部运行的工具创建的文件将属于主机上的root用户。这是可以理解的,也是预期的结果。
为了解决这个问题,我们可以为Docker守护进程启用用户命名空间。这个方法也可以正常工作。主机用户的UID是1000,subuid是493216。
如果我在一个属于1000的目录(在主机上)中运行docker-xyz-shim,并且容器开始创建文件,我最初的期望是这些文件会以1000的身份属于主机(即正向和反向映射)。
但是,它们实际上属于493216,即它们属于subuid而不是主机uid。只有正向映射(从主机uid到subuid),没有反向映射(从subuid到主机uid)。
我理解这是为什么,也知道这是预期的工作方式。首先,涉及到1:n的映射,将潜在的65536个subuid映射回一个主机uid是非常复杂的。这种设计允许我们在其他用例中做各种实用的事情。但是在我的特定情况下,我希望文件最终属于主机上的1000。
有没有什么办法可以解决这个问题呢?

方案2

使用脚本或工具来管理容器的启动顺序可能会增加复杂性,并且需要确保容器A和容器B之间的依赖关系正确设置。
另一种方法是编写脚本或使用工具来控制容器的运行顺序。你可以使用docker run命令来手动控制容器的启动顺序,或者使用一些第三方工具来管理容器的依赖关系。

示例:

以下是一个简单的bash脚本示例,可以在容器A启动后启动容器B:

#!/bin/bash
# 启动容器A
docker run -d --name container_a your_image_a
# 等待容器A完全启动
while ! docker exec container_a echo "Container A is ready"; do
  sleep 1
done
# 启动容器B
docker run -d --name container_b your_image_b

在这个示例中,我们首先使用docker run命令启动容器A,并将其命名为container_a。然后,使用一个循环来等待容器A完全启动(这里是通过在容器内运行echo命令来测试)。一旦容器A就绪,我们再使用docker run命令启动容器B,并将其命名为container_b

方案3

如果你不想使用Docker,还可以考虑使用habitat。Habitat可以隔离进程和它们自己的库,但不包括文件系统隔离和uid分离。

方案4

请注意以下操作注意版本差异及修改前做好备份。
你可以尝试以下命令,只要容器的entrypoint没有做任何奇怪的事情,它就会将文件的所有者设置为调用Docker的用户。

docker run -ti --rm \
  -v $PWD:/workdir \
  -v $HOME/.ssh:/root/.ssh \
  --user $(id -u):$(id -g) \
  dockerizedxyz "$@"

只要你在Docker镜像中的用户ID和组ID已经存在,这个方法就可以正常工作。

总结

在使用Docker时,如果希望容器内部创建的文件属于主机上的特定用户,可以通过启用用户命名空间或使用--user选项来实现。这样可以确保文件的所有者与调用Docker的用户一致。

正文完