kubernetes-存儲卷(十二)

爲了保證數據的持久性,必須保證數據在外部存儲在docker容器中,爲了實現數據的持久性存儲,在宿主機和容器內作映射,能夠保證在容器的生命週期結束,數據依舊能夠實現持久性存儲。可是在k8s中,因爲pod分佈在各個不一樣的節點之上,並不能實現不一樣節點之間持久性數據的共享,而且,在節點故障時,可能會致使數據的永久性丟失。爲此,k8s就引入了外部存儲卷的功能。html

Volume

https://kubernetes.io/docs/concepts/storage/volumes/node

Kubernetes中的Volume提供了在容器中掛載外部存儲的能力nginx

Pod須要設置捲來源(spec.volume)和掛載點(spec.containers.volumeMounts)兩個信息後纔可使用相應的Volumegit

k8s的存儲類型github

[root@k8s-master ~]# kubectl explain pod.spec.volumes #查看k8s支持的存儲類型 KIND: Pod VERSION: v1 經常使用分類: emptyDir(臨時目錄):Pod刪除,數據也會被清除,這種存儲成爲emptyDir,用於數據的臨時存儲。 hostPath(宿主機目錄映射): 本地的SAN(iSCSI,FC)、NAS(nfs,cifs,http)存儲 分佈式存儲(glusterfs,rbd,cephfs) 雲存儲(EBS,Azure Disk)
emptyDir

一個emptyDir 第一次建立是在一個pod被指定到具體node的時候,而且會一直存在在pod的生命週期當中,正如它的名字同樣,它初始化是一個空的目錄,pod中的容器均可以讀寫這個目錄,這個目錄能夠被掛在到各個容器相同或者不相同的的路徑下。當一個pod由於任何緣由被移除的時候,這些數據會被永久刪除。注意:一個容器崩潰了不會致使數據的丟失,由於容器的崩潰並不移除pod.web

emptyDir 磁盤的做用:
(1)普通空間,基於磁盤的數據存儲
(2)做爲從崩潰中恢復的備份點
(3)存儲那些那些須要長久保存的數據,例web服務中的數據
默認的,emptyDir 磁盤會存儲在主機所使用的媒介上,多是SSD,或者網絡硬盤,這主要取決於你的環境。固然,咱們也能夠將emptyDir.medium的值設置爲Memory來告訴Kubernetes 來掛在一個基於內存的目錄tmpfs,由於
tmpfs速度會比硬盤塊度了,可是,當主機重啓的時候全部的數據都會丟失。docker

建立emptyDir示例vim

[root@k8s-master1 volume]# vim pod-vol-demo.yaml apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html/
  - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent volumeMounts: - name: html mountPath: /data/ command: ['/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done'] volumes: - name: html emptyDir: {} [root@k8s-master1 volume]# kubectl apply -f pod-vol-demo.yaml pod/pod-demo configured [root@k8s-master1 volume]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-demo   2/2     Running   0          15m   172.17.32.3   192.168.0.125   <none>           <none>

在上面,咱們定義了2個容器,其中一個容器是輸入日期到index.html中,而後驗證訪問nginx的html是否能夠獲取日期。以驗證兩個容器之間掛載的emptyDir實現共享。以下訪問驗證:後端

[root@k8s-node01 ~]# curl 172.17.73.3 Wed Dec 26 09:03:21 UTC 2018 Wed Dec 26 09:03:23 UTC 2018 Wed Dec 26 09:03:25 UTC 2018 Wed Dec 26 09:03:27 UTC 2018 Wed Dec 26 09:03:29 UTC 2018 Wed Dec 26 09:03:31 UTC 2018 Wed Dec 26 09:03:33 UTC 2018 Wed Dec 26 09:03:35 UTC 2018
hostPath

hostPath宿主機路徑,就是把pod所在的宿主機之上的脫離pod中的容器名稱空間的以外的宿主機的文件系統的某一目錄和pod創建關聯關係,在pod刪除時,存儲數據不會丟失。api

[root@k8s-master1 volume]# vim pod-hostpath-vol.yaml apiVersion: v1 kind: Pod metadata: name: pod-vol-hostpath namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /data/pod/volume1 type: DirectoryOrCreate [root@k8s-master1 volume]# kubectl apply -f pod-hostpath-vol.yaml pod/pod-vol-hostpath created [root@k8s-master1 volume]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-vol-hostpath   1/1     Running   0          39s   172.17.73.3   192.168.0.126   <none>           <none>

訪問測試

