问题描述
在Ubuntu 18机器上托管了各种Docker容器。其中一些容器需要将数据存储在Synology NAS上。起初,用户使用主机机器的/etc/fstab
来控制NFS挂载,然后在容器中挂载它们(作为挂载点,而不是卷)。
然而,用户认为让容器将NFS映射到容器中的挂载点会更好。主机对挂载点没有实际用途,因此在主机上维护它们没有意义。
目前,用户正在配置NFS卷的方式如下(使用Docker Compose v3格式):
volumes:
data:
driver_opts:
type: nfs
o: addr=192.168.1.51,nolock,soft,rw
device: :/volume2/nextcloud
当NAS启动并正常工作时,这种配置非常好用。然而,用户遇到了一次停电后出现的各种问题。此外,机器的启动顺序(NAS与Ubuntu机器)会影响Docker容器卷的可靠性。在用户最后一次遇到的情况中,NAS没有开机。因此,当启动容器时,它失败了:
ERROR: for app Cannot start service app: error while mounting volume '/var/lib/docker/volumes/nextcloud_data/_data': error while mounting volume with options: type='nfs' device=':/volume2/nextcloud' o='addr=192.168.1.51,nolock,soft,rw': no route to host
如果Docker能够在NAS重新开机之前不断尝试挂载卷,那将非常好。这将使操作变得无需干预,并防止任何时序问题(网络上的设备启动顺序)导致此类永久性故障。
用户还不确定如果在任何时候创建了一个卷,而NAS在某个时刻关闭,会发生什么。卷是否仍然可用?Docker是否会继续尝试重新连接NFS挂载?用户感觉在这里几乎没有控制权。
请注意,用户只使用Docker Compose,不使用Swarm,出于一些技术原因这里不再详述。有人能推荐一种解决这些可靠性问题的方法吗?NFS卷在Docker中是否是最佳选择?是否应该回到在主机上挂载?是否有其他令人惊叹的第三种选择?
解决方案
请注意以下操作注意版本差异及修改前做好备份。
方案1
在Docker中,有一些选项可以重试容器的启动,例如在版本2中的restart
和版本3中的restart-policy
(需要启用兼容模式以使用版本3的语法)。然而,我认为它们只在容器内部应用程序失败时起作用,而不是在创建容器时出现卷挂载失败的情况(或者如果无法从注册表检索映像时也会发生)。
要处理卷挂载失败,我认为Swarm模式是您最好的选择,尽管您对此有异议。您可以使用docker swarm init
创建一个单节点集群,并使用docker stack deploy -c docker-compose.yml stack_name
部署您的compose文件,从而轻松过渡到docker-compose。Swarm模式会查看服务的整体状态,并不断尝试使当前状态与目标状态(在compose文件中定义)匹配,这将处理卷挂载失败并最终自行纠正。我现在没有NFS服务器进行测试,但以下是一个绑定挂载到缺失文件夹的场景示例:
version: '3'
volumes:
bind-test:
driver: local
driver_opts:
type: none
o: bind
device: /home/bmitch/data/docker/test/missing
services:
bind-test:
image: busybox
command: tail -f /dev/null
volumes:
- bind-test:/bind-test
从上面的示例中,您可以看到一旦创建了缺失的目录,绑定挂载就成功了,并且无法创建的容器会重试并成功启动。
方案2
由于某些服务需要访问主机上的设备,因此我无法使用Swarm。在Docker Stacks中无法在YML中指定
devices
。@void.pointer,你可以使用一个丑陋的解决方法:https://github.com/docker/swarmkit/issues/1244#issuecomment-394343097
我知道这个问题很旧,但我认为其他人也会遇到这个需求…
由于用户已经限制在这个主机上(这也是使用docker-compose而不是swarm的原因),我建议另一种方法。
Synology上的NFS非常麻烦。必须在服务器和客户端上管理UID以保持一致。无法更改Synology上的UID,因此只能调整客户端的UID以适应服务器的UID,这可能会导致ID冲突并且很麻烦。因此,我选择了SMB/CIFS路线。
可以通过/etc/fstab
文件将Synology共享目录挂载到主机目录。身份验证通过credentials=/.smbcredentials_3
选项完成。然后将此子目录挂载到容器中。这在compose.yml中是一个简单的设置。
关于NAS的重启问题。我现在已经运行了两年,没有遇到任何问题。我记不清是如何完成的,但我记得重新挂载是由主机自动完成的。
我的容器寿命很短,由cron作业创建。如果由于NAS关闭/重启而导致失败,下一次运行将再次找到已挂载的NAS共享。
以上是解决这个可靠性问题的两种方案。您可以根据自己的需求选择其中一种。希望对您有所帮助!