43

我有一个带有 v3 的 compose 文件,其中有 3 个服务共享/使用相同的卷。在使用 swarm 模式时,我们需要创建额外的容器和卷来跨集群管理我们的服务。

我计划使用 NFS 服务器,以便将单个 NFS 共享直接安装在集群内的所有主机上。

我发现了以下两种方法,但它需要在 docker 主机上执行额外的步骤 -

有没有一种标准方法,我可以通过在 docker 主机上只执行很少/不执行步骤(我知道无论如何都需要“nfs-common”包)来使用 docker compose v3 直接使用/挂载 NFS 共享?

4

6 回答 6

71

在发现这大量未记录后,这是使用堆栈和 docker compose 挂载 NFS 卷的正确方法。

最重要的是您需要使用version: "3.2"或更高。如果不这样做,您将遇到奇怪且不明显的错误。

第二个问题是卷在其定义更改时不会自动更新。这可能会导致您陷入一个认为您的更改不正确的兔子洞,而这些更改尚未应用。确保您docker rm VOLUMENAME在任何可能存在的地方,就好像该卷存在一样,它不会被验证。

第三个问题更多的是 NFS 问题 - 如果 NFS 文件夹不存在,则不会在服务器上创建它。这正是 NFS 的工作方式。在你做任何事情之前,你需要确保它存在。

(除非您确定自己知道自己在做什么,否则不要删除 'soft' 和 'nolock' - 如果您的 NFS 服务器消失,这会阻止 docker 冻结)

这是一个完整的例子:

[root@docker docker-mirror]# cat nfs-compose.yml
version: "3.2"

services:
  rsyslog:
    image: jumanjiman/rsyslog
    ports:
      - "514:514"
      - "514:514/udp"
    volumes:
      - type: volume
        source: example
        target: /nfs
        volume:
          nocopy: true
volumes:
  example:
    driver_opts:
      type: "nfs"
      o: "addr=10.40.0.199,nolock,soft,rw"
      device: ":/docker/example"



[root@docker docker-mirror]# docker stack deploy --with-registry-auth -c nfs-compose.yml rsyslog
Creating network rsyslog_default
Creating service rsyslog_rsyslog
[root@docker docker-mirror]# docker stack ps rsyslog
ID                  NAME                IMAGE                       NODE                DESIRED STATE       CURRENT STATE                     ERROR               PORTS
tb1dod43fe4c        rsyslog_rsyslog.1   jumanjiman/rsyslog:latest   swarm-4             Running             Starting less than a second ago
[root@docker docker-mirror]#

现在,在 swarm-4 上:

root@swarm-4:~# docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS               NAMES
d883e0f14d3f        jumanjiman/rsyslog:latest   "rsyslogd -n -f /e..."   6 seconds ago       Up 5 seconds        514/tcp, 514/udp    rsyslog_rsyslog.1.tb1dod43fe4cy3j5vzsy7pgv5
root@swarm-4:~# docker exec -it d883e0f14d3f df -h /nfs
Filesystem                Size      Used Available Use% Mounted on
:/docker/example          7.2T      5.5T      1.7T  77% /nfs
root@swarm-4:~#

该卷将在堆栈运行的任何 swarm 节点上创建(但不会销毁)。

root@swarm-4:~# docker volume inspect rsyslog_example
[
    {
        "CreatedAt": "2017-09-29T13:53:59+10:00",
        "Driver": "local",
        "Labels": {
            "com.docker.stack.namespace": "rsyslog"
        },
        "Mountpoint": "/var/lib/docker/volumes/rsyslog_example/_data",
        "Name": "rsyslog_example",
        "Options": {
            "device": ":/docker/example",
            "o": "addr=10.40.0.199,nolock,soft,rw",
            "type": "nfs"
        },
        "Scope": "local"
    }
]
root@swarm-4:~#
于 2017-09-29T04:03:28.863 回答
31

根据我需要如何使用音量,我有以下 3 个选项。

首先,您可以直接创建命名卷并将其用作 compose 中的外部卷,或用作docker runordocker service create命令中的命名卷。

  # create a reusable volume
  $ docker volume create --driver local \
      --opt type=nfs \
      --opt o=nfsvers=4,addr=nfs.example.com,rw \
      --opt device=:/path/to/dir \
      foo

接下来,有适用于and的--mount语法。这是一个相当长的选项,当您在另一个逗号分隔选项中嵌入逗号分隔选项时,您需要将一些引号(转义以便 shell 不会删除它们)传递给正在运行的命令。我倾向于将它用于需要访问 NFS 的一次性容器(例如,用于设置 NFS 目录的实用程序容器):docker rundocker service create

  # or from the docker run command
  $ docker run -it --rm \
    --mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=nfs,\"volume-opt=o=nfsvers=4,addr=nfs.example.com\",volume-opt=device=:/host/path \
    foo

  # or to create a service
  $ docker service create \
    --mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=nfs,\"volume-opt=o=nfsvers=4,addr=nfs.example.com\",volume-opt=device=:/host/path \
    foo

