k8s的存儲類

k8s有很多的服務,很多的資源對象。

如果要去創建服務,做數據持久化,需要預先知道可用PV有哪些?

如果爲了這個服務去提前創建PV,那麼我們還需要知道,這個服務,大概需要多大的空間?

環境介紹

主機 IP地址 服務
master 192.168.1.21 k8s
node01 192.168.1.22 k8s
node02 192.168.1.23 k8s

基於[ https://blog.51cto.com/14320361/2464655]() 的實驗繼續進行

存儲類介紹

Kubernetes集羣管理員通過提供不同的存儲類,可以滿足用戶不同的服務質量級別、備份策略和任意策略要求的存儲需求。動態存儲卷供應使用StorageClass進行實現,其允許存儲卷按需被創建。如果沒有動態存儲供應,Kubernetes集羣的管理員將不得不通過手工的方式類創建新的存儲卷。通過動態存儲卷,Kubernetes將能夠按照用戶的需要,自動創建其需要的存儲。

基於StorageClass的動態存儲供應整體過程如下圖所示:
k8s的存儲類

1)集羣管理員預先創建存儲類(StorageClass);
2)用戶創建使用存儲類的持久化存儲聲明(PVC:PersistentVolumeClaim);
3)存儲持久化聲明通知系統,它需要一個持久化存儲(PV: PersistentVolume);
4)系統讀取存儲類的信息;
5)系統基於存儲類的信息,在後臺自動創建PVC需要的PV;
6)用戶創建一個使用PVC的Pod;
7)Pod中的應用通過PVC進行數據的持久化;
8)而PVC使用PV進行數據的最終持久化處理。

先來簡單看一下這張圖實現的過程,然後我們再來研究一下

k8s的存儲類

說在前面的話,靜態供給的話,會需要我們手動去創建pv,如果沒有足夠的資源,找不到合適的pv,那麼pod就會處於pending等待的狀態,就是說找不到合適的伴侶了,所以解決這兩種問題,就給出了這種動態供給,主要是能夠自動幫你創建pv
,就是你需要多大的容量,就自動給你創建多大的容量,也就是pv,k8s幫你創建了,創建pvc的時候就需要找pv了,這個時候就交給這個存儲類了,而存儲類呢,去幫你創建這些pv,存儲類呢,就是實現了對指定存儲的一個支持,直接幫你去調用api去創建存儲類,所以就不需要人工的去幫你創建pv了。
而你去想想,當節點比較多,業務比較多的時候,再去人工手動創建pv,量還是很大的,而且也不是很好去維護。
而動態供給主要的一個實現就是StorageClass存儲對象,其實它就是聲明你使用哪個存儲,然後呢幫你去連接,再幫你去自動創建pv。

舉個例子更好去理解
話不多說下圖
k8s的存儲類

其實它是一個基於NFS實現的一個pv供給,它大概流程是這樣的,我們可能會創建一個statefulset有狀態的應用存儲,然後有一個管理的nfs-storageClass,因爲nfs目前是不支持這個自動的創建pv的,我們可以利用社區實現的插件來完成這個pv的自動創建,也就是StorageClass這一塊,創建完之後,然後pod再去引用。

一,Storage Class(存儲類)

作用:它可以動態的自動的創建所需要的PV

Provisioner(供給方,提供者):及提供了存儲資源的存儲系統。k8s內建有多重供給方,這些供給方的名字都以“kubernetes.io”爲前綴。並且還可以自定義。

Parameters(參數):存儲類使用參數描述要關聯到的存儲卷,注意不同的供給方參數也不同。

ReclaimPlicy: PV的回收策略,可用值有Delete(默認)和Retain

(1)確定基於NFS服務來做的SC。NFS開啓

[root@master yaml]# showmount -e

k8s的存儲類

(2)需要RBAC權限。

RBAC:rbac是k8s的API的安全策略,是基於用戶的訪問權限的控制。規定了誰,可以有什麼樣的權限。

爲了給SC資源操作k8s集羣的權限。

