NFS 容器化部署 & 配置参数详解

之前使用 Docker + NFS 的方案实现运算与存储分离,一直用的 NFSv3 搭配 Docker NFS Volume 来使用。这次折腾升级了下 NFSv4,发现细节上还是存在变化。本文主要介绍针对于 NFSv4 的服务端/客户端参数配置,以及如何使用 AutoFS 实现开机自动挂载。

容器化部署 NFS

这里使用的镜像是 gists/nfs-server,此镜像仅支持 NFSv4 协议,但配置起来非常简单。

services:
  core:
    environment:
      # 容器时区设置,非必须,个人习惯加一个而已
      - TZ=Asia/Shanghai
      # 此项与 volumes 有关,不设置的情况下默认是 /nfs-share
      - NFS_DIR=/nfs
      # 设置来访域,仅允许从该域的访问可以连接此 NFS,可以是域名或 IP 段
      - NFS_DOMAIN=192.168.0.0/16
      # NFS 服务端设置,具体参数含义参考后文。注意我这里配合 Docker 使用设置了 no_root_squash,如果作为普通的文件服务可以不设置这个。
      - NFS_OPTION=fsid=0,rw,sync,no_root_squash,no_subtree_check,nohide
    image: gists/nfs-server
    # 放开默认端口,如果调整了那挂载的时候也需要相应调整
    ports:
      - 2049:2049
    # 此容器需要以特权方式运行
    privileged: true
    restart: always
    volumes:
      # 此处 /opt/nfs 是 NFS 文件的本地存储路径。/nfs 是服务内部访问路径,可通过 NFS_DIR 设置。
      - /opt/nfs:/nfs

NFS 服务器导出参数详解

此部分讲解对应上文 NFS_OPTION 的设置

rw / ro
  挂载目录可读写/只读。
sync / async
  服务器接收到请求后,若设置为 async 将会在请求写入到稳定存储(如硬盘)之前回复请求,sync 将会等待请求写入稳定存储之后回复请求。
  注意如果设置 async,则在请求写入到稳定存储之前如果服务器遭遇意外停机可能会导致数据丢失或损坏。
wdelay / no_wdelay
  *如果上文设置了 async 则此项无效果。
  默认情况下如果服务器检测到有多个请求存在相关性,将会通过稍微延迟部分写请求的方式来将多个写请求通过一次操作提交到稳定存储,从而提升性能。
  但如果你的 NFS 经常处理细碎文件请求,此行为反而会降低性能,此时可以通过 no_wdelay 来关闭此默认行为。
hide / nohide
  此选项基于 IRIX NFS 提供的同名选项。
  通常当服务器导出两个嵌套挂载的文件系统时,如果客户端只挂载父文件系统,则在其子文件系统的位置将会看到一个空文件夹,即该文件系统是“隐藏的”。
  通过设置 nohide,文件系统将不再隐藏,适当授权的客户端将可以正确显示文件关系且不会注意到文件系统区别。
crossmnt
  此选项使客户端可以从标记为 crossmnt 的文件系统移动到挂载在其上的导出文件系统。
  因此,当子文件系统“B”挂载在父文件系统“A”上时,在“A”上设置crossmnt与在“B”上设置“nohide”具有相同的效果。
no_subtree_check
  禁用子树检查,从 nfs-utils 1.1.0 版本开始默认禁用。
  启用此选项会提升安全性,但是可能会导致客户端在打开文件时重命名文件时出现问题,建议禁用。
insecure_locks / no_auth_nlm
  *两个选项为同义项,如果设置的话只需设置任意一个。
  此选项告诉 NFS 服务器不要求对锁定请求(即使用NLM协议的请求)进行身份验证。
  对于较早期的 NFS 客户端实现没有在锁定请求时发送身份验证信息,如果你发现你只能锁定全局可读文件时则应设置此项。
no_acl
  在某些特别修补过的内核上,当导出支持 ACL 的文件系统时,此选项告诉 nfsd 不向客户端显示 ACL,因此客户端将只看到给定文件系统上的一部分实际权限。
  此选项仅针对支持它的特别修补过的内核上有效,即默认无需设置此项。
mountpoint=/path / mp=/path
  设置此项将会检测只有在给定目录成功挂载后才能允许 NFS 导出。
  默认不设置时会检测导出设置里的路径,以上文为例就是/opt/nfs(也就是容器里的/nfs)。
fsid=num|root|uuid
  NFS 的文件系统标识。
  对于 NFSv4,可以通过设置 fsid=root 或 fsid=0 来设置一个特殊的文件系统标识当前导出是所有导出文件系统的根。
root_squash / no_root_squash / all_squash
  用户身份映射,默认为 root_squash,即当客户端请求 root 身份操作时,服务端将操作映射为 anonymous 或 nobody 进行操作。
  但在特定情况下,此选项会导致程序尝试更改权限时报错,此时你可以使用 no_root_squash 关闭身份映射功能。
  你也可以使用 all_squash 来为所有用户身份启用映射,注意此时同样会遇到上述问题,所以一定要按场景选择此策略。
anonuid=num / anongid=num
  当用户身份映射不为 no_root_squash 时,当接收到需要身份映射的请求时要把对应的 uid/gid 映射到哪一个身份上。
  默认为 anonuid=65534 和 anongid=65534。

NFS 客户端挂载参数详解

注意上文设置了 fsid=0,客户端在挂载时使用的挂载路径则设置为 /,而不是 /nfs。

挂载 NFS 到本地路径

