FreeBSD通过NFS共享ZFS数据集
我在 ZFS Stripe条带化 (FreeBSD环境实践) 构建了测试环境FreeBSD存储,其中 zdata
存储池用于存储测试数据,也包括我日常开发学习的 docs
数据集。由于我在多个测试环境中需要共享数据,我规划将 zdata
存储池的数据集用于:
在Kubernetes中部署NFS 构建用于k8s的pod共享存储数据
日常学习开发使用 Docker容器使用NFS 将
docs
数据集挂载到 Debian镜像(tini进程管理器) 运行容器debian-dev
来方便工作
FreeBSD内建OpenZFS和NFS
FreeBSD内建集成了OpenZFS和NFS使得其非常容易实现NFS共享: OpenZFS提供了一个 sharenfs
属性,可以在OpenZFS文件系统上非常方便地管理NFS共享已经集成到脚本和监控维护流程中。
FreeBSD集成的NFS服务器和客户端支持 NFSv3
和 NFSv4
协议
准备工作
已经在 FreeBSD Jail访问ZFS文件系统 中构建了 zdata/docs
卷集:
zdata/docs
# 创建挂载到 /docs 目录的卷集 zdata/docs
#zfs create -o mountpoint=/docs zdata/docs
zfs create zdata/docs
Host主机设置
在host主机上配置
/etc/rc.conf
:
/etc/rc.conf
启用NFSnfs_server_enable="YES"
mountd_enable="YES"
rpc_lockd_enable="YES"
rpc_statd_enable="YES"
rpcbind_enable="YES"
对ZFS数据集启动
sharenfs
属性,并且相应配置允许的客户端IP:
sharenfs
属性#zfs set sharenfs="-rw,-alldirs,-network=192.168.7.0/24" zdata/docs
#zfs set sharenfs="[email protected]/24" zdata/docs
# 暂时没有解决权限问题,官方文档没有找到案例
# 参考solaris zfs文档存在实现偏差,例如solaris zfs文档是先设置sharefs参数,然后再设置 sharefs=on ,但是在FreeBSD上on直接覆盖了前面设置的参数
zfs set sharenfs=on zdata/docs
# 参考 https://man.freebsd.org/cgi/man.cgi?query=zfsprops&sektion=7&manpath=freebsd-release
# sharenfs=on 相当于默认共享参数: sec=sys,rw,crossmnt,no_subtree_check
启动NFS服务:
service nfsd start
service mountd reload
这里执行 service nfsd start
时输出信息如下:
nfsd
时信息NFSv4 is disabled
Starting rpcbind.
/etc/rc.d/mountd: WARNING: /etc/exports is not readable.
Starting mountd.
Starting nfsd.
检查ZFS数据集 zdata/docs
属性:
zdata/docs
的 sharenfs
属性zfs get all zdata/docs | grep nfs
输出信息如下:
zdata/docs
的 sharenfs
属性zdata/docs sharenfs -rw,-alldirs,-network=192.168.7.0/24 local
zdata/docs acltype nfsv4 default
客户端
我的客户端实际上是想实现 Docker容器使用NFS ,也就是在客户端host主机上挂载ZFS NFS服务器的输出卷,然后再将通过 docker volume
映射到容器内部使用:
在客户端Host主机上配置
/etc/fstab
:
/etc/fstab
192.168.7.200:/zdata/docs /home/admin/docs nfs rw,soft,intr,vers=3,proto=tcp,rsize=32768,wsize=32768 0 0
在客户端执行挂载:
mount /home/admin/docs
异常排查
客户端挂载报错
mount.nfs: access denied by server while mounting 192.168.7.200:/zdata/docs
mount: (hint) your fstab has been modified, but systemd still uses
the old version; use 'systemctl daemon-reload' to reload.
为什么服务器端拒绝了客户端挂载? 我发现是我前面实践时设置了 sharenfs="-rw,-alldirs,-network=192.168.7.0/24"
导致,由于暂时没有找到合适的参考文档,所以我简化成 sharenfs=on
,这样基本使用就没有问题(完全依靠客户端的 uid/gid
权限设置)
警告
我这里的简化案例设置了 sharenfs=on
,只能用于测试环境简单使用,相当于默认参数 sec=sys,rw,crossmnt,no_subtree_check
docker容器
在客户端Host实现了简单的NFS挂载之后,启动 Debian镜像(tini进程管理器) 的 acloud-dev
:
docker run -dt --name acloud-dev --hostname acloud-dev \
-p 1122:22 \
-p 13000:3000 \
-p 18080:8080 \
-p 14000:4000 \
-p 1180:80 \
-p 1443:443 \
-v /home/admin/secrets:/home/admin/.ssh \
-v /home/admin/docs:/home/admin/docs \
acloud-dev
# 如果需要在运行时注入环境变量,则添加类似如下参数(添加代理案例)
# -e HTTP_PROXY=http://172.17.0.1:3128 \
# -e HTTPS_PROXY=http://172.17.0.1:3128 \
# -e NO_PROXY=localhost,127.0.0.1,*.baidu.com,192.168.0.0/16,10.0.0.0/8 \
此时登陆到 acloud-dev
容器中,就可以看到host主机挂载的NFS共享( df -h
输出信息):
acloud-dev
容器中检查 df -h
输出可以看到NFS挂载Filesystem Size Used Avail Use% Mounted on
overlay 59G 15G 41G 27% /
tmpfs 64M 0 64M 0% /dev
shm 64M 0 64M 0% /dev/shm
/dev/mmcblk0p2 59G 15G 41G 27% /etc/hosts
192.168.7.200:/zdata/docs 6.2T 1.7T 4.5T 28% /home/admin/docs
tmpfs 4.0G 0 4.0G 0% /proc/asound
tmpfs 4.0G 0 4.0G 0% /sys/firmware
备注
需要保证NFS客户端和NFS服务端的用户 uid/gid
一致,这样才能正常读写共享文件。这里的用户是 admin
,其NFS客户端和服务器端都采用了相同的 uid/gid
异常排查
我重启了FreeBSD服务器和树莓派(Raspberry Pi OS, Debian 12),结果发现客户端再次无法挂载NFS:
mount.nfs: Protocol not supported
我了检查服务器已经启动了 nfsd
,并且ZFS的 sharenfs
显示如下 zfs get all /zdata/docs | grep -i nfs
:
sharenfs
设置zfs get all zdata/docs | grep nfs
输出显示当前是非常简单的 on
状态:
sharenfs
设置为 on
看起来没有问题zdata/docs sharenfs -rw,-alldirs,-network=192.168.7.0/24 local
zdata/docs acltype nfsv4 default
尝试详细信息输出:
mount -v
检查输出信息mount -t nfs 192.168.7.200:/zdata/docs /home/admin/docs -v
输出信息如下:
mount -v
检查输出信息显示v4协议不支持,v3协议portmap查询失败mount.nfs: timeout set for Sat Jun 28 19:00:37 2025
mount.nfs: trying text-based options 'vers=4.2,addr=192.168.7.200,clientaddr=192.168.7.221'
mount.nfs: mount(2): Protocol not supported
mount.nfs: trying text-based options 'vers=4,minorversion=1,addr=192.168.7.200,clientaddr=192.168.7.221'
mount.nfs: mount(2): Protocol not supported
mount.nfs: trying text-based options 'vers=4,addr=192.168.7.200,clientaddr=192.168.7.221'
mount.nfs: mount(2): Protocol not supported
mount.nfs: trying text-based options 'addr=192.168.7.200'
mount.nfs: prog 100003, trying vers=3, prot=6
mount.nfs: trying 192.168.7.200 prog 100003 vers 3 prot TCP port 2049
mount.nfs: prog 100005, trying vers=3, prot=17
mount.nfs: portmap query retrying: RPC: Program not registered
mount.nfs: prog 100005, trying vers=3, prot=6
mount.nfs: portmap query failed: RPC: Program not registered
mount.nfs: Protocol not supported
mount: (hint) your fstab has been modified, but systemd still uses
the old version; use 'systemctl daemon-reload' to reload.
为何客户端尝试v4和v3协议都不成功?
在Linux的NFS客户端执行
rpcinfo
命令检查远程服务的nfs输出协议情况:
rpcinfo 192.168.7.200 | egrep "service|nfs"
输出信息:
program version netid address service owner
100003 2 udp 0.0.0.0.8.1 nfs superuser
100003 3 udp 0.0.0.0.8.1 nfs superuser
100003 2 udp6 ::.8.1 nfs superuser
100003 3 udp6 ::.8.1 nfs superuser
100003 2 tcp 0.0.0.0.8.1 nfs superuser
100003 3 tcp 0.0.0.0.8.1 nfs superuser
100003 2 tcp6 ::.8.1 nfs superuser
100003 3 tcp6 ::.8.1 nfs superuser
可以看到服务器是支持 nfsv3
和 nfsv2
的 UDP
和 TCP
协议的(为何没有 nfsv4
?)
在Linux的NFS客户端执行
showmount
检查:
showmount
showmount -e 192.168.7.200
输出显示
showmount
显示没有注册mountd服务clnt_create: RPC: Program not registered
奇怪了
我检查了FreeBSD服务器的NFS启动配置 /etc/rc.conf
:
/etc/rc.conf
启用NFSnfs_server_enable="YES"
mountd_enable="YES"
rpc_lockd_enable="YES"
rpc_statd_enable="YES"
rpcbind_enable="YES"
明明配置是激活 mountd
的
在服务器上检查NFS相关服务,发现
mountd
服务果然没有启动:
root@xcloud:~ # service nfsd status
nfsd is running as pid 1747 1748.
root@xcloud:~ # service mountd status
mountd is not running.
root@xcloud:~ # service rpcbind status
rpcbind is running as pid 1663.
我检查了之前的执行步骤,发现之前在服务器上执行启动 nfsd
时候,有一个 service mountd reload
动作:
service nfsd start
service mountd reload
那么我再次执行 service mountd reload
,发现这个命令实际上要求 mountd
已经运行才行,现在我执行这条命令提示报错:
service mountd reload
报错mountd not running? (check /var/run/mountd.pid).
我尝试手工启动 mountd
服务:
mountd
service mountd start
发现原来 mountd
必须读取 /etc/exports
配置文件才能启动,当前没有这个文件,则拒绝启动:
mountd
报错/etc/rc.d/mountd: WARNING: /etc/exports is not readable.
/etc/rc.d/mountd: WARNING: failed precmd routine for mountd
按照ZFS手册,似乎是不需要配置 /etc/exports
配置就可以,所以我先尝试 touch
一个空配置文件,果然可以启动 mountd
服务了:
/etc/exports
空配置文件以后就能正常启动 mountd
root@xcloud:~ # touch /etc/exports
root@xcloud:~ # service mountd start
Starting mountd.
神奇了,现在再次在Linux NFS客户端执行 showmount
:
showmount
showmount -e 192.168.7.200
就能够看到FreeBSD正常输出了NFS:
showmount
终于看到正常的NFS服务输出信息Export list for 192.168.7.200:
/zdata/docs (everyone)
现在再次手工
mount -v
:
mount -v
检查输出信息mount -t nfs 192.168.7.200:/zdata/docs /home/admin/docs -v
amazing 终于成功了,输出信息如下:
root@acloud-w1:~# mount -t nfs 192.168.7.200:/zdata/docs /home/admin/docs -v
mount.nfs: timeout set for Sat Jun 28 19:45:58 2025
mount.nfs: trying text-based options 'vers=4.2,addr=192.168.7.200,clientaddr=192.168.7.221'
mount.nfs: mount(2): Protocol not supported
mount.nfs: trying text-based options 'vers=4,minorversion=1,addr=192.168.7.200,clientaddr=192.168.7.221'
mount.nfs: mount(2): Protocol not supported
mount.nfs: trying text-based options 'vers=4,addr=192.168.7.200,clientaddr=192.168.7.221'
mount.nfs: mount(2): Protocol not supported
mount.nfs: trying text-based options 'addr=192.168.7.200'
mount.nfs: prog 100003, trying vers=3, prot=6
mount.nfs: trying 192.168.7.200 prog 100003 vers 3 prot TCP port 2049
mount.nfs: prog 100005, trying vers=3, prot=17
mount.nfs: trying 192.168.7.200 prog 100005 vers 3 prot UDP port 1016
mount: (hint) your fstab has been modified, but systemd still uses
the old version; use 'systemctl daemon-reload' to reload.
root@acloud-w1:~# df -h
Filesystem Size Used Avail Use% Mounted on
udev 3.9G 0 3.9G 0% /dev
tmpfs 807M 5.6M 801M 1% /run
/dev/mmcblk0p2 59G 15G 41G 27% /
tmpfs 4.0G 0 4.0G 0% /dev/shm
tmpfs 5.0M 48K 5.0M 1% /run/lock
/dev/mmcblk0p1 510M 67M 444M 14% /boot/firmware
tmpfs 807M 0 807M 0% /run/user/501
overlay 59G 15G 41G 27% /var/lib/docker/overlay2/646f8cdc15cb8dc4c47b5065439373167c61324b4c763c10f79166905cfe2b45/merged
192.168.7.200:/zdata/docs 6.2T 1.8T 4.4T 29% /home/admin/docs
备注
虽然 ZFS sharenfs
不需要配置 /etc/exports
,但是由于 mountd
启动时检查 /etc/exports
配置。如果该配置文件不存在(可以为空)就会拒绝启动 mountd
。由于NFS服务输出需要 mountd
,所以这个 mountd
不启动,客户端是看不到服务器输出的卷集的。
有点搞...