在Docker中如何使NFS卷更可靠

55次阅读
没有评论

问题描述

在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共享。

以上是解决这个可靠性问题的两种方案。您可以根据自己的需求选择其中一种。希望对您有所帮助!

正文完