[root@master yaml]# vim rbac-rolebind.yaml
kind: Namespace
apiVersion: v1
metadata:
  name: bdqn-test
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-provisioner
  namespace: bdqn-test
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nfs-provisioner-runner
  namespace: bdqn-test
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: ["watch", "create", "update", "patch"]
   -  apiGroups: [""]
      resources: ["services", "endpoints"]
      verbs: ["get","create","list", "watch","update"]
   -  apiGroups: ["extensions"]
      resources: ["podsecuritypolicies"]
      resourceNames: ["nfs-provisioner"]
      verbs: ["use"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-provisioner
    namespace: bdqn-test
roleRef:
  kind: ClusterRole
  name: nfs-provisioner-runner
  apiGroup: rbac.authorization.k8s.io

運行一下

[root@master yaml]# kubectl apply -f rbac-rolebind.yaml 

(3)nfs-deployment

作用:其實它是一個NFS客戶端。但它通過K8S的內置的NFS驅動掛載遠端的NFS服務器到本地目錄;然後將自身作爲storage provider,關聯storage class。

[root@master yaml]# vim nfs-deployment.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  namespace: bdqn-test
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccount: nfs-provisioner    #指定賬戶
      containers:
        - name: nfs-client-provisioner
          image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
          volumeMounts:
            - name: nfs-client-root
              mountPath:  /persistentvolumes   #指定容器內的掛載目錄
          env:
            - name: PROVISIONER_NAME            #這是這個容器內置的變量
              value: bdqn-test                  #這是上面變量的值(名字)
            - name: NFS_SERVER                  #內置變量,用於指定nfs服務的IP
              value: 192.168.1.21
            - name: NFS_PATH                    #內置變量,指定的是nfs共享的目錄
              value: /nfsdata
      volumes:                                  #這下面是指定上面掛載到容器內的nfs的路徑及IP
        - name: nfs-client-root
          nfs:
            server: 192.168.1.21
            path: /nfsdata

執行一下

[root@master yaml]# kubectl apply -f nfs-deployment.yaml

(4)創建storageclass

[root@master yaml]# vim test-storageclass.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: stateful-nfs
  namespace: bdqn-test
provisioner: bdqn-test  #這裏要和第三個nfs-client-provisioner的env環境變量中的value值對應。
reclaimPolicy: Retain   #回收策略爲:retain,還有一個默認的值爲“default”

執行一下

[root@master yaml]# kubectl apply -f test-storageclass.yaml

(5)創建PVC

[root@master yaml]# vim test-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-claim
  namespace: bdqn-test
spec:
  storageClassName: stateful-nfs   #定義存儲類的名字,要和SC的名字對應
  accessModes:
    - ReadWriteMany         #訪問模式爲RWM
  resources:
    requests:
      storage: 500Mi

執行一下

[root@master yaml]# kubectl apply -f test-pvc.yaml 

查看一下

[root@master yaml]# kubectl get pvc

k8s的存儲類

(6)創建一個Pod

[root@master yaml]# vim test-pod.yaml
kind: Pod
apiVersion: v1
metadata:
  name: test-pod
  namespace: bdqn-test
spec:
  containers:
  - name: test-pod
    image: busybox
    args:
      - /bin/sh
      - -c
      - sleep 30000
    volumeMounts:
      - name: nfs-pvc
        mountPath: /test
  restartPolicy: OnFailure
  volumes:
    - name: nfs-pvc
      persistentVolumeClaim:
        claimName: test-claim  #這的名字要和PVC的名字一致

執行一下

[root@master yaml]# kubectl apply -f  test-pod.yaml 

查看一下

[root@master yaml]# kubectl get pod -n bdqn-test 

k8s的存儲類

(7)容器中添加內容,並查看掛載目錄

進入容器修改頁面內容

[root@master yaml]# kubectl exec -it test-pod -n bdqn-test /bin/sh
/ # cd test/
/test # touch test-file
/test # echo 123456 > test-file 
/test # cat test-file 
123456

查看掛載目錄

[root@master yaml]# ls /nfsdata/
bdqn-test-test-claim-pvc-79ddfcf1-65ae-455f-9e03-5bcfe6c6ce15
web1
web2
[root@master yaml]# cat /nfsdata/bdqn-test-test-claim-pvc-79ddfcf1-65ae-455f-9e03-5bcfe6c6ce15/test-file 
123456

二,如果,K8S集羣中, 有很多類似的PV, PVC在去向PV申請空間的時候,不僅會考慮名稱以及訪問控制模式,還會考慮你申請空間的大小,會分配給你最合適大小的PV。

運行一個web服務,採用Deployment資源,基於nginx鏡像,replicas爲3個。數據持久化目錄爲nginx服務的主訪問目錄:/usr/share/nginx/html

創建一個PVC,與上述資源進行關聯。

1. 基於nfs服務來做的PV和pvc

下載nfs所需安裝包

[root@node02 ~]# yum -y install nfs-utils  rpcbind

創建共享目錄

[root@master ~]# mkdir /nfsdata

創建共享目錄的權限

[root@master ~]# vim /etc/exports
/nfsdata *(rw,sync,no_root_squash)

開啓nfs和rpcbind

[root@master ~]# systemctl start nfs-server.service 
[root@master ~]# systemctl start rpcbind

測試一下

[root@master ~]# showmount -e

k8s的存儲類

2.先創建兩個PV, web- pV1(1G) ,web-pv2 (2G)

web1

[root@master yaml]# vim web.yaml 

apiVersion: v1
kind: PersistentVolume
metadata:
  name: web-pv
spec :
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: nfs
  nfs:
    path: /nfsdata/web1
    server: 192.168.1.21

web2

[root@master yaml]# vim web2.yaml 

apiVersion: v1
kind: PersistentVolume
metadata:
  name: web-pv2
spec :
  capacity :
    storage: 2Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: nfs
  nfs:
    path: /nfsdata/web2
    server: 192.168.1.21

3.創建所需文件夾

[root@master yaml]# mkdir /nfsdata/web1
[root@master yaml]# mkdir /nfsdata/web2

4.執行一下web和web2

[root@master yaml]# kubectl apply -f web.yaml 
[root@master yaml]# kubectl apply -f web2.yaml 

5.查看一下

[root@master yaml]# kubectl get pv

k8s的存儲類

6.創建web的pvc的yaml文件

[root@master yaml]# vim web-pvc.yaml 

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: web-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs

​ 執行一下

[root@master yaml]# kubectl apply -f web-pvc.yaml 

​ 查看一下

[root@master yaml]# kubectl get pvc

k8s的存儲類

系統會自動給pvc一個相近內存的pv,所以選擇了1G的那個

7.創建pod的yaml文件

[root@master yaml]# vim web-pod.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: web-pod
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: web-test
          mountPath: /usr/share/nginx/html
      volumes:
      - name: web-test
        persistentVolumeClaim:
          claimName: web-pvc
執行一下
[root@master yaml]# kubectl apply -f web-pod.yaml 
查看一下
[root@master yaml]# kubectl get pod

k8s的存儲類

8. 訪問一下nginx的網頁

查看一下nginx的ip
[root@master yaml]# kubectl get pod -o wide

k8s的存儲類

進入容器設置網頁內容
root@master yaml]# kubectl exec -it web-pod-8686d9c594-qxhr9 /bin/bash
root@web-pod-8686d9c594-qxhr9:/# cd /usr/share/nginx/html/
root@web-pod-8686d9c594-qxhr9:/usr/share/nginx/html# ls
root@web-pod-8686d9c594-qxhr9:/usr/share/nginx/html# echo 123456 > index.html
root@web-pod-8686d9c594-qxhr9:/usr/share/nginx/html# exit
訪問一下
[root@master yaml]# curl 10.244.2.17

