NFS详解

00、什么是 NFS (Network FileSystem)

  NFS 就是 Network FileSystem 的缩写,最早之前是由 sun这家公司所发展出来的。 他最大的功能就是可以透过网络,让不同的机器、不同的作业系统、可以彼此分享个别的档案 (share files)。所以,您也可以简单的将他看做是一个档案服务器 (file server) 呢!这个 NFS 服务器可以让您的 PC 来将网络远端的 NFS 主机分享的目录,挂载到本地端的机器当中, 在本地端的机器看起来,那个远端主机的目录就好像是自己的一个磁碟分割槽一样 (partition)!使用上面相当的便利!
NFS详解


  就如同上面的图示一般,当我们的 NFS Server 设定好了分享出来的 /home/sharefile 这个目录后,其他的 NFS Client 端就可以将这个目录挂载到自己系统上面的某个挂载点 (挂载点可以自订),例如前面图示中的 NFS client 1 与 NFS client 2 挂载的目录就不相同。我只要在 NFS client 1 系统中进入 /home/data/sharefile 内,就可以看到 NFS Server 系统内的 /home/sharefile 目录下的所有资料了 (当然,权限要足够)!这个 /home/data/sharefile 就好像 NFS client 1 自己机器里面的一个 partition 喔!只要权限对了,那么您可以使用 cp, cd, mv, rm... 等等磁碟或档案相关的指令

  好的,既然 NFS 是透过网络来进行资料的传输,那么经由 socket pair 的概念你会知道 NFS 应该会使用一些 port 吧?那么 NFS 使用哪个 port来进行传输呢? 因为 NFS 用来传输的 port 是随机选择小于 1024 以下的端口来使用的。 咦!那用户端怎么知道你服务器端使用那个 port 啊?此时就得要 远端程序呼叫 (Remote Procedure Call, RPC) 的协定来辅助!底下我们就来谈谈什么是 RPC?

01、什么是 RPC (Remote Procedure Call)

  因为 NFS 个支持的功能相当的多,而不同的功能都会使用不同的程序来启动, 每启动一个功能就会启用一些 port 来传输资料,因此, NFS 的功能所对应的 port 才没有固定住, 而是采用随机取用一些未被使用的小于 1024 的端口来作为传输之用。但如此一来又造成用户端想要连上服务器时的困扰, 因为用户端得要知道服务器端的相关端口才能够连线吧!

此时我们就得需要远端程序呼叫 (RPC) 的服务!RPC 最主要的功能就是在指定每个 NFS 功能所对应的 port number ,并且回报给用户端,让用户端可以连结到正确的端口上去。 那 RPC 又是如何知道每个 NFS 的端口呢?这是因为当服务器在启动 NFS 时会随机取用数个端口,并主动的向 RPC 注册,因此 RPC 可以知道每个端口对应的 NFS 功能,然后 RPC 又是固定使用 port 111 来监听用户端的需求并回报用户端正确的端口, 所以当然可以让 NFS 的启动更为轻松愉快了!

当用户端有 NFS 档案存取需求时,他会如何向服务器端要求资料呢?

1         用户端会向服务器端的 RPC (port 111) 发出 NFS 档案存取功能的询问要求;

2         服务器端找到对应的已注册的 NFS daemon 端口后,会回报给用户端;

3         用户端了解正确的端口后,就可以直接与 NFS daemon 来连线。

由于 NFS 的各项功能都必须要向 RPC 来注册,如此一来 RPC 才能了解 NFS 这个服务的各项功能之 port number, PID, NFS 在主机所监听的 IP 等等,而用户端才能够透过 RPC 的询问找到正确对应的端口。 也就是说,NFS 必须要有 RPC 存在时才能成功的提供服务, 因此我们称 NFS 为 RPC server 的一种。事实上,有很多这样的服务器都是向 RPC 注册的, 举例来说,NIS (Network Information Service) 也是 RPC server 的一种呢。 此外,由图二你也会知道,不论是用户端还是服务器端,要使用 NFS 时,两者都需要启动 RPC 才行喔!

NFS 启动的 RPC daemons

