Linux系统开发: 搭建NFS服务器实现文件共享

2022-01-27 20:18:01 浏览数 (1)

一、NFS服务器介绍

1.1 什么是NFS服务器

NFS 是Network File System的缩写,即网络文件系统。一种使用于分散式文件系统的协定,由Sun公司开发,于1984年向外公布。功能是通过网络让不同的机器、不同的操作系统能够彼此分享个别的数据,让应用程序在客户端通过网络访问位于服务器磁盘中的数据,是在类Unix系统间实现磁盘文件共享的一种方法。

NFS在文件传送或信息传送过程中依赖于RPC协议。RPC,远程过程调用 (Remote Procedure Call) 是能使客户端执行其他系统中程序的一种机制。NFS本身是没有提供信息传输的协议和功能的。

1.2 NFS挂载原理

NFS最大的功能就是可以通过网络,让不同的机器、不同的操作系统可以共享彼此的文件。

NFS服务器可以让PC将网络中的NFS服务器共享的目录挂载到本地端的文件系统中,而在本地端的系统中来看,那个远程主机的目录就好像是自己的一个磁盘分区一样,在使用上相当便利。

当我们在NFS服务器设置好一个共享目录/home/public后,其他有权访问NFS服务器的NFS客户端就可以将这个目录挂载到自己文件系统的某个挂载点,这个挂载点可以自己定义,如上图客户端1与客户端2挂载的目录就不相同。并且挂载好后我们在本地能够看到服务端/home/public的所有数据。如果服务器端配置的客户端只读,那么客户端就只能够只读。如果配置读写,客户端就能够进行读写。

挂载后,NFS客户端可以通过#df –h命令查看挂载的磁盘信息。

既然NFS是通过网络来进行服务器端和客户端之间的数据传输,那么两者之间要传输数据就要有相对应的网络端口,NFS服务器到底使用哪个端口来进行数据传输呢?

基本上NFS这个服务器的端口开在2049,但由于文件系统非常复杂。因此NFS还有其他的程序去启动额外的端口,这些额外的用来传输数据的端口是随机选择的,是小于1024的端口;既然是随机的那么客户端又是如何知道NFS服务器端到底使用的是哪个端口呢?这时就需要通过远程过程调用(Remote Procedure Call,RPC)协议来实现了!

查看/etc/services文件可以看到NFS服务器的端口号。

1.3 什么是RPC? 为什么要用RPC?

RPC是指远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

为什么要用RPC呢?就是无法在一个进程内,甚至一个计算机内通过本地调用的方式完成的需求,比如不同的系统间的通讯,甚至不同的组织间的通讯,由于计算能力需要横向扩展,需要在多台机器组成的集群上部署应用。

RPC就是要像调用本地的函数一样去调远程函数。

在研究RPC前,我们先看看本地调用是怎么调的。假设我们要调用函数Multiply来计算lvalue * rvalue的结果。

代码语言:javascript复制
1 int Multiply(int l, int r) {undefined

2    int y = l * r;

3    return y;

4 }

5

6 int lvalue = 10;

7 int rvalue = 20;

8 int l_times_r = Multiply(lvalue, rvalue);

那么在第8行时,我们实际上执行了以下操作:

将 lvalue 和 rvalue 的值压栈

进入Multiply函数,取出栈中的值10 和 20,将其赋予 l 和 r

执行第2行代码,计算 l * r ,并将结果存在 y

将 y 的值压栈,然后从Multiply返回

第8行,从栈中取出返回值 200 ,并赋值给 l_times_r

以上5步就是执行本地调用的过程。

在远程调用时,我们需要执行的函数体是在远程的机器上的,也就是说,Multiply是在另一个进程中执行的。这就带来了几个新问题:

Call ID映射。我们怎么告诉远程机器我们要调用Multiply,而不是Add或者FooBar呢?

在本地调用中,函数体是直接通过函数指针来指定的,我们调用Multiply,编译器就自动帮我们调用它相应的函数指针。但是在远程调用中,函数指针是不行的,因为两个进程的地址空间是完全不一样的。所以,在RPC中,所有的函数都必须有自己的一个ID。这个ID在所有进程中都是唯一确定的。客户端在做远程过程调用时,必须附上这个ID。然后我们还需要在客户端和服务端分别维护一个 {函数 <--> Call ID} 的对应表。两者的表不一定需要完全相同,但相同的函数对应的Call ID必须相同。当客户端需要进行远程调用时,它就查一下这个表,找出相应的Call ID,然后把它传给服务端,服务端也通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。序列化和反序列化。

