關注微信公眾號:CodingTechWork,一起學習進步。
NFS介紹
概述
網絡文件系統(Network File System, NFS),是基於內核的文件系統,nfs主要是通過網絡實現服務器和客戶端之間的數據傳輸,采用遠程過程調用RPC(Romete Procedure Call)機制,讓不同的機器節點共享文件目錄。只需將nfs服務器共享的文件目錄掛載到nfs客戶端,這樣客戶端就可以對遠程服務器上的文件進行讀寫操作。
一個NFS服務器可以對應多個nfs客戶端,基於RPC機制,用戶可以像訪問本地文件一樣訪問遠端的共享目錄文件,使用起來很nice!
原理
掛載原理
如圖所示,在NFS服務器創建並設置好一個共享目錄/nfs
,其他網絡互通的NFS客戶端可以將該目錄掛載到本地文件系統中的某個掛載點(可自定義),如NFS客戶端A掛載到/nfs-a/data
中,NFS客戶端B掛載到/nfs-b/data
中,這樣NFS客戶端可以在本地的掛載目錄即可看到NFS服務器共享目錄/nfs
內的所有數據。具體的權限(如只讀、讀寫等權限)根據服務器的配置而定。
通信原理
如圖所示,通過RPC和NFS服務傳輸數據。
- NFS服務端啟動RPC服務,開啟111端口,可以通過nfsnetstat。
- NFS服務端啟動NFS服務,並向RPC注冊端口信息。
- NFS客戶端啟動RPC服務,向服務端RPC服務請求NFS服務端口。
- NFS服務端RPC服務反饋NFS端口信息給NFS客戶端。
- NFS客戶端通過獲取的NFS端口簡歷和服務端的NFS連接,並通過RPC及底層TCP/IP協議進行數據傳輸。
NFS服務器搭建
部署步驟
可以在linux系統的k8s集群中任意一個node節點做nfs服務端。
-
檢查防火牆服務
$ systemctl status firewalld
若防火牆未關閉,使用如下命令進行關閉$ systemctl stop firewalld
$ systemctl disable firewalld
-
檢查SELinux
$ cat /etc/selinux/config
若未關閉禁用,使用如下命令:$ setenforce 0
$ sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config
-
安裝nfs相關服務軟件包
$ yum install -y nfs-utils rpcbind
-
創建共享存儲文件夾
$ mkdir /nfs
-
配置nfs
$ vi /etc/exports
輸入以下內容,格式為:nfs共享目錄 nfs客戶端地址1(param1, param2,...) nfs客戶端地址2(param1, param2,...)
/nfs 10.1.1.0/24(rw,async,no_root_squash)
-
啟動服務
先啟動rpc服務,再啟動nfs服務$ systemctl start rpcbind
$ systemctl enable rpcbind
$ systemctl enable nfs && systemctl restart nfs
-
查看服務狀態
$ systemctl status rpcbind
$ systemctl status nfs
-
查看可用的nfs地址
showmount -e 127.0.0.1
或showmount -e localhost
[root@k8s ~]# showmount -e localhost
Export list for localhost:
/nfs 10.1.1.0/24
共享目錄修改
創建好共享目錄通過/etc/exports
進行編輯配置,若修改后,可以通過systemctl reload nfs
或者exportfs -avr
進行nfs服務的重新加載發布,從而使修改過的/etc/exports
配置文件生效。
NFS客戶端配置
配置步驟
使用nfs共享目錄的都需要配置一遍以下步驟。
- 安裝nfs-utils和rpcbind
$ yum install -y nfs-utils rpcbind
- 創建掛載的文件夾
$ mkdir -p /nfs/data
- 掛載nfs
$ mount -t nfs 10.1.1.1:/nfs /nfs/data
其中:mount
:表示掛載命令-t
:表示掛載選項nfs
:掛載的協議10.1.1.1
:nfs服務器的ip地址/nfs
:nfs服務器的共享目錄/nfs/data
:本機客戶端要掛載的目錄 - 查看掛載信息
$ df -Th
- 測試掛載
可以進入本機的/nfs/data
目錄,上傳一個文件,然后去nfs服務器查看/nfs目錄中是否有該文件,若有則共享成功。反之在nfs服務器操作/nfs
目錄,查看本機客戶端的目錄是否共享。 - 取消掛載
$ umount /nfs/data
掛載的方式
除了上述通過mount -t nfs
命令指定的方式進行目錄掛載以外,還可以通過vim /etc/fstab
文件進行掛載。
10.1.1.1:/nfs /nfs/data nfs defaults 1 1
其中:
- 第一列
10.1.1.1:/nfs
:(Device)磁盤設備文件或該設備的Label或者UUID,此處即為nfs服務器的地址和共享目錄 - 第二列
/nfs/data
:(Mount point)是設備的掛載點,即本機掛載目錄 - 第三列
nfs
:(Filesystem)是磁盤文件系統的格式,如ext2、nfs、vfat等。 - 第四列
defaults
:(parameters)是文件系統的參數,defaults
即具有rw,suid,dev,exec,auto,nouser,async
等默認參數。 - 第五列
1
:(Dump)能夠被dump備份命令作用,一般是0或者1,0表示不用做dump備份,1表示每天進行dump操作,當然還有2,表示不定期進行dump操作。 - 第六列
1
:是否檢驗扇區,0表示不要檢驗,1表示最早檢驗(根目錄一般會設置),2表示1級別檢驗完成之后進行檢驗。
k8s基於nfs創建storageclass
下載開源插件
- 下載
git clone https://github.com/kubernetes-incubator/external-storage.git
或者git clone https://github.com/kubernetes-retired/external-storage.git
- 進入部署目錄
cd external-storage/nfs-client/deploy
部署授權
[root@k8s deploy]# cat rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
[root@k8s deploy] kubectl create -f rbac.yaml
[root@k8s deploy] kubectl get sa
NAME SECRETS AGE
default 1 82d
nfs-client-provisioner 1 25s
部署插件
[root@k8s deploy]# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: quay.io/external_storage/nfs-client-provisioner:latest
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
# 必須與class.yaml中的provisioner的名稱一致
value: fuseim.pri/ifs
- name: NFS_SERVER
# NFS服務器的ip地址
value: 10.1.1.0
- name: NFS_PATH
# 修改為實際創建的共享掛載目錄
value: /nfs
volumes:
- name: nfs-client-root
nfs:
# NFS服務器的ip地址
server: 10.154.2.154
# 修改為實際創建的共享掛載目錄
path: /nfs
[root@k8s deploy]# kubectl create -f deployment.yaml
[root@k8s deploy]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nfs-client-provisioner 1/1 1 1 10s
部署storageclass
[root@k8s deploy]# cat class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
# 必須與deployment.yaml中的PROVISIONER_NAME一致
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
archiveOnDelete: "false"
[root@k8s deploy]# kubectl create -f class.yaml
[root@k8s deploy]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
managed-nfs-storage fuseim.pri/ifs Delete Immediate false 15s
測試
測試pvc
[root@k8s deploy]# cat test-claim.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
annotations:
volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
[root@k8s deploy]# kubectl create -f test-claim.yaml
[root@k8s deploy]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-claim Bound pvc-938bb7ec-8a1f-44dd-afb8-2659e824564a 1Mi RWX managed-nfs-storage 10s
測試pod
[root@k8s deploy]# cat test-pod.yaml
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: gcr.io/google_containers/busybox:1.24
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1"
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim
[root@k8s deploy]# kubectl create -f test-pod.yaml
[root@k8s deploy]# kubectl get pods
NAME READY STATUS RESTARTS AGE
test-pod 1/1 Running 0 12s
至此,完美!
附
NFS配置文件參數
參數 | 說明 |
---|---|
ro | 只讀(默認) |
rw | 讀寫 |
sync | 同步,同時將數據寫入內存和硬盤中,保證不丟數據 |
async | 異步,優先將數據保存到內存,再寫入硬盤,有可能丟數據 |
root_squash | 當nfs客戶端以root管理員訪問時,映射為nfs服務器的匿名用戶 |
no_root_squash | 當nfs客戶端以root管理員訪問時,映射為nfs服務器的root管理員用戶 |
all_squash | 無論nfs客戶端以什么賬戶訪問,都映射為nfs服務器的匿名用戶 |