Docker swarm 数据持久化
Docker swarm 数据持久化是通过把宿主机的文件系统映射到容器中实现的。实现的方式主要有以下三种:
数据卷挂载(volume mounts)
绑定挂载(bind mounts)
volume NFS共享存储模式(推荐)
一,数据卷挂载
卷是绕过联合文件系统的一个或多个容器内的特定目录。卷被设计为保持数据,与容器的生命周期无关。因此,Docker在删除容器时不会自动删除卷,也不会“垃圾收集”不再由容器引用的卷。也称为:数据卷。 需要更详细了解volume可参考官方文档[1] 使用service的方式创建的volume数据卷,该service中的容器只会使用其所在节点服务器的中的volume。当使用本地数据卷驱动时,所用的容器都无法共享其数据。
创建数据卷
docker@manager1:~$ docker volume create 321
321
复制
docker@manager1:~$ docker volume ls
DRIVER VOLUME NAME
local 279da60b1cfc623e3a728a9c0dddca06809105892d6c6c89dc18e077cb0ebdfc
local 321
复制
查看数据卷详细信息
docker volume inspect <VOLUME-NAME>
复制
docker@manager1:~$ docker volume inspect 321
[
{
"CreatedAt": "2020-01-13T09:27:17Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/mnt/sda1/var/lib/docker/volumes/321/_data", # 本地位置
"Name": "321",
"Options": {},
"Scope": "local"
}
]
复制
docker@manager1:/mnt/sda1/var/lib/docker$ sudo -i
root@manager1:~# cd mnt/sda1/var/lib/docker/volumes/321/_data/
root@manager1:/mnt/sda1/var/lib/docker/volumes/321/_data# ll
root@manager1:/mnt/sda1/var/lib/docker/volumes/321/_data# ls -l
total 0
复制
docker@manager1:~$ docker service create --name mysql_volume_test --mount type=volume,src=321,dst=/root/my_volume --network mynet --replicas 2 haoxy/mysql:5.6
ms76afxdmswkrxhegdixwmm3i
overall progress: 2 out of 2 tasks
1/2: running [==================================================>]
2/2: running [==================================================>]
verify: Service converged
复制
docker@manager1:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
06ef0693cec6 haoxy/mysql:5.6 "/run.sh" 12 seconds ago Up 11 seconds 3306/tcp mysql_volume_test.2.si4z4ko1jw38uvsc7cquu54pd
docker@manager1:~$ docker exec -it 06e bin/bash
root@06ef0693cec6:/# df
Filesystem 1K-blocks Used Available Use% Mounted on
overlay 18714000 1750776 15974096 10%
tmpfs 65536 0 65536 0% dev
tmpfs 506608 0 506608 0% sys/fs/cgroup
shm 65536 0 65536 0% dev/shm
/dev/sda1 18714000 1750776 15974096 10% root/my_volume
tmpfs 506608 0 506608 0% proc/asound
tmpfs 506608 0 506608 0% proc/acpi
tmpfs 506608 0 506608 0% /proc/scsi
tmpfs 506608 0 506608 0% /sys/firmware
root@06ef0693cec6:/# cd root/
root@06ef0693cec6:~# ls
my_volume
root@06ef0693cec6:~# cd my_volume/
root@06ef0693cec6:~/my_volume# ls -l
total 0
复制
加入属性
docker service create --name mysql_volume_test --mount type=volume,src=321,dst=/root/my_volume,readonly --network mynet --replicas 2 haoxy/mysql:5.6
复制
readonly /root/my_volume 只可以读
为原来的服务添加volume
[root@docker ~]# docker service update website-test --mount-add type=volume,source=data,target=/var/lib/data
复制
二、 bind 方式
与卷相比,(bind)绑定挂到具有有限的功能。当您使用绑定挂载时,宿主机上的文件或目录被挂载到容器中。文件或目录由宿主机上的完整路径或相对路径引用(宿主机上的文件或目录要存在)。相比之下,当您使用卷时,会在宿主机上的Docker存储目录中创建一个新目录,并且Docker会管理该目录的内容。该文件或目录不需要已经存在于Docker宿主机上。如果它尚不存在,它会根据需求创建。绑定挂载非常高效,但它们依赖于具有特定目录结构的主机的文件系统。
读写挂载
docker service create \
--mount type=bind,src=<HOST-PATH>,dst=<CONTAINER-PATH> \
--name myservice \
<IMAGE>
复制
只读挂载
docker service create \
--mount type=bind,src=<HOST-PATH>,dst=<CONTAINER-PATH>,readonly \
--name myservice \
<IMAGE>
复制
例:
docker service create --name nginx --mount type=bind,target=/usr/share/nginx/html/,source=/opt/web/ --replicas 2 --publish 80:80/tcp nginx
docker service create --name bind --mount type=bind,src=/root/db_data,dst=/root/db_data --network mynet --replicas 2 website:7.7
docker service create --name bind --mount type=bind,src=/root/db_data,dst=/root/db_data,readonly --network mynet --replicas 2 website:7.7
复制
重要:虽然绑定挂载能用,但是也有可能导致一些问题:[2]
如果你挂载了一个主机路径到你的服务容器中,那么这个路径必须存在于 Swarm 集群中的每一个节点。Docker Swarm 调度器会把容器调度到任何满足资源可用性和满足你特定约束、位置偏好的节点上。 如果运行中的容器变得不健康或者不可用,那么 Docker Swarm 调度器可能会随时重新安排它。 主机绑定挂载是完全不可移植的。当你使用绑定挂载时,不能保证你的应用在开发中的运行方式与在生产中的运行方式相同。
三、通过nfs实现数据持久化
整理[3]
NFS(Network File System)即网络文件系统,是FreeBSD支持的文件系统中的一种,它允许网络中的计算机之间通过TCP/IP网络共享资源。在NFS的应用中,本地NFS的客户端应用可以透明地读写位于远端NFS服务器上的文件,就像访问本地文件一样。
3.1 环境部署
nfs服务器:创建/nfs目录 nfs客户端:不需要在nfs客户端提前mount,在Manager上创建副本的时候指定参数自动mount到nfs服务端
1、nfs服务端部署
[root@nfs ~]# yum -y install nfs-utils
[root@nfs ~]# mkdir /nfs
[root@nfs ~]# vim /etc/exports
/nfs 172.18.18.0/24(rw,sync,no_root_squash)
[root@nfs ~]# systemctl restart nfs
复制
nfs参数说明:
/nfs:nfs上的共享目录; 172.18.18.0/24:网络中可以访问这个NFS输出目录的主机; rw:共享目录的权限,rw 是可读写的权限,只读的权限是ro; sync:同步,数据更安全,速度慢; async:异步,速度快,效率高,安全性低; no_root_squash:NFS 服务共享的目录的属性, 如果用户是root, 对这个目录就有root的权限;
2、nfs客户端部署
在swarm集群所有节点安装部署:
[root@Manager ~]# yum -y install nfs-utils
[root@agent01 ~]# yum -y install nfs-utils
[root@agent02 ~]# yum -y install nfs-utils
复制
3.2 使用格式
#docker service create \
--replicas 1或2或3... \
--name myservice \
--mount \
'type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>, \
volume-driver=local,volume-opt=type=nfs,volume-opt=device=<nfs-server>:<nfs-path>, \
"volume-opt=o=addr=<nfs-address>,vers=4,soft,timeo=180,bg,tcp,rw"' \
<IMAGE>
复制
3.3 案例演示
1、演示
我们还是在Manager上创建nginx副本来演示,同样把nfs共享目录:/nfs挂载到副本的(/ysr/share/nginx/html)目录中。
[root@Manager ~]# docker service create --replicas 3 --name web-nfs --mount 'type=volume,src=nfs-vol,dst=/usr/share/nginx/html,volume-driver=local,volume-opt=type=nfs,volume-opt=device=:/nfs,"volume-opt=o=addr=172.18.18.90,vers=4,soft,timeo=180,bg,tcp,rw"' nginx
复制
参数说明:
--replicas:创建3个nginx副本; --name:自定义命名为web-nfs; type=volume:必须为volume挂载,不能用bind的挂载方式; src:src挂载源为nginx-vol,相当于执行了docker volume nginx-vol; dst:dst挂载目的路径为nginx容器中的路径/usr/share/nginx/html; volume-opt=type=nfs:指定挂载卷类型为nfs模式; volume-opt=device=:/nfs:这是nfs服务器共享目录的名称; "volume-opt=o=addr=172.18.18.90:指定nfs服务器地址; vers=4,soft,timeo=180,bg,tcp,rw:指定nfs版本号、超时时间、后台挂载、协议可选TCP/UDP、读写权限等信息; nginx:通过nginx镜像来运行;
2、查看副本运行信息
[root@Manager ~]# docker service ps web-nfs
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
q67t67ucdba2 web-nfs.1 nginx:latest agent01 Running Running 12 minutes ago
3cs5jh8chegz web-nfs.2 nginx:latest Manager Running Running 10 minutes ago
0hykerf7n3a4 web-nfs.3 nginx:latest agnet02 Running Running 13 minutes ago
复制
3个nginx副本分别分配到了swarm集群的3个节点上。
3、df 查看文件挂载信息,省略无用信息
[root@Manager ~]# df -h
Filesystem Size Used Avail Use% Mounted on
...
:/nfs 50G 9.6G 41G 20% /var/lib/docker/volumes/nfs-vol/_data
...
复制
你在其它几个agnet节点上df查看也同样有这些信息。
4、回到nfs服务端,创建测试数据
[root@nfs nfs]# cd /nfs/
[root@nfs nfs]# touch nfs.html
复制
5、进入swarm中所有节点,查看数据是否同步
进入Manager查看:
[root@Manager ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f176e66dc9f2 nginx:latest "nginx -g 'daemon of…" 14 minutes ago Up 14 minutes 80/tcp web-nfs.2.3cs5jh8chegz4ncid8qd2as8q
[root@Manager ~]# docker exec -it f176e66dc9f2 bash
root@f176e66dc9f2:/# ls /usr/share/nginx/html/
50x.html index.html nfs.html
复制
进入agnet01查看,agent02就不演示了,大家自己查看一下:
[root@agent01 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b9b7dcc5bdfa nginx:latest "nginx -g 'daemon of…" 17 minutes ago Up 17 minutes 80/tcp web-nfs.1.q67t67ucdba2c7b5srkm9b58n
[root@agent01 ~]# docker exec -it b9b7dcc5bdfa bash
root@b9b7dcc5bdfa:/# ls /usr/share/nginx/html/
50x.html index.html nfs.html
复制
6、用docker volume ls验证数据卷
[root@Manager ~]# docker volume ls
DRIVER VOLUME NAME
local nfs-vol
local nginx-vol
[root@agent01 ~]# docker volume ls
DRIVER VOLUME NAME
local nfs-vol
local nginx-vol
复制
7、通过rm删除副本验证
[root@Manager ~]# docker service rm web-nfs
[root@Manager ~]#df -h
复制
我们把刚才创建的副本删除掉,然后通过df -h查看挂载的文件,发现也跟着不在了,其它节点也一样不存在了;然后你回到nfs服务端查看/nfs共享目录,数据是不变的。这就表现了,通过nfs挂载,副本被删除,不影响nfs服务端的源数据。只要数据在nfs服务端,就可实现数据的持久化。
参考资料
官方文档: https://docs.docker.com/storage/volumes/
[2]重要:虽然绑定挂载能用,但是也有可能导致一些问题:: https://www.jianshu.com/p/b6d1a53f04dd
[3]整理: https://blog.csdn.net/weixin_34162695/article/details/92978377