CentOS 7 配置NFS

CentOS 7使用 systemctl 管理和设置NFS,以下按照服务端和客户端设置分别介绍。

设置Linux服务端

将移动硬盘挂载到 /data 目录:

mount /dev/sdb1 /data

使用以下命令安装 NFS 支持:

yum install nfs-utils

启动nfs服务并设置nfs相关服务在操作系统启动时启动:

systemctl enable --now rpcbind
systemctl enable --now nfs-server
systemctl enable --now nfs-lock
systemctl enable --now nfs-idmap

服务器端设置NFS卷输出,即编辑 /etc/exports 添加:

/data   192.168.122.0/24(rw,sync,no_root_squash,no_subtree_check)

参数解析:

  • /data – 共享目录

  • 192.168.122.0/24/24 – 允许访问NFS的客户端IP地址段(这里使用是针对libvirt虚拟化NAT网段)

  • rw – 允许对共享目录进行读写

  • sync – 实时同步共享目录,设置同步

  • no_root_squash – 允许root访问

  • no_all_squash - 允许用户授权

  • no_subtree_check - 如果卷的一部分被输出,从客户端发出请求文件的一个常规的调用子目录检查验证卷的相应部分。如果是整个卷输出,禁止这个检查可以加速传输。

NFS服务器排查

启动 nfs-server 时候报错

# systemctl start nfs-server
Job for nfs-server.service failed. See 'systemctl status nfs-server.service' and 'journalctl -xn' for details.

# systemctl status nfs-server.service
nfs-server.service - NFS server and services
Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled)
Active: failed (Result: exit-code) since Wed 2015-09-16 16:54:14 CST; 51s ago
Process: 17476 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=1/FAILURE)

Sep 16 16:54:14 ats-30-1 systemd[1]: Starting NFS server and services...
Sep 16 16:54:14 ats-30-1 exportfs[17476]: exportfs: /iso requires fsid= for NFS export
Sep 16 16:54:14 ats-30-1 systemd[1]: nfs-server.service: control process exited, code=exited status=1
Sep 16 16:54:14 ats-30-1 systemd[1]: Failed to start NFS server and services.
Sep 16 16:54:14 ats-30-1 systemd[1]: Unit nfs-server.service entered failed state.
Hint: Some lines were ellipsized, use -l to show in full.

参考 Using exportfs with NFSv4

NFSv4客户端可以查看NFSv4服务器输出的所有exorts作为一个单一文件系统,称为 NFSv4 伪文件系统( ``NFSv4 pseudo-file system`` )。在Red Hat Enterprise Linux上,这个伪文件系统被标识伪一个单一的,真实文件系统,通过 ``fsid=0`` 选项输出。

修改 /etc/exportfs ,添加 fsid=0

/iso    *(fsid=0,rw,sync,no_subtree_check,all_squash,anonuid=36,anongid=36)

NFS客户端挂载

Linux挂载NFS的客户端非常简单的命令,先创建挂载目录,然后用 -t nfs 参数挂载就可以了

mount -t nfs  192.168.122.1:/data /data

如果要设置客户端启动时候就挂载NFS,可以配置 /etc/fstab 添加以下内容

192.168.122.1:/data    /data  nfs auto,rw,vers=3,hard,intr,tcp,rsize=32768,wsize=32768      0   0

然后在客户端简单使用以下命令就可以挂载

mount /data

如果出现以下类似报错,则检查一下系统是否缺少 mount.nfs 程序,如果缺少,则表明尚未安装 nfs-utils 工具包,需要补充安装后才能作为客户端挂载NFS

mount: wrong fs type, bad option, bad superblock on 192.168.122.1:/data,
       missing codepage or helper program, or other error
       (for several filesystems (e.g. nfs, cifs) you might
       need a /sbin/mount.<type> helper program)

       In some cases useful info is found in syslog - try
       dmesg | tail or so.

通过防火墙挂载NFS服务

在生产环境,可能会因为安全需求在NFS服务器和客户端之间部署防火墙。此时,NFS客户端挂载的时候会有如下输出报错

mount.nfs: Connection timed out

参考 Running NFS Behind a Firewall 设置防火墙允许访问NFS服务器的服务端口,注意,需要配置NFS服务使用固定端口。