我们现在知道 NFS 服务器在启动的时候就得要向 RPC 注册,所以 NFS 服务器也被称为 RPC server 之一。 那么 NFS 服务器主要的任务是进行档案系统的分享,档案系统的分享则与权限有关。 所以 NFS 服务器启动时至少需要两个 daemons ,一个管理 client 端是否能够登入的问题, 一个管理 client 端能够取得的权限。如果你还想要管理 quota 的话,那么 NFS 还得要再载入其他的 RPC 程序就是了。我们以较单纯的 NFS 主机来说∶

  • rpc.nfsd∶
    这个 daemon 主要的功能就是在管理 Client 是否能够登入主机的权限,其中还包含这个登入者的 ID 的判别喔!
  • rpc.mountd
    这个 daemon 主要的功能,则是在管理 NFS 的档案系统哩!当 Client 端顺利的通过 rpc.nfsd 而登入主机之后,在他可以使用 NFS 服务器提供的档案之前,还会经过档案使用权限 (就是那个 -rwxrwxrwx 与 owner, group 那几个权限) 的认证程序!他会去读 NFS 的设定档 /etc/exports 来比对 Client 的权限,当通过这一关之后 Client 就可以取得使用 NFS 档案的权限! (注∶这个也是我们用来管理 NFS 分享之目录的使用权限与安全设定的地方哩!)
  • rpc.lockd (非必要)
    这个玩意儿可以用在管理档案的锁定 (lock) 用途。为何档案需要『锁定』呢? 因为既然分享的 NFS 档案可以让用户端使用,那么当多个用户端同时尝试写入某个档案时, 就可能对于该档案造成一些问题!这个 rpc.lockd 则可以用来克服这个问题。 但 rpc.lockd 必须要同时在用户端与服务器端都开启才行喔!此外, rpc.lockd 也常与 rpc.statd 同时启用。
  • rpc.statd (非必要)
    可以用来检查档案的一致性,与 rpc.lockd 有关!若发生因为用户端同时使用同一档案造成档案可能有所损毁时, rpc.statd 可以用来检测并尝试回复该档案。与 rpc.lockd 同样的,这个功能必须要在服务器端与用户端都启动才会生效。

NFS 的档案存取权限

不知道你有没有想过这个问题,在图一的环境下,假如我在 NFS client 1 上面以 sweet 这个使用者身份想要去存取 /home/data/sharefile/ 这个来自 NFS server 所提供的档案系统时, 请问 NFS server 所提供的档案系统会让我以什么身份去存取?是 sweet 还是?

为什么会这么问呢?这是因为 NFS 本身的服务并没有进行身份登入的识别, 所以说,当你在用户端以 sweet 的身份想要存取服务器端的档案系统时, 服务器端会以用户端的使用者 UID 与 GID 等身份来尝试读取服务器端的档案系统。这时有个有趣的问题就产生! 那就是如果用户端与服务器端的使用者身份并不一致怎么办
  当我以 sweet 这个一般身份使用者要去存取来自服务器端的档案时,你要先注意到的是∶ 档案系统的 inode 所记录的属性为 UID, GID 而非帐号与群组名。 那一般 Linux 主机会主动的以自己的 /etc/passwd, /etc/group 来查询对应的使用者、群组名称。 所以当 sweet 进入到该目录后,会参照 NFS client 1 的使用者与群组名称。 但是由于该目录的档案主要来自 NFS server ,所以可能就会发现几个情况∶

  • NFS server/NFS client 刚好有相同的帐号与群组
    则此时使用者可以直接以 sweet 的身份进行服务器所提供的档案系统之存取。

  • NFS server 的 501 这个 UID 帐号对应为 vbird
    若 NFS 服务器上的 /etc/passwd 里面 UID 501 的使用者名称为 vbird 时, 则用户端的 sweet 可以存取服务器端的 vbird 这个使用者的档案喔!只因为两者具有相同的 UID 而已。这就造成很大的问题了!因为没有人可以保证用户端的 UID 所对应的帐号会与服务器端相同, 那服务器所提供的资料不就可能会被错误的使用者乱改?

  • NFS server 并没有 501 这个 UID
    另一个极端的情况是,在服务器端并没有 501 这个 UID 的存在,则此时 sweet 的身份在该目录下会被压缩成匿名者, 一般 NFS 的匿名者会以 UID 为 65534 为其使用者,早期的 Linux distributions 这个 65534 的帐号名称通常是 nobody ,我们的 RHEL5 则取名为 nfsnobody 。

  • 如果使用者身份是 root 时
    有个比较特殊的使用者,那就是每个 Linux 主机都有的 UID 为 0 的 root 。 想一想,如果用户端可以用 root 的身份去存取服务器端的档案系统时,那服务器端的资料哪有什么保护性? 所以在预设的情况下, root 的身份会被主动的压缩成为匿名者。

