docker:使用正确的权限迁移卷

docker:使用正确的权限迁移卷

我对 docker 卷的权限有疑问。

我现在已经在多台服务器上设置了 docker,对于某些容器,我使用绑定挂载点,对于其他容器,我使用命名卷,对我来说这似乎是一样的 - 我看到的唯一区别是目录(/var/lib/docker/volumes/...或自行选择)。

现在我有一个有关 docker 部署最佳实践的问题。

UID 和 GUID 与主机系统共享。假设容器 A 有一个以用户 db 身份运行的应用程序,UID 为 800,相应的卷上有非常重要的生产数据。在我的主机系统上,UID 800 基本上可以是任何服务,假设它是一种易于接管的服务。该服务可能会访问容器的数据。

在这种情况下,最好使用命名卷,因为它们位于受保护的目录中,以防止普通用户访问,或者至少不在公共位置(/,/srv,...)创建卷,

当我最初创建命名卷时,它会在 内创建/var/lib/docker/volumes/...。大多数情况下,这意味着容器内不以 root 身份运行的应用程序无法在卷上创建任何文件。因此,每个需要特定文件夹和权限的应用程序都必须在 ENTRYPOINT 脚本中设置它,然后再移交给应用程序。

这是预期的行为吗?现在如何移动命名卷?Docker 似乎不支持开箱即用。我见过很多方法,只使用 tar 或创建一个导出卷的容器,但这似乎很难自动化。有没有更简单/官方/可编写脚本的方法来迁移(命名)卷,最好是通过创建一个易于导入的 tarball?还是我在这里误解了什么?

答案1

大多数情况下,这意味着容器内未以 root 身份运行的应用程序无法在卷上创建任何文件。

仅当您用于创建命名卷的映像中没有目录,或者映像中的目录不属于正确的用户时,才会出现这种情况。 /var/lib/docker 被锁定为仅允许 root 用户,但绝不会阻止容器以用户身份使用该目录内的卷。

命名卷通常具有较少的权限问题,因为它们将使用给定位置的映像内容进行初始化。当您创建映像以及该映像内的用户时,您需要在映像构建过程中对用户需要访问的任何目录进行 chown/chmod 操作。我从尝试此操作的人那里看到可能出现的问题:

  • 在 Dockerfile 中定义卷,然后尝试更新目录。这不会起作用,在 RUN 命令期间,目录将作为卷安装在临时容器中,并且 RUN 命令完成后,对该卷的任何更改都将被丢弃。如果您可以控制卷定义,我通常建议从 Dockerfile 中删除它们。

  • 在运行时将用户更改为与映像内的 uid 不同的 uid。在这种情况下,映像未正确设置目录权限,并且会错误地初始化命名卷。由于您在运行时更改了 uid,因此您需要使用入口点或装载相同卷的第二个容器在运行时修复权限。

  • 在某人已经部署了基于旧版本的命名卷的容器后,修改映像内的 uid 或目录。命名卷仅在为空时才初始化,因此更改映像不会更改现在具有错误所有者/权限的现有卷。

  • 两个不同的容器同时使用同一个命名卷。在这种情况下,命名卷将被初始化一次,而使用哪个映像来初始化该卷的问题是一个竞争条件,取决于哪个容器先被创建。

请注意,主机卷的安全风险在于,主机上的易受攻击的应用程序(使用与容器内特权应用程序相同的 UID 运行)可以访问该容器。虽然这不太好,但并不是容器逃逸。

您可以启用用户命名空间来避免这种风险,但这样做时请注意,有意映射到主机上的用户或组的主机卷将不再起作用,包括开发人员为快速开发而安装的代码,以及安装 docker 套接字进行管理的工具。由于用户命名空间是在整个 docker 实例上实现的,而不是每个容器,因此您需要确保在进行更改之前不存在它们无法正常工作的情况。

将数据移入和移出命名卷始终使用 tar 和 docker I/O 重定向,但如果将所有权从主机更改为容器,则需要在此之后添加 chmod/chown 步骤:

# import data
tar -cC source_dir . | \
  docker run --rm -i -v target_vol:/target busybox tar -xC /target
# export data
docker run --rm -v source_vol:/source busybox tar -cC /source . | \
  tar -xC target_dir

相关内容