k8s存儲資源之持久化存儲資源存儲卷PV與PVC理解與應用(七)

k8s持久化存儲

探討:k8s中爲什麼要做持久化存儲?

在k8s中部署的應用都是以pod容器的形式運行的,假如我們部署MySQL、Redis等數據庫,需要對這些數據庫產生的數據做備份。因爲Pod是有生命週期的,如果pod不掛載數據卷,那pod被刪除或重啓後這些數據會隨之消失,如果想要長久的保留這些數據就要用到pod數據持久化存儲。

1、k8s持久化存儲:emptyDir

查看k8s支持哪些存儲

[root@k8s-master1 ~]# kubectl explain pods.spec.volumes
KIND:     Pod
VERSION:  v1
RESOURCE: volumes <[]Object>
DESCRIPTION:
     List of volumes that can be mounted by containers belonging to the pod.
     More info: https://kubernetes.io/docs/concepts/storage/volumes
     Volume represents a named volume in a pod that may be accessed by any
     container in the pod.
FIELDS:
   awsElasticBlockStore	<Object>
   azureDisk	<Object>
   azureFile	<Object>
   cephfs	<Object>
   cinder	<Object>
   configMap	<Object>
   csi	<Object>
   downwardAPI	<Object>
   emptyDir	<Object>
   ephemeral	<Object>
   fc	<Object>
   flexVolume	<Object>
   flocker	<Object>
   gcePersistentDisk	<Object>
   gitRepo	<Object>
   glusterfs	<Object>
   hostPath	<Object>
   iscsi	<Object>
   name	<string> -required-
   nfs	<Object>
   persistentVolumeClaim	<Object>
   photonPersistentDisk	<Object>
   portworxVolume	<Object>
   projected	<Object>
   quobyte	<Object>
   rbd	<Object>
   scaleIO	<Object>
   secret	<Object>
   storageos	<Object>
   vsphereVolume	<Object>