k8s的存儲類

三,如果兩個PV,大小一樣,名稱一樣,訪問控制模式不一樣,PVC會關聯哪一個? (驗證PV和PVC 關聯的時候,訪問模式必須一樣)

兩個PV,大小一樣,名稱一樣,訪問控制模式不一樣

<1>創建兩個pv

web1
[root@master yaml]# vim web1.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: web-pv
spec :
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce  #能以讀-寫mount到單個的節點
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: nfs
  nfs:
    path: /nfsdata/web1
    server: 192.168.1.21
web2
[root@master yaml]# vim web2.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: web-pv
spec :
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany        #能以讀-寫mount到多個的節點
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: nfs
  nfs:
    path: /nfsdata/web1
    server: 192.168.1.21
創建所需文件
[root@master yaml]# mkdir /nfsdata/web1
執行一下
[root@master yaml]# kubectl apply -f web1.yaml 
[root@master yaml]# kubectl apply -f web2.yaml 

k8s的存儲類

<2>創建pvc

[root@master yaml]# vim web-pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: web-pvc
spec:
  accessModes:
  - ReadWriteMany    #能以讀-寫mount到多個的節點
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs
執行一下
[root@master yaml]# kubectl apply -f web-pvc.yaml 

<3>查看一下

[root@master yaml]# kubectl get pv

