咱們常常會說:容器和 Pod 是短暫的。
其含義是它們的生命週期可能很短,會被頻繁地銷燬和建立。容器銷燬時,保存在容器內部文件系統中的數據都會被清除。docker
爲了持久化保存容器的數據,可使用 Kubernetes Volume。api
Volume 的生命週期獨立於容器,Pod 中的容器可能被銷燬和重建,但 Volume 會被保留。服務器
本質上,Kubernetes Volume 是一個目錄,這一點與 Docker Volume 相似。當 Volume 被 mount 到 Pod,Pod 中的全部容器均可以訪問這個 Volume。Kubernetes Volume 也支持多種 backend 類型,包括 emptyDir、hostPath、GCE Persistent Disk、AWS Elastic Block Store、NFS、Ceph 等,完整列表可參考 https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumesapp
Volume 提供了對各類 backend 的抽象,容器在使用 Volume 讀寫數據的時候不須要關心數據究竟是存放在本地節點的文件系統中呢仍是雲硬盤上。對它來講,全部類型的 Volume 都只是一個目錄。ide
emptyDir 是最基礎的 Volume 類型。一個 emptyDir Volume 是 Host 上的一個空目錄。spa
emptyDir Volume 對於容器來講是持久的,對於 Pod 則不是。當 Pod 從節點刪除時,Volume 的內容也會被刪除。但若是隻是容器被銷燬而 Pod 還在,則 Volume 不受影響。3d
也就是說:emptyDir Volume 的生命週期與 Pod 一致。code
Pod 中的全部容器均可以共享 Volume,它們能夠指定各自的 mount 路徑。server
下面經過例子來實踐 emptyDir對象
第一步:配置文件以下:
這裏咱們模擬了一個 producer-consumer 場景。Pod 有兩個容器 producer和 consumer,它們共享一個 Volume。producer 負責往 Volume 中寫數據,consumer 則是從 Volume 讀取數據。
① 文件最底部 volumes 定義了一個 emptyDir 類型的 Volume shared-volume。
② producer 容器將 shared-volume mount 到 /producer_dir 目錄。
③ producer 經過 echo 將數據寫到文件 hello 裏。
④ consumer 容器將 shared-volume mount 到 /consumer_dir 目錄。
⑤ consumer 經過 cat 從文件 hello 讀數據。
第二步:執行以下命令建立 Pod:
[root@ken ~]# kubectl get pod NAME READY STATUS RESTARTS AGE producer-consumer 2/2 Running 0 2m1s [root@ken ~]# kubectl logs producer-consumer consumer hello world
kubectl logs 顯示容器 consumer 成功讀到了 producer 寫入的數據,驗證了兩個容器共享 emptyDir Volume。
由於 emptyDir 是 Docker Host 文件系統裏的目錄,其效果至關於執行了 docker run -v /producer_dir 和 docker run -v /consumer_dir。
第三步:經過 docker inspect 查看容器的詳細配置信息,咱們發現兩個容器都 mount 了同一個目錄:
這裏 /var/lib/kubelet/pods/4dcc0366-245f-11e9-9172-000c292d5bb8/volumes/kubernetes.io~empty-dir/shared-volume 就是 emptyDir 在 Host 上的真正路徑。
emptyDir 是 Host 上建立的臨時目錄,其優勢是可以方便地爲 Pod 中的容器提供共享存儲,不須要額外的配置。但它不具有持久性,若是 Pod 不存在了,emptyDir 也就沒有了。根據這個特性,emptyDir 特別適合 Pod 中的容器須要臨時共享存儲空間的場景,好比前面的生產者消費者用例。
hostPath Volume 的做用是將 Docker Host 文件系統中已經存在的目錄 mount 給 Pod 的容器。大部分應用都不會使用 hostPath Volume,由於這實際上增長了 Pod 與節點的耦合,限制了 Pod 的使用。不過那些須要訪問 Kubernetes 或 Docker 內部數據(配置文件和二進制庫)的應用則須要使用 hostPath。
好比 kube-apiserver 和 kube-controller-manager 就是這樣的應用,經過
kubectl edit --namespace=kube-system pod kube-apiserver-k8s-master
查看 kube-apiserver Pod 的配置,下面是 Volume 的相關部分:
這裏定義了三個 hostPath volume k8s、certs 和 pki,分別對應 Host 目錄 /etc/kubernetes、/etc/ssl/certs 和 /etc/pki。
若是 Pod 被銷燬了,hostPath 對應的目錄也還會被保留,從這點看,hostPath 的持久性比 emptyDir 強。不過一旦 Host 崩潰,hostPath 也就無法訪問了。
PersistentVolume (PV) 是外部存儲系統中的一塊存儲空間,由管理員建立和維護。與 Volume 同樣,PV 具備持久性,生命週期獨立於 Pod。
PersistentVolumeClaim (PVC) 是對 PV 的申請 (Claim)。PVC 一般由普通用戶建立和維護。須要爲 Pod 分配存儲資源時,用戶能夠建立一個 PVC,指明存儲資源的容量大小和訪問模式(好比只讀)等信息,Kubernetes 會查找並提供知足條件的 PV。
有了 PersistentVolumeClaim,用戶只須要告訴 Kubernetes 須要什麼樣的存儲資源,而沒必要關心真正的空間從哪裏分配,如何訪問等底層細節信息。這些 Storage Provider 的底層信息交給管理員來處理,只有管理員才應該關心建立 PersistentVolume 的細節信息。
Kubernetes 支持多種類型的 PersistentVolume,好比 AWS EBS、Ceph、NFS 等,完整列表請參考 https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes
第一步:需在 k8s-master 節點上搭建了一個 NFS 服務器,目錄爲 /nfsdata:
要更改目錄屬主,不然沒有寫入權限: chown -R nfsnobody.nfsnobody /nfsdata
[root@ken ~]# showmount -e Export list for ken: /nfsdata *
第二步:建立一個 PV mypv1,配置文件 nfs-pv1.yml 以下:
[root@ken ~]# cat nfs-pv1.yml apiVersion: v1 kind: PersistentVolume metadata: name: mypv1 spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle storageClassName: nfs nfs: path: /nfsdata/pv1 #須要建立pv1目錄,不然pod起不來 server: 172.20.10.2
① capacity 指定 PV 的容量爲 1G。
② accessModes 指定訪問模式爲 ReadWriteOnce,支持的訪問模式有:
ReadWriteOnce – PV 能以 read-write 模式 mount 到單個節點。
ReadOnlyMany – PV 能以 read-only 模式 mount 到多個節點。
ReadWriteMany – PV 能以 read-write 模式 mount 到多個節點。
③ persistentVolumeReclaimPolicy 指定當 PV 的回收策略爲 Recycle,支持的策略有:
Retain – 須要管理員手工回收。
Recycle – 清除 PV 中的數據,效果至關於執行 rm -rf /thevolume/*。
Delete – 刪除 Storage Provider 上的對應存儲資源,例如 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。
④ storageClassName 指定 PV 的 class 爲 nfs。至關於爲 PV 設置了一個分類,PVC 能夠指定 class 申請相應 class 的 PV。
⑤ 指定 PV 在 NFS 服務器上對應的目錄。
第三步:建立 mypv1:
[root@ken ~]# kubectl apply -f nfs-pv1.yml
persistentvolume/mypv1 created
第四步:查看pv
[root@ken ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mypv1 1Gi RWO Recycle Available nfs 48s
STATUS 爲 Available,表示 mypv1 就緒,能夠被 PVC 申請。
第五步:接下來建立 PVC mypvc1,配置文件 nfs-pvc1.yml 以下:
注意:
1. storageClassName須要與上面定義的pv保持一致!
2. 各個節點都須要下載nfs-utils
PVC 就很簡單了,只須要指定 PV 的容量,訪問模式和 class。
[root@ken ~]# kubectl apply -f nfs-pvc1.yml
persistentvolumeclaim/mypvc1 created
第六步:查看pvc
[root@ken ~]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE mypvc1 Bound mypv1 1Gi RWO nfs 112s [root@ken ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mypv1 1Gi RWO Recycle Bound default/mypvc1 nfs 6m5s
從 kubectl get pvc 和 kubectl get pv 的輸出能夠看到 mypvc1 已經 Bound 到 mypv1,申請成功。
第七步:接下來就能夠在 Pod 中使用存儲了,Pod 配置文件 pod1.yml 以下:
與使用普通 Volume 的格式相似,在 volumes 中經過 persistentVolumeClaim 指定使用 mypvc1 申請的 Volume。
第八步:建立 mypod1:
[root@ken ~]# kubectl apply -f pod1.yml
pod/mypod1 created
[root@ken ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mypod1 1/1 Running 0 51s 10.244.1.59 host1 <none> <none>
第九步:驗證 PV 是否可用:
[root@ken ~]# kubectl exec mypod1 touch /mydata/hello [root@ken ~]# ls /nfsdata/pv1/ hello
可見,在 Pod 中建立的文件 /mydata/hello 確實已經保存到了 NFS 服務器目錄 /nfsdata/pv1 中。
當 PV 再也不須要時,可經過刪除 PVC 回收。
當 PVC mypvc1 被刪除後,Kubernetes 啓動了一個新 Pod recycler-for-mypv1,這個 Pod 的做用就是清除 PV mypv1 的數據。此時 mypv1 的狀態爲 Released,表示已經解除了與 mypvc1 的 Bound,正在清除數據,不過此時還不可用。
當數據清除完畢,mypv1 的狀態從新變爲 Available,此時則能夠被新的 PVC 申請。
由於 PV 的回收策略設置爲 Recycle,因此數據會被清除,但這可能不是咱們想要的結果。若是咱們但願保留數據,能夠將策略設置爲 Retain。
第一步:將策略設置爲 Retain。
[root@ken ~]# cat nfs-pv1.yml apiVersion: v1 kind: PersistentVolume metadata: name: mypv1 spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: nfs nfs: path: /nfsdata/pv1 server: 172.20.10.2
第二步:經過 kubectl apply 更新 PV:
root@ken ~]# kubectl apply -f nfs-pv1.yml persistentvolume/mypv1 configured [root@ken ~]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE mypv1 1Gi RWO Retain Available nfs 65m
回收策略已經變爲 Retain
另外使用retain雖然刪除pod後的數據獲得了保留,但其 PV 狀態會一直處於 Released,不能被其餘 PVC 申請。爲了從新使用存儲資源,能夠刪除並從新建立 PV。刪除操做只是刪除了 PV 對象,存儲空間中的數據並不會被刪除。