本文轉(zhuǎn)載自 https://www.cnblogs.com/DaweiJ/articles/8618317.html
首先我們會學(xué)習(xí) Volume,以及 Kubernetes 如何通過 Volume 為集群中的容器提供存儲;
然后我們會實踐幾種常用的 Volume 類型并理解它們各自的應(yīng)用場景;
最后,我們會討論 Kubernetes 如何通過 Persistent Volume 和 Persistent Volume Claim 分離集群管理員與集群用戶的職責(zé),并實踐 Volume 的靜態(tài)供給。
Volume
本節(jié)我們討論 Kubernetes 的存儲模型 Volume,學(xué)習(xí)如何將各種持久化存儲映射到容器。
我們經(jīng)常會說:容器和 Pod 是短暫的。
其含義是它們的生命周期可能很短,會被頻繁地銷毀和創(chuàng)建。容器銷毀時,保存在容器內(nèi)部文件系統(tǒng)中的數(shù)據(jù)都會被清除。
為了持久化保存容器的數(shù)據(jù),可以使用 Kubernetes Volume。
Volume 的生命周期獨立于容器,Pod 中的容器可能被銷毀和重建,但 Volume 會被保留。
本質(zhì)上,Kubernetes Volume 是一個目錄,這一點與 Docker Volume 類似。當(dāng) 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-volumes
Volume 提供了對各種 backend 的抽象,容器在使用 Volume 讀寫數(shù)據(jù)的時候不需要關(guān)心數(shù)據(jù)到底是存放在本地節(jié)點的文件系統(tǒng)中呢還是云硬盤上。對它來說,所有類型的 Volume 都只是一個目錄。
我們將從最簡單的 emptyDir 開始學(xué)習(xí) Kubernetes Volume。
emptyDir
emptyDir 是最基礎(chǔ)的 Volume 類型。正如其名字所示,一個 emptyDir Volume 是 Host 上的一個空目錄。
emptyDir Volume 對于容器來說是持久的,對于 Pod 則不是。當(dāng) Pod 從節(jié)點刪除時,Volume 的內(nèi)容也會被刪除。但如果只是容器被銷毀而 Pod 還在,則 Volume 不受影響。
也就是說:emptyDir Volume 的生命周期與 Pod 一致。
Pod 中的所有容器都可以共享 Volume,它們可以指定各自的 mount 路徑。下面通過例子來實踐 emptyDir,配置文件如下:
apiVersion: v1
kind: Pod
metadata:
name: producer-consumer
spec:
containers:
- name: producer
image: 10.193.9.54:5000/library/busybox
volumeMounts:
- mountPath: /producer_dir
name: shared-volume
args:
- /bin/sh
- -c
- echo "hello world" > /producer_dir/hello ; sleep 30000
- name: consumer
image: 10.193.9.54:5000/library/busybox
volumeMounts:
- mountPath: /consumer_dir
name: shared-volume
args:
- /bin/sh
- -c
- cat /consumer_dir/hello ; sleep 30000
volumes:
- name: shared-volume
emptyDir: {}