可以在Linux NFS服务器上执行以下命令获得NFS端口信息

rpcinfo -p

输出:

program vers proto   port  service
 100000    4   tcp    111  portmapper    <= rpcbind 服务
 100000    3   tcp    111  portmapper    <= rpcbind 服务
 100000    2   tcp    111  portmapper    <= rpcbind 服务
 100000    4   udp    111  portmapper    <= rpcbind 服务
 100000    3   udp    111  portmapper    <= rpcbind 服务
 100000    2   udp    111  portmapper    <= rpcbind 服务
 100024    1   udp  33948  status        <= rpc.statd 服务
 100024    1   tcp  35264  status        <= rpc.statd 服务
 100005    1   udp  20048  mountd        <= rpc.mount 服务
 100005    1   tcp  20048  mountd        <= rpc.mount 服务
 100005    2   udp  20048  mountd        <= rpc.mount 服务
 100005    2   tcp  20048  mountd        <= rpc.mount 服务
 100005    3   udp  20048  mountd        <= rpc.mount 服务
 100005    3   tcp  20048  mountd        <= rpc.mount 服务
 100003    3   tcp   2049  nfs
 100003    4   tcp   2049  nfs
 100227    3   tcp   2049  nfs_acl
 100003    3   udp   2049  nfs
 100003    4   udp   2049  nfs
 100227    3   udp   2049  nfs_acl
 100021    1   udp  48508  nlockmgr
 100021    3   udp  48508  nlockmgr
 100021    4   udp  48508  nlockmgr
 100021    1   tcp  38808  nlockmgr
 100021    3   tcp  38808  nlockmgr
 100021    4   tcp  38808  nlockmgr
  • rpc.mount 服务端口:

通过 lsof | grep rpc.mount 命令检查,可以看到 rpc.mount 服务使用的端口是

rpc.mount 27681          root    7u     IPv4           18221951        0t0        UDP *:mountd
rpc.mount 27681          root    8u     IPv4           18221953        0t0        TCP *:mountd (LISTEN)

这里 *:mountd 可以从 /etc/serives 配置文件中找出对应的端口是 20048

#grep mountd /etc/services
mountd          20048/tcp               # NFS mount protocol
mountd          20048/udp               # NFS mount protocol
  • rpc.statd 服务端口

lsof | grep rpc.statd 命令检查可以看到

rpc.statd 27663       rpcuser    8u     IPv4           18236210        0t0        UDP *:33948
rpc.statd 27663       rpcuser    9u     IPv4           18236212        0t0        TCP *:35264 (LISTEN)
  • rpcbind 服务端口

lsof | grep rpcbind 命令可以查看到

rpcbind   43419           rpc    4u     IPv4              28734        0t0        TCP *:sunrpc (LISTEN)
rpcbind   43419           rpc    7u     IPv4           11838817        0t0        UDP *:sunrpc
rpcbind   43419           rpc    8u     IPv4           11838818        0t0        UDP *:766

检查对应端口:

#grep sunrpc /etc/services
sunrpc          111/tcp         portmapper rpcbind      # RPC 4.0 portmapper TCP
sunrpc          111/udp         portmapper rpcbind      # RPC 4.0 portmapper UDP

设置RPC服务使用端口

由于NFS需要rpcbind,动态分配RPC服务端口会导致无法配置防火墙规则。

默认情况下,NFS使用的rpcbind使用动态设置RPC服务端口,需要修改以下配置:

  • 配置 /etc/sysconfig/nfs 文件来设置RPC服务使用的端口

    # 需要固定端口设置项前面的"#"符号需要去除,以便激活静态配置端口
    
    # Optional arguments passed to rpc.mountd. See rpc.mountd(8)
    RPCMOUNTDOPTS=""
    # Port rpc.mountd should listen on.
    MOUNTD_PORT=892
    
    # Optional arguments passed to rpc.statd. See rpc.statd(8)
    STATDARG=""
    # Port rpc.statd should listen on.
    STATD_PORT=662
    
    # Outgoing port statd should used. The default is port
    # is random
    STATD_OUTGOING_PORT=2020
    
  • 配置 /etc/modprobe.d/lockd.conf 中设置 nlockmgr 服务端口

    options lockd nlm_tcpport=32768
    options lockd nlm_udpport=32768
    options nfs callback_tcpport=32764  # 可选参数
    

