NFS(Network File System)即网络文件系统,用于实现Unix或类Unix系统之间通过TCP/IP网络共享资源。在NFS的应用中,NFS的客户端可以将远端NFS服务器共享的目录挂载于本地,透明地读写,就像访问本地文件一样。
一、NFS原理
1、NFS依赖于RPC
NFS支持的功能很多,不同的功能会使用不同的进程,每启动一个功能就需要开启一些端口传输数据,因此,NFS功能所对应的端口不是固定的,而是随机取用一些未被使用的端口。这样一来,客户端与NFS服务器之间的沟通就成了一大问题。NFS借助rpc解决这个问题。
RPC(remote procedure call protocol):远程过程调用。让客户端所执行的程式可以呼叫远端电脑上的的程式来帮其执行相关服务,然后再将结果传回客户端。
RPC最主要的功能就是指定每个NFS功能所对应的端口号,并且告知客户端,让客户端可以连结到正确的端口上去。负责RPC服务的一支关键daemon叫portmap(centos 6.x之后称为rpcbind),当服务器在启动NFS时会随机取用数个端口,并主动向RPC注册,portmap就会动态分配端口号给那些提供NFS服务的相关daemon,因此当Client端在对NFS Server提出服务请求时,必须先联系portmap进程(监听在111号端口),portmap将NFS服务相关daemon的端口号告知,然后Client才知道要跟哪些端口沟通。
既然nfs依赖于rpc,因此要启动nfs就必须要启动rpc,且要先启动rpc,否则nfs无法完成端口注册
2、nfs启动的daemons:
rpc.nfsd:管理clinet是否有权限登录,以及判别登录者的UID等,监听在2049号端口上
rpc.mountd:管理NFS文件系统,它会读取/etc/exports,控制客户端的访问权限,监听于随机端口
rpc.idmapd:nfs v4中提供的守护进程,用于处理UID和GID的映射,监听于随机端口
rpc.lockd(非必须):文件锁,保证文件在同一时间只有一个人访问。lockd要在服务端和客户端都开启
rpc.statd(非必须):检查文件一致性。常与lockd同时启用,同样要求服务端和客户端同时开启
3、用户映射
通过 NFS 中的用户映射,可以将伪或实际用户和组的标识赋给一个正在对 NFS 卷进行操作的用户。这个客户端用户具有被映射成的用户和组所许可的权限。对 NFS 卷使用一个通用的用户/组可以提供一定的安全性和灵活性,而不会带来很多管理负荷。
nfs服务器会根据客户端用户的 UID 与 GID(而非用户名与群组名)来做映射,有以下几种情况:
①服务器端存在该UID,则客户端使用者具有该UID在服务器上对应用户的权限。有可能出现如下情况,该UID在客户端和服务端对应的用户名不同,例如 一个UID在客户端对应的用户名为federa,但在服务器上却为debian,这样可能造成服务器端的资料被错误的使用者访问
②服务器端不存在该UID,则使用者的身份在该目录下会被压缩成匿名用户,一般NFS的匿名用户会以UID为 65534为其使用者,这个65534的用户名称通常是nobody
③为安全起见,若客户端尝试以UID=0(即root)的身份尝试访问共享目录时,默认会被压缩为匿名用户
二、nfs的配置
1、程序安装与启动:
RPC主程序:rpcbind(服务器和客户端都要安装)
NFS主程序:nfs-utils(即提供nfsd及mountd这两个NFS daemons与其他相关documents与执行文件等的软件)
CentOS 6.5上这两个程序默认已安装
service rpcbind start #默认已启动
service nfs start [service nfslock start]
2、rpcinfo:显示RPC的相关信息
用法:rpcinfo- p [host]
-p(probe):列出所有host(缺省为本机)上用portmap注册的RPC程序
3、在/etc/exports文件中定义要共享的文件系统和可使用的客户端
格式:directory (or file system) client1(option1,option2...) client2(option1,option2...)
client可以为:ip、FQDN、domain
例如,/tmp 192.168.100.0/24(ro) localhost(rw) *.ev.ncku.edu.tw(ro,sync)
常用选项:
rw:允许NFS客户端进行读/写访问,缺省选项是ro(只读)
async/sync:sync代表数据会同步写入到内存与硬盘中,async则代表数据会先暂存于内存当中,而非直接写入硬盘;默认为sycn
secure:此选项是缺省选项,它使用了1024以下的TCP/IP端口实现NFS的连接。指定 insecure 可以禁用这个选项。
与用户映射相关的选项:
root_squash:root用户访问此目录,会被压缩成匿名用户,缺省选项
no_root_squash:不压缩root用户身份,危险!
all_squash:这个选项对于公共访问的 NFS 卷来说非常有用,它会限制所有的 UID 和 GID,只使用匿名用户。缺省设置是 no_all_squash。
anonuid=XXX 和 anongid=XXX:这两个选项将匿名 UID 和 GID 修改成特定用户和组帐号。这个特定用户和组帐号必须存在于/etc/passwd中
4、exportfs:管理当前NFS共享的文件系统列表
用法:exportfs [option] [directory]
选项:
-a:导出或取消导出所有目录
-r:更新配置,重新读取/etc/exports。
-u:取消一个或多个目录的共享。它与-a选项结合使用时,表示取消共享所有目录;-u directory表示取消共享指定目录
-i file:导出其它文件(非/etc/exports)中的目录
5、showmount:查询NFS服务器的相关信息
用法:showmount [option] NFSSERVER_IP
常用选项:
-e:显示nfs服务器上所有共享出去的目录
-a:显示目前主机与客户端的 NFS 联机分享的状态
-d:仅显示被客户端挂载的目录
6、客户端挂载NFS文件系统:
mount -t nfs SERVER:/path/to/sharedfs /path/to/mount_point
例如 mount -t nfs 192.168.30.20/share/nfs /mnt
开机自动挂载nfs:
vim /etc/fstab
添加 SERVER:/PATH/TO/EXPORTED_FS /mount_point nfs defaults,_netdev 0 0 #_netdev明确说明要挂载的是网络设备,有挂载超时时长,用来防止因无法挂载nfs共享目录而导致无法开机的问题
7、客户端使用者对nfs共享资源的访问权限取决于以下二者的交集:
/etc/exports文件中授予的权限
映射后的用户对所访问的目录或文件所具有的权限
以下的示例中,node2为nfs服务端,node1为客户端
[root@node2 ~]# rpm -q nfs-utils nfs-utils-1.2.3-64.el6.x86_64 [root@node2 ~]# rpm -q rpcbind rpcbind-0.2.0-11.el6.x86_64 [root@node2 ~]# rpm -ql nfs-utils /etc/nfsmount.conf /etc/rc.d/init.d/nfs /etc/rc.d/init.d/nfslock /etc/rc.d/init.d/rpcgssd /etc/rc.d/init.d/rpcidmapd /etc/rc.d/init.d/rpcsvcgssd /etc/request-key.d/id_resolver.conf /etc/sysconfig/nfs /sbin/mount.nfs /sbin/mount.nfs4 /sbin/nfs_cache_getent /sbin/rpc.statd /sbin/umount.nfs /sbin/umount.nfs4 /usr/sbin/exportfs /usr/sbin/mountstats /usr/sbin/nfsidmap /usr/sbin/nfsiostat /usr/sbin/nfsstat /usr/sbin/rpc.gssd /usr/sbin/rpc.idmapd /usr/sbin/rpc.mountd /usr/sbin/rpc.nfsd /usr/sbin/rpc.svcgssd /usr/sbin/rpcdebug /usr/sbin/showmount /usr/sbin/sm-notify /usr/sbin/start-statd ... /var/lib/nfs /var/lib/nfs/etab #记录了NFS所共享出来的目录的完整权限设定值 ... [root@node2 ~]# service rpcbind status #默认已启动 rpcbind (pid 54488) is running... [root@node2 ~]# rpcinfo -p program vers proto port service 100000 4 tcp 111 portmapper 100000 3 tcp 111 portmapper 100000 2 tcp 111 portmapper 100000 4 udp 111 portmapper 100000 3 udp 111 portmapper 100000 2 udp 111 portmapper 100024 1 udp 34746 status 100024 1 tcp 44274 status [root@node2 ~]# service nfs start Starting NFS services: [ OK ] Starting NFS quotas: [ OK ] Starting NFS mountd: [ OK ] Starting NFS daemon: [ OK ] Starting RPC idmapd: [ OK ] [root@node2 ~]# rpcinfo -p program vers proto port service 100000 4 tcp 111 portmapper 100000 3 tcp 111 portmapper 100000 2 tcp 111 portmapper 100000 4 udp 111 portmapper 100000 3 udp 111 portmapper 100000 2 udp 111 portmapper 100011 1 udp 875 rquotad 100011 2 udp 875 rquotad 100011 1 tcp 875 rquotad 100011 2 tcp 875 rquotad 100005 1 udp 37839 mountd 100005 1 tcp 49192 mountd 100005 2 udp 47785 mountd 100005 2 tcp 48271 mountd 100005 3 udp 34856 mountd 100005 3 tcp 60003 mountd 100003 2 tcp 2049 nfs 100003 3 tcp 2049 nfs 100003 4 tcp 2049 nfs 100227 2 tcp 2049 nfs_acl 100227 3 tcp 2049 nfs_acl 100003 2 udp 2049 nfs 100003 3 udp 2049 nfs 100003 4 udp 2049 nfs 100227 2 udp 2049 nfs_acl 100227 3 udp 2049 nfs_acl 100021 1 udp 57644 nlockmgr 100021 3 udp 57644 nlockmgr 100021 4 udp 57644 nlockmgr 100021 1 tcp 57018 nlockmgr 100021 3 tcp 57018 nlockmgr 100021 4 tcp 57018 nlockmgr 100024 1 udp 40429 status 100024 1 tcp 34062 status [root@node2 ~]# netstat -tanp Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name ... tcp 0 0 0.0.0.0:875 0.0.0.0:* LISTEN 55969/rpc.rquotad tcp 0 0 0.0.0.0:34062 0.0.0.0:* LISTEN 56259/rpc.statd tcp 0 0 0.0.0.0:48271 0.0.0.0:* LISTEN 55973/rpc.mountd tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 54488/rpcbind tcp 0 0 0.0.0.0:57018 0.0.0.0:* LISTEN - tcp 0 0 0.0.0.0:2049 0.0.0.0:* LISTEN - tcp 0 0 0.0.0.0:60003 0.0.0.0:* LISTEN 55973/rpc.mountd tcp 0 0 0.0.0.0:49192 0.0.0.0:* LISTEN 55973/rpc.mountd tcp 0 0 :::111 :::* LISTEN 54488/rpcbind tcp 0 0 :::41844 :::* LISTEN - tcp 0 0 :::35573 :::* LISTEN 55973/rpc.mountd tcp 0 0 :::39927 :::* LISTEN 55973/rpc.mountd tcp 0 0 :::2049 :::* LISTEN - tcp 0 0 :::39876 :::* LISTEN 56259/rpc.statd tcp 0 0 :::44548 :::* LISTEN 55973/rpc.mountd ... [root@node2 ~]# mkdir -p /share/nfs [root@node2 ~]# cp /etc/fstab /share/nfs [root@node2 ~]# ls -ld /share/nfs drwxr-xr-x 2 root root 4096 Nov 23 21:16 /share/nfs [root@node2 ~]# vim /etc/exports #配置共享目录 /share/nfs 192.168.30.10(rw) 192.168.30.30(ro) [root@node2 ~]# cat /var/lib/nfs/etab /share/nfs 192.168.30.10(rw,sync,wdelay,hide,nocrossmnt,secure,root_squash,no_all_squash,no_subtree_check,secure_locks,acl,anonuid=65534,anongid=65534,sec=sys,rw,root_squash,no_all_squash) /share/nfs 192.168.30.30(ro,sync,wdelay,hide,nocrossmnt,secure,root_squash,no_all_squash,no_subtree_check,secure_locks,acl,anonuid=65534,anongid=65534,sec=sys,ro,root_squash,no_all_squash)
[root@node1 ~]# showmount -e 192.168.30.20 #查看指定nfs服务器的共享信息 Export list for 192.168.30.20: /share/nfs 192.168.30.30,192.168.30.10 [root@node1 ~]# mount -t nfs 192.168.30.20:/share/nfs /mnt #挂载共享文件系统 [root@node1 ~]# mount /dev/sda2 on / type ext4 (rw) proc on /proc type proc (rw) sysfs on /sys type sysfs (rw) devpts on /dev/pts type devpts (rw,gid=5,mode=620) tmpfs on /dev/shm type tmpfs (rw) /dev/sda1 on /boot type ext4 (rw) none on /proc/sys/fs/binfmt_misc type binfmt_misc (rw) /dev/mapper/myvg-mydata on /mydata type ext4 (rw) sunrpc on /var/lib/nfs/rpc_pipefs type rpc_pipefs (rw) nfsd on /proc/fs/nfsd type nfsd (rw) 192.168.30.20:/share/nfs on /mnt type nfs (rw,vers=4,addr=192.168.30.20,clientaddr=192.168.30.10) [root@node1 ~]# vim /etc/fstab #加入开机自动挂载 ... 192.168.30.20:/share/nfs /mnt nfs defaults,_netdev 0 0 [root@node1 ~]# ls /mnt fstab [root@node1 ~]# ll /mnt/fstab -rw-r--r-- 1 root root 881 Nov 23 21:42 /mnt/fstab [root@node1 ~]# tail -1 /mnt/fstab LABEL=MYDATA /mydata ext4 defaults 0 0 [root@node1 ~]# echo "hello" >> /mnt/fstab #root用户被压缩为匿名用户,而匿名用户对该文件是没有写权限的 -bash: /mnt/fstab: Permission denied [root@node1 ~]# touch /mnt/a.txt touch: cannot touch `/mnt/a.txt': Permission denied
[root@node2 ~]# chmod 757 /share/nfs #修改共享目录的权限,使其它用户能够写入
[root@node1 ~]# touch /mnt/a.txt [root@node1 ~]# ll /mnt total 8 -rw-r--r-- 1 nfsnobody nfsnobody 0 Nov 23 22:07 a.txt #可以看到,root用户的确被压缩为nfsnobody -rw-r--r-- 1 root root 881 Nov 23 21:42 fstab
[rose@node1 ~]$ id uid=501(rose) gid=501(rose) groups=501(rose) [rose@node1 ~]$ touch /mnt/b.txt [rose@node1 ~]$ ll /mnt total 8 -rw-r--r-- 1 nfsnobody nfsnobody 0 Nov 23 22:07 a.txt -rw-rw-r-- 1 tesla tesla 0 Nov 23 22:10 b.txt #用户rose的UID为501,此UID值对应于服务器端的tesla,故该使用者具有tesla的权限 -rw-r--r-- 1 root root 881 Nov 23 21:42 fstab