CentOS 上如何确保挂载NFS完成后再启动 Docker:从踩坑到最终解决方案
前言
如果你的 Docker 容器依赖远程存储(如 NFS 共享目录),而服务器开机时 挂载顺序晚于 Docker 启动,容器就会无法访问挂载点,频繁报错,甚至导致整个服务无法运行。
本文通过一个实际案例,手把手实现:CentOS 上自动挂载远程存储,并在挂载完成后再启动 Docker,并讲清楚 systemd 配置路径、Docker 配置两种修改方式,避免升级风险。
1. 问题现象
假设我们想把远程存储挂载到 /data,在 /etc/fstab 中写了:
1 | storage.example.com:/share /data nfs defaults,_netdev 0 0 |
重启后发现:
- 日志出现:
mount.nfs: Failed to resolve server … Name or service not known - Docker 启动,但容器无法访问
/data; - 手动执行
systemctl start data.mount却能正常挂载。
2. 为什么会这样?
启动时,systemd 只保证网络接口启动 (network.target),但:
- DNS 服务可能还没就绪(无法解析远程主机);
- NFS 挂载失败,目录没挂上;
- Docker 没有等待挂载完成,直接启动;
- 即使挂载后来补上,容器内卷也已初始化失败。
3. 常见但不稳定的“解决方案”
有人会:
- 在
rc.local或脚本里手动延迟挂载; - Docker 设为
restart: always,依赖自动重启。
这些办法可能短期有效,但风险很大:
- DNS 慢、网络不稳,依旧失败;
- 容器可能在挂载前启动,导致卷不可用。

4. 最终解决方案
第一步:用 systemd .mount 管理挂载
创建 /etc/systemd/system/data.mount:
1 | [Unit] |
关键点:
NetworkManager-wait-online.service:等待网络和 DNS 就绪;Before=docker.service:挂载必须先于 Docker;_netdev:让 systemd 知道这是网络设备挂载。
第二步:让 Docker 等待挂载
不建议直接修改 /usr/lib/systemd/system/docker.service,因为它里面已经有其他依赖,直接替换会破坏服务启动逻辑。
推荐方法:使用 override 文件,仅追加挂载依赖:
1 | mkdir -p /etc/systemd/system/docker.service.d |
添加以下内容:
1 | [Unit] |
然后重新加载,验证修改是否正确:
1 | systemctl daemon-reload |
你会看到原本的依赖(如 containerd.service、network-online.target)仍然存在,并额外加上了 data.mount。
重启docker服务
1 | systemctl restart docker |
这样,docker.service 启动时既会依赖它原本的 containerd.service、network-online.target,也会等待 data.mount 完成后再启动。
如果你真的要直接改 /usr/lib/systemd/system/docker.service,必须小心:
- 找到原本的
Requires=和After=,把data.mount加进去,而不是覆盖; - 升级 Docker 时,这些修改容易被覆盖,所以不推荐。
第三步:启用并验证
1 | systemctl enable NetworkManager-wait-online.service |
检查状态:
1 | systemctl status data.mount |
挂载和 Docker 都会在启动时自动就绪,容器可直接访问 /data。
5. systemd 三个路径的区别
理解这三个目录,才能知道配置应该改哪里。
/usr/lib/systemd/system/
- 存放软件包默认提供的服务文件(系统安装时生成)。
- 不建议直接改,更新时可能被覆盖。
/run/systemd/system/
- 临时,系统运行时生成的,重启后消失。
/lib/systemd/system/
- 部分发行版使用的路径,功能和
/usr/lib/systemd/system相同。 - 在 CentOS/RHEL 上通常是
/usr/lib/systemd/system的符号链接。
/etc/systemd/system/
- 用户自定义和覆盖文件,优先级最高。
- 使用
override.conf可以覆盖系统服务而不修改原文件。
优先级顺序:
1 | /etc/systemd/system/ > /run/systemd/system/ > /usr/lib/systemd/system/ (/lib/systemd/system/) |
查看最终生效配置:
1 | systemctl cat docker.service |
最终完整解决方案思路
- 挂载单元
/etc/systemd/system/data.mount(使用时替换实际地址); - Docker 依赖挂载(通过 override,避免覆盖系统文件);
- 启用等待网络,避免 DNS 未就绪导致挂载失败。
这样,每次服务器重启时:
- 系统等待网络和 DNS;
- 自动挂载
/data; - 挂载完成后 Docker 启动,容器立即能用该目录。