客户端怎么把参数值传给远程的函数呢?在本地调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。但是在远程过程调用时,客户端跟服务端是不同的进程,不能通过内存来传递参数。甚至有时候客户端和服务端使用的都不是同一种语言(比如服务端用C ,客户端用Java或者Python)。这时候就需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。这个过程叫序列化和反序列化。同理,从服务端返回的值也需要序列化反序列化的过程。网络传输。远程调用往往用在网络上,客户端和服务端是通过网络连接的。所有的数据都需要通过网络传输,因此就需要有一个网络传输层。网络传输层需要把Call ID和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传回客户端。只要能完成这两者的,都可以作为传输层使用。因此,它所使用的协议其实是不限的,能完成传输就行。尽管大部分RPC框架都使用TCP协议,但其实UDP也可以,而GRPC干脆就用了HTTP2。Java的Netty也属于这层的东西。

所以,要实现一个RPC框架,其实只需要把以上三点实现了就基本完成了。Call ID映射可以直接使用函数字符串,也可以使用整数ID。映射表一般就是一个哈希表。

1.4 RPC与NFS如何通讯

因为NFS支持的功能相当多,而不同的功能都会使用不同的程序来启动,每启动一个功能就会启用一些端口来传输数据,因此NFS的功能对应的端口并不固定,客户端要知道NFS服务器端的相关端口才能建立连接进行数据传输,而RPC就是用来统一管理NFS端口的服务,并且统一对外的端口是111,RPC会记录NFS端口的信息,如此我们就能够通过RPC实现服务端和客户端沟通端口信息。PRC最主要的功能就是指定每个NFS功能所对应的port number,并且通知客户端,记客户端可以连接到正常端口上去。

  那么RPC又是如何知道每个NFS功能的端口呢?

  首先当NFS启动后,就会随机的使用一些端口,然后NFS就会向RPC去注册这些端口,RPC就会记录下这些端口,并且RPC会开启111端口,等待客户端RPC的请求,如果客户端有请求,那么服务器端的RPC就会将之前记录的NFS端口信息告知客户端。如此客户端就会获取NFS服务器端的端口信息,就会以实际端口进行数据的传输了。

提示:在启动NFS SERVER之前,首先要启动RPC服务(即portmap服务,下同)否则NFS SERVER就无法向RPC服务区注册,另外,如果RPC服务重新启动,原来已经注册好的NFS端口数据就会全部丢失。因此此时RPC服务管理的NFS程序也要重新启动以重新向RPC注册。特别注意:一般修改NFS配置文档后,是不需要重启NFS的,直接在命令执行/etc/init.d/nfs reload或exportfs –rv即可使修改的/etc/exports生效。

1.5 NFS客户端和NFS服务端通讯过程简图

1)首先服务器端启动RPC服务,并开启111端口

2)服务器端启动NFS服务,并向RPC注册端口信息

3)客户端启动RPC(portmap服务),向服务端的RPC(portmap)服务请求服务端的NFS端口

4)服务端的RPC(portmap)服务反馈NFS端口信息给客户端。

5)客户端通过获取的NFS端口来建立和服务端的NFS连接并进行数据的传输。

1.6 RPC服务工作原理简图

二、部署NFS服务器

2.1 查看内核版本信息

先查看系统版本和内核参数。同一个软件在不同版本,内核之间是有差异的,所以部署的方法也不一样。

代码语言:javascript复制
[wbyq@wbyq /]$ cat /etc/redhat-release

Red Hat Enterprise Linux Server release 6.3 (Santiago)

[wbyq@wbyq /]$ uname -a

Linux wbyq 2.6.32-279.el6.i686 #1 SMP Wed Jun 13 18:23:32 EDT 2012 i686 i686 i386 GNU/Linux

[wbyq@wbyq /]$

2.2 安装NFS服务器

Ubuntu 系统在线安装NFS服务器:

