# 32.3.网络文件系统（NFS）

FreeBSD 支持网络文件系统（NFS），它允许服务器通过网络与客户端共享目录和文件。使用 NFS，用户和程序可以像访问本地文件一样访问远程系统上的文件。

NFS 有许多实际应用。一些常见的用途包括：

* 原本会在每个客户端上重复的数据可以保存在一个位置，并由网络上的客户端访问。
* 多个客户端可能需要访问 **/usr/ports/distfiles** 目录。共享该目录可以快速访问源文件，而无需将其下载到每个客户端。
* 在大型网络中，通常将所有用户的主目录存储在一个中央 NFS 服务器上会更方便。用户可以在网络中的任何客户端上登录，并访问他们的主目录。
* 管理 NFS 导出变得简化。例如，只需要设置一个文件系统的安全性或备份策略。
* 可移动存储介质可以被网络上的其他机器使用。这减少了网络中的设备数量，并提供了一个集中管理其安全性的地方。通常，从一个集中安装的介质上为多台机器安装软件更加方便。

NFS 由一个服务器和一个或多个客户端组成。客户端远程访问存储在服务器机器上的数据。为了使这一功能正常工作，必须配置并运行一些进程。

服务器上必须运行以下守护进程：

| 守护进程    | 描述                         |
| ------- | -------------------------- |
| nfsd    | NFS 守护进程，处理来自 NFS 客户端的请求。  |
| mountd  | NFS 挂载守护进程，处理来自 nfsd 的请求。  |
| rpcbind | 允许 NFS 客户端发现 NFS 服务器使用的端口。 |

