1.Volume簡介
我們經常會說:容器和 Pod 是短暫的。
其含義是它們的生命周期可能很短,會被頻繁地銷毀和創建。容器銷毀時,保存在容器內部文件系統中的數據都會被清除。
為了持久化保存容器的數據,可以使用 Kubernetes Volume。
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 等。
Volume 提供了對各種 backend 的抽象,容器在使用 Volume 讀寫數據的時候不需要關心數據到底是存放在本地節點的文件系統中呢還是雲硬盤上。對它來說,所有類型的 Volume 都只是一個目錄。
2.Volume之emptyDir
emptyDir 是最基礎的 Volume 類型。正如其名字所示,一個 emptyDir Volume 是 Host 上的一個空目錄。
emptyDir Volume 對於容器來說是持久的,對於 Pod 則不是。當 Pod 從節點刪除時,Volume 的內容也會被刪除。但如果只是容器被銷毀而 Pod 還在,則 Volume 不受影響。
也就是說:emptyDir Volume 的生命周期與 Pod 一致。
Pod 中的所有容器都可以共享 Volume,它們可以指定各自的 mount 路徑。下面通過例子來實踐 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
讀數據。
執行命令創建
kubectl logs
顯示容器 consumer
成功讀到了 producer
寫入的數據,驗證了兩個容器共享 emptyDir Volume。
因為 emptyDir 是 Docker Host 文件系統里的目錄,其效果相當於在k8s-node1上執行了 docker run -v /producer_dir
和 docker run -v /consumer_dir
。通過 docker inspect
查看容器的詳細配置信息,我們發現兩個容器都 mount 了同一個目錄:
[root@k8s-node1 ~]# docker inspect f0268ff431c0
[root@k8s-node1 ~]# docker inspect 613bbefe294c
這里/var/lib/kubelet/pods/83d4f810-e517-11e8-a73d-000c299e8d28/volumes/kubernetes.io~empty-dir/shared-volume就是 emptyDir 在 Host 上的真正路徑。
emptyDir 是 Host 上創建的臨時目錄,其優點是能夠方便地為 Pod 中的容器提供共享存儲,不需要額外的配置。但它不具備持久性,如果 Pod 不存在了,emptyDir 也就沒有了。根據這個特性,emptyDir 特別適合 Pod 中的容器需要臨時共享存儲空間的場景,比如前面的生產者消費者用例。
3.Volume之hostPath
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 也就沒法訪問了。
4.外部存儲
如果 Kubernetes 部署在諸如 AWS、GCE、Azure 等公有雲上,可以直接使用雲硬盤作為 Volume,下面是 AWS Elastic Block Store 的例子:
要在 Pod 中使用 ESB volume,必須先在 AWS 中創建,然后通過 volume-id 引用。其他雲硬盤的使用方法可參考各公有雲廠商的官方文檔。
Kubernetes Volume 也可以使用主流的分布式存,比如 Ceph、GlusterFS 等,下面是 Ceph 的例子:
Ceph 文件系統的 /some/path/in/side/cephfs
目錄被 mount 到容器路徑 /test-ceph。
相對於 emptyDir 和 hostPath,這些 Volume 類型的最大特點就是不依賴 Kubernetes。Volume 的底層基礎設施由獨立的存儲系統管理,與 Kubernetes 集群是分離的。數據被持久化后,即使整個 Kubernetes 崩潰也不會受損。
當然,運維這樣的存儲系統通常不是項簡單的工作,特別是對可靠性、高可用和擴展性有較高要求時。
Volume 提供了非常好的數據持久化方案,不過在可管理性上還有不足。