代码语言:javascript复制
ubuntu@VM-0-7-ubuntu:/$ sudo apt-get install nfs-kernel-server

Centos系统在线安装NFS服务器:

代码语言:javascript复制
[root@localhost ~]# yum install -y rpc-bind nfs-utils  

#安装nfs服务

[root@localhost ~]# yum install -y rpcbind

#安装rpc服务

RedHat6.3系统,可以在系统安装光盘映像里得到NFS服务器的安装包:

2.3 启动NFS服务

Ubuntu系统操作步骤:

代码语言:javascript复制
/etc/init.d/nfs-kernel-server start #启动NFS服务 
ufw disable #关闭防火墙

CentOS系统操作步骤:

代码语言:javascript复制
[root@localhost ~]# systemctl start rpcbind    #先启动rpc服务 
[root@localhost ~]# systemctl enable rpcbind   #设置开机启动 
[root@localhost ~]# systemctl start nfs-server nfs-secure-server      #启动nfs服务和nfs安全传输服务 
[root@localhost ~]# systemctl enable nfs-server nfs-secure-server 
[root@localhost /]# firewall-cmd --permanent --add-service=nfs success   #配置防火墙放行nfs服务 
[root@localhost /]# firewall-cmd  --reload success

RedHat6.3系统操作步骤:

代码语言:javascript复制
service nfs restart    #重启 NFS 服务器

service iptables stop  #关闭防火墙

[wbyq@wbyq /]$ sudo service nfs start

启动 NFS 服务:                                            [确定]

关掉 NFS 配额:                                            [确定]

启动 NFS mountd:                                          [确定]

启动 NFS 守护进程:                                        [确定]

[wbyq@wbyq /]$ sudo service nfs stop

关闭 NFS 守护进程:                                        [确定]

关闭 NFS mountd:                                          [确定]

关闭 NFS quotas:                                           [确定]

关闭 NFS 服务:                                            [确定]

[wbyq@wbyq /]$ sudo service nfs restart

关闭 NFS 守护进程:                                        [失败]

关闭 NFS mountd:                                          [失败]

关闭 NFS quotas:                                           [失败]

启动 NFS 服务:                                            [确定]

关掉 NFS 配额:                                            [确定]

启动 NFS mountd:                                           [确定]

启动 NFS 守护进程:                                         [确定]

三、编写NFS服务器的配置文件

3.1 NFS服务器配置文件

NFS服务的配置文件为/etc/exports,系统没有默认值,所以这个文件不一定会存在,可以使用vim手动建立,然后在文件里面写入配置内容。

配置实例:

代码语言:javascript复制
/home/wbyq/rootfs *(rw,no_root_squash,sync)

NFS服务器共享/home/wbyq/rootfs目录给所有NFS客户端访问,权限为读写。

3.2 指定 NFS客户端地址的配置详细说明

客户端地址

具体地址

说 明

授权单一客户端访问NFS

10.0.0.30

一般情况,生产环境中此配置不多

授权整个网段可访问NFS

10.0.0.0/24

其中的24等同于255.255.255.0 ,指定网段为生产环境中最常见的配置。配置简单,维护方便

授权整个网段可访问NFS

10.0.0.*

指定网段的另外写法(不推荐使用)

授权某个域名客户端访问

nfs.oldboyedu.com

此方法生产环境中一般情况不常用

授权整个域名客户端访问

*.oldboyedu.com

此方法生产环境中一般情况不常用

授权所有网段

*

权限比较开放,一般生产环境情况中不常用

3.3 NFS配置参数说明

参数

说明

rw

可读写的权限

ro

只读的权限

no_root_squash

登入NFS主机,使用该共享目录时相当于该目录的拥有者,如果是root的话,那么对于这个共享的目录来说,他就具有root的权限,这个参数『比较开放』,在生产环境中不建议使用

root_squash

登入NFS主机,使用该共享目录时相当于该目录的拥有者。但是如果是以root身份使用这个共享目录的时候,那么这个使用者(root)的权限将被压缩成为匿名使用者,即通常他的UID与GID都会变成nobody那个身份

all_squash

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

anonuid

可以自行设定这个UID的值,这个UID必需要存在于你的/etc/passwd当中

