Docker Compose挂载NFS卷时出现连接超时问题求助
我之前帮朋友排查过几乎一模一样的情况——手动挂载NFS完全正常,但Docker Compose创建NFS卷就报连接超时,大概率是以下几个原因导致的,你可以逐一排查:
1. NFS动态端口未开放(针对NFSv3)
NFSv3除了111(rpcbind)和2049(nfsd)端口外,还依赖mountd、rpc.statd、lockd这些服务的动态端口,默认情况下这些端口是随机的,防火墙可能没放行。而手动挂载时系统可能临时打通了这些端口,但Docker容器的网络环境下没有权限访问。
解决方法:固定动态端口并开放防火墙
- CentOS/RHEL系统:编辑
/etc/sysconfig/nfs,添加或修改以下内容:
MOUNTD_PORT=20048 STATD_PORT=4001 LOCKD_TCPPORT=4002 LOCKD_UDPPORT=4002
- Debian/Ubuntu系统:编辑
/etc/default/nfs-kernel-server,添加:
RPCMOUNTDOPTS="--port 20048"
同时编辑/etc/default/nfs-common:
STATDOPTS="--port 4001 --outgoing-port 4002" LOCKD_TCPPORT=4002 LOCKD_UDPPORT=4002
然后重启NFS相关服务:
# CentOS/RHEL systemctl restart nfs-server rpcbind # Debian/Ubuntu systemctl restart nfs-kernel-server nfs-common
最后在NFS服务器的防火墙开放这些端口(包括TCP和UDP):
# 以firewalld为例 firewall-cmd --add-port=111/tcp --add-port=111/udp --permanent firewall-cmd --add-port=2049/tcp --add-port=2049/udp --permanent firewall-cmd --add-port=20048/tcp --add-port=20048/udp --permanent firewall-cmd --add-port=4001/tcp --add-port=4001/udp --permanent firewall-cmd --add-port=4002/tcp --add-port=4002/udp --permanent firewall-cmd --reload
2. 尝试切换到NFSv4(更省心的方案)
NFSv4只需要2049端口,不需要依赖那些动态端口,能避开很多网络权限问题。你可以修改docker-compose.yml里的NFS选项,指定版本为4:
volumes: django-static: driver_opts: type: "nfs" o: "addr=<NFS_IP>,rw,vers=4" device: ":/root/app/django-static" django-media: driver_opts: type: "nfs" o: "addr=<NFS_IP>,rw,vers=4" device: ":/root/app/django-media"
修改后执行docker-compose down -v清理旧卷,再重新启动试试。
3. 检查NFS共享目录的权限
你共享的是/root/app下的目录,而/root目录默认权限是700,即使exports里设置了no_root_squash,NFS客户端的挂载进程(包括Docker的守护进程)可能因为无法访问/root目录而失败。
解决方法:
- 最好把共享目录迁移到非root用户目录下,比如
/data/app/django-static,然后修改/etc/exports配置,再执行exportfs -rv重新加载配置。 - 如果一定要用/root下的目录,临时测试可以修改/root的权限为
755(不推荐长期这么做,有安全风险):
chmod 755 /root
4. 验证Docker容器网络能否访问NFS端口
有时候Docker的桥接网络被防火墙规则限制了,你可以用一个测试容器验证端口连通性:
# 测试2049端口 docker run --rm alpine nc -zv <NFS_IP> 2049 # 如果用NFSv3,还要测试111、20048等端口 docker run --rm alpine nc -zv <NFS_IP> 111 docker run --rm alpine nc -zv <NFS_IP> 20048
如果测试失败,需要在NFS服务器的防火墙规则里允许Docker客户端的网络段(比如默认的172.17.0.0/16)访问这些端口。
最后,记得每次修改exports配置后,都要执行exportfs -rv让配置生效,避免配置没加载的问题。
内容的提问来源于stack exchange,提问作者NesuGH