常用的如下:
emptyDir 
hostPath 
nfs 
persistentVolumeClaim
glusterfs
cephfs
configMap
secret
![image](https://img2020.cnblogs.com/blog/1279547/202109/1279547-20210921164925518-1605215530.png)

我們想要使用存儲卷,需要經歷如下步驟
1、定義pod的volume,這個volume指明它要關聯到哪個存儲上的
2、在容器中要使用volumemounts掛載對應的存儲

經過以上兩步才能正確的使用存儲卷

emptyDir類型的Volume是在Pod分配到Node上時被創建,Kubernetes會在Node上自動分配一個目錄,因此無需指定宿主機Node上對應的目錄文件。 這個目錄的初始內容爲空,當Pod從Node上移除時,emptyDir中的數據會被永久刪除。emptyDir Volume主要用於某些應用程序無需永久保存的臨時目錄,多個容器的共享目錄等。

創建一個pod,掛載臨時目錄emptyDir

Emptydir的官方網址:
https://kubernetes.io/docs/concepts/storage/volumes#emptydir

[root@k8s-master1 ~]# cat emptydir.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-empty
spec:
  containers:
  - name: container-empty
    image: nginx
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - emptyDir:
     {}
    name: cache-volume

\#更新資源清單文件
[root@k8s-master1 ~]# kubectl apply -f emptydir.yaml 
pod/pod-empty created

查看本機臨時目錄存在的位置,可用如下方法:
\#查看pod調度到哪個節點
[root@k8s-master1 ~]# kubectl get pods -o wide | grep empty
pod-empty      1/1     Running     0       10.244.1.30   k8s-node1

\#查看pod的uid
[root@k8s-master1 ~]# kubectl get pods pod-empty -o yaml | grep uid
uid: 1e0a1665-3a9c-4b0a-b11e-dbe2e7b2b54e

\#登錄到k8s-node1上
[root@k8s-node1 ~]# tree /var/lib/kubelet/pods/1e0a1665-3a9c-4b0a-b11e-dbe2e7b2b54e
/var/lib/kubelet/pods/1e0a1665-3a9c-4b0a-b11e-dbe2e7b2b54e

image

由上可知,臨時目錄在本地的/var/lib/kubelet/pods/38d60544-8591-468d-b70d-2a66df3a1cf6/volumes/kubernetes.io~empty-dir/cache-volume/下

2、k8s持久化存儲:hostPath

hostPath Volume是指Pod掛載宿主機上的目錄或文件。 hostPath Volume使得容器可以使用宿主機的文件系統進行存儲,hostpath(宿主機路徑):節點級別的存儲卷,在pod被刪除,這個存儲卷還是存在的,不會被刪除,所以只要同一個pod被調度到同一個節點上來,在pod被刪除重新被調度到這個節點之後,對應的數據依然是存在的。

  1. 查看hostPath存儲卷的用法
[root@k8s-master1 ~]# kubectl explain pods.spec.volumes.hostPath
KIND:     Pod
VERSION:  v1
RESOURCE: hostPath <Object>
DESCRIPTION:
     HostPath represents a pre-existing file or directory on the host machine
     that is directly exposed to the container. This is generally used for
     system agents or other privileged things that are allowed to see the host
     machine. Most containers will NOT need this. More info:
     https://kubernetes.io/docs/concepts/storage/volumes#hostpath
     Represents a host path mapped into a pod. Host path volumes do not support
     ownership management or SELinux relabeling.
FIELDS:
   path	<string> -required-
   type	<string>

把tomcat.tar.gz上傳到k8s-node2和k8s-node1上,手動解壓並導入

#創建一個pod,掛載hostPath存儲卷
[root@k8s-master1 ~]# cat hostpath.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: test-hostpath
spec:
  containers:
  - image: nginx
    name: test-nginx
    volumeMounts:
    - mountPath: /test-nginx
      name: test-volume
  - image: tomcat:8.5-jre8-alpine
    name: test-tomcat
    volumeMounts:
    - mountPath: /test-tomcat
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      path: /data1
      type: DirectoryOrCreate 

注意:
# DirectoryOrCreate表示本地有/data1目錄,就用本地的,本地沒有就會在pod調度到的節點自動創建一個
#更新資源清單文件

[root@k8s-master1 ~]# kubectl apply -f hostpath.yaml 
pod/test-hostpath created

\#查看pod調度到了哪個物理節點
[root@k8s-master1 volume]# kubectl get pod -owide | grep hostpath
test-hostpath               2/2     Running   0          43s     10.244.2.26   k8s-node2
\#由上面可以知道pod調度到了k8s-node2上,登錄到k8s-node2機器,查看是否在這臺機器創建了存儲目錄

[root@k8s-node1 ~]# ll /data1/
total 0
\#上面可以看到已經創建了存儲目錄/data1,這個/data1會作爲pod的持久化存儲目錄

\#在k8s-node2上的/data1下創建一個目錄
[root@k8s-node2 ~]# cd /data1/
[root@k8s-node2 data1]# mkdir testdir
\#測試存儲卷是否可以正常使用,登錄到nginx容器

[root@k8s-master1 ~]# kubectl exec -it test-hostpath -c test-nginx -- /bin/bash      
root@test-hostpath:/# cd /test-nginx/  
\#/test-nginx/目錄存在,說明已經把宿主機目錄掛載到了容器裏
root@test-hostpath:/test-nginx# ls
testdir

測試存儲卷是否可以正常使用,登錄到tomcat容器

[root@k8s-master1 ~]# kubectl exec -it test-hostpath -c test-tomcat -- /bin/bash
root@test-hostpath:/usr/local/tomcat# cd /test-tomcat/
\#/test-tomcat/目錄存在,說明已經把宿主機目錄掛載到了容器裏
root@test-hostpath:/test-tomcat# ls
testdir

通過上面測試可以看到,同一個pod裏的test-nginx和test-tomcat這兩個容器是共享存儲卷的。

hostpath存儲卷缺點:
單節點
pod刪除之後重新創建必須調度到同一個node節點,數據纔不會丟失

可以用分佈式存儲:
nfs,cephfs,glusterfs

3、k8s持久化存儲:nfs

上節說的hostPath存儲,存在單點故障,pod掛載hostPath時,只有調度到同一個節點,數據纔不會丟失。那可以使用nfs作爲持久化存儲。
1、搭建nfs服務
以k8s的控制節點作爲NFS服務端
[root@k8s-master1 ~]# yum install nfs-utils -y
#在宿主機創建NFS需要的共享目錄
[root@k8s-master1 ~]# mkdir /data/volumes -pv
mkdir: created directory ‘/data’
mkdir: created directory ‘/data/volumes’
配置nfs共享服務器上的/data/volumes目錄
[root@k8s-master1 ~]# systemctl start nfs
[root@k8s-master1 ~]# vim /etc/exports
/data/volumes 192.168.1.0/24(rw,no_root_squash)
no_root_squash: 用戶具有根目錄的完全管理訪問權限
#使NFS配置生效
[root@k8s-master1 ~]# exportfs -arv
exporting 192.168.1.0/24:/data/volumes
[root@k8s-master1 ~]# service nfs start
Redirecting to /bin/systemctl start nfs.service
#設置成開機自啓動
[root@k8s-master1 ~]# systemctl enable nfs && systemctl status nfs
Active: active
看到nfs是active,說明nfs正常啓動了
#k8s-node2和k8s-node1上也安裝nfs驅動
yum install nfs-utils -y && systemctl enable nfs

在k8s-node1上手動掛載試試:
[root@k8s-node1 ~]# mkdir /test
[root@k8s-node1 ~]# mount 192.168.1.56:/data/volumes /test/
[root@k8s-node1 ~]# df -h
192.168.1.56:/data/volumes 50G 5.2G 45G 11% /test

nfs可以被正常掛載
手動卸載:
[root@k8s-node1 ~]# umount /test

#創建Pod,掛載NFS共享出來的目錄

Pod掛載nfs的官方地址:
https://kubernetes.io/zh/docs/concepts/storage/volumes/

下面編寫yaml,使用nfs掛載

[root@k8s-master1 ~]# cat nfs.yaml 
apiVersion: v1
kind: Pod
metadata:
 name: test-nfs-volume
spec:
 containers:
 - name: test-nfs
   image: nginx
   imagePullPolicy: IfNotPresent
   ports:
   - containerPort: 80
     protocol: TCP
   volumeMounts:
   - name: nfs-volumes
     mountPath: /usr/share/nginx/html
 volumes:
 - name: nfs-volumes
   nfs:
    path: /data/volumes
    server: 192.168.1.56

注:path: /data/volumes #nfs的共享目錄
server:192.168.1.56是k8s-master1機器的ip,這個是安裝nfs服務的地址

#更新資源清單文件
[root@k8s-master1 ~]# kubectl apply -f nfs.yaml
#查看pod是否創建成功
[root@k8s-master1 volumes]# kubectl get pods -o wide | grep nfs
test-nfs-volume 1/1 Running 10.244.187.108 k8s-node1
在nfs服務器上的共享目錄創建一個index.html
root@k8s-master1 volumes]# pwd
/data/volumes
[root@k8s-master1 volumes]# cat index.html
Hello, World
My name is PeterXu

