使用 NFS 作为 Docker Swarm 持久卷
折腾了两天,最后还是决定先拿 NFS 和 Swarm 组合,做一个最简单的集群,防止第一个应用上线就陷入 k8s 的汪洋大海。。
Swarm 集群
注意替换 IP 和 token 为实际。先是主节点:
docker swarm init --advertise-addr 10.0.0.220
然后是工作节点:
docker swarm join --token SWMTKN-1-1761ucm1qtwp5zudzrpej70bsg3oh91s58m96nl1aw8outyx4e-7qho23q4nr65byy9u61amrzgm 10.0.0.220:2377
最后在主节点确认都已经加入,所有节点应该都是 Active。
docker node ls
NFS 服务
首先,你得有一个 NFS 服务器,假定是 10.0.0.200
,共享的目录是 /volumes1/swarm
。
在每个 swarm 节点安装 NFS 客户端,并检查可挂载。
sudo apt install -y nfs-common
sudo showmount -e 10.0.0.200
能显示出 NFS 服务器上的卷,表明是可挂载的。
Export list for 10.0.0.200:
/volume1/swarm *
Stack 配置文件引用
既然是集群,我们就不会希望跑到每个节点上面去配 NFS 挂载和映射。做集群共享卷的关键,要在 compose 文件中创建 volume。语法如下:
volumes:
my-vol:
driver_opts:
type: "nfs"
o: "addr=10.0.0.200,nolock,soft,rw"
device: ":/volume1/swarm"
注意替换 o 属性中的 NFS 服务器地址,以及 device 属性中的挂载点。为了数据安全,现在我们就只能为每个 volume 建立一个 nfs 挂载点。
与应用结合
下面我们来一个稍微复杂一点的 stack 配置,Prometheus 与 Grafana 两个容器,其中 Grafana 挂载 NFS 卷作为持久化存储,两个容器通过 overlay 网络互访。
version: '3.7'
services:
grafana:
image: grafana/grafana:latest
hostname: grafana
deploy:
restart_policy:
delay: 10s
max_attempts: 10
window: 60s
networks:
- monitor_distributed
ports:
- 3000:3000
volumes:
- grafana-data:/var/lib/grafana
prometheus:
image: prom/prometheus:latest
hostname: prometheus
deploy:
restart_policy:
delay: 10s
max_attempts: 10
window: 60s
networks:
- monitor_distributed
networks:
monitor_distributed:
driver: overlay
volumes:
grafana-data:
driver_opts:
type: "nfs"
o: "addr=10.0.0.200,nolock,soft,rw"
device: ":/volume1/grafana"
执行命令启动 stack:
docker stack deploy --compose-file=docker-compose.yaml monitor_stack
docker stack ls
docker stack service monitor_stack
直到两个容器都运行起来。
存储分析
执行命令查看卷:
docker volume ls
docker volume inspect monitor_stack_grafana-data
结果如下:
[
{
"CreatedAt": "2019-06-09T13:34:03Z",
"Driver": "local",
"Labels": {
"com.docker.stack.namespace": "monitor_stack"
},
"Mountpoint": "/var/lib/docker/volumes/monitor_stack_grafana-data/_data",
"Name": "monitor_stack_grafana-data",
"Options": {
"device": ":/volume1/grafana",
"o": "addr=10.0.0.200,nolock,soft,rw",
"type": "nfs"
},
"Scope": "local"
}
]
可以看到,实际上 NFS 目录还是被挂载到节点宿主机上的,只不过这一过程不需要我们人工干预,swarm 会自动根据容器位置进行动态挂载。
在这几个节点上分别执行 docker ps
,找到 Grafana 所在的主机,然后执行(注意替换四位 id 为自己的实际):
docker exec -it d313 /bin/bash
mount
其中一行应该是
:/volume1/grafana on /var/lib/grafana type nfs (rw,relatime,vers=3,rsize=131072,wsize=131072,namlen=255,soft,nolock,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=10.0.0.200,mountvers=3,mountproto=tcp,local_lock=all,addr=10.0.0.200)
为了确认,还可以去 NFS 服务器上打开目录看看里面是不是有 Grafana 生成的文件。
多实例共享分析
我们把 Grafana 的副本数增加一个:
docker service scale monitor_stack_grafana=2
稍等一下,用 docker service ls
就会发现 Grafana 容器的副本数增加为 2/2
。找到另一个容器所在的目录,然后同样执行上一节的 mount
命令。结果应该是一样的。
要注意的是,这种共享持久化卷怎么说都还是 NFS,文件级的共享是可以的。数据库这种还是要依赖应用自己的高可用。