[root@k8s-node02 ~]# echo "test hostpath" > /data/pod/volume1/index.html [root@k8s-node02 ~]# curl 172.17.73.3 test hostpath

nfs共享存儲卷

nfs使的咱們能夠掛在已經存在的共享到的咱們的Pod中,和emptyDir不一樣的是,emptyDir會被刪除當咱們的Pod被刪除的時候,可是nfs不會被刪除,僅僅是解除掛在狀態而已,這就意味着NFS可以容許咱們提早對數據進行處理,並且這些數據能夠在Pod之間相互傳遞.而且,nfs能夠同時被多個pod掛在並進行讀寫

準備nfs服務
[root@localhost ~]# yum install -y nfs-utils [root@localhost ~]# mkdir /data/volumes -p [root@localhost ~]# vim /etc/exports /data/volumes 192.168.0.0/24(rw,no_root_squash) [root@localhost ~]# systemctl start nfs [root@localhost ~]# showmount -e Export list for localhost.localdomain: /data/volumes 192.168.0.0/24 node測試掛載 [root@k8s-node01 ~]# yum install -y nfs-utils [root@k8s-node01 ~]# mount -t nfs 192.168.0.122:/data/volumes /mnt [root@k8s-node01 ~]# mount . . . . . 192.168.0.122:/data/volumes on /mnt type nfs4 (rw,relatime,vers=4.1,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.0.125,local_lock=none,addr=192.168.0.122) [root@k8s-node01 ~]# umount /mnt
使用nfs存儲卷示例
[root@k8s-master1 volume]# vim pod-nfs-vol.yaml apiVersion: v1 kind: Pod metadata: name: pod-vol-nfs namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html nfs: path: /data/volumes server: 192.168.0.122 [root@k8s-master1 volume]# kubectl apply -f pod-nfs-vol.yaml pod/pod-vol-nfs created [root@k8s-master1 volume]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-vol-hostpath   1/1     Running   0          29m   172.17.73.3   192.168.0.126   <none>           <none> pod-vol-nfs        1/1     Running   0          13s   172.17.73.4   192.168.0.126   <none>           <none> 在nfs建立index.html,訪問測試 [root@localhost ~]# cat /data/volumes/index.html <h1>nfs test</h1> [root@k8s-node01 ~]# curl 172.17.73.4
<h1>nfs test</h1>

PVC和PV的概念

Kubernetes支持持久卷的存儲插件:https://kubernetes.io/docs/concepts/storage/persistent-volumes/

kubernetes提供那麼多存儲接口,可是首先kubernetes的各個Node節點能管理這些存儲,可是各類存儲參數也須要專業的存儲工程師才能瞭解,由此咱們的kubernetes管理變的更加複雜的。由此kubernetes提出了PV和PVC的概念,這樣開發人員和使用者就不須要關注後端存儲是什麼,使用什麼參數等問題。以下圖:

PersistentVolume(PV)是集羣中已由管理員配置的一段網絡存儲。 集羣中的資源就像一個節點是一個集羣資源。 PV是諸如卷之類的卷插件,可是具備獨立於使用PV的任何單個pod的生命週期。 該API對象捕獲存儲的實現細節,即NFS,iSCSI或雲提供商特定的存儲系統。

PersistentVolumeClaim(PVC)是用戶存儲的請求。PVC的使用邏輯:在pod中定義一個存儲卷(該存儲卷類型爲PVC),定義的時候直接指定大小,pvc必須與對應的pv創建關係,pvc會根據定義去pv申請,而pv是由存儲空間建立出來的。pv和pvc是kubernetes抽象出來的一種存儲資源。

PV是集羣中的資源。 PVC是對這些資源的請求,也是對資源的索賠檢查。 PV和PVC之間的相互做用遵循這個生命週期:

Provisioning(配置)---> Binding(綁定)--->Using(使用)---> Releasing(釋放) ---> Recycling(回收)
Provisioning

這裏有兩種PV的提供方式:靜態或者動態

靜態-->直接固定存儲空間:
    集羣管理員建立一些 PV。它們攜帶可供集羣用戶使用的真實存儲的詳細信息。 它們存在於Kubernetes API中,可用於消費。

動態-->經過存儲類進行動態建立存儲空間:
    當管理員建立的靜態 PV 都不匹配用戶的 PVC 時,集羣可能會嘗試動態地爲 PVC 配置卷。此配置基於 StorageClasses:PVC 必須請求存儲類,而且管理員必須已建立並配置該類才能進行動態配置。 要求該類的聲明有效地爲本身禁用動態配置。

