NFS共享存储

NFS共享存储



1. NFS共享存储的作用

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

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

NFS一般用来存储共享视频,图片等静态数据。

1.1 NFS在网站集群架构中的作用

  • 当网站集群中没有使用共享存储时,会存在一些问题,如下图:

image

集群架构中有3台WEB服务器提供WEB服务,前端使用负载均衡设备对用户的请求进行自动分配到各个WEB服务器上,当A用户访问网站时,加入负载均衡设备将其分配到WEB1服务器上,用户A在WEB1上上传了一张图片,此时图片是存放在WEB1服务器的磁盘上的;当用户B登录网站时,负载均衡设备不幸将其调度到了WEB2服务器上,这样用户B就无法看到用户A上传的图片。

  • 当使用了共享存储了情况下,A用户上传的图片并不会存放在WEB1的本地磁盘上,而是存放在共享存储设备上,B用户访问站点时,无论被负载均衡调度到哪一台WEB服务器上,都可以通过访问共享存储上的资源查看用户A上传的图片。

image

  • 总结:使用共享存储可以解决集群架构中的以下问题:

    • 解决多台WEB服务器静态资源的共享;
    • 解决多台WEB服务器静态资源的一致性,任何用户看到的资源时一致的;
    • 解决多台WEB服务器的硬盘资源的浪费;
    • 如果需要对静态资源进行加速,可以把共享存储上的资源统一推送到CDN,实现资源的加速访问;
  • 注意:使用共享存储时,每次客户的访问静态资源时都需要经过网络读取数据,造成一定的网络延时,因此并不能带来网站访问速度的提升。

2. NFS的实现原理

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

image

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客户端和服务端的通信过程如下:

  1. 首先服务器端启动RPC服务,并开启111端口;
  2. 服务器端启动NFS服务,并向RPC注册端口信息;
  3. 客户端启动RPC(portmap服务),向服务端的RPC(portmap)服务请求服务端的NFS端口;
  4. 服务端的RPC(portmap)服务反馈NFS端口信息给客户端;
  5. 客户端通过获取的NFS端口来建立和服务端的NFS连接并进行数据的传输;

image

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。

  1. 服务端修改服务端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)
    
  2. 服务端建立对应的用户

    [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)
    
  3. 服务端重启服务

    [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)
    
  4. 服务端修改/data目录权限

    [root@nfs-30 ~]# chown -R www.www /data/
    
  5. 客户端挂载测试

    [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
    
  6. 客户端测试写入文件

    [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
    
  7. 建议在客户端也创建一个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:
      
posted @ 2021-06-09 23:45  向往自由的独行者  阅读(439)  评论(0编辑  收藏  举报