在很多应用中,我们可能会遇到文件上传功能(尽管现在 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文件系统版本概述