這里我們模擬了一個 producer-consumer 場景。
Pod 有兩個容器 producer 和 consumer,它們共享一個 Volume。
producer 負(fù)責(zé)往 Volume 中寫數(shù)據(jù),consumer則是從 Volume 讀取數(shù)據(jù)。
① 文件最底部 volumes 定義了一個 emptyDir 類型的 Volume shared-volume。
② producer 容器將 shared-volume mount 到 /producer_dir 目錄。
③ producer 通過 echo 將數(shù)據(jù)寫到文件 hello 里。
④ consumer 容器將 shared-volume mount 到 /consumer_dir 目錄。
⑤ consumer 通過 cat 從文件 hello 讀數(shù)據(jù)。
執(zhí)行命令創(chuàng)建pod并查看pod日志
[root@master clay]# kubectl get pod
NAME READY STATUS RESTARTS AGE
producer-consumer 2/2 Running 0 8s
[root@master clay]# kubectl logs producer-consumer consumer
hello world
kubectl logs 顯示容器 consumer 成功讀到了 producer 寫入的數(shù)據(jù),驗證了兩個容器共享 emptyDir Volume。
因為 emptyDir 是 Docker Host 文件系統(tǒng)里的目錄,其效果相當(dāng)于執(zhí)行了 docker run -v /producer_dir 和 docker run -v /consumer_dir。通過 docker inspect 查看容器的詳細(xì)配置信息,我們發(fā)現(xiàn)兩個容器都 mount 了同一個目錄:
這里/var/lib/kubelet/pods/59a1fa91-8054-11e9-8f26-000c29114255/volumes/kubernetes.io~empty-dir/shared-volume 就是 emptyDir 在 Host 上的真正路徑。
emptyDir 是 Host 上創(chuàng)建的臨時目錄,其優(yōu)點是能夠方便地為 Pod 中的容器提供共享存儲,不需要額外的配置。
但它不具備持久性,如果 Pod 不存在了,emptyDir 也就沒有了。
根據(jù)這個特性,emptyDir 特別適合 Pod 中的容器需要臨時共享存儲空間的場景,比如前面的生產(chǎn)者消費者用例。
下一節(jié)我們學(xué)習(xí) hostPath Volume。
hostPath Volume
hostPath Volume 的作用是將 Docker Host 文件系統(tǒng)中已經(jīng)存在的目錄 mount 給 Pod 的容器。
大部分應(yīng)用都不會使用 hostPath Volume,因為這實際上增加了 Pod 與節(jié)點的耦合,限制了 Pod 的使用。
不過那些需要訪問 Kubernetes 或 Docker 內(nèi)部數(shù)據(jù)(配置文件和二進制庫)的應(yīng)用則需要使用 hostPath。
如果 Pod 被銷毀了,hostPath 對應(yīng)的目錄也還會被保留,從這點看,hostPath 的持久性比 emptyDir 強。不過一旦 Host 崩潰,hostPath 也就沒法訪問了。
PersistentVolume & PersistentVolumeClaim
Volume 提供了非常好的數(shù)據(jù)持久化方案,不過在可管理性上還有不足。
拿前面 AWS EBS 的例子來說,要使用 Volume,Pod 必須事先知道如下信息:
- 當(dāng)前 Volume 來自 AWS EBS。
- EBS Volume 已經(jīng)提前創(chuàng)建,并且知道確切的 volume-id。
Pod 通常是由應(yīng)用的開發(fā)人員維護,而 Volume 則通常是由存儲系統(tǒng)的管理員維護。開發(fā)人員要獲得上面的信息:
- 要么詢問管理員。
- 要么自己就是管理員。
這樣就帶來一個管理上的問題:應(yīng)用開發(fā)人員和系統(tǒng)管理員的職責(zé)耦合在一起了。如果系統(tǒng)規(guī)模較小或者對于開發(fā)環(huán)境這樣的情況還可以接受。但當(dāng)集群規(guī)模變大,特別是對于生成環(huán)境,考慮到效率和安全性,這就成了必須要解決的問題。
Kubernetes 給出的解決方案是 PersistentVolume 和 PersistentVolumeClaim。
PersistentVolume (PV) 是外部存儲系統(tǒng)中的一塊存儲空間,由管理員創(chuàng)建和維護。與 Volume 一樣,PV 具有持久性,生命周期獨立于 Pod。
PersistentVolumeClaim (PVC) 是對 PV 的申請 (Claim)。PVC 通常由普通用戶創(chuàng)建和維護。需要為 Pod 分配存儲資源時,用戶可以創(chuàng)建一個 PVC,指明存儲資源的容量大小和訪問模式(比如只讀)等信息,Kubernetes 會查找并提供滿足條件的 PV。
有了 PersistentVolumeClaim,用戶只需要告訴 Kubernetes 需要什么樣的存儲資源,而不必關(guān)心真正的空間從哪里分配,如何訪問等底層細(xì)節(jié)信息。這些 Storage Provider 的底層信息交給管理員來處理,只有管理員才應(yīng)該關(guān)心創(chuàng)建 PersistentVolume 的細(xì)節(jié)信息。
Kubernetes 支持多種類型的 PersistentVolume,比如 AWS EBS、Ceph、NFS 等,完整列表請參考 https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes
PV
下面創(chuàng)建一個 PV mypv1,配置文件 my-pv1.yml 如下:
apiVersion: v1
kind: PersistentVolume
metadata:
name: mypv1
labels:
type: local
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: manual
hostPath:
path: /data/pv1
① capacity 指定 PV 的容量為 1G。
② accessModes 指定訪問模式為 ReadWriteOnce,支持的訪問模式有:
ReadWriteOnce – PV 能以 read-write 模式 mount 到單個節(jié)點。
ReadOnlyMany – PV 能以 read-only 模式 mount 到多個節(jié)點。
ReadWriteMany – PV 能以 read-write 模式 mount 到多個節(jié)點。
③ persistentVolumeReclaimPolicy 指定當(dāng) PV 的回收策略為 Recycle,支持的策略有:
Retain – 需要管理員手工回收。
Recycle – 清除 PV 中的數(shù)據(jù),效果相當(dāng)于執(zhí)行 rm -rf /thevolume/*。
Delete – 刪除 Storage Provider 上的對應(yīng)存儲資源,例如 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。
④ storageClassName 指定 PV 的 class 為 manual。相當(dāng)于為 PV 設(shè)置了一個分類,PVC 可以指定 class 申請相應(yīng) class 的 PV。
⑤ 指定 PV 在服務(wù)器上對應(yīng)的目錄。
創(chuàng)建 mypv1:
STATUS 為 Available,表示 mypv1 就緒,可以被 PVC 申請。
接下來創(chuàng)建 PVC mypvc1,配置文件 my-pvc1.yml 如下:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: manual
PVC 就很簡單了,只需要指定 PV 的容量,訪問模式和 class。
創(chuàng)建 mypvc1:
從 kubectl get pvc 和 kubectl get pv 的輸出可以看到 mypvc1 已經(jīng) Bound 到 mypv1,申請成功。
接下來就可以在 Pod 中使用存儲了,Pod 配置文件 pod1.yml 如下:
apiVersion: v1
kind: Pod
metadata:
name: mypod1
spec:
containers:
- name: mypod1
image: 10.193.9.54:5000/library/busybox
args:
- /bin/sh
- -c
- sleep 30000
volumeMounts:
- mountPath: "/mydata"
name: mydata
volumes:
- name: mydata
persistentVolumeClaim:
claimName: mypvc1
與使用普通 Volume 的格式類似,在 volumes 中通過 persistentVolumeClaim 指定使用 mypvc1 申請的 Volume。
創(chuàng)建 mypod1:
驗證 PV 是否可用:
可見,在 Pod 中創(chuàng)建的文件 /mydata/hello 確實已經(jīng)保存到了 服務(wù)器10.193.9.55的 /data/pv1 中。
如果不再需要使用 PV,可用刪除 PVC 回收 PV,下節(jié)我們詳細(xì)討論。
回收PV
在使用本地存儲時,需要刪除pod以及對應(yīng)的pvc,這時候pv狀態(tài)為failed
這個時候pv狀態(tài)為failed,無法提供服務(wù),需要刪除重建,但是數(shù)據(jù)還會保留
重新創(chuàng)建pv, pvc, pod會發(fā)現(xiàn)數(shù)據(jù)依然存在