NFS 共享上的 Docker 卷 - 空目录

mr.*_*ski 1 nfs share nfs4 docker

我们的业务应用程序在两个节点(节点 1 和节点 2)上运行 Docker Swarm 部署。

应用程序需要一个卷来存储持久数据。由于尚不清楚容器部署在哪里(节点 1 或节点 2),并且应用程序的两个容器可能应该在两个节点上运行,因此我们需要一个解决方案来为所有节点提供共享卷。

为了共享卷,我们使用以下 /etc/exports 文件在第三个节点 3 上设置 NFS 服务器:

/srv          *(rw,sync,anonuid=1000,anongid=1000,all_squash,subtree_check,crossmnt,fsid=root)
Run Code Online (Sandbox Code Playgroud)

(我使用 anonuid/gid 为导出中的每个文件显式设置 node3 系统中已知用户的用户信息。 all_squash 用于确保所有访问用户的所有文件权限都重写给该本地用户)

在我们的 docker-compose.yml 中,我们使用以下设置来包含卷:

volumes:
  nfs-data:
    driver: local
    driver_opts:
      type: nfs
      o: nfsvers=4,addr=node3.example.com,rw,nolock,soft
Run Code Online (Sandbox Code Playgroud)

我们现在遇到了一个问题,容器只是不想启动,错误消息是:

failed to copy file info for /var/lib/docker/volumes/MY_CONTAINER_nfs-data/_data: failed to chown /var/lib/docker/volumes/MY_CONTAINER_nfs-data/_data: lchown /var/lib/docker/volumes/MY_CONTAINER_nfs-data/_data: operation not permitted
Run Code Online (Sandbox Code Playgroud)

经过一番挖掘后,我发现问题在于 Node3 服务器上导出的 NFS 目录上的初始空文件夹。一旦我放入一个空文件,节点 1 和节点 2 中的容器启动就完全正常。

有人对此有解释吗?

BMi*_*tch 5

当命名卷从空/新状态初始化时,docker 会将镜像目录的内容复制到命名卷中。有几种选择可以解决这个问题:

  1. 在容器启动之前用内容初始化命名卷。正如您所看到的,这会禁用卷初始化步骤。
  2. 更新映像以在目录上具有所需的 uid/gid 并包含带有RUN chown -R 1000:1000 /path. 这应该可以防止出现问题,但您需要进行测试以确保仍然没有 chown 尝试从 docker 运行,具体取决于它初始化这些文件的方式。
  3. 禁用 NFS 上的压缩。这是 docker 卷出现问题的常见原因,我不确定您可以获得什么安全优势。如果您确实需要避免 root,您可以尝试使用用户命名空间配置 docker,但这会破坏您假设 uid 匹配的主机卷,因此请做好准备。
  4. 禁用卷初始化。在当前的 compose 规范中,您可以使用长语法将“nocopy”选项添加到服务卷规范中。这是在使用卷的服务上完成的,而不是在定义卷的顶层完成的。

docker 文档中有关“nocopy”选项的示例如下所示:

version: "3.8"
services:
  web:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - type: volume
        source: mydata
        target: /data
        volume:
          nocopy: true

volumes:
  mydata:
Run Code Online (Sandbox Code Playgroud)