anongid

同anonuid,但是变成groupID就是了

sync

资料同步写入到内存与硬盘当中

async

资料会先暂存于内存当中,而非直接写入硬盘

insecure

允许从这台机器过来的非授权访问

3.4 NFS服务器配置文件常见编写案例

常用格式说明

要共享的目录客户端IP地址或IP段权限设置实例

配罝例一

/work 10.0.0.0/24(ro,sync) 说明:允许客户端读写,并且数据同步写入到服务器揣的磁盘里 注意:24和"("之间不能有空格

配置例二

/work 10.0.0.0/24(rw,sync/all_squash,anonuid=2000,anongid=2000) 说明:允许客户端读写,并且数据同步写到服务器揣的磁盘里,并且指走客户端的用户UID和GID,早期生产环境的一种配罝,适合多客户端共享一个NFS服务 单目录,如果所有服务器的nfsnobody账户UID都是65534,则本例没什么必要了,早期centos5.5的系统默认情况下nfsnobody的UID不一定是65534, 此时如果这些服务器共享一个NFS目录,就会出现访问权限问题.

配置例三

/work 10.0.0.0/24(ro) 说明:只读共享 用途:例如在生产环境中,开发人员有查看生产眼务器日志的需求,但又不希望给开发生产服务器的权限,那么就可以给开发提供从某个测试服务器NFS客户端 上查看某个生产服务器的日志目录(NFS共享)的权限,当然这不是唯一的方法, 例如可以把程序记录的日志发送到测试服务器供开发查看或者通过收集日志等其它方式展现

配置例四

/work *(rw,no_root_squash,sync) 说明:允许所有客户端读写,并且数据同步写到服务器揣的磁盘里,登入NFS主机,使用该共享目录时相当于该目录的拥有者,如果是root的话,那么对于这个共享的目录来说,他就具有root的权限

配置例五

/work *(insecure,rw,no_root_squash,sync) 说明: 允许客户端的非授权访问,允许所有客户端读写,并且数据同步写到服务器揣的磁盘里,登入NFS主机,使用该共享目录时相当于该目录的拥有者,如果是root的话,那么对于这个共享的目录来说,他就具有root的权限。 非授权访问情况说明: 正常情况下mount 客户端请求服务器源端口必须小于 1024 (然而在使用 NAT 网络地址转换时端口一般总是大于 1024的),默认情况下是开启这个选项的,如果要禁止这个选项,则使用 insecure 标识,如果不禁止该选项,客户端在挂载服务器时会出现错误。 错误如下: [wbyq@wbyq Camera_Client]$ sudo mount -t nfs -o v3 106.53.95.179:/work_mnt /home/wbyq/mnt/ mount.nfs: access denied by server while mounting 106.53.95.179:/work_mnt 安装时服务器拒绝访问 说明: 一般在公网下搭建NFS服务器时,就需要在服务器配置文件里加上insecure选项。

四、NFS服务器挂载实例

4.1 启动NFS服务器实例

以Redhat6.3系统为例:

1. 编写NFS配置文件

代码语言:javascript复制
[wbyq@wbyq /]$ sudo vim /etc/exports  /home/wbyq/project *(rw,no_root_squash,sync)

2. 手动(静态)设置服务器端IP地址

代码语言:javascript复制
ifconfig eth0 192.168.10.11

也可以通过系统右上角的小电脑或者setup命令进行设置。

[wbyq@wbyq 桌面]$ sudo setup

3. 关闭防火墙

代码语言:javascript复制
service iptables stop #关闭防火墙

也可以通过setup命令,打开图形配置页面关闭。

4. 重新NFS服务器

代码语言:javascript复制
service nfs restart   #重启 NFS 服务器 
说明: 如果之前没有开启过NFS服务器,第一次重新启动NFS服务器会出现错误提示(没启动就会启动,相当于执行service nfs start),
再次执行该命令,第二次就没有错误了。

4.2 exportfs 命令

在NFS服务器端,exportfs很常用,比如你想要重新修改/etc/exports 文件,当重新设定完 /etc/exports 后

需不需要重新启动 nfs ? 不需要 ,如果重新启动 nfs 的话,要得再向 RPC 注册!