#請求pod,看結果
[root@k8s-master1 volumes]# curl 10.244.187.108
Hello, World
My name is PeterXu
#通過上面可以看到,在共享目錄創建的index.html已經被pod掛載了
#登錄到pod驗證下
[root@k8s-master1 volumes]# kubectl exec -it test-nfs-volume -- /bin/bash
root@test-nfs-volume:/# cat /usr/share/nginx/html/index.html
Hello, World
My name is PeterXu

#上面說明掛載nfs存儲捲成功了,nfs支持多個客戶端掛載,可以創建多個pod,掛載同一個nfs服務器共享出來的目錄;但是nfs如果宕機了,數據也就丟失了,所以需要使用分佈式存儲,常見的分佈式存儲有glusterfs和cephfs

4、k8s持久化存儲: PVC

參考官網:
https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes

4.1 k8s PV是什麼?

PersistentVolume(PV)是羣集中的一塊存儲,由管理員配置或使用存儲類動態配置。 它是集羣中的資源,就像pod是k8s集羣資源一樣。 PV是容量插件,如Volumes,其生命週期獨立於使用PV的任何單個pod。

4.2 k8s PVC是什麼?

PersistentVolumeClaim(PVC)是一個持久化存儲卷,我們在創建pod時可以定義這個類型的存儲卷。 它類似於一個pod。 Pod消耗節點資源,PVC消耗PV資源。 Pod可以請求特定級別的資源(CPU和內存)。 pvc在申請pv的時候也可以請求特定的大小和訪問模式(例如,可以一次讀寫或多次只讀)。

4.3 k8s PVC和PV工作原理

PV是羣集中的資源。 PVC是對這些資源的請求。
PV和PVC之間的相互作用遵循以下生命週期:

