NFS共享存储
NFS共享存储
1. NFS共享存储的作用
NFS就是Network File System的缩写,它最大的功能就是可以通过网络,让不同的机器、不同的操作系统可以共享彼此的文件。
NFS服务器可以让PC将网络中的NFS服务器共享的目录挂载到本地端的文件系统中,而在本地端的系统中来看,那个远程主机的目录就好像是自己的一个磁盘分区一样,在使用上相当便利。
NFS一般用来存储共享视频,图片等静态数据。
1.1 NFS在网站集群架构中的作用
- 当网站集群中没有使用共享存储时,会存在一些问题,如下图:
集群架构中有3台WEB服务器提供WEB服务,前端使用负载均衡设备对用户的请求进行自动分配到各个WEB服务器上,当A用户访问网站时,加入负载均衡设备将其分配到WEB1服务器上,用户A在WEB1上上传了一张图片,此时图片是存放在WEB1服务器的磁盘上的;当用户B登录网站时,负载均衡设备不幸将其调度到了WEB2服务器上,这样用户B就无法看到用户A上传的图片。
- 当使用了共享存储了情况下,A用户上传的图片并不会存放在WEB1的本地磁盘上,而是存放在共享存储设备上,B用户访问站点时,无论被负载均衡调度到哪一台WEB服务器上,都可以通过访问共享存储上的资源查看用户A上传的图片。
-
总结:使用共享存储可以解决集群架构中的以下问题:
- 解决多台WEB服务器静态资源的共享;
- 解决多台WEB服务器静态资源的一致性,任何用户看到的资源时一致的;
- 解决多台WEB服务器的硬盘资源的浪费;
- 如果需要对静态资源进行加速,可以把共享存储上的资源统一推送到CDN,实现资源的加速访问;
-
注意:使用共享存储时,每次客户的访问静态资源时都需要经过网络读取数据,造成一定的网络延时,因此并不能带来网站访问速度的提升。
2. NFS的实现原理
如下图示,当我们在NFS服务器设置好一个共享目录/home/public后,其他的有权访问NFS服务器的NFS客户端就可以将这个目录挂载到自己文件系统的某个挂载点,这个挂载点可以自己定义,如上图客户端A与客户端B挂载的目录就不相同。并且挂载好后我们在本地能够看到服务端/home/public的所有数据。如果服务器端配置的客户端只读,那么客户端就只能够只读。如果配置读写,客户端就能够进行读写。挂载后,NFS客户端可以使用df命令查看挂载信息。
2.1 RPC在NFS中的作用
既然NFS是通过网络来进行服务器端和客户端之间的数据传输,那么两者之间要传输数据就要有对应的网络端口。
因为NFS支持的功能相当多,而不同的功能都会使用不同的程序来启动,每启动一个功能就会启用一些端口来传输数据,因此NFS的功能对应的端口并不固定,客户端要知道NFS服务器端的相关端口才能建立连接进行数据传输,而RPC就是用来统一管理NFS端口的服务,并且统一对外的端口是111,RPC会记录NFS端口的信息,如此我们就能够通过RPC实现服务端和客户端沟通端口信息。PRC最主要的功能就是指定每个NFS功能所对应的端口号,并且通知客户端,这样客户端可以连接到正常端口上去。
那么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的,直接在命令执行systemctl reload nfs或exportfs –rv即可使修改的/etc/exports生效。
-
portmap服务
功能:主要是把RPC程序号转化为Internet的端口号。
特点:只在第一次建立连接时候帮助网络应用程序找到正确的port,当双方正确连接时,端口就和应用绑定,portmap就没用了。相当于媒婆。
RPC中的主要服务如下:
- rpc.mountd:认证;提供认证的功能,nfs实现的是基于IP地址的认证。
- rpc.lockd:加锁;当多个用户同时访问nfs文件系统时,对多个文件同时写操作,会把文件加锁,只允许一个用户写文件。
- rpc.statd:状态;用于记录nfs会话连接状态,客户端连接断开重连时可以继续之前的操作。
2.2 NFS客户端和服务端的通信过程
NFS客户端和服务端的通信过程如下:
- 首先服务器端启动RPC服务,并开启111端口;
- 服务器端启动NFS服务,并向RPC注册端口信息;
- 客户端启动RPC(portmap服务),向服务端的RPC(portmap)服务请求服务端的NFS端口;
- 服务端的RPC(portmap)服务反馈NFS端口信息给客户端;
- 客户端通过获取的NFS端口来建立和服务端的NFS连接并进行数据的传输;
2.3 NFS服务的优缺点
-
优点
- 节省本地存储空间,将数据存放在一台服务器可以通过网络访问
- 简单容易上手
- 方便部署非常快速,维护十分简单,满足中小企业需求
-
缺点
- 局限性容易发生单点故障,server机宕机了所有客户端都不能访问
- 在高并发下NFS效率/性能有限
- 客户端没用用户认证机制,且数据是通过明文传送,安全性一般(一般建议在局域网内使用)
- NFS的数据是明文的,对数据完整性不做验证
- 多台机器挂载NFS服务器时,连接管理维护麻烦
3. NFS服务的部署实现
3.1 NFS需要的软件包
安装NFS服务,需要安装两个软件,分别是:
-
RPC主程序:rpcbind
NFS 其实可以被视为一个 RPC 服务,因为启动任何一个 RPC 服务之前,我们都需要做好 port 的对应 (mapping) 的工作才行,这个工作其实就是 rpcbind 这个服务所负责的。也就是说, 在启动任何一个 RPC 服务之前,我们都需要启动 rpcbind 才行! (在 CentOS 5.x 以前这个软件称为 portmap,在 CentOS 6.x 之后才称为 rpcbind 的!)。
-
NFS主程序:nfs-utils
就是提供 rpc.nfsd 及 rpc.mountd 这两个 NFS daemons 与其他相关 documents 与说明文件、执行文件等的软件!这个就是 NFS 服务所需要的主要软件。
-
安装软件包(安装nfs-utils时会自动安装rpcbind包,均来自于base仓库):
[root@nfs-30 ~]# yum install nfs-utils.x86_64 -y
3.2 NFS的文件结构
NFS的主要文件如下:
-
配置文件:/etc/exports或/etc/exports.d/
这是 NFS 的主要配置文件。该文件是空白的,有的系统可能不存在这个文件,主要手动建立。
-
NFS 文件系统维护指令:/usr/sbin/exportfs
这个是维护 NFS 分享资源的指令,可以利用这个指令重新分享 /etc/exports 变更的目录资源、将 NFS Server 分享的目录卸除或重新分享。
-
分享资源的登录档:/var/lib/nfs/tab
NFS 服务器的登录文件都放置到 /var/lib/nfs/ 目录里面,在该目录下有两个比较重要的登录档, 一个是 etab ,主要记录了 NFS 所分享出来的目录的完整权限设定值;另一个 xtab 则记录曾经链接到此 NFS 服务器的相关客户端数据。
-
客户端查询服务器分享资源的指令:/usr/sbin/showmount
exportfs 是用在 NFS Server 端,而 showmount 则主要用在 Client 端。showmount 可以用来察看 NFS 分享出来的目录资源。
3.2.1 配置文件格式:
/etc/exports配置文件中一行代表把自身的哪个目录共享出去,允许哪个客户端以何种权限来进行访问,格式为:
/PATH/TO/SOME_DIR clients1(export_options, ...) clients2(export_options, ...)
注意:NFS客户端地址与权限之间没有空格。
其中:
- /PATH/TO/SOME_DIR:代表共享自身的目录;
- clients:代表允许哪个客户端连接,支持以下格式:
- 主机:支持主机名,例如192.168.20.1,www.abc,com;
- 网段:address/netmask, 支持长短格式的掩码;
- wildcards:主机名通配,例如:*.abc.com;
- netgroups:NIS域内的主机组;@group_name;
- anonymous:使用“*”通配所有主机;
- export_options:表示客户端访问目录资源时拥有的权限,主要权限如下:
- ro:只读权限;
- rw:读写权限;
- sync:同步,同时将数据写入内存和磁盘中;
- async:异步,先将数据写到内存,然后再写入磁盘,效率较高,可能丢失数据;
- root_squash:压缩root用户,当NFS客户端以root用户访问时,将其映射为nfsnobody用户;
- no_root_squash:不压缩root用户,正常映射为root用户;
- all_squash:压缩所有用户,即客户端任何用户访问服务端时,在服务端都将其映射为nfsnobody用户;
- no_all_squash:不压缩任何用户;
- anonuid:需要配合all_squash使用,将客户端的所有用户在服务端映射为指定UID的用户,该UID在服务端必须存在;
- anongid:需要配合all_squash使用,将客户端的所有用户组在服务端映射为指定GID的用户组,该GID在服务端必须存在;
3.3 NFS服务搭建步骤
3.3.1 服务端配置
-
第一步:关闭服务端和客户端的防火墙和selinux
[root@nfs-30 ~]# systemctl stop firewalld [root@nfs-30 ~]# setenforce 0
-
第二步:修改配置文件
#把NFS server的/data目录共享出去,允许192.168.20.17有读写权限,192.168.20.0/24的其他主机有只读权限 [root@nfs-30 ~]# vim /etc/exports /data 192.168.20.17(rw) 192.168.20.0/24(ro)
-
第三步:启动rpcbind和nfs服务,根据nfs工作原理,需要先启用rpcbind服务,再启动nfs服务
[root@nfs-30 ~]# systemctl start rpcbind.service nfs-server.service [root@nfs-30 ~]# systemctl enable rpcbind.service nfs-server.service Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service. #查看服务启动情况: [root@nfs-30 ~]# systemctl status rpcbind.service nfs-server.service ● rpcbind.service - RPC bind service Loaded: loaded (/usr/lib/systemd/system/rpcbind.service; enabled; vendor preset: enabled) Active: active (running) since Wed 2021-06-09 22:28:32 CST; 38s ago Main PID: 3123 (rpcbind) CGroup: /system.slice/rpcbind.service └─3123 /sbin/rpcbind -w Jun 09 22:28:32 nfs-30 systemd[1]: Starting RPC bind service... Jun 09 22:28:32 nfs-30 systemd[1]: Started RPC bind service. ● nfs-server.service - NFS server and services Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled; vendor preset: disabled) Drop-In: /run/systemd/generator/nfs-server.service.d └─order-with-mounts.conf Active: active (exited) since Wed 2021-06-09 22:28:33 CST; 37s ago Main PID: 3150 (code=exited, status=0/SUCCESS) CGroup: /system.slice/nfs-server.service Jun 09 22:28:33 nfs-30 systemd[1]: Starting NFS server and services... Jun 09 22:28:33 nfs-30 systemd[1]: Started NFS server and services. #查看端口监听情况 [root@nfs-30 ~]# ss -ntulp Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port udp UNCONN 0 0 *:111 *:* users:(("rpcbind",pid=3123,fd=6)) udp UNCONN 0 0 *:747 *:* users:(("rpcbind",pid=3123,fd=7)) udp UNCONN 0 0 127.0.0.1:766 *:* users:(("rpc.statd",pid=3134,fd=5)) udp UNCONN 0 0 *:52202 *:* users:(("rpc.statd",pid=3134,fd=8)) udp UNCONN 0 0 *:20048 *:* users:(("rpc.mountd",pid=3148,fd=7)) udp UNCONN 0 0 [::]:111 [::]:* users:(("rpcbind",pid=3123,fd=9)) udp UNCONN 0 0 [::]:747 [::]:* users:(("rpcbind",pid=3123,fd=10)) udp UNCONN 0 0 [::]:20048 [::]:* users:(("rpc.mountd",pid=3148,fd=9)) udp UNCONN 0 0 [::]:35424 [::]:* users:(("rpc.statd",pid=3134,fd=10)) tcp LISTEN 0 128 *:111 *:* users:(("rpcbind",pid=3123,fd=8)) tcp LISTEN 0 128 *:20048 *:* users:(("rpc.mountd",pid=3148,fd=8)) tcp LISTEN 0 128 *:48805 *:* users:(("rpc.statd",pid=3134,fd=9)) tcp LISTEN 0 128 [::]:111 [::]:* users:(("rpcbind",pid=3123,fd=11)) tcp LISTEN 0 128 [::]:20048 [::]:* users:(("rpc.mountd",pid=3148,fd=10)) tcp LISTEN 0 128 [::]:46621 [::]:* users:(("rpc.statd",pid=3134,fd=11)) tcp LISTEN 0 64 [::]:2049 [::]:*
-
第四步:修改/data目录的权限允许nfsnobody读写,因为默认情况下客户端root用户都会被压缩为nfsnobody用户,故nfsnobody用户对/data目录需要有rwx权限
[root@nfs-30 ~]# chown -R nfsnobody.nfsnobody /data/ 或: [root@nfs-30 ~]# chmod -R 777 /data/
安装nfs包时会自动创建nfsnobody用户:
[root@nfs-30 ~]# id nfsnobody uid=65534(nfsnobody) gid=65534(nfsnobody) groups=65534(nfsnobody)
在/var/lib/nfs/etab文件中会记录目录和权限的详细信息:
[root@nfs-30 ~]# cat /var/lib/nfs/etab /data 192.168.20.17(rw,sync,wdelay,hide,nocrossmnt,secure,root_squash,no_all_squash,no_subtree_check,secure_locks,acl,no_pnfs,anonuid=65534,anongid=65534,sec=sys,rw,secure,root_squash,no_all_squash) /data 192.168.20.0/24(ro,sync,wdelay,hide,nocrossmnt,secure,root_squash,no_all_squash,no_subtree_check,secure_locks,acl,no_pnfs,anonuid=65534,anongid=65534,sec=sys,ro,secure,root_squash,no_all_squash
3.3.2 客户端测试
-
客户端直接可以使用mount目录挂载使用,格式为
mount -t nfs servername:/path/to/share /path/to/mount_point [-rvVwfnsh ] [-o options]
#把nfs server的/data目录挂载到本机的/mnt目录下 [root@xuzhichao ~]# mount -t nfs 192.168.20.30:/data/ /mnt [root@xuzhichao ~]# df Filesystem 1K-blocks Used Available Use% Mounted on 192.168.20.30:/data 154057344 33152 154024192 1% /mnt [root@xuzhichao ~]# mount 192.168.20.30:/data on /mnt type nfs4 (rw,relatime,vers=4.1,rsize=131072,wsize=131072,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.20.17,local_lock=none,addr=192.168.20.30)
-
将挂载信息写到/etc/fatab文件中进行永久挂载
[root@xuzhichao ~]# vim /etc/fstab 192.168.201.30:/data /mnt nfs defaults 0 0
-
测试文件读写功能
[root@xuzhichao ~]# cd /mnt/ #测试读权限 [root@xuzhichao mnt]# ll total 60 -rwxrwxrwx 1 root root 1017 Jun 2 11:45 acl.bak -rwxrwxrwx 1 root root 54080 Jun 1 22:57 cat drwxrwsrwx 2 root root 19 Jun 1 22:43 project drwxrwxrwx 3 root root 81 Jun 9 22:54 test #测试写权限 [root@xuzhichao mnt]# touch nfstset [root@xuzhichao mnt]# echo "123" > nfstset [root@xuzhichao mnt]# cat nfstset #默认root用户被压缩成了nfsnobody用户 [root@xuzhichao mnt]# ll -rw-r--r-- 1 nfsnobody nfsnobody 4 Jun 9 22:55 nfstset
-
测试普通用户的权限‘
[root@xuzhichao mnt]# su - xu Last login: Wed Jun 9 23:06:39 CST 2021 on pts/0 [xu@xuzhichao ~]$ df Filesystem 1K-blocks Used Available Use% Mounted on devtmpfs 485896 0 485896 0% /dev tmpfs 497840 0 497840 0% /dev/shm tmpfs 497840 7812 490028 2% /run tmpfs 497840 0 497840 0% /sys/fs/cgroup /dev/mapper/centos-root 52403200 1623188 50780012 4% / /dev/sda1 1038336 139940 898396 14% /boot /dev/mapper/centos-home 154057220 33132 154024088 1% /data tmpfs 99572 0 99572 0% /run/user/0 192.168.20.30:/data 154057344 33152 154024192 1% /mnt [xu@xuzhichao ~]$ cd /mnt/ [xu@xuzhichao mnt]$ touch xutset #普通用户没有被压缩 [xu@xuzhichao mnt]$ ll xutset -rw-rw-r-- 1 xu xu 0 Jun 9 23:07 xutset
-
卸载NFS目录
[root@xuzhichao mnt]# umount /mnt umount.nfs4: /mnt: device is busy #强制卸载 [root@xuzhichao mnt]# umount /mnt -lf
-
在企业工作场景,通常情况NFS服务器共享的只是普通静态数据(图片、附件、视频) ,不需要执行suid、exec等权限,挂载的这个文件系统只能作为数据存取之用,无法执行程序,对于客户端来讲增加了安全性。例如:很多木马篡改站点文件都是由上传入口上传的程序到存储目录,然后执行的。同时也要考虑性能情况。
[root@xuzhichao mnt]# mount -t nfs -o nosuid,noexec,nodev 192.168.20.30:/data /mnt [root@xuzhichao mnt]# mount -t nfs -o noatime,nodiratime 192.168.20.30:/data /mnt
3.3.3 把客户端用户映射为特定用户
需要把所有用户都映射为www用户,uid为888,gid为888。
-
服务端修改服务端nfs配置文件/etc/exports
#all_squash是把所有用户都压缩为888用户,若没有该参数,则只压缩客户root用户为888用户 [root@nfs-30 ~]# vim /etc/exports /data 192.168.20.17(rw,all_squash,anonuid=888,anongid=888) 192.168.20.0/24(ro)
-
服务端建立对应的用户
[root@nfs-30 ~]# groupadd -g 888 www [root@nfs-30 ~]# useradd -u 888 -g 888 www [root@nfs-30 ~]# id www uid=888(www) gid=888(www) groups=888(www)
-
服务端重启服务
[root@nfs-30 ~]# exportfs -arv exporting 192.168.20.17:/data exporting 192.168.20.0/24:/data 或: [root@nfs-30 ~]# systemctl restart nfs-server.service [root@nfs-30 ~]# cat /var/lib/nfs/etab /data 192.168.20.17(rw,sync,wdelay,hide,nocrossmnt,secure,root_squash,all_squash,no_subtree_check,secure_locks,acl,no_pnfs,anonuid=888,anongid=888,sec=sys,rw,secure,root_squash,all_squash) /data 192.168.20.0/24(ro,sync,wdelay,hide,nocrossmnt,secure,root_squash,no_all_squash,no_subtree_check,secure_locks,acl,no_pnfs,anonuid=65534,anongid=65534,sec=sys,ro,secure,root_squash,no_all_squash)
-
服务端修改/data目录权限
[root@nfs-30 ~]# chown -R www.www /data/
-
客户端挂载测试
[root@xuzhichao mnt]# mount -t nfs 192.168.20.30:/data/ /mnt/ [root@xuzhichao mnt]# df -h 192.168.20.30:/data 147G 33M 147G 1% /mnt
-
客户端测试写入文件
[root@xuzhichao mnt]# mkdir dir [root@xuzhichao mnt]# cd dir/ [root@xuzhichao dir]# touch abc [root@xuzhichao dir]# echo "123" > abc [root@xuzhichao dir]# cd .. #因为在客户端没有uid为888的用户,所以这里显示的是uid [root@xuzhichao mnt]# ll -d dir/ drwxr-xr-x 2 888 888 17 Jun 9 23:27 dir/ [root@xuzhichao mnt]# ll -d dir/abc -rw-r--r-- 1 888 888 4 Jun 9 23:27 dir/abc
-
建议在客户端也创建一个uid和gid为888的www用户,和服务端保持一致,避免后续出现权限不足的情况
[root@xuzhichao mnt]# groupadd -g 888 www [root@xuzhichao mnt]# useradd -u 888 -g 888 www [root@xuzhichao mnt]# id www uid=888(www) gid=888(www) groups=888(www) #文件属主属组显示为www用户 [root@xuzhichao mnt]# ll dir/ total 4 -rw-r--r-- 1 www www 4 Jun 9 23:27 abc
3.4 exportfs和showmount命令
-
exportfs: 服务端命令,当/etc/exportfs文件改变时不需要重启服务,只需要使用exportfs命令让新配置文件生效。
常用选项为:
- -r:重新导出;
- -a:所有文件系统;
- -v:详细信息;
- -u:取消导出文件系统;
- exportfs -arv 表示重读配置文件。
- exportfs -auv 表示取消导出的文件系统。
[root@nfs-30 ~]# exportfs -arv exporting 192.168.20.17:/data exporting 192.168.20.0/24:/data
-
showmount :客户端使用的命令,用于查看服务端共享的目录情况,主要用法如下:
-
showmount -e NFS_SERVER_IP: 查看指定的nfs server上导出的所有文件系统;
[root@xuzhichao mnt]# showmount -e 192.168.20.30 Export list for 192.168.20.30: /data 192.168.20.0/24
-
showmount -a:在nfs server上查看nfs服务的所有客户端列表;
[root@nfs-30 ~]# showmount -a All mount points on nfs-30:
-