NFS 客户端¶
NFS 客户端¶
NFS 版本 2 协议最早在 RFC1094(1989 年 3 月)中进行了文档化。此后,NFS 又发布了两个主要版本,NFSv3 在 RFC1813(1995 年 6 月)中进行了文档化,NFSv4 在 RFC3530(2003 年 4 月)中进行了文档化。
Linux NFS 客户端目前支持上述所有已发布的版本,并且正在努力添加对 NFSv4 协议的次要版本 1 的支持。
本文档的目的是提供有关 NFS 客户端的一些特殊功能的信息,这些功能可以由系统管理员配置。
nfs4_unique_id 参数¶
NFSv4 要求客户端使用一个唯一的字符串向服务器标识自己。客户端和服务器之间共享的文件打开和锁定状态与此身份相关联。为了支持健壮的 NFSv4 状态恢复和透明状态迁移,此身份字符串在客户端重新启动后不得更改。
在没有任何其他干预的情况下,Linux 客户端使用包含本地系统节点名称的字符串。然而,系统管理员通常不注意确保节点名称是完全限定的,并且在客户端系统的生命周期内不会更改。节点名称可能有其他管理要求,需要特定的行为,而这些行为作为 nfs_client_id4 字符串的一部分并不适用。
nfs.nfs4_unique_id 引导参数指定了一个唯一的字符串,当 NFS 客户端向服务器标识自己时,可以与系统节点名称一起使用。因此,如果系统节点名称不唯一,其 nfs.nfs4_unique_id 可以帮助防止与其他客户端的冲突。
nfs.nfs4_unique_id 字符串通常是一个 UUID,尽管它可以包含任何被认为在所有 NFS 客户端中都是唯一的字符串。应该在安装客户端系统时选择一个 nfs4_unique_id 字符串,就像系统根文件系统在安装时其标签中获得一个新的 UUID 一样。
该字符串应在客户端的整个生命周期内保持不变。如果小心确保客户端干净关闭且所有未完成的 NFSv4 状态已过期,以防止 NFSv4 状态丢失,则可以安全地更改它。
此字符串可以存储在 NFS 客户端的 grub.conf 中,也可以通过 PXE 等网络启动设施提供。它也可以指定为 nfs.ko 模块参数。
此唯一标识符字符串对于所有在容器中运行的 NFS 客户端都将相同,除非通过写入 /sys/fs/nfs/net/nfs_client/identifier 的值进行覆盖,该值将是写入进程的网络命名空间的本地值。
DNS 解析器¶
NFSv4 允许一个服务器通过特殊的“fs_locations”属性将 NFS 客户端引导至已迁移到另一个服务器上的数据。请参阅 RFC3530 第 6 节:文件系统迁移和复制 和 NFSv4 中引用的实现指南。
fs_locations 信息可以采用 IP 地址和路径的形式,也可以采用 DNS 主机名和路径的形式。后者要求 NFS 客户端进行 DNS 查找才能挂载新卷,因此需要一个向上调用以允许用户空间提供此服务。
假设用户已将“rpc_pipefs”文件系统挂载到通常的 /var/lib/nfs/rpc_pipefs,则向上调用包括以下步骤
进程检查 dns_resolve 缓存以查看它是否包含有效条目。如果包含,则返回该条目并退出。
如果不存在有效条目,则运行帮助脚本“/sbin/nfs_cache_getent”(可以使用“nfs.cache_getent”内核引导参数更改),带两个参数:- 缓存名称,“dns_resolve” - 要解析的主机名
在查找相应的 IP 地址后,帮助脚本将结果写入 rpc_pipefs 伪文件“/var/lib/nfs/rpc_pipefs/cache/dns_resolve/channel”,格式如下(文本)
“<ip 地址> <主机名> <ttl>n”
其中 <ip 地址> 采用常见的 IPv4 (123.456.78.90) 或 IPv6 (ffee:ddcc:bbaa:9988:7766:5544:3322:1100, ffee::1100, ...) 格式。<主机名> 与帮助脚本的第二个参数相同,<ttl> 是此缓存条目的“生存时间”(以秒为单位)。
注意
如果 <ip 地址> 无效,例如字符串“0”,则会创建一个负条目,这将导致内核将该主机名视为没有有效的 DNS 翻译。
一个基本的 /sbin/nfs_cache_getent 示例¶
#!/bin/bash
#
ttl=600
#
cut=/usr/bin/cut
getent=/usr/bin/getent
rpc_pipefs=/var/lib/nfs/rpc_pipefs
#
die()
{
echo "Usage: $0 cache_name entry_name"
exit 1
}
[ $# -lt 2 ] && die
cachename="$1"
cache_path=${rpc_pipefs}/cache/${cachename}/channel
case "${cachename}" in
dns_resolve)
name="$2"
result="$(${getent} hosts ${name} | ${cut} -f1 -d\ )"
[ -z "${result}" ] && result="0"
;;
*)
die
;;
esac
echo "${result} ${name} ${ttl}" >${cache_path}