(1)pv的供應方式
可以通過兩種方式配置PV:靜態或動態。

靜態的:
集羣管理員創建了許多PV。它們包含可供羣集用戶使用的實際存儲的詳細信息。它們存在於Kubernetes API中,可供使用。

動態的:
當管理員創建的靜態PV都不匹配用戶的PersistentVolumeClaim時,羣集可能會嘗試爲PVC專門動態配置卷。此配置基於StorageClasses,PVC必須請求存儲類,管理員必須創建並配置該類,以便進行動態配置。

(2)綁定
用戶創建pvc並指定需要的資源和訪問模式。在找到可用pv之前,pvc會保持未綁定狀態

(3)使用
a)需要找一個存儲服務器,把它劃分成多個存儲空間;
b)k8s管理員可以把這些存儲空間定義成多個pv;
c)在pod中使用pvc類型的存儲卷之前需要先創建pvc,通過定義需要使用的pv的大小和對應的訪問模式,找到合適的pv;
d)pvc被創建之後,就可以當成存儲捲來使用了,我們在定義pod時就可以使用這個pvc的存儲卷
e)pvc和pv它們是一一對應的關係,pv如果被pvc綁定了,就不能被其他pvc使用了;
f)我們在創建pvc的時候,應該確保和底下的pv能綁定,如果沒有合適的pv,那麼pvc就會處於pending狀態。

(4)回收策略
當我們創建pod時如果使用pvc做爲存儲卷,那麼它會和pv綁定,當刪除pod,pvc和pv綁定就會解除,解除之後和pvc綁定的pv卷裏的數據需要怎麼處理,目前,卷可以保留,回收或刪除:
Retain
Recycle (不推薦使用,1.15可能被廢棄了)
Delete
1、Retain
當刪除pvc的時候,pv仍然存在,處於released狀態,但是它不能被其他pvc綁定使用,裏面的數據還是存在的,當我們下次再使用的時候,數據還是存在的,這個是默認的回收策略

Delete
刪除pvc時即會從Kubernetes中移除PV,也會從相關的外部設施中刪除存儲資產

4.4 創建pod,使用pvc作爲持久化存儲卷

1、創建nfs共享目錄
#在宿主機創建NFS需要的共享目錄
[root@k8s-master1 ~]# mkdir /data/volume_test/v{1,2,3,4,5,6,7,8,9,10} -p
#配置nfs共享宿主機上的/data/volume_test/v1..v10目錄

[root@k8s-master1 ~]# cat /etc/exports
/data/volumes 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v1 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v2 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v3 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v4 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v5 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v6 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v7 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v8 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v9 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v10 192.168.1.0/24(rw,no_root_squash)
#重新加載配置,使配置成效
[root@k8s-master1 ~]# exportfs -arv

2、如何編寫pv的資源清單文件
查看定義pv需要的字段

[root@k8s-master1 ~]# kubectl explain pv
KIND:     PersistentVolume
VERSION:  v1
DESCRIPTION:
     PersistentVolume (PV) is a storage resource provisioned by an
     administrator. It is analogous to a node. More info:
     https://kubernetes.io/docs/concepts/storage/persistent-volumes
FIELDS:
   apiVersion	<string>s
   kind	<string>
   metadata	<Object>
   spec	<Object>

\#查看定義nfs類型的pv需要的字段
[root@k8s-master1 ~]# kubectl explain pv.spec.nfs
KIND:     PersistentVolume
VERSION:  v1
RESOURCE: nfs <Object>
FIELDS:
   path	<string> -required-
   readOnly	<boolean>
   server	<string> -required-

3、創建pv

參考:https://kubernetes.io/zh/docs/concepts/storage/persistent-volumes/#reclaiming

