NFS(網絡文件系統)
1. nfs概述
網絡文件系統,英文Network File System(NFS),是由SUN公司研製的UNIX表示層協議(presentation layer protocol),能使使用者訪問網絡上別處的文件就像在使用自己的計算機一樣。
特性:
- NFS(Network File System)即網絡文件系統,是FreeBSD支持的文件系統中的一種,它允許網絡中的計算機之間通過TCP/IP網絡共享資源
- 在NFS的應用中,本地NFS的客戶端應用可以透明地讀寫位於遠端NFS服務器上的文件,就像訪問本地文件一樣
- nfs適用於Linux與Unix之間實現文件共享,不能實現Linux與Windows間的文件共享功能
- nfs是運行在應用層的協議,其監聽於2049/tcp和2049/udp套接字上
- nfs服務只能基於IP進行認證,這也是它的缺點之一
作用:
- 節省本地存儲空間,將常用的數據存放在一臺NFS服務器上且可以通過網絡訪問,那麼本地終端將可以減少自身存儲空間的使用
- 用戶不需要在網絡中的每個機器上都建有Home目錄,Home目錄可以放在NFS服務器上且可以在網絡上被訪問使用
- 一些存儲設備如軟驅、CDROM和Zip(一種高儲存密度的磁盤驅動器與磁盤)等都可以在網絡上被別的機器使用。這可以減少整個網絡上可移動介質設備的數量
nfs系統架構:
- nfs架構至少由
一臺nfs服務器
和若干臺客戶機
兩個主要部分組成- 客戶機通過TCP/IP網絡遠程訪問存放在NFS服務器上的數據
- 在NFS服務器正式啓用前,需要根據實際環境和需求,配置一些NFS參數
nfs的應用場景:
- 多個機器共享一臺CDROM或其他設備。這對於在多臺機器中安裝軟件來說更加便宜與方便
- 在大型網絡中,配置一臺中心NFS服務器用來放置所有用戶的home目錄可能會帶來便利。這些目錄能被輸出到網絡以便用戶不管在哪臺工作站上登錄,總能得到相同的home目錄
- 不同客戶端可在NFS上觀看影視文件,節省本地空間
- 在客戶端完成的工作數據,可以備份保存到NFS服務器上用戶自己的路徑下
2. nfs工作原理
nfs
是基於rpc
來實現網絡文件系統共享的 。
就如同上面的圖示一般,當我們的 NFS Server 設定好了分享出來的 /home/sharefile 這個目錄後,其它的 NFS Client 端就可以將這個目錄掛載到自己系統上面的某個掛載點(掛載點可以自定義)
2.1 RPC
RPC(Remote Procedure Call Protocol),遠程過程調用協議
,它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的協議。
RPC協議假定某些傳輸協議的存在,如TCP或UDP,爲通信程序之間攜帶信息數據。在OSI網絡通信模型中,RPC跨越了傳輸層和應用層。
RPC採用客戶機/服務器模式。請求程序就是一個客戶機,而服務提供程序就是一個服務器。
- 客戶端程序發起一個RPC系統調用基於TCP協議發送給另一臺主機(服務端)
- 服務端監聽在某個套接字上,當收到客戶端的系統調用請求以後,將收到的請求和其所傳遞的參數通過本地的系統調用執行一遍,並將結果返回給本地的服務進程
- 服務端的服務進程收到返回的執行結果後將其封裝成響應報文,再通過rpc協議返回給客戶端
- 客戶端調用進程接收答覆信息,獲得進程結果,然後調用執行繼續進行
2.2 NIS
-
NIS(Network Information System),網絡信息系統,是對主機帳號等系統提供集中管理的網絡服務。
-
用戶登錄任何一臺NIS客戶機都會從NIS服務器進行登錄認證,可實現用戶帳號的集中管理。
-
NIS協議是明文的,所以NIS一般不建議在公網中使用而通常在局域網中使用。
-
此章主要是講NFS,所以NIS的配置這裏就不詳說了,有興趣的朋友可以去網上搜索。
2.3 NFS工作機制
//NFS服務器端運行着四個進程:
- nfsd
- nfs的守護進程,監聽在2049/tcp和2049/udp端口上
- 不負責文件存儲(由NFS服務器本地內核負責調度存儲),用於理解客戶端發起的rpc請求,並將其轉交給本地內核,而後存儲在指定的文件系統上
- mountd
- 用於驗證客戶端是否在允許訪問此NFS文件系統的客戶端列表中,在則允許訪問(發放一個令牌,持令牌去找nfsd),否則拒絕訪問
- mountd的服務端口是隨機的,由rpc服務(portmapper)提供隨機端口號
- idmapd
實現用戶帳號的集中映射,把所有的帳號都映射爲NFSNOBODY,但是在訪問時卻能以本地用戶的身份去訪問 - portmapper
NFS服務器的rpc服務,其監聽於111/TCP和111/UDP套接字上,用於管理遠程過程調用(RPC)
例
需求:查看file文件的信息,此file存儲在遠程NFS服務端主機上(掛載在本地目錄/shared/nfs中)
- 客戶端發起查看file信息的指令(ls file)給內核,內核通過NFS模塊得知此文件並不是本地文件系統中的文件,而是在遠程NFS主機上的一個文件
- 客戶端主機的內核通過RPC協議把查看file信息的指令(系統調用)封裝成rpc請求通過TCP的111端口發送給NFS服務端主機的portmapper
- NFS服務端主機的portmapper(RPC服務進程)告訴客戶端說NFS服務端的mountd服務在某某端口上,你去找它驗證
因爲mountd在提供服務時必須要向portmapper註冊一個端口號,所以portmapper是知道其工作於哪個端口的
- 客戶端得知服務端的mountd進程端口號後,通過已知的服務端mountd端口號請求驗證
- mountd收到驗證請求後驗證發起請求的客戶端是否在允許訪問此NFS文件系統的客戶端列表中,在則允許訪問(發放一個令牌,持令牌去找nfsd),否則拒絕訪問
- 驗證通過後客戶端持mountd發放的令牌去找服務端的nfsd進程,請求查看某文件
- 服務端的nfsd進程發起本地系統調用,向內核請求查看客戶端要查看的文件的信息
- 服務端的內核執行nfsd請求的系統調用,並將結果返回給nfsd服務
- nfsd進程收到內核返回的結果後將其封裝成rpc請求報文並通過tcp/ip協議返回給客戶端
3. exports文件格式
nfs的主配置文件是/etc/exports,在此文件中,可以定義NFS系統的輸出目錄(即共享目錄)、訪問權限和允許訪問的主機等參數。該文件默認爲空,沒有配置輸出任何共享目錄,這是基於安全性的考慮,如此即使系統啓動了NFS服務也不會輸出任何共享資源。
exports文件中每一行提供了一個共享目錄的設置,其命令格式爲:
<輸出目錄> [客戶端1(選項1,選項2,...)] [客戶端2(選項1,選項2,...)]
其中,除輸出目錄是必選參數外,其他參數均是可選項。另外,格式中的輸出目錄和客戶端之間、客戶端與客戶端之間都使用空格分隔,但客戶端與選項之間不能有空格。
客戶端是指網絡中可以訪問這個NFS共享目錄的計算機。客戶端的指定非常靈活,可爲單個主機的IP或域名,亦可爲某個子網或域中的主機等。
客戶端常用的指定方式:
客戶端 | 說明 |
---|---|
192.168.25.150 | 指定IP地址的主機 |
192.168.25.0/24(或192.168.25.*) | 指定子網中的所有主機 |
www.example.com | 指定域名的主機 |
*.example.com | 指定example.com域中的所有主機 |
*(或缺省) | 所有主機 |
選項用來設置共享目錄的訪問權限、用戶映射等。exports文件中的選項比較多,一般可分爲三類:
- 訪問權限選項(用於控制共享目錄的訪問權限)
- 用戶映射選項
- 默認情況下,當客戶端訪問NFS服務器時,若遠程訪問的用戶是root用戶,則NFS服務器會將其映射成一個本地的匿名用戶(該用戶爲nfsnobody),並將其所屬的用戶組也映射成匿名用戶組(該用戶組也爲nfsnobody),如此有助於提高系統的安全性。
- 其他選項
訪問權限選項:
訪問權限選項 | 說明 |
---|---|
ro | 設置輸出目錄只讀 |
rw | 設置輸出目錄可讀寫 |
用戶映射選項:
用戶映射選項 | 說明 |
---|---|
all_squash | 將遠程訪問的所有普通用戶及所屬組都映射爲匿名用戶或用戶組(nfsnobody) |
no_all_squash | 不將遠程訪問的所有普通用戶及所屬用戶組都映射爲匿名用戶或用戶組(默認設置) |
root_squash | 將root用戶及所屬用戶組都映射爲匿名用戶或用戶組(默認設置) |
no_root_squash | 不將root用戶及所屬用戶組都映射爲匿名用戶或用戶組 |
anonuid=xxx | 將遠程訪問的所有用戶都映射爲匿名用戶,並指定該匿名用戶爲本地用戶帳戶(UID=xxx) |
anongid=xxx | 將遠程訪問的所有用戶組都映射爲匿名用戶組,並指定該匿名用戶組爲本地用戶組(GID=xxx) |
常用的其他選項:
其他選項 | 說明 |
---|---|
secure | 限制客戶端只能從小於1024的TCP/IP端口連接NFS服務器(默認設置) |
insecure | 允許客戶端從大於1024的TCP/IP端口連接NFS服務器 |
sync | 將數據同步寫入內存緩衝區或磁盤中,效率較低,但可保證數據一致性 |
async | 將數據先保存在內存緩衝區中,必要時才寫入磁盤 |
wdelay | 檢查是否有相關的寫操作,如果有則這些寫操作一起執行,可提高效率(默認設置) |
no_wdelay | 若有寫操作則立即執行,應與sync配置使用 |
subtree_check | 若輸出目錄是一個子目錄,則NFS服務器將檢查其父目錄的權限(默認設置) |
no_subtree_check | 即使輸出目錄是一個子目錄,NFS服務亦不檢查其父目錄的權限,可提高效率 |
nohide | 若將一個目錄掛載到另一個目錄之上,則原來的目錄通常就被隱藏起來或看起來像空的一樣。要禁用這種行爲,需啓用hide選項 |
4. nfs管理
nfs安裝:
//安裝
yum -y install nfs-utils
//啓動
systemctl start rpcbind nfs-server
使用shoumount命令測試NFS服務器的輸出目錄狀態:
//語法:showmount [選項] [NFS服務器名稱或地址]
//常用的選項有:
-a //顯示指定NFS服務器的所有客戶端主機及其所連接的目錄
-d //顯示指定的NFS服務器中已被客戶端連接的所有輸出目錄
-e //顯示指定的NFS服務器上所有輸出的共享目錄
在客戶端掛載NFS文件系統:
mount -t nfs SERVER:/path/to/sharedfs /path/to/mount_point
在客戶端設置開機自動掛載nfs:編輯/etc/fstab文件,添加如下格式的內容
- rsize:其值是從服務器讀取的字節數(緩衝)。默認爲1024。若使用比較高的值,如8192,可以提高傳輸速度
- wsize:其值是寫入到服務器的字節數(緩衝)。默認爲1024。若使用比較高的值,如8192,可以提高傳輸速度
exportfs //維護exports文件導出的文件系統表的專用工具
-a //輸出在/etc/exports文件中所設置的所有目錄
-r //重新讀取/etc/exports文件中的設置,並使其立即生效,無需重啓服務
-u //停止輸出某一目錄
-v //在輸出目錄時將目錄顯示到屏幕上
檢查輸出目錄所使用的選項:
在配置文件/etc/exports中,即使在命令行中只設置了一兩個選項,但在真正輸出目錄時,實際上還帶有很多默認的選項。通過查看/var/lib/nfs/etab文件,可以看到具體使用了何選項
[root@node02-linux ~]# cat /var/lib/nfs/etab
5. 實例
1.手動搭建一個nfs服務器
開放/nfs/shared目錄,供所有用戶查閱資料
開放/nfs/upload目錄爲172.16.12.0/24網段的數據上傳目錄,並將所有用戶及所屬的用戶組都映射爲nfs-upload,其UID與GID均爲300
客戶端:node01
服務端:node02
[root@node02-linux ~]# mkdir -p /nfs/{shared,upload} //創建/nfs/shared nfs/upload目錄
[root@node02-linux ~]# ll /nfs/
total 0
drwxr-xr-x. 2 root root 6 May 6 15:08 shared
drwxr-xr-x. 2 root root 6 May 6 15:08 upload
[root@node02-linux ~]# yum -y install nfs-utils //服務端安裝nfs-utils服務
[root@node01-linux ~]# yum -y install nfs-utils //客戶端安裝nfs-utils服務
[root@node02-linux ~]# cat /etc/exports 修改/etc/exports文件
/nfs/shared *(ro) //目錄/nfs/shared 所有用戶可查看
[root@node02-linux ~]# groupadd -g 300 nfs-upload //創建gid爲300的nfs-upload組
[root@node02-linux ~]# useradd -r -M -s /sbin/nologin -g 300 -u 300 nfs-upload //創一個系統用戶,不需要家目錄,設置不允許登陸系統 gid爲300 uid爲300 的nfs-upload用戶
[root@node02-linux ~]# cat /etc/exports 修改/etc/exports文件
/nfs/shared *(ro)
/nfs/upload 192.168.25.*(rw,anonuid=300,anongid=300) //目錄/nfs/upload爲192.168.25.0/24網段的uid爲300 gid爲300的用戶可寫入
[root@node02-linux ~]# setfacl -m u:nfs-upload:rwx /nfs/upload //設置指定用戶能夠讀寫執行目錄/nfs/upload
[root@node02-linux nfs]# getfacl upload/
# file: upload/
# owner: root
# group: root
user::rwx
user:nfs-upload:rwx
group::r-x
mask::rwx
other::r-x
[root@node02-linux nfs]# systemctl enable --now nfs-serve //設置nfs服務開機自動開啓
[root@node02-linux nfs]# systemctl stop firewalld //關閉防火牆
客戶端驗證
[root@node01-linux ~]# showmount -e 192.168.25.130 // 顯示NFS服務器的輸出清單
Export list for 192.168.25.130:
/nfs/shared *
/nfs/upload 192.168.25.*
[root@node01-linux ~]# mkdir /media/{shared,upload} //創建目錄media/shared media/upload
[root@node01-linux ~]# ls /media/
shared upload
[root@node01-linux ~]# mount -t nfs 192.168.25.130:/nfs/shared /media/shared/ //掛載服務端/nfs/shared到客戶端/media/shared/
[root@node01-linux ~]# mount -t nfs 192.168.25.130:/nfs/upload /media/upload/ //掛載服務端/nfs/upload到客戶端/media/upload/
[root@node01-linux ~]# df -h //查看磁盤容量的使用情況
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/centos-root 17G 1.1G 16G 7% /
devtmpfs 476M 0 476M 0% /dev
tmpfs 488M 0 488M 0% /dev/shm
tmpfs 488M 7.6M 480M 2% /run
tmpfs 488M 0 488M 0% /sys/fs/cgroup
/dev/sda1 1014M 130M 885M 13% /boot
tmpfs 98M 0 98M 0% /run/user/0
192.168.25.130:/nfs/shared 17G 1.1G 16G 7% /media/shared
192.168.25.130:/nfs/upload 17G 1.1G 16G 7% /media/upload
[root@node01-linux ~]# cd /media/shared/
[root@node01-linux shared]# touch abc //創建abc文件
touch: cannot touch ‘abc’: Read-only file system
[root@node01-linux shared]# cd ..
[root@node01-linux media]# cd upload
[root@node01-linux upload]# touch abc //創建abc文件
[root@node01-linux upload]# ll
total 0
-rw-r--r--. 1 300 300 0 May 6 15:46 abc
[root@node02-linux nfs]# ls
shared upload
[root@node02-linux nfs]# cd upload
[root@node02-linux upload]# ll
total 0
-rw-r--r--. 1 nfs-upload nfs-upload 0 May 6 15:46 abc
通過腳本搭建nfs並在客戶端上掛載
ssh免交互腳本編寫步驟:
- 安裝軟件
[root@node01-linux ~]# yum -y install expect
[root@node02-linux ~]# yum -y install expect
[root@node01-linux ~]# cat ssh-keygen.exp
#!/usr/bin/expect
set user root
set ip 192.168.25.130
set pass zcq996616
spawn ssh-keygen -t rsa
expect {
"(*id_rsa):" { send "\r";exp_continue }
"(*passphrase):" { send "\r";exp_continue }
"*again:" { send "\r" }
}
expect eof
spawn ssh-copy-id $user@$ip
expect {
"*(yes/no)?" {send "yes\r";exp_continue}
"*password:" {send "$pass\r"}
}
expect eof
- 腳本
[root@node01-linux ~]# cat ssh-keygen.sh
#!/bin/bash
remote_user=root
remote_pass=zcq996616
remote_ip=192.168.25.130
/usr/bin/expect <<EOF
spawn ssh-keygen -t rsa
expect {
"(*id_rsa):" { send "\r";exp_continue }
"(*passphrase):" { send "\r";exp_continue }
"*again:" { send "\r" }
}
expect eof
spawn ssh-copy-id $remote_user@$remote_ip
expect {
"*(yes/no)?" {send "yes\r";exp_continue}
"*password:" {send "$remote_pass\r"}
}
expect eof
EOF
多臺主機免交互
[root@node01-linux remote_config]# cat info
192.168.25.130:root:123456
192.168.25.131:root:654321
[root@node01-linux remote_config]# cat ssh-keygen.sh
#!/bin/bash
function ssh-keygen(){
/usr/bin/expect <<EOF
spawn ssh-copy-id $1@$2
expect {
"*(yes/no)?" {send "yes\r";exp_continue}
"*password:" {send "$3\r"}
}
expect eof
EOF
}
if [ ! -f ~/.ssh/id_rsa ];then
/usr/bin/expect <<EOF
spawn ssh-keygen -t rsa
expect {
"(*id_rsa):" { send "\r";exp_continue }
"(*passphrase):" { send "\r";exp_continue }
"*again:" { send "\r" }
}
expect eof
EOF
fi
for info in $(cat info);do
user=$(echo $info|awk -F: '{print $2}')
pass=$(echo $info|awk -F: '{print $3}')
ip=$(echo $info|awk -F: '{print $1}')
ssh-keygen $user $ip $pass
done