# mount -v -t nfs -o vers=4,port=2049 NFS_SERVER_IP:/ /LOCAL_PATH
# 比如假设上文服务器位于 192.168.1.10,要把导出的文件挂载到客户机的 /opt/nfs 路径下,则需要运行以下命令:
sudo mkdir /opt/nfs
mount -v -t nfs -o vers=4,port=2049 192.168.1.10:/ /opt/nfs

# 取消挂载
umount /opt/nfs

挂载参数详解

此部分参数应用于客户端 mount -o 参数

rw / ro
  挂载路径为可读写/只读
soft / hard
  当 NFS 请求超时后,此项不设置或设置为 hard 时,NFS 将会无限重试请求。
  如果设置为 soft 时,当请求超时超过 retrans 所设定的次数后将会向调用方返回文件操作错误。
timeo=num
  NFS 请求超时时间(单位是 0.1 秒)
retrans=num
  NFS 请求超时重试次数,当设置 hard 时此项无效
rsize=num
  每次 NFS 请求时能从服务器读取的最大数据量,最大值为 1,048,576 字节。
  此值存在自动转换规则,规则为:小于 4096 时取 4096,大于 1048576 时取 1048576,在两个值区间内但不为 1024 倍数向下取最近的 1024 倍数值。
  若不设置,或设置值大于客户端或服务端所能接受的最大值,则会自动取双方所能共同支持的最大值。
wsize=num
  每次 NFS 请求时能从服务器写入的最大数据量,基本规则同 rsize
ac / noac
  设置客户端是否应当缓存文件属性,默认启用。禁用此项将会显著降低性能。
acregmin=num / acregmax=num
  文件属性缓存最小/最大刷新时间(秒),默认为 3 / 60
acdirmin=num / acdirmax=num
  目录属性缓存最小/最大刷新时间(秒),默认为 30 / 60
actimeo=num
  统一设置文件属性/目录属性的缓存时间,不设置此项将会自动使用上述默认值
bg / fg
  当请求挂载失败时,此项不设置或为 fg 将会导致主进程立刻以非0状态结束。
  此项为 bg 将会新建一个进程持续尝试请求挂载,且主进程会以0状态结束。
retry=num
  挂载失败重试次数
sharecache / nosharecache
  多个实例挂载同目录时是否共享文件/目录属性缓存
resvport / noresvport
  不设置或设置为 resvport 时只使用限定的部分端口进行连接,一般无需设置。
  设置为 noresvport 时可以使用全部端口进行连接,可以增加可使用端口范围。
lookupcache=all|none|pos|positive
  调整客户端缓存行为,一般无需设置。
port=num
  设置 NFS 连接端口,不设置使用默认端口连接
nfsvers=num / vers=num
  设置 NFS 协议版本,不设置会从 NFSv4 开始向上尝试协议版本
intr / nointr
  挂载点上的文件操作是否可以被信号中断。
  如果指定了 intr 选项,当一个正在进行的 NFS 操作被信号中断时,系统调用会返回 EINTR 错误,如果指定了 nointr 选项,信号不会中断 NFS 操作。
  使用 intr 选项比使用 soft 选项更好,因为它导致数据损坏的可能性较小。
  注意在内核 2.6.25 之后,只有 SIGKILL 信号可以中断挂起的 NFS 操作,因此这个选项在这些内核中将不会生效。
cto / nocto
  控制缓存一致性,设置为 cto 将会在文件打开和关闭时检查和刷新缓存,nocto 将会使用非标准方法确定文件是否更改,不适用于频繁更改的数据。
clientaddr=n.n.n.n
  用于指定一个单一的 IPv4 地址(点分十进制形式)或非链路本地的 IPv6 地址,供 NFS 客户端在挂载点上允许服务器执行 NFSv4 回调请求,默认会自动发现。

使用 AutoFS 实现 NFS 客户端自动挂载

注意!AutoFS 章节适用于 Ubuntu/Debian 操作系统,演示代码测试于 Ubuntu Server 22.04 LTS

安装 AutoFS:

sudo apt update
sudo apt-get install autofs

AutoFS 有两个关键文件,一个是 /etc/auto.master,另一个是 /etc/auto.misc。这两个文件在你安装 AutoFS 后应该会自动生成。

首先编辑 /etc/auto.master

# /etc/auto.master
# 在此文件开头添加一行:
/-    /etc/auto.misc    --timeout 180

然后编辑 /etc/auto.misc,按照如下释义设置你的挂载点

# /etc/auto.misc
# 本地挂载路径    挂载参数                   NFS 服务器信息
# /opt/nfs       -fstype=nfs4,rw           NFS_SERVER_IP:/
# /opt/nfs       -fstype=nfs,nfsvers=3,rw  NFS_SERVER_IP:/

# 比如假设上文服务器位于 192.168.1.10,要把导出的文件挂载到客户机的 /opt/nfs 路径下,则需要设置为
/opt/nfs  -fstype=nfs4,rw  192.168.1.10:/

启动 AutoFS 服务

# 启动服务
sudo /etc/init.d/autofs start
# 设置开机自启动
sudo systemctl enable autofs.service

后续如果对挂载文件进行了更改,可以通过以下命令管理 AutoFS

# 停止 AutoFS 服务
sudo systemctl stop autofs.service
# 启动 AutoFS 服务
sudo systemctl start autofs.service
# 重启 AutoFS 服务
sudo systemctl restart autofs.service

# 关闭 AutoFS 服务开机自启
sudo systemctl disable autofs.service

参考引用


NFS 容器化部署 & 配置参数详解
https://blog.tihus.com//archives/1a62d61a-8f0f-45cf-9068-7b179b01776f
作者
MitsuhaYuki
发布于
2024年10月08日
更新于
2025年03月04日
许可协议