Binding

在動態配置的狀況下,用戶建立或已經建立了具備特定數量的存儲請求和特定訪問模式的PersistentVolumeClaim。 主機中的控制迴路監視新的PVC,找到匹配的PV(若是可能),並將 PVC 和 PV 綁定在一塊兒。 若是爲新的PVC動態配置PV,則循環將始終將該PV綁定到PVC。 不然,用戶老是至少獲得他們要求的內容,可是卷可能超出了要求。 一旦綁定,PersistentVolumeClaim綁定是排他的,無論用於綁定它們的模式。

若是匹配的卷不存在,PVC將保持無限期。 隨着匹配卷變得可用,PVC將被綁定。 例如,提供許多50Gi PV的集羣將不匹配要求100Gi的PVC。 當集羣中添加100Gi PV時,能夠綁定PVC。

Using

Pod使用PVC做爲卷。 集羣檢查聲明以找到綁定的卷並掛載該卷的卷。 對於支持多種訪問模式的卷,用戶在將其聲明用做pod中的卷時指定所需的模式。

一旦用戶有聲明而且該聲明被綁定,綁定的PV屬於用戶,只要他們須要它。 用戶經過在其Pod的卷塊中包含PersistentVolumeClaim來安排Pods並訪問其聲明的PV。

Releasing

當用戶完成卷時,他們能夠從容許資源回收的API中刪除PVC對象。 當聲明被刪除時,卷被認爲是「釋放的」,可是它還不能用於另外一個聲明。 之前的索賠人的數據仍然保留在必須根據政策處理的捲上.

Reclaiming

PersistentVolume的回收策略告訴集羣在釋放其聲明後,該卷應該如何處理。 目前,卷能夠是保留,回收或刪除。 保留能夠手動回收資源。 對於那些支持它的卷插件,刪除將從Kubernetes中刪除PersistentVolume對象,以及刪除外部基礎架構(如AWS EBS,GCE PD,Azure Disk或Cinder卷)中關聯的存儲資產。 動態配置的卷始終被刪除

Recycling

若是受適當的卷插件支持,回收將對卷執行基本的擦除(rm -rf / thevolume / *),並使其再次可用於新的聲明。

靜態建立nfs類型的pv示例
建立pv [root@k8s-master1 volume]# vim pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: my-pv spec: capacity: storage: 5Gi accessModes: - ReadWriteMany nfs: path: /data/volumes/wwwroot server: 192.168.0.122 [root@k8s-master1 volume]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE my-pv 5Gi RWX Retain Available 8s 建立容器應用 [root@k8s-master1 volume]# cat pod-nfs-pvc.yaml apiVersion: apps/v1beta1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html ports: - containerPort: 80 volumes: - name: wwwroot persistentVolumeClaim: claimName: my-pvc --- 定義pvc:卷需求模板 apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi [root@k8s-master1 volume]# kubectl apply  -f pod-nfs-pvc.yaml deployment.apps/nginx-deployment created persistentvolumeclaim/my-pvc created [root@k8s-master1 volume]# kubectl get pv,pvc #查看pvc綁定 NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE persistentvolume/my-pv   5Gi        RWX            Retain           Bound    default/my-pvc 11m NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE persistentvolumeclaim/my-pvc   Bound    my-pv 5Gi RWX 9s [root@k8s-master1 volume]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-deployment-57fbd964dc-f5qx9   1/1     Running   0          22s   172.17.32.3   192.168.0.125   <none>           <none> nginx-deployment-57fbd964dc-hrlq9   1/1     Running   0          22s   172.17.32.4   192.168.0.125   <none>           <none> nginx-deployment-57fbd964dc-qqmh9   1/1     Running   0          22s   172.17.73.3   192.168.0.126   <none>           <none> 訪問測試 [root@localhost volumes]# cat /data/volumes/wwwroot/index.html hello world! [root@k8s-node01 ~]# curl 172.17.32.3 hello world! [root@k8s-node01 ~]# curl 172.17.32.4 hello world! [root@k8s-node01 ~]# curl 172.17.73.3 hello world!

 動態生成nfs類型的pv示例

Dynamic Provisioning機制工做的核心在於StorageClass的API對象。
StorageClass聲明存儲插件,用於自動建立PV。

參考文檔:https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client/deploy/objects

建立storageclass
[root@k8s-master1 volume]# vim storageclass-nfs.yaml apiVersion: storage.k8s.io/v1beta1 kind: StorageClass metadata: name: managed-nfs-storage provisioner: fuseim.pri/ifs [root@k8s-master1 volume]# kubectl apply -f storageclass-nfs.yaml storageclass.storage.k8s.io/managed-nfs-storage created
 建立rbac受權