[root@k8s-master1 ~]# cat pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name:  v1
spec:
  capacity:
    storage: 1Gi  #pv的存儲空間容量
  accessModes: ["ReadWriteOnce"]
  nfs:
    path: /data/volume_test/v1 #把nfs的存儲空間創建成pv
    server: 192.168.1.56     #nfs服務器的地址
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name:  v2
spec:
  capacity:
      storage: 2Gi
  accessModes: ["ReadWriteMany"]
  nfs:
    path: /data/volume_test/v2
    server: 192.168.1.56
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name:  v3
spec:
  capacity:
      storage: 3Gi
  accessModes: ["ReadOnlyMany"]
  nfs:
    path: /data/volume_test/v3
    server: 192.168.1.56
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name:  v4
spec:
  capacity:
      storage: 4Gi
  accessModes: ["ReadWriteOnce","ReadWriteMany"]
  nfs:
    path: /data/volume_test/v4
    server: 192.168.1.56
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name:  v5
spec:
  capacity:
      storage: 5Gi
  accessModes: ["ReadWriteOnce","ReadWriteMany"]
  nfs:
    path: /data/volume_test/v5
    server: 192.168.1.56
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name:  v6
spec:
  capacity:
      storage: 6Gi
  accessModes: ["ReadWriteOnce","ReadWriteMany"]
  nfs:
    path: /data/volume_test/v6
    server: 192.168.1.56
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name:  v7
spec:
  capacity:
      storage: 7Gi
  accessModes: ["ReadWriteOnce","ReadWriteMany"]
  nfs:
    path: /data/volume_test/v7
    server: 192.168.1.56
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name:  v8
spec:
  capacity:
      storage: 8Gi
  accessModes: ["ReadWriteOnce","ReadWriteMany"]
  nfs:
    path: /data/volume_test/v8
    server: 192.168.1.56
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name:  v9
spec:
  capacity:
      storage: 9Gi
  accessModes: ["ReadWriteOnce","ReadWriteMany"]
  nfs:
    path: /data/volume_test/v9
    server: 192.168.1.56
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name:  v10
spec:
  capacity:     
      storage: 10Gi
  accessModes: ["ReadWriteOnce","ReadWriteMany"]
  nfs:
    path: /data/volume_test/v10  
    server: 192.168.1.56

更新資源清單文件

[root@k8s-master1 ~]# kubectl apply -f pv.yaml 
persistentvolume/v1 created
persistentvolume/v2 created
persistentvolume/v3 created
persistentvolume/v4 created
persistentvolume/v5 created
persistentvolume/v6 created
persistentvolume/v7 created
persistentvolume/v8 created
persistentvolume/v9 created
persistentvolume/v10 created

#查看pv資源
[root@k8s-master1 ~]# kubectl get pv
#STATUS是Available,表示pv是可用的

image

4、創建pvc,和符合條件的pv綁定

[root@k8s-master1 ~]# cat pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 2Gi

#更新資源清單文件
[root@k8s-master1 ~]# kubectl apply -f pvc.yaml 
persistentvolumeclaim/my-pvc created
#查看pv和pvc
[root@k8s-master1 ~]# kubectl get pv

image

STATUS是Bound,表示這個pv已經被my-pvc綁定了

[root@k8s-master1 ~]# kubectl get pvc
NAME     STATUS   VOLUME   CAPACITY   ACCESS MODES   
my-pvc     Bound       v2         2Gi         RWX        
pvc的名字-綁定到pv-綁定的是v2這個pv-pvc可使用的容量是2G

5、創建pod,掛載pvc

[root@k8s-master1 ~]# cat pod_pvc.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-pvc
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: nginx-html
      mountPath: /usr/share/nginx/html
  volumes:
  - name: nginx-html
    persistentVolumeClaim:
      claimName: my-pvc
#更新資源清單文件
[root@k8s-master1 ~]# kubectl apply -f pod_pvc.yaml 
pod/pod-pvc created
#查看pod狀態
[root@k8s-master1 ~]# kubectl get pods | grep pod-pvc
pod-pvc                              1/1     Running     0          27s
#通過上面可以看到pod處於running狀態,正常運行

注:使用pvc和pv的注意事項
1、我們每次創建pvc的時候,需要事先有劃分好的pv,這樣可能不方便,那麼可以在創建pvc的時候直接動態創建一個pv這個存儲類,pv事先是不存在的
2、pvc和pv綁定,如果使用默認的回收策略retain,那麼刪除pvc之後,pv會處於released狀態,我們想要繼續使用這個pv,需要手動刪除pv,kubectl delete pv pv_name,刪除pv,不會刪除pv裏的數據,當我們重新創建pvc時還會和這個最匹配的pv綁定,數據還是原來數據,不會丟失。

5、 k8s存儲類:storageclass

