排查通过 SSH Tunnel
使用共享NFS卷¶
在 (正在探索)Docker Desktop for mac部署kind容器通过 SSH Tunnel 使用共享NFS卷 采用 SSH隧道 来打通 Docker Desktop 中容器访问 Docker Desktop on Mac 虚拟机 之外的物理主机( macOS )的NFS共享。存在的技术难点其实和 在防火墙之后运行NFS服务器 是一样的。
排查和折腾过程记录在此,也算经验积累:
实践环境¶
首先完成:
Docker Desktop for mac 端口转发(port forwarding) 在容器和 macOS 之间部署了一台中间桥接容器
dev-gw
部署 macos_nfs 共享 物理主机的一个目录
此时的实践环境已经具备,通过 SSH隧道 建立起NFS clinet 和 server之间的网络同路就类似于 在防火墙之后运行NFS服务器
测试¶
在Docker容器 ubuntu 测试客户端测试 Ubuntu NFS部署 :
安装Ubuntu的NFS客户端:
sudo apt install nfs-common
挂载NFS服务器测试,注意,NFS服务器使用
dev-gw
在docker network
中的网络IP172.22.0.12
,而服务器端的目录则是 macOS 物理主机前面配置的 macOS系统NFS服务 输出目录:mkdir /studio mount -t nfs 172.22.0.12:/Users/huataihuang/docs/studio /studio
这里有一个提示错误:
mount.nfs: rpc.statd is not running but is required for remote locking.
mount.nfs: Either use '-o nolock' to keep locks local, or start statd.
mount.nfs: Operation not permitted
修改参数,添加 -o nolock
mount -t nfs -o nolock 172.22.0.12:/Users/huataihuang/docs/studio /studio
此时提示错误:
mount.nfs: Operation not permitted
这个问题在 Docker容器使用NFS 已经排查过,是因为Docker容器安全限制,需要在运行容器时添加参数 --cap-add sys_admin
重新启动一个
fedora-dev-tini
容器,在 Fedora镜像(采用tini替代systemd) 运行fedora-dev-tini
容器的命令基础上加上--cap-add sys_amdin
参数:
docker run -itd -p 1122:22 --network kind \
--cap-add sys_admin \
--hostname fedora-dev-tini --name fedora-dev-tini fedora-dev-tini
测试挂载:
mkdir /stuido
mount -t nfs -o nolock,nfsvers=3,tcp 172.22.0.12:/Users/huataihuang/docs/studio /studio
非常奇怪,我在 dev-gw
服务器上观察发现没有任何连接到NFS相关监听端口,而 fedora-dev-tini
过了很久只显示一个输出:
mount.nfs: Connection refused
在
fedora-dev-tini
主机上检查telnet 172.22.0.12 111
端口是打开的检查
rpcinfo
# rpcinfo -p 172.22.0.12 172.22.0.12: RPC: Remote system error - Connection refused
发现 dev-gw
拒绝了连接,但是在 dev-gw
上使用:
$ netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:2049 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:1017 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:1021 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:1003 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:685 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.11:35477 0.0.0.0:* LISTEN
...
可以看到端口是监听的,但是没有客户端连接
尝试 systemd NFS客户端¶
之前在 Docker容器使用NFS 中提到:
方法一:在容器内部安装 nfs-utils
,就如同常规到NFS客户端一样,在容器内部直接通过rpcbind方式挂载NFS共享输出,这种方式需要每个容器独立运行rpcbind服务,并且要使用 Docker systemd进程管理器 ,复杂且消耗较多资源。不过,优点是完全在容器内部控制,符合传统SA运维方式。
备注
kind(本地docker模拟k8s集群) 在node节点是使用了完整的 Systemd进程管理器 来实现的,所以部署 在Kubernetes中部署NFS 是满足节点提供 rpcbind 服务的。
对啊,要在Docker容器中测试NFS挂载,必须也是运行 Systemd进程管理器 的Docker容器
重新部署 Fedora镜像 (内置 Systemd进程管理器 ) ,使用镜像是
fedora-ssh
,执行以下运行命令:docker run -itd --privileged=true -p 1122:22 --network kind \ --hostname fedora-ssh --name fedora-ssh fedora-ssh
备注
Fedora 配置NFS方法采用 CentOS 7 配置NFS 相同客户端方式
安装NFS客户端:
dnf install nfs-utils
果然,使用 Systemd进程管理器 的Docker容器,挂载时会自动启动
rpc-statd.service
# mount -t nfs 172.22.0.12:/Users/huataihuang/docs/studio /studio Created symlink /run/systemd/system/remote-fs.target.wants/rpc-statd.service → /usr/lib/systemd/system/rpc-statd.service. mount.nfs: Protocol not supported
不过,还是报错:
mount.nfs: Protocol not supported
排查方法参考 mount.nfs: requested NFS version or transport protocol is not supported 添加 -v
参数可以详细输出信息 :
mount -t nfs -v -o tcp 172.22.0.12:/Users/huataihuang/docs/studio /studio
此时会看到NFS客户端先尝试 NFS v4 系列,然后再尝试 NFS v3 系列,但是在RPC调用时失败(连接拒绝):
mount.nfs: timeout set for Thu Feb 2 00:01:08 2023
mount.nfs: trying text-based options 'vers=4.2,addr=172.22.0.12,clientaddr=172.22.0.13'
mount.nfs: mount(2): Protocol not supported
mount.nfs: trying text-based options 'vers=4,minorversion=1,addr=172.22.0.12,clientaddr=172.22.0.13'
mount.nfs: mount(2): Protocol not supported
mount.nfs: trying text-based options 'vers=4,addr=172.22.0.12,clientaddr=172.22.0.13'
mount.nfs: mount(2): Protocol not supported
mount.nfs: trying text-based options 'addr=172.22.0.12'
mount.nfs: prog 100003, trying vers=3, prot=6
mount.nfs: trying 172.22.0.12 prog 100003 vers 3 prot TCP port 2049
mount.nfs: prog 100005, trying vers=3, prot=17
mount.nfs: portmap query retrying: RPC: Unable to receive - Connection refused
mount.nfs: prog 100005, trying vers=3, prot=6
mount.nfs: trying 172.22.0.12 prog 100005 vers 3 prot TCP port 975
mount.nfs: portmap query failed: RPC: Remote system error - Connection refused
mount.nfs: Protocol not supported
通过 -v
可以看到,客户端 portmap
会尝试 RPC ,失败
改为 -o vers=3,tcp
就看到客户端会连接服务器端口:
mount.nfs: timeout set for Thu Feb 2 00:05:18 2023
mount.nfs: trying text-based options 'vers=3,tcp,addr=172.22.0.12'
mount.nfs: prog 100003, trying vers=3, prot=6
mount.nfs: trying 172.22.0.12 prog 100003 vers 3 prot TCP port 2049
mount.nfs: prog 100005, trying vers=3, prot=6
mount.nfs: trying 172.22.0.12 prog 100005 vers 3 prot TCP port 975
mount.nfs: portmap query failed: RPC: Remote system error - Connection refused
...
既然端口 975
少了,我重新修订 ~/.ssh/config
添加上 975端口,输出信息果然变化:
# mount -t nfs -vvvv -o vers=3,tcp 172.22.0.12:/Users/huataihuang/docs/studio /studio
mount.nfs: timeout set for Thu Feb 2 00:11:32 2023
mount.nfs: trying text-based options 'vers=3,tcp,addr=172.22.0.12'
mount.nfs: prog 100003, trying vers=3, prot=6
mount.nfs: trying 172.22.0.12 prog 100003 vers 3 prot TCP port 2049
mount.nfs: prog 100005, trying vers=3, prot=6
mount.nfs: trying 172.22.0.12 prog 100005 vers 3 prot TCP port 975
mount.nfs: mount(2): Permission denied
mount.nfs: access denied by server while mounting 172.22.0.12:/Users/huataihuang/docs/studio
看起来是被macOS的NFS服务器拒绝了
参考 Enabling network (NFS) shares in Mac OS X 看来需要设置macOS NFS服务器端的允许IP地址段
之前Linux物理服务器客户端测试,客户端IP地址和服务器端在同一个网段,似乎没有问题。但是这次是Docker容器,网段是 172.22.0.0/16
似乎就不行
修改 /etc/exports
:
#如果不配置客户端的IP地址范围,似乎只有相同子网的客户端能够访问,跨网段NFS服务器会拒绝:
# mount.nfs: mount(2): Permission denied
# mount.nfs: access denied by server while mounting 172.22.0.12:/Users/huataihuang/docs/studio
# 配置过于简单,没有配置NFS客户端IP地址范围
#/Users/huataihuang/docs/studio -maproot=501:20
# 增加NFS客户端IP范围
/Users/huataihuang/docs/studio -maproot=501:20 -network 172.22.0.0 -mask 255.255.0.0
再次挂载NFS(指定NFS v3):
mount -t nfs -v -o vers=3,tcp 172.22.0.12:/Users/huataihuang/docs/studio /studio
输出显示 portmap query failed: RPC: Unable to receive - Connection reset by peer
:
mount.nfs: timeout set for Thu Feb 2 00:26:01 2023
mount.nfs: trying text-based options 'vers=3,tcp,addr=172.22.0.12'
mount.nfs: prog 100003, trying vers=3, prot=6
mount.nfs: trying 172.22.0.12 prog 100003 vers 3 prot TCP port 2049
mount.nfs: portmap query failed: RPC: Unable to receive - Connection reset by peer
mount.nfs: Connection reset by peer
portmap query failed: RPC: Unable to receive - Connection reset by peer
是什么意思呢?
mount.nfs: portmap query failed: RPC: Unable to receive - Connection refused in Centos 7 client 提供了一个排查思路:
rpcinfo -l <nfsserver> 100003 3
我这里实践:
# rpcinfo -l 172.22.0.12 100003 3
program vers tp_family/name/class address service
100003 3 inet/udp/clts 172.22.0.12.8.1 nfs
100003 3 inet/tcp/cots_ord 172.22.0.12.8.1 nfs
我想起来以前尝试过穿透防火墙设置NFS,需要特殊的固定端口配置,否则挂载时,服务器端和客户端协商会打开随机端口进行连接,此时就会被防火墙阻塞。这个问题在我的 SSH Tunneling 也存在
参考 NFS client mount fails behind firewall 看来还需要在服务器端做不少配置来来确保服务器端返回连接客户端不采用随机端口…
Fixing Ports Used by NFSv3 Server 介绍了Linxu上如何配置固定端口 /etc/sysconfig/nfs
,不知道有没有办法移植到 macOS 上
参考¶
Running NFS Behind a Firewall 提供了需要暴露的端口信息列表参考