k8s的存儲類

[root@master yaml]# kubectl get pvc

k8s的存儲類

現在可以看到pv和pvc關聯成功,但是爲什麼只有一個pv呢?(pv掛載的目錄要相同)

那是因爲當創建了兩個相同名字的pv時它並不會認爲這是兩個不同的pv,而會把他們當成是同一個pv,後創建的pv會刷新前面創建的pv。然後,當創建了pvc,並且pvc的訪問模式和後面創建pv的訪問模式一樣,他們就會關聯成功,反之不成功。(當然這些條件下還需要考慮,pv的內存)

三,小實驗

(1)以自己的名稱創建一個名稱空間。以下所有資源都在此名稱空間之下。

<1>編寫namespace的yam文件

[root@master yaml]# vim namespace.yaml 
kind: Namespace
apiVersion: v1
metadata:
  name: xgp-znb

<2>執行一下

[root@master yaml]# kubectl apply -f namespace.yaml 

<3>查看一下

[root@master yaml]# kubectl get ns

k8s的存儲類

(2)設置rbac權限。

下載所需鏡像

docker pull registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner

<1>編寫rbac的yam文件

[root@master yaml]# vim rbac-rolebind.yaml
kind: Namespace
apiVersion: v1
metadata:
  name: xgp-znb
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-provisioner
  namespace: xgp-znb
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nfs-provisioner-runner
  namespace: xgp-znb
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: ["watch", "create", "update", "patch"]
   -  apiGroups: [""]
      resources: ["services", "endpoints"]
      verbs: ["get","create","list", "watch","update"]
   -  apiGroups: ["extensions"]
      resources: ["podsecuritypolicies"]
      resourceNames: ["nfs-provisioner"]
      verbs: ["use"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-provisioner
    namespace: xgp-znb
roleRef:
  kind: ClusterRole
  name: nfs-provisioner-runner
  apiGroup: rbac.authorization.k8s.io

<2>執行一下

[root@master yaml]# kubectl apply -f  rbac-rolebind.yaml 

(3)創建nfs-deployment.yaml

<1>編寫deployment的yam文件

[root@master yaml]# vim nfs-deployment.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  namespace: xgp-znb
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccount: nfs-provisioner
      containers:
        - name: nfs-client-provisioner
          image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
          volumeMounts:
            - name: nfs-client-root
              mountPath:  /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: xgp-znb
            - name: NFS_SERVER
              value: 192.168.1.21
            - name: NFS_PATH
              value: /nfsdata
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.1.21
            path: /nfsdata

<2>執行一下

[root@master yaml]# kubectl apply -f nfs-deployment.yaml

(4)創建storageclass自動創建PV。

<1>編寫storageclass的yam文件

[root@master yaml]# vim storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: test-sc
provisioner: xgp-znb   #通過provisioner字段關聯到上述Deploy
reclaimPolicy: Retain

<2>執行一下

[root@master yaml]# kubectl apply -f storageclass.yaml

(5)創建PVC

<1>編寫PVC的yaml文件

[root@master yaml]# vim pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-claim
  namespace: xgp-znb
spec:
  storageClassName: test-sc
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 500Mi

<2>執行一下

[root@master yaml]# kubectl apply -f pvc.yaml 

<3>查看一下

[root@master yaml]# kubectl get pvc -n xgp-znb

k8s的存儲類

(6)創建一個Pod, 基於nginx運行一個web服務,使用Deployment資源對象,replicas=3.持久化存儲目錄爲默認主目錄

<1>編寫deployment的yam文件

[root@master yaml]# vim pod.yaml 
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: web-pod
  namespace: xgp-znb
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: web-test
          mountPath: /usr/share/nginx/html
      volumes:
      - name: web-test
        persistentVolumeClaim:
          claimName: test-claim

<2>執行一下

[root@master yaml]# kubectl apply -f pvc.yaml 

<3>查看一下

[root@master yaml]# kubectl get pod -n xgp-znb

k8s的存儲類

(7)訪問nginx頁面

修改nginx主頁

[root@master yaml]# kubectl exec -it web-pod-8cd956cc7-6szjb -n xgp-znb /bin/bash
//進入容器之中
root@web-pod-8cd956cc7-6szjb:/# echo  xgp-znb > /usr/share/nginx/html/index.html
//添加自定義內容主機

訪問一下

[root@master yaml]# curl 10.244.2.18

k8s的存儲類

四,五個可移植性建議

  1. 把你的 pvc,和 其它一系列配置放一起, 比如說deployment,configmap
  2. 不要把你的pv放在其它配置裏, 因爲用戶可能沒有權限創建pv
  3. 初始化pvc 模版的時候, 提供一個storageclass
  4. 在你的工具軟件中,watch那些沒有bound的pvc,並呈現給用戶
  5. 集羣啓動的時候啓用DefaultStorageClass, 但是不要指定某一類特定的class, 因爲不同provisioner的class,參數很難一致

五,四個階段(volumn phase)

1. 在PVC中綁定一個PV,可以根據下面幾種條件組合選擇

  • Access Modes, 按照訪問模式選擇pv
  • Resources, 按照資源屬性選擇, 比如說請求存儲大小爲8個G的pv
  • Selector, 按照pv的label選擇
  • Class, 根據StorageClass的class名稱選擇, 通過annotation指定了Storage Class的名字, 來綁定特定類型的後端存儲

2. 關於根據class過濾出pv的說明:

所有的 PVC 都可以在不使用 StorageClass 註解的情況下,直接使用某個動態存儲。把一個StorageClass 對象標記爲 “default” 就可以了。StorageClass 用註解http://storageclass.beta.kubernetes.io/is-default-class 就可以成爲缺省存儲。有了缺省的 StorageClass,用戶創建 PVC 就不用 storage-class 的註解了,1.4 中新加入的DefaultStorageClass 准入控制器會自動把這個標註指向缺省存儲類。PVC 指定特定storageClassName,如fast時, 綁定名稱爲fast的storageClassPVC中指定storageClassName爲“”時, 綁定no class的pv(pv中無class annotation, 或者其值爲“”)PVC不指定storageClassName時, DefaultStorageClass admission plugin 開啓與否(在apiserver啓動時可以指定), 對default class的解析行爲是不同的。當DefaultStorageClass admission plugin啓用時, 針對沒有storageClass annotation的pvc,DefaultStorageClass會分配一個默認的class, 這個默認的class需要用戶指定,比如在創建storageclass對象時加入annotation,如 http://storageclass.beta.kubernetes.io/is-default-class: “true” 。如果有多個默認的class, 則pvc會被拒絕創建, 如果用戶沒有指定默認的class, 則這個DefaultStorageClass admission plugin不會起任何作用。 pvc會找那些no class的pv做綁定。當DefaultStorageClass admission plugin沒有啓用時, 針對沒有storageClass annotation的pvc, 會綁定no class的pv(pv中無class annotation, 或者其值爲“”)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章