最后,您可以在撰写文件中定义命名卷。执行此操作时的一个重要注意事项是,名称卷仅创建一次,并且不会随任何更改而更新。因此,如果您需要修改已命名的卷,您需要给它一个新名称。

  # inside a docker-compose file
  ...
  services:
    example-app:
      volumes:
      - "nfs-data:/data"
  ...
  volumes:
    nfs-data:
      driver: local
      driver_opts:
        type: nfs
        o: nfsvers=4,addr=nfs.example.com,rw
        device: ":/path/to/dir"
  ...

在每个示例中:

  • 类型设置为nfs,而不是nfs4。这是因为 docker 在addr现场提供了一些不错的功能,但仅限于nfs类型。
  • 这些o是传递给 mount 系统调用的选项。mount 系统调用和 Linux 中的 mount 命令之间的一个区别是设备在:移入addr选项之前具有部分。
  • nfsvers用于设置 NFS 版本。这避免了由于操作系统首先尝试其他 NFS 版本而造成的延迟。
  • addr使用时可能是 DNS 名称type=nfs,而不仅仅是 IP 地址。如果您有多个具有使用相同 DNS 名称的不同 NFS 服务器的 VPC,或者如果您想在将来调整 NFS 服务器而不更新每个卷挂载,这将非常有用。
  • 其他选项(例如rw(读写))可以传递给该o选项。
  • device字段是远程 NFS 服务器上的路径。前导冒号是必需的。这是 mount 命令如何将 IP 地址移动到addr系统调用字段的工件。在将卷装入容器之前,该目录必须存在于远程主机上。
  • --mount语法中,dst字段是容器内的路径。对于命名卷,您可以在命令的卷安装右侧(以简短语法)设置此路径docker run -v

如果您在访问远程 NFS 卷时遇到权限问题,我遇到的一个常见原因是容器以 root 身份运行,而 NFS 服务器设置为 root squash(将所有 root 访问权限更改为 nobody 用户)。您要么需要将容器配置为作为可以访问 NFS 服务器上的目录的众所周知的非 root UID 运行,要么在 NFS 服务器上禁用 root squash。

于 2019-06-17T13:00:56.713 回答
10

是的,您可以直接从撰写文件中引用 NFS:

volumes:
   db-data:
      driver: local
      driver_opts:
        type: nfs
        o: addr=$SOMEIP,rw
        device: ":$PathOnServer"

并且以类似的方式,您可以在每个主机上创建一个 nfs 卷。

docker volume create --driver local --opt type=nfs --opt o=addr=$SomeIP,rw --opt device=:$DevicePath --name nfs-docker
于 2017-07-24T14:27:46.803 回答
5

我的 AWS EFS 解决方案有效:

  1. 创建EFS(别忘了在安全组打开NFS 2049端口)
  2. 安装 nfs-common 包:

    sudo apt-get install -y nfs-common

  3. 检查您的 efs 是否有效:

    mkdir efs 测试点
    sudo chmod go+rw efs-测试点
    sudo mount -t nfs -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport [YOUR_EFS_DNS]:/efs-test-point
    触摸 efs-test-point/1.txt
    sudo umount efs-测试点/
    ls -la efs-测试点/

    目录必须为空

    sudo mount -t nfs -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport [YOUR_EFS_DNS]:/efs-test-point

    ls -la efs-test-point/

    文件 1.txt 必须存在

  4. 配置 docker-compose.yml 文件:

    服务:
      旁白:
        卷:
          - uploads_tmp_efs:/home/application/public/uploads/tmp
      ...
    卷:
      uploads_tmp_efs:
        司机:本地
        driver_opts:
          类型:nfs
          o: addr=[YOUR_EFS_DNS],nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2
          设备:[YOUR_EFS_DNS]:/

于 2018-10-12T15:46:47.760 回答
3

将驱动程序选项类型更改为 NFS4 解决了我的问题。

volumes:
  my-nfs-share:
    driver: local
    driver_opts:
      type: "nfs4"
      o: "addr=172.24.0.107,rw"
      device: ":/mnt/sharedwordpress"
于 2019-06-16T11:31:53.057 回答
0

如果您也使用 AutoFS,则docker-compose可以添加:shared到所有路径,如下所示:

volumes:
  - /some/nfs/mounted:/path:shared

多亏了一位同事,我发现这是处理我的案子的更好方法。我们的用户遇到错误,指出“符号链接过多”...

干杯!

于 2022-01-28T08:24:38.607 回答