总之,用户端使用者能做的事情是与 UID 及其 GID 有关的,那当用户端与服务器端的 UID 及帐号的对应不一致时, 可能就会造成档案系统使用上的困扰,这个就是 NFS 档案系统在使用上面的一个很重要的地方! 而在了解使用者帐号与 UID 及档案系统的关系之后,要实际在用户端以 NFS 取用服务器端的档案系统时, 你还得需要具有∶

  • NFS 服务器有开放可写入的权限 (与 /etc/exports 设定有关);
  • 实际的档案权限具有可写入 (w) 的权限。

当你满足了

(1)使用者帐号,亦即 UID 的相关身份;

(2)NFS 服务器允许有写入的权限;

(3)档案系统确实具有 w 的权限时,你才具有该档案的可写入权限喔! 尤其是身份 (UID) 确认的环节部分,最容易搞错!也因为如此, 所以 NFS 通常需要与 NIS 这一个可以确认用户端与服务器端身份一致的服务搭配使用,以避免身份的错乱啊!

02、NFS Server 端的设定

既然要使用 NFS 的话,就得要安装 NFS 所需要的套件了!底下让我们查询一下系统有无安装所需要的套件, NFS 套件的架构以及如何设定 NFS 主机吧!

所需要的套件

以 RHEL5 为例的话,要设定好 NFS 服务器我们必须要有两个套件才行,分别是∶

  • NFS 主程序∶nfs-utils
  • RPC 主程序∶portmap  #rhel5.x  RHEL6,不需要了,rpcbind服务

portmap
就如同刚刚提的到,我们的 NFS 其实可以被视为一个 RPC 程序,而要启动任何一个 RPC 程序之前,我们都需要做好 port 的对应 (mapping) 的工作才行,这个工作其实就是『 portmap 』这个服务所负责的!也就是说, 在启动任何一个 RPC server 之前,我们都需要启动 portmap 才行!
 

nfs-utils
就是提供 rpc.nfsd 及 rpc.mountd 这两个 NFS daemons 与其他相关 documents 与说明文件、执行档等的套件!这个就是 NFS 的主要套件!一定要有喔!

NFS 的套件结构