上面介紹的PV和PVC模式都是需要先創建好PV,然後定義好PVC和pv進行一對一的Bond,但是如果PVC請求成千上萬,那麼就需要創建成千上萬的PV,對於運維人員來說維護成本很高,Kubernetes提供一種自動創建PV的機制,叫StorageClass,它的作用就是創建PV的模板。k8s集羣管理員通過創建storageclass可以動態生成一個存儲卷pv供k8s pvc使用。

每個StorageClass都包含字段provisioner,parameters和reclaimPolicy。

具體來說,StorageClass會定義以下兩部分:
1、PV的屬性 ,比如存儲的大小、類型等;
2、創建這種PV需要使用到的存儲插件,比如Ceph、NFS等

有了這兩部分信息,Kubernetes就能夠根據用戶提交的PVC,找到對應的StorageClass,然後Kubernetes就會調用 StorageClass聲明的存儲插件,創建出需要的PV。

查看定義的storageclass需要的字段

[root@k8s-master1 ~]# kubectl explain storageclass
KIND:     StorageClass
VERSION:  storage.k8s.io/v1
DESCRIPTION:
     StorageClass describes the parameters for a class of storage for which
     PersistentVolumes can be dynamically provisioned.
     StorageClasses are non-namespaced; the name of the storage class according
     to etcd is in ObjectMeta.Name.
FIELDS:
   allowVolumeExpansion	<boolean>
   allowedTopologies	<[]Object>
   apiVersion	<string>
   kind	<string>
   metadata	<Object>
   mountOptions	<[]string>
   parameters	<map[string]string>
   provisioner	<string> -required-
   reclaimPolicy	<string>
   volumeBindingMode	<string>

provisioner:供應商,storageclass需要有一個供應者,用來確定我們使用什麼樣的存儲來創建pv,常見的provisioner如下