[root@k8s-master1 volume]# cat rbac.yaml apiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1beta1 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: ["list", "watch", "create", "update", "patch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1beta1 metadata: name: run-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner namespace: default roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io [root@k8s-master1 volume]# kubectl apply -f rbac.yaml serviceaccount/nfs-client-provisioner created clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created

 運行nfs-client-provisioner

[root@k8s-master1 volume]# cat deployment-nfs.yaml apiVersion: apps/v1beta1 kind: Deployment metadata: name: nfs-client-provisioner spec: replicas: 1 strategy: type: Recreate template: metadata: labels: app: nfs-client-provisioner spec: imagePullSecrets: - name: registry-pull-secret serviceAccount: nfs-client-provisioner containers: - name: nfs-client-provisioner image: lizhenliang/nfs-client-provisioner:v2.0.0 volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: fuseim.pri/ifs - name: NFS_SERVER value: 192.168.0.122
            - name: NFS_PATH value: /data/volumes volumes: - name: nfs-client-root nfs: server: 192.168.0.122 path: /data/volumes [root@k8s-master1 volume]# kubectl apply -f deployment-nfs.yaml deployment.apps/nfs-client-provisioner created [root@k8s-master1 volume]# kubectl get storageclass NAME PROVISIONER AGE managed-nfs-storage   fuseim.pri/ifs 65s [root@k8s-master1 volume]# kubectl get pod NAME READY STATUS RESTARTS AGE nfs-client-provisioner-f69cd5cf-wvwlq   1/1     Running   0 21s nginx-deployment-57fbd964dc-f5qx9       1/1     Running   0 7m42s nginx-deployment-57fbd964dc-hrlq9       1/1     Running   0 7m42s nginx-deployment-57fbd964dc-qqmh9       1/1     Running   0          7m42s
建立deployment示例
[root@k8s-master1 volume]# cat deployment-demo.yaml apiVersion: apps/v1beta1 kind: Deployment metadata: name: nginx-deployment2 spec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx volumeMounts: - name: wwwroot mountPath: /usr/share/nginx/html ports: - containerPort: 80 volumes: - name: wwwroot persistentVolumeClaim: claimName: my-pvc2 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc2 spec: accessModes: - ReadWriteMany storageClassName: managed-nfs-storage resources: requests: storage: 5Gi [root@k8s-master1 volume]# kubectl apply -f deployment-demo.yaml deployment.apps/nginx-deployment2 created persistentvolumeclaim/my-pvc2 created [root@k8s-master1 volume]# kubectl get pod NAME READY STATUS RESTARTS AGE nfs-client-provisioner-f69cd5cf-wvwlq   1/1     Running   0 6m14s nginx-deployment-57fbd964dc-f5qx9       1/1     Running   0 13m nginx-deployment-57fbd964dc-hrlq9       1/1     Running   0 13m nginx-deployment-57fbd964dc-qqmh9       1/1     Running   0 13m nginx-deployment2-8685f649c9-82zgg      1/1     Running   0 52s nginx-deployment2-8685f649c9-tjbdm      1/1     Running   0 52s nginx-deployment2-8685f649c9-tkrwq      1/1     Running   0 52s [root@k8s-master1 volume]# kubectl get pv,pvc        #查看自動生成my-pvc2 NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE persistentvolume/default-my-pvc2-pvc-c9c9861f-09b4-11e9-b58a-000c298a2b5f   5Gi        RWX            Delete           Bound    default/my-pvc2   managed-nfs-storage 79s persistentvolume/my-pv                                                      5Gi        RWX            Retain           Bound    default/my-pvc 24m NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE persistentvolumeclaim/my-pvc    Bound    my-pv 5Gi RWX 14m persistentvolumeclaim/my-pvc2   Bound    default-my-pvc2-pvc-c9c9861f-09b4-11e9-b58a-000c298a2b5f   5Gi        RWX            managed-nfs-storage 79s #查看nfs自動生成的目錄 [root@localhost ~]# ll /data/volumes/ total 4 drwxrwxrwx 2 root root  6 Dec 27 16:52 default-my-pvc2-pvc-c9c9861f-09b4-11e9-b58a-000c298a2b5f -rw-r--r-- 1 root root 18 Dec 27 09:46 index.html drwxr-xr-x 2 root root 24 Dec 27 11:18 wwwroot
相關文章
相關標籤/搜索