Docker Swarm 是如何实现卷共享的?
How does Docker Swarm implement volume sharing?
Docker Swarm 可以管理两种类型的存储:
volume
和 bind
虽然 Docker 文档不建议 bind
,因为它在本地目录(在每个 swarm 节点上)与任务之间创建绑定,但未提及 volume
实现,所以我不明白任务之间如何共享卷?
- Docker Swarm 如何在节点之间共享卷?
- 卷保存在哪里(在一个管理器上?如果有多个管理器?)
- 在不同网络的不同机器上运行节点之间没有问题吗?
- 它会创建 VPN 吗?
您问的是一个常见问题。卷数据和该卷的功能由卷驱动程序管理。就像您可以使用不同的网络驱动程序,如 overlay
、bridge
或 host
,您可以使用不同的卷驱动程序。
Docker 和 Swarm 仅随附开箱即用的标准 local
驱动程序。它对 Swarm 没有任何感知,它只会在您的服务任务安排在哪个节点上为您的数据创建新卷。这通常不是你想要的。
您需要一个支持 Swarm 的第 3 方驱动程序插件,并将确保您为服务任务创建的卷在正确的时间在正确的节点上可用。选项包括使用 "Docker for AWS/Azure" 及其包含的 CloudStor driver, or the popular open source REX-Ray 解决方案。
有很多第 3 方卷驱动程序,您可以在 Docker Store.
上找到它们
Swarm 模式本身对卷没有任何不同,它运行您在容器 运行 所在的节点上提供的任何卷安装命令。如果您的卷挂载在该节点本地,那么您的数据将保存在该节点本地。没有在节点之间自动移动数据的内置功能。
有一些基于软件的分布式存储解决方案,如 GlusterFS,Docker 有一个名为 Infinit 的解决方案尚未正式发布,其开发已退居 EE 中的 Kubernetes 集成。
典型的结果是您要么需要在应用程序中管理存储复制(例如 etcd 和其他基于 raft 的算法),要么在外部存储系统上执行挂载(希望有自己的 HA)。安装外部存储系统有两个选项,基于块或基于文件。基于块的存储(例如 EBS)通常具有更高的性能,但仅限于安装在单个节点上。为此,您通常需要一个第三方卷插件驱动程序来为您的 docker 节点提供对该块存储的访问权限。基于文件的存储(例如EFS)性能较低,但更便携,并且可以同时挂载在多个节点上,这对于复制服务很有用。
最常见的基于文件的网络存储是 NFS(这与 EFS 使用的协议相同)。您可以在没有任何 3rd 方插件驱动程序的情况下安装它。不幸的是 docker 附带的名为 "local" 的卷插件驱动程序让您可以选择将您想要的任何值传递给带有驱动程序选项的 mount 命令,如果没有选项,它默认将卷存储在 docker目录/var/lib/docker/volumes。使用选项,您可以将 NFS 参数传递给它,它甚至会在 NFS 主机名上执行 DNS 查找(NFS 通常没有的东西)。下面是使用本地卷驱动程序挂载 NFS 文件系统的不同方法的示例:
# create a reusable volume
$ docker volume create --driver local \
--opt type=nfs \
--opt o=nfsvers=4,addr=192.168.1.1,rw \
--opt device=:/path/to/dir \
foo
# 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=192.168.1.1\",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=192.168.1.1\",volume-opt=device=:/host/path \
foo
# inside a docker-compose file
...
volumes:
nfs-data:
driver: local
driver_opts:
type: nfs
o: nfsvers=4,addr=192.168.1.1,rw
device: ":/path/to/dir"
...
如果您在最后使用撰写文件示例,请注意,只要卷存在,对卷的更改(例如更新服务器路径或地址)就不会反映在现有的命名卷中。您需要重命名您的卷或将其删除,以允许 swarm 使用新值重新创建它。
我在大多数 NFS 使用中看到的另一个常见问题是 "root squash" 在服务器上启用。当容器 运行 作为 root 尝试将文件写入卷时,这会导致权限问题。您也有类似的 UID/GID 权限问题,其中容器 UID/GID 是需要写入卷的权限的容器,这可能需要在 NFS 服务器上调整目录所有权和权限。
我的 AWS EFS 解决方案有效:
- Create EFS(别忘了在安全组打开NFS 2049端口)
安装nfs-common包:
sudo apt-get install -y nfs-common
检查您的 efs 是否有效:
mkdir efs-test-point
sudo chmod go+rw efs-test-point
sudo mount -t nfs -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport [YOUR_EFS_DNS]:/ efs-test-point
touch efs-test-point/1.txt
sudo umount efs-test-point/
ls -la efs-test-point/
directory must be empty
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/
file 1.txt must exists
配置docker-compose.yml文件:
services:
sidekiq:
volumes:
- uploads_tmp_efs:/home/application/public/uploads/tmp
...
volumes:
uploads_tmp_efs:
driver: local
driver_opts:
type: nfs
o: addr=[YOUR_EFS_DNS],nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2
device: [YOUR_EFS_DNS]:/
我对本地托管群的解决方案:
每个工作节点都安装了一个 nfs 共享,由我们的文件服务器在 /mnt/docker-data
上提供。当我在服务组合文件中定义卷时,我将设备设置为 /mnt/docker-data
下的某个路径,例如:
volumes:
traefik-logs:
driver: local
driver_opts:
o: bind
device: /mnt/docker-data/services/traefik/logs
type: none
使用此解决方案,docker 在每个节点上创建卷,将服务部署到 - 令人惊讶的是 - 已经有数据,因为它是相同的路径,被卷上的卷使用其他节点。
如果您仔细查看节点文件系统,您会发现我的文件服务器挂载是在 /var/lib/docker/volumes
下创建的,请参见此处:
root@node-3:~# df -h
Dateisystem Größe Benutzt Verf. Verw% Eingehängt auf
[...]
fs.mydomain.com:/srv/shares/docker-data/services/traefik/logs 194G 141G 53G 73% /var/lib/docker/volumes/traefik_traefik-logs/_data
默认情况下,swarm 总是会寻找本地卷驱动程序,所以最好的方法是
- 创建 nfs 共享,即
yum -y install nfs-utils
- 将其导出到 /etc/exports 中,如下所示,
/root/nfshare 192.168.1.0/24(rw,sync,no_root_squash)
- 打开所需的端口,在我的例子中,我在下面做了,
firewall-cmd --permanent --add-service mountd ; firewall-cmd --permanent --add-service rpc-bind ; firewall-cmd --permanent --add-service nfs ; firewall-cmd --zone=public --permanent --add-port 2049/tcp
- 在 docker 个工作节点上安装新创建的共享,然后
docker service create --name my-web --replicas 3 -p 80:80 --mount 'type=volume,source=nfshare,target=/usr/share/nginx/html/,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/root/nfshare,"volume-opt=o=addr=192.168.1.8,rw"' nginx:latest
- 在上面的示例中,我在 192.168.1.8 主机上创建了 nfshare 并使用 /etc/exports 文件
导出
- 已启动守护进程
systemctl start nfs-server rpcbind & systemctl enable nfs-server rpcbind
- exportfs -r 使更改生效
- /root/nfshare 有我自己的 index.html
10.check 仔细输入卷驱动器,它也可以是外部的 & 哇,它对我有用
- 更多参考https://docs.docker.com/storage/volumes/
Docker Swarm 可以管理两种类型的存储:
volume
和 bind
虽然 Docker 文档不建议 bind
,因为它在本地目录(在每个 swarm 节点上)与任务之间创建绑定,但未提及 volume
实现,所以我不明白任务之间如何共享卷?
- Docker Swarm 如何在节点之间共享卷?
- 卷保存在哪里(在一个管理器上?如果有多个管理器?)
- 在不同网络的不同机器上运行节点之间没有问题吗?
- 它会创建 VPN 吗?
您问的是一个常见问题。卷数据和该卷的功能由卷驱动程序管理。就像您可以使用不同的网络驱动程序,如 overlay
、bridge
或 host
,您可以使用不同的卷驱动程序。
Docker 和 Swarm 仅随附开箱即用的标准 local
驱动程序。它对 Swarm 没有任何感知,它只会在您的服务任务安排在哪个节点上为您的数据创建新卷。这通常不是你想要的。
您需要一个支持 Swarm 的第 3 方驱动程序插件,并将确保您为服务任务创建的卷在正确的时间在正确的节点上可用。选项包括使用 "Docker for AWS/Azure" 及其包含的 CloudStor driver, or the popular open source REX-Ray 解决方案。
有很多第 3 方卷驱动程序,您可以在 Docker Store.
上找到它们Swarm 模式本身对卷没有任何不同,它运行您在容器 运行 所在的节点上提供的任何卷安装命令。如果您的卷挂载在该节点本地,那么您的数据将保存在该节点本地。没有在节点之间自动移动数据的内置功能。
有一些基于软件的分布式存储解决方案,如 GlusterFS,Docker 有一个名为 Infinit 的解决方案尚未正式发布,其开发已退居 EE 中的 Kubernetes 集成。
典型的结果是您要么需要在应用程序中管理存储复制(例如 etcd 和其他基于 raft 的算法),要么在外部存储系统上执行挂载(希望有自己的 HA)。安装外部存储系统有两个选项,基于块或基于文件。基于块的存储(例如 EBS)通常具有更高的性能,但仅限于安装在单个节点上。为此,您通常需要一个第三方卷插件驱动程序来为您的 docker 节点提供对该块存储的访问权限。基于文件的存储(例如EFS)性能较低,但更便携,并且可以同时挂载在多个节点上,这对于复制服务很有用。
最常见的基于文件的网络存储是 NFS(这与 EFS 使用的协议相同)。您可以在没有任何 3rd 方插件驱动程序的情况下安装它。不幸的是 docker 附带的名为 "local" 的卷插件驱动程序让您可以选择将您想要的任何值传递给带有驱动程序选项的 mount 命令,如果没有选项,它默认将卷存储在 docker目录/var/lib/docker/volumes。使用选项,您可以将 NFS 参数传递给它,它甚至会在 NFS 主机名上执行 DNS 查找(NFS 通常没有的东西)。下面是使用本地卷驱动程序挂载 NFS 文件系统的不同方法的示例:
# create a reusable volume
$ docker volume create --driver local \
--opt type=nfs \
--opt o=nfsvers=4,addr=192.168.1.1,rw \
--opt device=:/path/to/dir \
foo
# 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=192.168.1.1\",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=192.168.1.1\",volume-opt=device=:/host/path \
foo
# inside a docker-compose file
...
volumes:
nfs-data:
driver: local
driver_opts:
type: nfs
o: nfsvers=4,addr=192.168.1.1,rw
device: ":/path/to/dir"
...
如果您在最后使用撰写文件示例,请注意,只要卷存在,对卷的更改(例如更新服务器路径或地址)就不会反映在现有的命名卷中。您需要重命名您的卷或将其删除,以允许 swarm 使用新值重新创建它。
我在大多数 NFS 使用中看到的另一个常见问题是 "root squash" 在服务器上启用。当容器 运行 作为 root 尝试将文件写入卷时,这会导致权限问题。您也有类似的 UID/GID 权限问题,其中容器 UID/GID 是需要写入卷的权限的容器,这可能需要在 NFS 服务器上调整目录所有权和权限。
我的 AWS EFS 解决方案有效:
- Create EFS(别忘了在安全组打开NFS 2049端口)
安装nfs-common包:
sudo apt-get install -y nfs-common
检查您的 efs 是否有效:
mkdir efs-test-point sudo chmod go+rw efs-test-point
sudo mount -t nfs -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport [YOUR_EFS_DNS]:/ efs-test-point
touch efs-test-point/1.txt sudo umount efs-test-point/ ls -la efs-test-point/
directory must be empty
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/
file 1.txt must exists
配置docker-compose.yml文件:
services: sidekiq: volumes: - uploads_tmp_efs:/home/application/public/uploads/tmp ... volumes: uploads_tmp_efs: driver: local driver_opts: type: nfs o: addr=[YOUR_EFS_DNS],nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 device: [YOUR_EFS_DNS]:/
我对本地托管群的解决方案:
每个工作节点都安装了一个 nfs 共享,由我们的文件服务器在 /mnt/docker-data
上提供。当我在服务组合文件中定义卷时,我将设备设置为 /mnt/docker-data
下的某个路径,例如:
volumes:
traefik-logs:
driver: local
driver_opts:
o: bind
device: /mnt/docker-data/services/traefik/logs
type: none
使用此解决方案,docker 在每个节点上创建卷,将服务部署到 - 令人惊讶的是 - 已经有数据,因为它是相同的路径,被卷上的卷使用其他节点。
如果您仔细查看节点文件系统,您会发现我的文件服务器挂载是在 /var/lib/docker/volumes
下创建的,请参见此处:
root@node-3:~# df -h
Dateisystem Größe Benutzt Verf. Verw% Eingehängt auf
[...]
fs.mydomain.com:/srv/shares/docker-data/services/traefik/logs 194G 141G 53G 73% /var/lib/docker/volumes/traefik_traefik-logs/_data
默认情况下,swarm 总是会寻找本地卷驱动程序,所以最好的方法是
- 创建 nfs 共享,即
yum -y install nfs-utils
- 将其导出到 /etc/exports 中,如下所示,
/root/nfshare 192.168.1.0/24(rw,sync,no_root_squash)
- 打开所需的端口,在我的例子中,我在下面做了,
firewall-cmd --permanent --add-service mountd ; firewall-cmd --permanent --add-service rpc-bind ; firewall-cmd --permanent --add-service nfs ; firewall-cmd --zone=public --permanent --add-port 2049/tcp
- 在 docker 个工作节点上安装新创建的共享,然后
docker service create --name my-web --replicas 3 -p 80:80 --mount 'type=volume,source=nfshare,target=/usr/share/nginx/html/,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/root/nfshare,"volume-opt=o=addr=192.168.1.8,rw"' nginx:latest
- 在上面的示例中,我在 192.168.1.8 主机上创建了 nfshare 并使用 /etc/exports 文件 导出
- 已启动守护进程
systemctl start nfs-server rpcbind & systemctl enable nfs-server rpcbind
- exportfs -r 使更改生效
- /root/nfshare 有我自己的 index.html 10.check 仔细输入卷驱动器,它也可以是外部的 & 哇,它对我有用
- 更多参考https://docs.docker.com/storage/volumes/