很麻烦~这个时候我们可以透过 exportfs 这个指令来帮忙。

exportfs命令用法如下:

代码语言:javascript复制
exportfs [-aruv]

选项与参数:

-a :全部挂载(或卸除) /etc/exports 文件内的设定

-r :重新挂载 /etc/exports 里面的设定,此外,亦同步更新 /etc/exports及 /var/lib/nfs/xtab 的内容!

-u :卸除某一目录

-v :将分享的目录显示到屏幕上!

实例操作:

1. 重新挂载一次 /etc/exports 文件的设定内容

代码语言:javascript复制
[wbyq@wbyq ~]$ sudo exportfs -arv

exporting *:/home/wbyq/project

exporting *:/home/wbyq/rootfs

2. 将已经分享的 NFS 目录资源,通通都卸除

代码语言:javascript复制
[wbyq@wbyq ~]$ sudo exportfs -auv

# 这时如果你再使用 showmount -e localhost 就会看不到任何资源了!

4.3 NFS的联机观察

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

代码语言:javascript复制
[root@www ~]# showmount [-ae] [hostname|IP]

选项与参数:

-a :显示目前主机与客户端的 NFS 联机分享的状态;

-e :显示某部主机的 /etc/exports 所分享的目录数据。

示例:

代码语言:javascript复制
[wbyq@wbyq ~]$ sudo showmount -e localhost

Export list for localhost:

/home/wbyq/project *

/home/wbyq/rootfs  *

[wbyq@wbyq ~]$ sudo showmount -e 192.168.10.11

Export list for 192.168.10.11:

/home/wbyq/project *

/home/wbyq/rootfs  *

当你要扫瞄某一部主机他提供的 NFS 分享的目录时,就使用showmount -e IP (或 hostname) 即可!非常的方便!这也是 NFS client 端最常用的指令。

4.4 客户端访问实例

客户端访问服务器前,需要知道NFS服务器的IP地址和共享的目录路径。

如果是局域网访问,那么需要保证客户端与服务器在同一网段下,如果是公网访问,需要保证客户端这个能过正常连接外网网络。

1. NFS客户端挂载实例: 挂载NFS服务器的目录到本地目录

代码语言:javascript复制
[wbyq@wbyq ~]$ sudo mount -t nfs 192.168.10.11:/home/wbyq/project /home/wbyq/mnt/

将192.168.10.11服务器的/home/wbyq/project目录,挂载到本地/home/wbyq/mnt/目录下。

如果挂载服务器时,提示mount命令卡住了,或者报错提示无法加锁等提示时,需要在挂载命令上加一个-o nolock参数。

代码语言:javascript复制
sudo mount -t nfs -o nolock 192.168.10.11:/home/wbyq/project /home/wbyq/mnt/

2. 取消目录挂载

代码语言:javascript复制
[wbyq@wbyq ~]$ sudo umount /home/wbyq/mnt/

如果不再使用服务器的目录,一定要取消挂载。

4.5 查看客户端的挂载情况

/var/lib/nfs/etab、/var/lib/nfs/rmtab这两个文件就能够查看服务器上共享了什么目录,到底有多少客户端挂载了共享,能查看到客户端挂载的具体信息。

1、etab这个文件能看到服务器上共享了哪些目录,执行哪些人可以使用,并且设定的参数为何。

2、rmtab这个文件就是能够查看到共享目录被挂载的情况。

代码语言:javascript复制
[wbyq@wbyq ~]$ cat /var/lib/nfs/rmtab

192.168.10.10:/home/wbyq/rootfs:0x0000007b

192.168.10.123:/home/wbyq/rootfs:0x00000001

192.168.10.10:/home/wbyq/project:0x00000029

[wbyq@wbyq ~]$ cat /var/lib/nfs/etab

/home/wbyq/project        *(rw,sync,wdelay,hide,nocrossmnt,secure,no_root_squash,no_all_squash,no_subtree_check,secure_locks,acl,anonuid=65534,anongid=65534)

/home/wbyq/rootfs        *(rw,sync,wdelay,hide,nocrossmnt,secure,no_root_squash,no_all_squash,no_subtree_check,secure_locks,acl,anonuid=65534,anongid=65534)

0 人点赞