第一章、前言
默認情況下容器的數據都是非持久化的, 在容器消亡以后數據也跟着丟失, 所以 Docker 提供了 Volume 機制以便將數據持久化存儲。 類似的, Kubernetes 提供了更強大的 Volume 機制和豐富的插件, 解決了容器數據持久化和容器間共享數據的問題。
與 Docker 不同, Kubernetes Volume 的生命周期與 Pod 綁定容器掛掉后 Kubelet 再次重啟容器時, Volume 的數據依然還在而 Pod 刪除時, Volume 才會清理。
數據是否丟失取決於具體的 Volume 類型, 比如 emptyDir 的數據會丟失, 而 PV 的數據則不會丟
PersistentVolume(pv)和PersistentVolumeClaim(pvc)是k8s提供的兩種API資源,用於抽象存儲細節。管理員關注於如何通過pv提供存儲功能而無需關注用戶如何使用,同樣的用戶只需要掛載pvc到容器中而不需要關注存儲卷采用何種技術實現。
pvc和pv的關系與pod和node關系類似,前者消耗后者的資源。pvc可以向pv申請指定大小的存儲資源並設置訪問模式。
第二章、pv pvc相關知識
生命周期
pv和pvc遵循以下生命周期:
1.供應准備。管理員在集群中創建多個pv供用戶使用。
2.綁定。用戶創建pvc並指定需要的資源和訪問模式。在找到可用pv之前,pvc會保持未綁定狀態。
3.使用。用戶可在pod中像volume一樣使用pvc。
4.釋放。用戶刪除pvc來回收存儲資源,pv將變成“released”狀態。由於還保留着之前的數據,這些數據需要根據不同的策略來處理,否則這些存儲資源無法被其他pvc使用。
5.回收。pv可以設置三種回收策略:保留(Retain),回收(Recycle)和刪除(Delete)。
保留策略允許人工處理保留的數據。
刪除策略將刪除pv和外部關聯的存儲資源,需要插件支持。
回收策略將執行清除操作,之后可以被新的pvc使用,需要插件支持。
pv屬性
pv擁有以下屬性:
容量。目前僅支持存儲大小,未來可能支持IOPS和吞吐量等。
訪問模式。ReadWriteOnce:單個節點讀寫。ReadOnlyMany:多節點只讀。ReadWriteMany:多節點讀寫。掛載時只能使用一種模式。
回收策略。目前NFS和HostPath支持回收。 AWS、EBS、GCE、PD和Cinder支持刪除。
階段。分為Available(未綁定pvc)、Bound(已綁定)、Released(pvc已刪除但資源未回收)、Failed(自動回收失敗)
pvc屬性
訪問模式。與pv的語義相同。在請求資源時使用特定模式。
資源。申請的存儲資源數量
pv類型
emptyDir
hostPath
gcePersistentDisk
awsElasticBlockStore
nfs
iscsi
flocker
glusterfs
rbd
cephfs
gitRepo
secret
persistentVolumeClaim
downwardAPI
azureFileVolume
................
........(以下省略)
目前常用Volume 類型
emptyDir
如果 Pod 設置了 emptyDir 類型 Volume, Pod 被分配到 Node 上時候, 會創建emptyDir, 只要 Pod 運行在 Node 上, emptyDir 都會存在( 容器掛掉不會導致emptyDir 丟失數據) , 但是如果 Pod 從 Node 上被刪除( Pod 被刪除, 或者 Pod 發生遷移) , emptyDir 也會被刪除, 並且永久丟失。
hostPath
hostPath 允許掛載 Node 上的文件系統到 Pod 里面去。 如果 Pod 需要使用 Node 上的文件, 可以使用 hostPath
NFS
NFS 是 Network File System 的縮寫, 即網絡文件系統。 Kubernetes 中通過簡單地配置就可以掛載 NFS 到 Pod 中, 而 NFS 中的數據是可以永久保存的, 同時 NFS 支持同時寫操作。
gcePersistentDisk
gcePersistentDisk 可以掛載 GCE 上的永久磁盤到容器, 需要 Kubernetes 運行在 GCE的 VM 中
awsElasticBlockStore
awsElasticBlockStore 可以掛載 AWS 上的 EBS 盤到容器, 需要 Kubernetes 運行在AWS 的 EC2 上。
gitRepo
gitRepo volume 將 git 代碼下拉到指定的容器路徑中
Projected Volume
Projected volume 將多個 Volume 源映射到同一個目錄中, 支持 secret、 downwardAPI和 configMap
第三章、簡單示例
emptyDir (節點級存儲,生命周期與pod相同)
[root@k8s-master01 volume]# cat pod-vol-demo.yaml #pod中有兩個container掛載同一個emptyDir,nginx提供web服務,busybox則循環向掛載目錄下的index.html文件寫入數據 apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: myapp containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html - name: busybox image: busybox:latest volumeMounts: #見pod的volume掛載到container中 - name: html #名稱需要和 volumes中的name一致 mountPath: /data #掛載volume在container中的路徑 command: - "/bin/sh" - "-c" - "while true; do echo $(date) >> /data/index.html; sleep 2; done" volumes: #創建pod可以使用的volume,可以有多個 - name: html emptyDir: {} #volume類型,默認不限制使用空間
查看pod是否運行,並訪問
[root@k8s-master01 volume]# kubectl get pod -o wide #查看pod地址 NAME READY STATUS RESTARTS AGE IP NODE myapp-deploy-5cfd895984-2gmmd 1/1 Running 0 2d 10.244.1.37 k8s-node01 myapp-deploy-5cfd895984-58csg 1/1 Running 0 2d 10.244.2.71 k8s-node02 myapp-deploy-5cfd895984-9s6zn 1/1 Running 0 2d 10.244.1.36 k8s-node01 myapp-deploy-5cfd895984-hwtlt 1/1 Running 0 2d 10.244.1.35 k8s-node01 myapp-deploy-5cfd895984-xclv4 1/1 Running 0 2d 10.244.2.70 k8s-node02 pod-demo 2/2 Running 0 22s 10.244.1.44 k8s-node01 pod-pvc 1/1 Running 0 11h 10.244.2.78 k8s-node02 tomcat-deploy-5bf584448b-7dbn2 1/1 Running 0 2d 10.244.2.73 k8s-node02 tomcat-deploy-5bf584448b-r7ng5 1/1 Running 0 2d 10.244.2.74 k8s-node02 tomcat-deploy-5bf584448b-xxj8n 1/1 Running 0 2d 10.244.1.39 k8s-node01 [root@k8s-master01 volume]# while true; do curl 10.244.1.44; sleep 1; done #直接訪問 Fri Nov 9 02:18:49 UTC 2018 Fri Nov 9 02:18:51 UTC 2018 Fri Nov 9 02:18:53 UTC 2018 Fri Nov 9 02:18:55 UTC 2018 Fri Nov 9 02:18:57 UTC 2018 Fri Nov 9 02:18:59 UTC 2018 ......
hostPath (節點級存儲,生命周期和node相同)
apiVersion: v1 kind: Pod metadata: name: pod-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/volumel" #依據type的值來確定掛載路徑是否需要創建 type: DirectoryOrCreate #掛載目錄不存在則創建, 具體type的值可以查看官方文檔: https://kubernetes.io/docs/concepts/storage/volumes#hostpath
[root@k8s-master01 ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE myapp-deploy-5cfd895984-2gmmd 1/1 Running 0 2d 10.244.1.37 k8s-node01 myapp-deploy-5cfd895984-58csg 1/1 Running 0 2d 10.244.2.71 k8s-node02 myapp-deploy-5cfd895984-9s6zn 1/1 Running 0 2d 10.244.1.36 k8s-node01 myapp-deploy-5cfd895984-hwtlt 1/1 Running 0 2d 10.244.1.35 k8s-node01 myapp-deploy-5cfd895984-xclv4 1/1 Running 0 2d 10.244.2.70 k8s-node02 pod-hostpath 1/1 Running 0 34s 10.244.2.80 k8s-node02 #所在node節點 tomcat-deploy-5bf584448b-7dbn2 1/1 Running 0 2d 10.244.2.73 k8s-node02 tomcat-deploy-5bf584448b-r7ng5 1/1 Running 0 2d 10.244.2.74 k8s-node02 tomcat-deploy-5bf584448b-xxj8n 1/1 Running 0 2d 10.244.1.39 k8s-node01 [root@k8s-master01 ~]# ssh k8s-node02 "ls -l /data/pod/volumel" #查看該節點上是否存在該目錄 總用量 0
刪除pod手動創建掛載目錄並添加HTML文件測試
[root@k8s-master01 volume]# kubectl delete pod pod-hostpath pod "pod-hostpath" deleted #所有node節點上進行如下操作,注意index中的內容是當前節點名稱以示區別 [root@k8s-master01 ~]# mkdir /data/pod/volume1 #創建掛載的目錄 [root@k8s-master01 ~]# cd /data/pod/volume1 [root@k8s-master01 volume1]# echo "node1" > /data/pod/volume1/index.html #添加一個index.html測試文件 [root@k8s-master01 volume]# kubectl apply -f pod-hostpath-vol.yaml pod "pod-hostpath" created [root@k8s-master01 volume]# kubectl get pod pod-hostpath -o wide NAME READY STATUS RESTARTS AGE IP NODE pod-hostpath 1/1 Running 0 12s 10.244.2.191 k8s-node02 [root@k8s-master01 volume]# curl 10.244.2.191 node2
NFS(永久存儲,生命周期與NFS server相同)
[root@k8s-master01 volume]# cat pod-nfs-vol.yaml apiVersion: v1 kind: Pod metadata: name: pod-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/v1" #該目錄在NFS server上必須存在並可以被集群中node節點可以掛載,node節點需要安裝nfs-utils,可以執行NFS 掛載操作 server: 172.16.150.155 #該server需要安裝NFS 服務,並共享path中的目錄或文件 [root@k8s-node02 ~]# mount -t nfs 172.16.150.155:/data/volumes/v1 /mnt 在任意一節點上進行掛載測試,確定可以掛載是否可以成功,需要安裝nfsutils工具包 [root@k8s-node02 ~]# df -h |grep mnt #查看掛載狀態 172.16.150.155:/data/volumes/v1 77G 3.5G 74G 5% /mnt [root@k8s-node02 ~]# umount /mnt #確認沒有問題后卸載 [root@k8s-master01 volume]# kubectl apply -f pod-nfs-vol.yaml #創建pod pod "pod-nfs" created [root@k8s-master01 volume]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE pod-nfs 1/1 Running 0 17s 10.244.1.154 k8s-node01 #在NFS server上添加一個測試HTML文件 [root@k8s-node-02 ~]# cd /data/volumes/v1/ #掛載目錄 [root@k8s-node-02 v1]# echo "<h1>NFS Server volume v1</h1>" > index.html #訪問一下pod [root@k8s-master01 volume]# curl 10.244.1.154 <h1>NFS Server volume v1</h1> [root@k8s-master01 volume]# kubectl delete pod pod-nfs #刪除剛剛創建的pod pod "pod-nfs" deleted [root@k8s-master01 volume]# kubectl apply -f pod-nfs-vol.yaml #再重新創建 pod "pod-nfs" created [root@k8s-master01 volume]# kubectl get pod -o wide #查看新創建后pod所在的node節點級IP地址 NAME READY STATUS RESTARTS AGE IP NODE counter 3/3 Running 0 1d 10.244.1.68 k8s-node01 pod-hostpath 1/1 Running 0 29m 10.244.2.191 k8s-node02 pod-nfs 1/1 Running 0 17s 10.244.2.192 k8s-node02 sa-demo 1/1 Running 0 8d 10.244.2.98 k8s-node02 [root@k8s-master01 volume]# curl 10.244.2.192 #再次訪問一下,文件依然存在,文件不會隨着pod的終結而銷毀 <h1>NFS Server volume v1</h1>
第四章、創建PV和PVC(以NFS為例)
NFS server上創建多個掛載目錄,並共享
[root@k8s-node-02 v1]# cat /etc/exports /data/volumes/v1 172.16.150.0/24(rw,no_root_squash) /data/volumes/v2 172.16.150.0/24(rw,no_root_squash) /data/volumes/v3 172.16.150.0/24(rw,no_root_squash) /data/volumes/v4 172.16.150.0/24(rw,no_root_squash) /data/volumes/v5 172.16.150.0/24(rw,no_root_squash) [root@k8s-node-02 v1]# ll /data/volumes/ 總用量 0 drwxr-xr-x 2 root root 24 2018-11-20 22:28 v1 drwxr-xr-x 2 root root 6 2018-11-08 22:17 v2 drwxr-xr-x 2 root root 6 2018-11-08 22:17 v3 drwxr-xr-x 2 root root 6 2018-11-08 22:17 v4 drwxr-xr-x 2 root root 6 2018-11-08 22:17 v5 [root@k8s-node-02 v1]# exportfs /data/volumes/v1 172.16.150.0/24 /data/volumes/v2 172.16.150.0/24 /data/volumes/v3 172.16.150.0/24 /data/volumes/v4 172.16.150.0/24 /data/volumes/v5 172.16.150.0/24 [root@k8s-node-02 v1]# showmount -e Export list for k8s-node-02: /data/volumes/v5 172.16.150.0/24 /data/volumes/v4 172.16.150.0/24 /data/volumes/v3 172.16.150.0/24 /data/volumes/v2 172.16.150.0/24 /data/volumes/v1 172.16.150.0/24
將NFS server共享的目錄創建為PV
apiVersion: v1 kind: PersistentVolume metadata: name: nfs-vol-01 #不允許定義名稱空間,應為pv是屬於集群級別的
labels:
name: nfs-vol-01 #建議對PV添加labels,后期PVC可以通過labels指定PV spec: capacity: #pv的大小 storage: 5Gi accessModes: #訪問的模型,具體訪問模型官方文檔鏈接: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes - ReadWriteOnce #支持的訪問模型與具體的共享存儲設備類型有關,具體見上方鏈接,可以有多個 - ReadWriteMany persistentVolumeReclaimPolicy: Recycle #pv的回收策略 nfs: path: /data/volumes/v1 server: 172.16.150.155 --- apiVersion: v1 kind: PersistentVolume metadata: name: nfs-vol-02 spec: capacity: storage: 5Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle nfs: path: /data/volumes/v2 server: 172.16.150.155 --- apiVersion: v1 kind: PersistentVolume metadata: name: nfs-vol-03 spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce - ReadWriteMany persistentVolumeReclaimPolicy: Recycle nfs: path: /data/volumes/v3 server: 172.16.150.155 --- apiVersion: v1 kind: PersistentVolume metadata: name: nfs-vol-04 spec: capacity: storage: 15Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle nfs: path: /data/volumes/v4 server: 172.16.150.155 --- apiVersion: v1 kind: PersistentVolume metadata: name: nfs-vol-05 spec: capacity: storage: 20Gi accessModes: - ReadWriteOnce - ReadWriteMany persistentVolumeReclaimPolicy: Recycle nfs: path: /data/volumes/v5 server: 172.16.150.155 [root@k8s-master01 volume]# kubectl apply -f nfs-vol.yaml persistentvolume "nfs-vol-01" created persistentvolume "nfs-vol-02" created persistentvolume "nfs-vol-03" created persistentvolume "nfs-vol-04" created persistentvolume "nfs-vol-05" created [root@k8s-master01 volume]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE nfs-vol-01 5Gi RWO,RWX Recycle Available 7s nfs-vol-02 5Gi RWO Recycle Available 7s nfs-vol-03 10Gi RWO,RWX Recycle Available 7s nfs-vol-04 15Gi RWO Recycle Available 7s nfs-vol-05 20Gi RWO,RWX Recycle Available 7s
創建一個PVC
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc namespace: default spec: accessModes: ["ReadWriteOnce"] #pvc的訪問模式一定是pv訪問模式的子集
selector:
matchLabels:
name: nfs-vol-01 #選擇指定的PV resources: requests: storage: 5Gi --- apiVersion: v1 kind: Pod metadata: name: pod-pvc namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html persistentVolumeClaim: claimName: my-pvc [root@k8s-master01 volume]# kubectl apply -f pod-pvc-vol.yaml persistentvolumeclaim "my-pvc" created pod "pod-pvc" created [root@k8s-master01 volume]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE my-pvc Bound nfs-vol-02 5Gi RWO 1m [root@k8s-master01 volume]# kubectl get pv #查看pv狀態的變化,nfs-vol-02被 default名稱空間下my-pvc申請並綁定 NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON A nfs-vol-01 5Gi RWO,RWX Recycle Bound default/my-pvc 9 nfs-vol-02 5Gi RWO Recycle Available 9 nfs-vol-03 10Gi RWO,RWX Recycle Available 9 nfs-vol-04 15Gi RWO Recycle Available 9 nfs-vol-05 20Gi RWO,RWX Recycle Available
查看下pod的創建信息
[root@k8s-master01 volume]# kubectl describe pod pod-pvc ...... Volumes: html: Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace) ClaimName: my-pvc ReadOnly: false default-token-tcwjz: Type: Secret (a volume populated by a Secret) SecretName: default-token-tcwjz Optional: false QoS Class: BestEffort Node-Selectors: <none> Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s node.kubernetes.io/unreachable:NoExecute for 300s Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 8m (x2 over 8m) default-scheduler pod has unbound PersistentVolumeClaims (repeated 2 times) Normal Scheduled 8m default-scheduler Successfully assigned pod-pvc to k8s-node01 Normal SuccessfulMountVolume 8m kubelet, k8s-node01 MountVolume.SetUp succeeded for volume "default-token-tcwjz" Normal SuccessfulMountVolume 8m kubelet, k8s-node01 MountVolume.SetUp succeeded for volume "nfs-vol-02" Normal Pulled 8m kubelet, k8s-node01 Container image "ikubernetes/myapp:v1" already present on machine Normal Created 7m kubelet, k8s-node01 Created container Normal Started 7m kubelet, k8s-node01 Started container
#處於綁定狀態下的pv無法直接被刪除,如果需要刪除被綁定的pv,需要先刪除申請綁定的PVC
第五章、PV released狀態下重新分配到PVC
當 PV 已經處在 released 狀態下,它是沒有辦法直接回到 available 狀態,也就是說接下來無法被一個新的 PVC 去做綁定。
1.刪除PVC及pod,查看pv的狀態
[root@k8s-master01 volume]#kubectl delete -f pod-pvc-vol.yaml persistentvolumeclaim "my-pvc" deleted pod "pod-pvc" deleted [root@k8s-master01 volume]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE nfs-vol-01 5Gi RWO,RWX Retain Released default/my-pvc 18m #狀態變成了Released nfs-vol-02 5Gi RWO Retain Available 18m nfs-vol-03 10Gi RWO,RWX Retain Available 18m nfs-vol-04 15Gi RWO Retain Available 18m nfs-vol-05 20Gi RWO,RWX Retain Available 18m
2.再次創建PVC使用nfs-vol-01,並觀察pv及pod狀態
[root@k8s-master01 volume]#kubectl apply -f pod-pvc-vol.yaml persistentvolumeclaim/my-pvc created pod/pod-pvc created [root@k8s-master01 volume]#kubectl get pods |grep pod-pvc pod-pvc 0/1 Pending 0 8m23s [root@k8s-master01 volume]#kubectl describe pod pod-pvc #可以看到,pod處於pending狀態,原因是沒有綁定的PVC可以使用
...... Warning FailedScheduling 19s (x7 over 9m6s) default-scheduler pod has unbound immediate PersistentVolumeClaims (repeated 6 times)
3.修改PV的配置,刪除spec下claimRef字段及包含內容
[root@k8s-master-155-221 manifests]# kubectl edit pv nfs-vol-01 spec: claimRef: apiVersion: v1 kind: PersistentVolumeClaim name: my-pvc namespace: default resourceVersion: "7762570" uid: 628b5026-35dc-11ea-87ad-525400512eca ....
再次查看
[root@k8s-master-155-221 manifests]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE nfs-vol-01 5Gi RWO,RWX Retain Available 39m nfs-vol-02 5Gi RWO Retain Available 39m nfs-vol-03 10Gi RWO,RWX Retain Available 39m nfs-vol-04 15Gi RWO Retain Available 39m nfs-vol-05 20Gi RWO,RWX Retain Available 39m
4.創建PVC及pod,查看狀態
[root@k8s-master01 volume]#kubectl apply -f pod-pvc-vol.yaml persistentvolumeclaim/my-pvc created pod/pod-pvc created [root@k8s-master01 volume]#kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE nfs-vol-01 5Gi RWO,RWX Retain Bound default/my-pvc 39m nfs-vol-02 5Gi RWO Retain Available 39m nfs-vol-03 10Gi RWO,RWX Retain Available 39m nfs-vol-04 15Gi RWO Retain Available 39m nfs-vol-05 20Gi RWO,RWX Retain Available 39m [root@k8s-master01 volume]#kubectl get pods|grep pod-pvc pod-pvc 1/1 Running 0 22s