这里 callback_tcpport 是用于 NFSv4.0 callback ,也就是设置 /proc/sys/fs/nfs/nfs_callback_tcpport ,并且还需要设置防火墙允许服务器能够连接客户端的端口 32764 。不过,对于NFSv4.1或更高版本,不需要此步骤,并且在纯NFSv4环境,也不需要 mountd, statdlockd 的端口。

lockd.conf 配置参考 Debian SecuringNFS

这个参数也可以通过 /etc/sysctl.conf 或者 /etc/sysctl.d/nfs-static-ports.conf 内核参数传递

  • 在CentOS 7上,内核参数 fs.nfs.nlm_tcpportfs.nfs.nlm_udpport 默认都是 0

    fs.nfs.nfs_callback_tcpport = 32764
    fs.nfs.nlm_tcpport = 32768
    fs.nfs.nlm_udpport = 32768
    
  • 重新加载NFS配置和服务(貌似 status 服务和 nlockmgr 服务端口不生效):

    systemctl restart nfs-config
    systemctl restart nfs-server
    

再次使用 rpcinfo -p 确认端口配置是否生效。

  • 改为重启以下服务,此时检查发现 status 端口正确改成 662 ,但是 nlockmgr 因为内核没有重新加载模块,所以端口没有修改

    systemctl restart nfs-idmap
    systemctl restart nfs-lock
    systemctl restart nfs-server
    systemctl restart rpcbind
    
  • 通过 sysctl 修改 nlockmgr 端口,但是发现如果不重新加载内核模块是不能订正 nlockmgr 端口

    sysctl -w fs.nfs.nlm_tcpport=32768
    sysctl -w fs.nfs.nlm_udpport=32768
    

暂时没有找到解决方法,所以还是通过重启操作系统来使得 nlockmgr 端口调整到 32768

配置防火墙端口

NFS的TCP和UDP端口2049

rpcbind/sunrpc的TCP和UDP端口111

设置 MOUNTD_PORT 的TCP和UDP端口

设置 STATD_PORT 的TCP和UDP端口

设置 LOCKD_TCPPORT 的TCP端口

设置 LOCKD_UDPPORT 的UDP端口

  • 使用 firewalld 的配置方法:

在 Linux NFS 服务器上使用以下命令开启iptables防火墙允许访问以上端口

firewall-cmd --permanent --add-port=2049/tcp
firewall-cmd --permanent --add-port=2049/udp
firewall-cmd --permanent --add-port=111/tcp
firewall-cmd --permanent --add-port=111/udp
firewall-cmd --permanent --add-port=892/tcp
firewall-cmd --permanent --add-port=892/udp
firewall-cmd --permanent --add-port=662/tcp
firewall-cmd --permanent --add-port=662/udp
firewall-cmd --permanent --add-port=32768/tcp
firewall-cmd --permanent --add-port=32768/udp

在 Linux NFS 服务器上使用以下命令重新加载防火墙规则

firewall-cmd --reload
  • 使用 iptables 的配置方法

    iptables -A INPUT -p tcp -m tcp --dport 2049 -j ACCEPT
    iptables -A INPUT -p udp -m udp --dport 2049 -j ACCEPT
    iptables -A INPUT -p tcp -m tcp --dport 111 -j ACCEPT
    iptables -A INPUT -p udp -m udp --dport 111 -j ACCEPT
    iptables -A INPUT -p tcp -m tcp --dport 892 -j ACCEPT
    iptables -A INPUT -p udp -m udp --dport 892 -j ACCEPT
    iptables -A INPUT -p tcp -m tcp --dport 662 -j ACCEPT
    iptables -A INPUT -p udp -m udp --dport 662 -j ACCEPT
    iptables -A INPUT -p tcp -m tcp --dport 32803 -j ACCEPT
    iptables -A INPUT -p udp -m udp --dport 32769 -j ACCEPT
    

如果要指定接口,也可以加上参数如 -i virbr0-nic ,例如 iptables -A INPUT -i virbr0-nic -p tcp -m tcp --dport 2049 -j ACCEPT

参考