在很多应用中,我们可能会遇到文件上传功能(尽管现在 OSS
服务大行其道,但是仍不应该允许前端直接上传文件到 OSS
上,为了安全起见,需要服务器进行中转处理)、文件解析功能、文件生成并导出下载功能等一些列操作本地文件的功能和需求。
在单机的情况下,通过 volume
可以很容易的挂载数据卷,实现数据持久化和文件共享。
但是到了 Swarm
集群中,每个服务运行的位置可能是任何一个节点,而且文件数据需要互通。
举个实际例子:
在应用中,需要导出数据到Excel,并提供下载。由于数据量过大(通常万条起步),无法在浏览器中实现导出,所以选择在服务器中通过 Stream
从数据库中获取数据流,并流式写入到本地文件中,之后提供给前端一个文件路径地址,浏览器就可以下载了。
但是在 Swarm
集群中,每个副本所生成的文件没有特殊配置是不可互通的,因为 Docker volume
设定为本地卷,下一次前端的下载请求进来,通过 overlay
网络后无法保证一定会落到生成文件的服务中,因此就会出现 404 Not Found
错误。这个时候就要考虑如何共享文件/文件夹了。
通过多方资源查找,90%的解决方案都是NFS文件系统。因此,本篇也采用这个方案来解决需求。
思考
个人觉得这个方案可能不够严谨,如果说NFS服务器挂了,那岂不是集群就挂了?还是说NFS服务器可以做成容灾集群?但并没有找到NFS服务器做成容灾集群的方法
搭建NFS服务器
假设有5台Ubuntu 20.04
服务器,内网 IP
分别为: 10.87.23.111-115
,选择 10.87.23.111
作为 NFS
服务器。
Step1.
安装 nfs
服务
$ sudo apt install nfs-kernel-server # 安装 $ sudo systemctl start nfs-kernel-server.service # 启动点击复制复制失败已复制
Step2.
建立 nfs
共享文件夹
$ sudo mkdir -p /data/nfs/docker $ sudo chmod 777 -R /data/nfs点击复制复制失败已复制
Step3.
共享配置
修改 /etc/exports
文件,加入如下配置:
/data/nfs *(rw,insecure,no_root_squash,sync,no_wdelay,no_subtree_check)点击复制复制失败已复制
相关语法详见nfs挂载解析
Step4.
测试
在其他服务器上查看共享文件
$ showmount -e 10.87.23.111 Export list for 10.87.23.111: /data/nfs *点击复制复制失败已复制
可以看到 /data/nfs
已经可以挂载了。
共享 volume
配置
在 yaml
文件中配置示例:
version: "3.8" services: master: image: ****** volumes: - master-public:/app/public volumes: master-public: driver: local driver_opts: type: nfs4 # 注意不是nfs! o: "addr=10.87.23.111,rw" device: ":/data/nfs/docker"点击复制复制失败已复制
注意
网上很多文章都会先用 docker volume create
来创建一个数据卷,然后在写到 yaml文件
中,这个是画蛇添足的作法!因为 Docker Swarm
会根据 stack名称
来自动创建network
, volume
等,无需手动创建。
还有很多地方在 type
字段设置为 nfs
,那样就会默认使用 NFSv3
,而不是最新的 NFSv4
。不要使用旧版!它有很大的缺陷,亲身采坑,原因是文件锁,关于版本的差别详见:NFS文件系统版本概述