NFS 这个咚咚真的是很简单,上面我们提到的 NFS 套件中,设定档只有一个,执行档也不多, 记录档也三三两两而已呐!赶紧先来看一看吧! ^_^

  • /etc/exports
    这个档案就是 NFS 的主要设定档了!不过,系统并没有预设值,所以这个档案『 不一定会存在』,您可能必须要使用 vi 主动的建立起这个档案喔!我们等一下要谈的设定也仅只是这个档案而已呐!
  • /usr/sbin/exportfs
    这个是维护 NFS 分享资源的指令,我们可以利用这个指令重新分享 /etc/exports 变更的目录资源、将 NFS Server 分享的目录卸载或重新分享等等,这个指令是 NFS 系统里面相当重要的一个喔!至于指令的用法我们在底下会再介绍。
  • /usr/sbin/showmount
    这是另一个重要的 NFS 指令。exportfs 是用在 NFS Server 端,而 showmount 则主要用在 Client 端。这个 showmount 可以用来察看 NFS 分享出来的目录资源喔!
  • /var/lib/nfs/*tab
    在 NFS 服务器的登录档都放置到 /var/lib/nfs/ 目录里面,在该目录下有两个比较重要的登录档, 一个是 etab ,主要记录了 NFS 所分享出来的目录的完整权限设定值;另一个 xtab 则记录曾经连结到此 NFS 主机的相关用户端资料。

03、/etc/exports 设定档的语法与参数

  在开始 NFS 服务器的设定之前,您必须要了解的是,NFS 会直接使用到核心功能,所以你的核心必须要有个援 NFS 才行。 万一如果你的核心版本小于 2.2 版,或者重新自行编译过核心的话,那么就得要很注意! 因为你可能会忘记选择 NFS 的核心个援啊!

还好,我们 RHEL5 或者是其他版本的 Linux ,预设核心通常是个援 NFS 功能的, 所以你只要确认你的核心版本是目前新的 2.6.x 版,并且使用你的 distribution 所提供的核心, 那应该就不会有问题!

至于 NFS 服务器的架设实在很简单,你只要编辑好主要设定档 /etc/exports 之后, 先启动 portmap ,然后再启动 nfs ,你的 NFS 就成功了! 不过这样的设定能否对用户端生效?那就得要考虑你权限方面的设定能力了。 废话少说,我们就直接来看看那个 /etc/exports 应该如何设定吧! 某些 distributions 并不会主动提供 /etc/exports 档案,所以请您自行手动建立他吧

[root@linux     ~]# vi /etc/exports

/tmp         192.168.1.0/24(ro)   localhost(rw)   *.ev.ncku.edu.tw(ro,sync)

#     [分享目录] [第一部主机(权限)]   [可用主机名]    [可用万用字元]

  • 可以使用完整的 IP 或者是网域,例如 192.168.1.10 或 192.168.1.0/24 ,或 192.168.1.0/255.255.255.0 都可以接受!

  • 可以使用主机名称,这个主机名称要在 /etc/hosts 内或使用 DNS 可以被找到才行啊!重点是可找到 IP 就是了。如果是主机名称的话,那么他可以个援万用字元,例如 * 或 ? 均可接受。

至于权限方面 (就是小括号内的参数) 常见的参数则有∶

  • rw∶read-write,可读写的权限

  • ro∶read-only,唯读的权限

  • sync∶资料同步写入到记忆体与硬盘当中;

  • async∶资料会先暂存于记忆体当中,而非直接写入硬盘!

  • no_root_squash∶
    登入 NFS 主机使用分享目录的使用者,如果是 root 的话,那么对于这个分享的目录来说,他就具有 root 的权限! 这个项目『极不安全』,不建议使用!

  • root_squash∶    #squash  权限压制
    在登入 NFS 主机使用分享之目录的使用者如果是 root 时,那么这个使用者的权限将被压缩成为匿名使用者,通常他的 UID 与 GID 都会变成 nobody(nfsnobody) 那个系统帐号的身份;

  • all_squash∶
    不论登入 NFS 的使用者身份为何, 他的身份都会被压缩成为匿名使用者,通常也就是 nobody(nfsnobody) !

  • anonuid∶
    anon 意指 anonymous (匿名者) 前面关于 *_squash 提到的匿名使用者的 UID 设定值,通常为 nobody(nfsnobody),但是您可以自行设定这个 UID 的值!当然,这个 UID 必需要存在于您的 /etc/passwd 当中!

  • anongid∶同 anonuid ,但是变成 group ID 就是了!

04、启动 NFS

[root@linux ~]# /etc/init.d/portmap start

# 如果 portmap 本来就已经在执行了,那就不需要启动啊!

[root@linux ~]# /etc/init.d/nfs start

# 有时候可能会出现如下的警告讯息∶

exportfs: /etc/exports [3]: No 'sync' or 'async' option specified

for export "192.168.0.100:/home/test".

  Assuming default behaviour ('sync').

# 上面的警告讯息仅是在告知因为我们没有指定 sync 或 async 的参数,

# 则 NFS 将预设会使用 sync 的资讯而已。你可以不理他,也可以加入 /etc/exports。

[root@linux ~]# vi /etc/exports

/tmp          *(rw,no_root_squash,sync)

/home/public  192.168.0.0/24(rw,sync)    *(ro,sync)

/home/test    192.168.0.100(rw,sync)

/home/linux   *.linux.org(rw,all_squash,anonuid=40,anongid=40,sync)

[root@linux ~]# /etc/init.d/nfs restart

那个 portmap 根本就不需要设定!只要直接启动他就可以!启动之后,会出现一个 port 111 的 sunrpc 的服务,那就是 portmap !至于 nfs 则会启动至少两个以上的 daemon 出现!然后就开始在监听 Client 端的需求!你必须要很注意萤幕上面的输出资讯, 因为如果设定档写错的话,萤幕上会显示出错误的地方喔!

此外,如果你想要增加一些 NFS 服务器的资料一致性功能时,可能需要用到 rpc.lockd 及 rpc.statd 等 RPC 服务, 那么或许你可以增加一个服务,那就是 nfslock

[root@linux ~]# /etc/init.d/nfslock start

动之后,请赶快到 /var/log/messages 里面看看有没有被正确的启动呢?

在确认没有问题之后,接下来我们来瞧一瞧那么 NFS 到底开了哪些端口?

NFS 的连线观察

在你的 NFS 服务器设定妥当之后,我们可以先自我测试一下是否可以连线喔! 就是利用 showmount 这个指令来查阅!

[root@linux ~]# showmount [-ae] [hostname|IP]

参数∶

-a ∶显示目前主机与用户端的 NFS 连线分享的状态;

-e ∶显示某部主机的 /etc/exports 所分享的目录资料。

范例一∶请显示出刚刚我们所设定好的相关 exports 资讯

[root@linux ~]# showmount -e localhost

Export list for localhost:

/tmp         *

/home/linux  *.linux.org

/home/public (everyone)

/home/test   192.168.0.100

另外,如果你想要重新处理 /etc/exports 档案,当重新设定完 /etc/exports 后需不需要重新启动 nfs ? 不需要!如果重新启动 nfs 的话,要得要向 RPC 注册!很麻烦~ 这个时候我们可以透过 exportfs 这个指令来帮忙喔!

[root@linux ~]# exportfs [-aruv]

参数∶

-a ∶全部挂载(或卸载) /etc/exports 档案内的设定

-r ∶重新挂载 /etc/exports 里面的设定,此外,亦同步更新 /etc/exports

     及 /var/lib/nfs/xtab 的内容!

-u ∶卸载某一目录

-v ∶在 export 的时候,将分享的目录显示到萤幕上!

范例一∶重新挂载一次 /etc/exports 的设定

[root@linux ~]# exportfs -arv

exporting 192.168.0.100:/home/test

exporting 192.168.0.0/24:/home/public

exporting *.linux.org:/home/linux

exporting *:/home/public

exporting *:/tmp

范例二∶全部都卸载

[root@linux ~]# exportfs -auv

远端 NFS 服务器的挂载

你要如何挂载 NFS 服务器所提供的档案系统呢?基本上,可以这样做∶

1         确认本地端已经启动了 portmap 服务!

2         扫瞄 NFS 服务器分享的目录有哪些,并了解我们是否可以使用 (showmount);

3         在本地端建立预计要挂载的挂载点目录 (mkdir);

4         利用 mount 将远端主机直接挂载到相关目录。

好,现在假设用户端在 192.168.0.100 这部机器上,而服务器是 192.168.0.2 , 那么赶紧来检查一下我们是否已经有 portmap 的启动,另外远端主机有什么可用的目录呢

[root@linux ~]# /etc/init.d/portmap start

[root@linux ~]# /etc/init.d/nfslock start

# 一般来说,系统预设会启动 portmap ,

# 另外,如果服务器端有启动 nfslock 的话,用户端也要启动才能生效!

[root@linux ~]# showmount -e 192.168.0.2

Export list for 192.168.0.2:

/tmp         *

/home/linux  *.linux.org

/home/public (everyone)   <==这是等一下我们要挂载的目录

/home/test   192.168.0.100

接下来我想要将远端主机的 /home/public 挂载到本地端主机的 /home/nfs/public , 所以我就得要在本地端主机先建立起这个挂载点目录才行啊!然后就可以用 mount 这个指令直接挂载 NFS 的档案系统!

[root@linux     ~]# mkdir -p /home/nfs/public

[root@linux     ~]# mount -t nfs 192.168.0.2:/home/public /home/nfs/public

#     注意一下挂载的语法!『 -t nfs 』指定档案系统类型,

#     IP:/dir 则是指定某一部主机的某个提供的目录

[root@linux     ~]# df

Filesystem    1K-blocks      Used Available Use% Mounted on

192.168.0.2:/home/public

               10080512   2135072       7433344  23% /home/nfs/public