(https://kubernetes.io/zh/docs/concepts/storage/storage-classes/):

provisioner既可以由內部供應商提供,也可以由外部供應商提供,如果是外部供應商可以參考https://github.com/kubernetes-incubator/external-storage/ 下提供的方法創建。

https://github.com/kubernetes-sigs/sig-storage-lib-external-provisioner

以NFS爲例,要想使用NFS,我們需要一個nfs-client的自動裝載程序,稱之爲provisioner,這個程序會使用我們已經配置好的NFS服務器自動創建持久卷,也就是自動幫我們創建PV。

reclaimPolicy:回收策略

allowVolumeExpansion:允許卷擴展,PersistentVolume 可以配置成可擴展。將此功能設置爲true時,允許用戶通過編輯相應的 PVC 對象來調整卷大小。當基礎存儲類的allowVolumeExpansion 字段設置爲 true 時,以下類型的卷支持卷擴展。

注意:此功能僅用於擴容卷,不能用於縮小卷。

5.1 安裝nfs provisioner,用於配合存儲類動態生成pv

把nfs-subdir-external-provisioner.tar.gz上傳到k8s-node2和k8s-node1上,手動解壓
[root@k8s-node2 ~]# docker load -i nfs-subdir-external-provisioner.tar.gz
[root@k8s-node1 ~]# docker load -i nfs-subdir-external-provisioner.tar.gz

1、創建運行nfs-provisioner需要的sa賬號
[root@k8s-master1 nfs]# cat serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-provisioner

[root@k8s-master1 nfs]# kubectl apply -f serviceaccount.yaml
serviceaccount/nfs-provisioner created

擴展:什麼是sa?
sa的全稱是serviceaccount。
serviceaccount是爲了方便Pod裏面的進程調用Kubernetes API或其他外部服務而設計的。

指定了serviceaccount之後,我們把pod創建出來了,我們在使用這個pod時,這個pod就有了我們指定的賬戶的權限了。

2、對sa授權
[root@k8s-master1]# kubectl create clusterrolebinding nfs-provisioner-clusterrolebinding --clusterrole=cluster-admin --serviceaccount=default:nfs-provisioner

3、安裝nfs-provisioner程序

[root@k8s-master1 ~]# mkdir /data/nfs_pro -p
\#把/data/nfs_pro變成nfs共享的目錄
[root@k8s-master1 ~]# cat /etc/exports
/data/volumes 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v1 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v2 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v3 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v4 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v5 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v6 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v7 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v8 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v9 192.168.1.0/24(rw,no_root_squash)
/data/volume_test/v10 192.168.1.0/24(rw,no_root_squash)
/data/nfs_pro 192.168.1.0/24(rw,no_root_squash)

[root@k8s-master1 ~]# exportfs -arv
exporting 192.168.1.0/24:/data/nfs_pro
exporting 192.168.1.0/24:/data/volume_test/v10
exporting 192.168.1.0/24:/data/volume_test/v9
exporting 192.168.1.0/24:/data/volume_test/v8
exporting 192.168.1.0/24:/data/volume_test/v7
exporting 192.168.1.0/24:/data/volume_test/v6
exporting 192.168.1.0/24:/data/volume_test/v5
exporting 192.168.1.0/24:/data/volume_test/v4
exporting 192.168.1.0/24:/data/volume_test/v3
exporting 192.168.1.0/24:/data/volume_test/v2
exporting 192.168.1.0/24:/data/volume_test/v1
exporting 192.168.1.0/24:/data/volumes

[root@k8s-master1 ~]# cat nfs-deployment.yaml 
kind: Deployment
apiVersion: apps/v1
metadata:
  name: nfs-provisioner
spec:
  selector:
    matchLabels:
       app: nfs-provisioner
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-provisioner
    spec:
      serviceAccount: nfs-provisioner
      containers:
        - name: nfs-provisioner
          image: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: example.com/nfs
            - name: NFS_SERVER
              value: 192.168.1.56
            - name: NFS_PATH
              value: /data/nfs_pro
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.1.56
            path: /data/nfs_pro
#更新資源清單文件
[root@k8s-master1 ~]# kubectl apply -f nfs-deployment.yaml 
deployment.apps/nfs-provisioner created
#查看nfs-provisioner是否正常運行
[root@k8s-master1 nfs]# kubectl get pods | grep nfs
nfs-provisioner-7c55b8bbf7-mnndl      1/1     Running 

5.2 創建storageclass,動態供給pv

[root@k8s-master1]# cat nfs-storageclass.yaml 
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: nfs
provisioner: example.com/nfs
[root@k8s-master1]# kubectl apply -f nfs-storageclass.yaml
#查看storageclass是否創建成功
[root@k8s-master1 nfs]# kubectl get storageclass
NAME       PROVISIONER           RECLAIMPOLICY   VOLUMEBINDINGMODE   
nfs       example.com/nfs         Delete          Immediate
#顯示內容如上,說明storageclass創建成功了

注意:provisioner處寫的example.com/nfs應該跟安裝nfs provisioner時候的env下的PROVISIONER_NAME的value值保持一致,如下:
env:
    - name: PROVISIONER_NAME
     value: example.com/nfs

5.3 創建pvc,通過storageclass動態生成pv

[root@k8s-master1]# cat claim.yaml 
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim1
spec:
  accessModes:  ["ReadWriteMany"]
  resources:
    requests:
      storage: 1Gi
  storageClassName:  nfs
[root@k8s-master1]# kubectl apply -f claim.yaml 
persistentvolumeclaim/test-claim1 created
#查看是否動態生成了pv,pvc是否創建成功,並和pv綁定
[root@k8s-master1 nfs]# kubectl get pvc

通過上面可以看到test-claim1的pvc已經成功創建了,綁定的pv是pvc-cbf42792-e7ee-41bc-86a1-84d59d147e09,這個pv是由storageclass調用nfs provisioner自動生成的。
image

步驟總結:
1、供應商:創建一個nfs provisioner
2、創建storageclass,storageclass指定剛纔創建的供應商
3、創建pvc,這個pvc指定storageclass

5.4 創建pod,掛載storageclass動態生成的pvc:test-claim1

[root@k8s-master1]# cat read-pod.yaml 
kind: Pod
apiVersion: v1
metadata:
  name: read-pod
spec:
  containers:
  - name: read-pod
    image: nginx
    volumeMounts:
      - name: nfs-pvc
        mountPath: /usr/share/nginx/html
  restartPolicy: "Never"
  volumes:
    - name: nfs-pvc
      persistentVolumeClaim:
        claimName: test-claim1
#更新資源清單文件
[root@k8s-master1 nfs]# kubectl apply -f read-pod.yaml 
pod/read-pod created
#查看pod是否創建成功
[root@k8s-master1 nfs]# kubectl get pods | grep read
read-pod                             1/1     Running     0
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章