在客户端运行 [nfsiod(8)](https://man.freebsd.org/cgi/man.cgi?query=nfsiod\&sektion=8\&format=html) 可以提高性能，但不是必需的。

## 32.3.1. 配置服务器

NFS 服务器将共享的文件系统在 **/etc/exports** 中指定。该文件中的每一行指定一个要导出的文件系统，哪些客户端有权限访问该文件系统，以及任何访问选项。添加条目时，每个导出的文件系统、它的属性以及允许的主机必须在同一行上。如果在条目中没有列出客户端，则网络中的任何客户端都可以挂载该文件系统。

以下 **/etc/exports** 条目演示了如何导出文件系统。这些示例可以根据读者网络中的文件系统和客户端名称进行修改。此文件中有许多选项，但这里只提到几个。有关完整选项列表，请参阅 [exports(5)](https://man.freebsd.org/cgi/man.cgi?query=exports\&sektion=5\&format=html)。

以下示例展示了如何将 **/cdrom** 导出到名为 *alpha*、*bravo* 和 *charlie* 的三台主机：

```sh
/cdrom -ro alpha bravo charlie
```

`-ro` 标志将文件系统设为只读，防止客户端对导出的文件系统进行任何更改。该示例假设主机名在 DNS 或 **/etc/hosts** 中。如果网络中没有 DNS 服务器，请参考 [hosts(5)](https://man.freebsd.org/cgi/man.cgi?query=hosts\&sektion=5\&format=html)。

下一个示例将 **/home** 导出到三个客户端，通过 IP 地址指定。这对于没有 DNS 或 **/etc/hosts** 条目的网络很有用。`-alldirs` 标志允许子目录作为挂载点。换句话说，它不会自动挂载子目录，但允许客户端根据需要挂载所需的目录。

```sh
/usr/home  -alldirs  10.0.0.2 10.0.0.3 10.0.0.4
```

下一个示例将 **/a** 导出，以便来自不同域的两个客户端可以访问该文件系统。`-maproot=root` 允许远程系统上的 `root` 用户以 `root` 身份写入导出的文件系统。如果未指定 `-maproot=root`，客户端的 `root` 用户将被映射为服务器上的 `nobody` 账户，并将受到定义为 `nobody` 的访问限制。

```sh
/a  -maproot=root  host.example.com box.example.org
```

每个文件系统只能指定一个客户端。例如，如果 **/usr** 是一个文件系统，则以下条目无效，因为两个条目都指定了相同的主机：

```sh
# Invalid when /usr is one file system
/usr/src   client
/usr/ports client
```

此情况的正确格式是使用一个条目：

```sh
/usr/src /usr/ports  client
```

以下是一个有效的导出列表示例，其中 **/usr** 和 **/exports** 是本地文件系统：

```sh
# 将 src 和 ports 导出到 client01 和 client02，但只有
# client01 拥有 root 权限
/usr/src /usr/ports -maproot=root    client01
/usr/src /usr/ports               client02
# 客户端机器具有 root 权限，并且可以在 /exports 上任意挂载
# 世界上任何人都可以以只读方式挂载 /exports/obj
/exports -alldirs -maproot=root      client01 client02
/exports/obj -ro
```

要在启动时启用 NFS 服务器所需的进程，请将以下选项添加到 **/etc/rc.conf**：

```sh
rpcbind_enable="YES"
nfs_server_enable="YES"
mountd_enable="YES"
```

现在可以通过运行以下命令启动服务器：

```sh
# service nfsd start
```

每当启动 NFS 服务器时，mountd 会自动启动。然而，mountd 只在启动时读取 **/etc/exports**。要使后续的 **/etc/exports** 编辑立即生效，可以强制 mountd 重新读取它：

```sh
# service mountd reload
```

有关通过 NFS 使用 `sharenfs` ZFS 属性导出 ZFS 数据集的描述，请参阅 [zfs-share(8)](https://man.freebsd.org/cgi/man.cgi?query=zfs-share\&sektion=8\&format=html)。

有关 NFS 版本 4 配置的描述，请参阅 [nfsv4(4)](https://man.freebsd.org/cgi/man.cgi?query=nfsv4\&sektion=4\&format=html)。

## 32.3.2. 配置客户端

要启用 NFS 客户端，在每个客户端的 **/etc/rc.conf** 文件中设置以下选项：

```sh
nfs_client_enable="YES"
```

然后，在每个 NFS 客户端上运行以下命令：

```sh
# service nfsclient start
```

客户端现在拥有挂载远程文件系统所需的一切。在这些示例中，服务器的名称是 `server`，客户端的名称是 `client`。要将 **/home** 挂载到 `client` 上的 **/mnt** 挂载点：

```sh
# mount server:/home /mnt
```

现在，**/home** 中的文件和目录将可在 `client` 上的 **/mnt** 目录中访问。

要在每次客户端启动时自动挂载远程文件系统，请将其添加到 **/etc/fstab** 文件中：

```sh
server:/home    /mnt    nfs    rw    0    0
```

有关所有可用选项的描述，请参考 [fstab(5)](https://man.freebsd.org/cgi/man.cgi?query=fstab\&sektion=5\&format=html)。

## 32.3.3. 锁定

某些应用程序需要文件锁定才能正确运行。要启用锁定，在客户端和服务器上执行以下命令：

```sh
# sysrc rpc_lockd_enable="YES"
```

然后启动 [rpc.lockd(8)](https://man.freebsd.org/cgi/man.cgi?query=rpc.lockd\&sektion=8\&format=html) 服务：

```sh
# service lockd start
```

如果服务器不需要锁定，则可以通过在挂载时包含 `-L` 选项来配置 NFS 客户端进行本地锁定。有关更多详细信息，请参见 [mount\_nfs(8)](https://man.freebsd.org/cgi/man.cgi?query=mount_nfs\&sektion=8\&format=html)。

## 32.3.4. 使用 [autofs(5)](https://man.freebsd.org/cgi/man.cgi?query=autofs\&sektion=5\&format=html) 自动挂载

> **注意**
>
> 从 FreeBSD 10.1-RELEASE 开始支持 [autofs(5)](https://man.freebsd.org/cgi/man.cgi?query=autofs\&sektion=5\&format=html) 自动挂载功能。要在较旧版本的 FreeBSD 中使用自动挂载功能，请改用 [amd(8)](https://man.freebsd.org/cgi/man.cgi?query=amd\&sektion=8\&format=html)。本章仅描述 [autofs(5)](https://man.freebsd.org/cgi/man.cgi?query=autofs\&sektion=5\&format=html) 自动挂载功能。

[autofs(5)](https://man.freebsd.org/cgi/man.cgi?query=autofs\&sektion=5\&format=html) 是多个组件的通用名称，这些组件共同实现了每当访问该文件系统中的文件或目录时，自动挂载远程和本地文件系统的功能。它包括内核组件 [autofs(5)](https://man.freebsd.org/cgi/man.cgi?query=autofs\&sektion=5\&format=html) 和几个用户空间应用程序：[automount(8)](https://man.freebsd.org/cgi/man.cgi?query=automount\&sektion=8\&format=html)、[automountd(8)](https://man.freebsd.org/cgi/man.cgi?query=automountd\&sektion=8\&format=html) 和 [autounmountd(8)](https://man.freebsd.org/cgi/man.cgi?query=autounmountd\&sektion=8\&format=html)。它作为 FreeBSD 早期版本中 [amd(8)](https://man.freebsd.org/cgi/man.cgi?query=amd\&sektion=8\&format=html) 的替代方案提供。为了向后兼容，仍然提供 amd，因为两者使用不同的映射格式；autofs 使用的映射格式与其他 SVR4 自动挂载器相同，如 Solaris、MacOS X 和 Linux 中的自动挂载器。

[autofs(5)](https://man.freebsd.org/cgi/man.cgi?query=autofs\&sektion=5\&format=html) 虚拟文件系统由 [automount(8)](https://man.freebsd.org/cgi/man.cgi?query=automount\&sektion=8\&format=html) 挂载在指定的挂载点，通常在启动时调用。

每当进程尝试访问 [autofs(5)](https://man.freebsd.org/cgi/man.cgi?query=autofs\&sektion=5\&format=html) 挂载点中的文件时，内核将通知 [automountd(8)](https://man.freebsd.org/cgi/man.cgi?query=automountd\&sektion=8\&format=html) 守护进程，并暂停触发的进程。[automountd(8)](https://man.freebsd.org/cgi/man.cgi?query=automountd\&sektion=8\&format=html) 守护进程将处理内核请求，通过查找合适的映射并挂载相应的文件系统，随后通知内核释放被阻塞的进程。[autounmountd(8)](https://man.freebsd.org/cgi/man.cgi?query=autounmountd\&sektion=8\&format=html) 守护进程在一定时间后自动卸载自动挂载的文件系统，除非这些文件系统仍在使用中。

主要的 autofs 配置文件是 **/etc/auto\_master**。它将单独的映射分配给顶级挂载点。有关 **auto\_master** 和映射语法的说明，请参见 [auto\_master(5)](https://man.freebsd.org/cgi/man.cgi?query=auto_master\&sektion=5\&format=html)。

有一个特殊的自动挂载映射挂载在 **/net** 目录下。当访问该目录中的文件时，[autofs(5)](https://man.freebsd.org/cgi/man.cgi?query=autofs\&sektion=5\&format=html) 会查找相应的远程挂载并自动挂载它。例如，尝试访问 **/net/foobar/usr** 中的文件将会告诉 [automountd(8)](https://man.freebsd.org/cgi/man.cgi?query=automountd\&sektion=8\&format=html) 挂载来自 `foobar` 主机的 **/usr** 导出文件系统。

**示例 2. 使用** [**autofs(5)**](https://man.freebsd.org/cgi/man.cgi?query=autofs\&sektion=5\&format=html) **挂载导出文件系统**

在这个示例中，`showmount -e` 显示了可以从 NFS 服务器 `foobar` 挂载的文件系统：

```sh
% showmount -e foobar
Exports list on foobar:
/usr                               10.10.10.0
/a                                 10.10.10.0
% cd /net/foobar/usr
```

`showmount` 输出显示 **/usr** 是一个导出文件系统。当切换到 **/net/foobar/usr** 目录时，[automountd(8)](https://man.freebsd.org/cgi/man.cgi?query=automountd\&sektion=8\&format=html) 拦截请求并尝试解析主机名 `foobar`。如果成功， [automountd(8)](https://man.freebsd.org/cgi/man.cgi?query=automountd\&sektion=8\&format=html) 会自动挂载源导出文件系统。

要在启动时启用 [autofs(5)](https://man.freebsd.org/cgi/man.cgi?query=autofs\&sektion=5\&format=html)，请在 **/etc/rc.conf** 中添加以下行：

```sh
autofs_enable="YES"
```

然后，可以通过运行以下命令启动 [autofs(5)](https://man.freebsd.org/cgi/man.cgi?query=autofs\&sektion=5\&format=html)：

```sh
# service automount start
# service automountd start
# service autounmountd start
```

[autofs(5)](https://man.freebsd.org/cgi/man.cgi?query=autofs\&sektion=5\&format=html) 映射格式与其他操作系统中的格式相同。从其他来源获取的关于此格式的信息也会很有帮助，例如 [Mac OS X 文档](http://web.archive.org/web/20160813071113/http://images.apple.com/business/docs/Autofs.pdf)。

有关更多信息，请参阅 [automount(8)](https://man.freebsd.org/cgi/man.cgi?query=automount\&sektion=8\&format=html)、[automountd(8)](https://man.freebsd.org/cgi/man.cgi?query=automountd\&sektion=8\&format=html)、[autounmountd(8)](https://man.freebsd.org/cgi/man.cgi?query=autounmountd\&sektion=8\&format=html) 和 [auto\_master(5)](https://man.freebsd.org/cgi/man.cgi?query=auto_master\&sektion=5\&format=html) 手册。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://handbook.bsdcn.org/di-32-zhang-wang-luo-fu-wu-qi/32.3.-wang-luo-wen-jian-xi-tong-nfs.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
