談談 Kubernetes 的存儲設計理念
談談 Kubernetes 的存儲設計理念
用三篇文章學習容器編排系統存儲方面的知識點。今天這節課,我們先來探討下 Kubernetes 的存儲設計理念。
Kubernetes 的存儲設計考量
Kubernetes 在規劃持久化存儲能力的時候,依然遵循着它的一貫設計哲學,用戶負責以資源和聲明式 API 來描述自己的意圖,Kubernetes 負責根據用戶意圖來完成具體的操作。不過我認爲,就算只是描述清楚用戶的存儲意圖,也不是一件容易的事情,相比 Kubernetes 提供的其他能力的資源,它內置的存儲資源其實格外地複雜,甚至可以說是有些繁瑣的。
-
相關技術
概念:Volume、PersistentVolume、PersistentVolumeClaim、Provisioner、StorageClass、Volume Snapshot、Volume Snapshot Class、Ephemeral Volumes、FlexVolume Driver、Container Storage Interface、CSI Volume Cloning、Volume Limits、Volume Mode、Access Modes、Storage Capacity……
操作:Mount、Bind、Use、Provision、Claim、Reclaim、Reserve、Expand、Clone、Schedule、Reschedule……
其實啊,Kubernetes 之所以有如此多關於存儲的術語概念,最重要的原因是存儲技術本來就有很多種類,爲了儘可能多地兼容各種存儲,Kubernetes 不得不預置了很多 In-Tree(意思是在 Kubernetes 的代碼樹裏)插件來對接,讓用戶根據自己的業務按需選擇。爲了兼容那些不在預置範圍內的需求場景,Kubernetes 也支持用戶使用 FlexVolume 或者 CSI 來定製 Out-of-Tree(意思是在 Kubernetes 的代碼樹之外)的插件,實現更加豐富多樣的存儲能力。
事實上,迫使 Kubernetes 存儲設計得如此複雜的原因,除了是要擴大兼容範疇之外,還有一個非技術層面的因素,就是 Kubernetes 是一個工業級的、面向生產應用的容器編排系統。
而這就意味着,即使 Kubernetes 發現了某些已存在的功能有更好的實現方式,但直到舊版本被淘汰出生產環境以前,原本已支持的功能都不允許突然間被移除或者替換掉。否則,當生產系統更新版本時,已有的功能就會出現異常,那就會極大威脅到產品的信譽。
當然,在一定程度上,我們可以原諒 Kubernetes 爲了實現兼容而導致的繁瑣,但這樣的設計確實會讓 Kubernetes 的學習曲線變得更加陡峭。官方文檔只是平鋪可用功能,有利於熟練的管理員快速查詢到關鍵信息,卻不利於初學者去理解 Kubernetes 的設計思想。
如此一來,因爲很難理解那些概念和操作的本意,初學者往往就只能死記硬背,很難分辨出它們應該如何被 “更正確” 地使用。而介紹 Kubernetes 設計理念的職責,只能由 Kubernetes 官方的 Blog 這類信息渠道,或者其他非官方資料去完成。
所以接下來,我會從 Volume 的概念開始,以操作系統到 Docker,再到 Kubernetes 的演進歷程爲主線,帶你去梳理前面提到的那些概念與操作,以此幫你更好地理解 Kubernetes 的存儲設計。
首先,我們來看看 Mount 和 Volume 這兩個概念。
Mount 和 Volume
Mount 和 Volume 都是來源於操作系統的常用術語,Mount 是動詞,表示將某個外部存儲掛載到系統中;(linux 用外部存儲安裝過軟件的同學應該都用過這個掛載命令)
Volume 是名詞,表示物理存儲的邏輯抽象,目的是爲物理存儲提供有彈性的分割方式。
而我們知道,容器是源於對操作系統層的虛擬化,爲了滿足容器內生成數據的外部存儲需求,我們也很自然地會把 Mount 和 Volume 的概念延至容器中。因此,要想了解容器存儲的發展,我們不妨就以 Docker 的 Mount 操作爲起始點。
目前,Docker 內建支持了三種掛載類型,分別是 Bind(--mount type=bind)、Volume(--mount type=volume)和 tmpfs(--mount type=tmpfs),如下圖所示。其中,tmpfs 主要用於在內存中讀寫臨時數據,跟我們這個小章節要討論的對象 “持久化存儲” 並不相符,所以後面我們只着重關注 Bind 和 Volume 兩種掛載類型就可以了。
Bind Mount 是 Docker 最早提供的(發佈時就支持)掛載類型,作用是把宿主機的某個目錄(或文件)掛載到容器的指定目錄(或文件)下,比如下面命令中,參數 - v 表達的意思就是把外部的 HTML 文檔,掛到 Nginx 容器的默認網站根目錄下:
docker run -v /icyfenix/html:/usr/share/nginx/html nginx:latest
請注意,雖然命令中 - v 參數是 --volume 的縮寫,但 - v 最初只是用來創建 Bind Mount,而不是創建 Volume Mount 的。
這種迷惑的行爲其實也並不是 Docker 的本意,只是因爲 Docker 剛發佈的時候考慮得不夠周全,隨隨便便就在參數中佔用了 “Volume” 這個詞,到後來真的需要擴展 Volume 的概念來支持 Volume Mount 的時候,前面的 - v 已經被用戶廣泛使用了,所以也就只能如此將就着繼續用。
從 Docker 17.06 版本開始,Bind 就在 Docker Swarm 中借用了 --mount 參數過來,這個參數默認創建的是 Volume Mount,用戶可以通過明確的 type 子參數來指定另外兩種掛載類型。比如說,前面給到的命令,就可以等價於下面所示的 --mount 版本:
docker run --mount type=bind,source=/icyfenix/html,destination=/usr/share/nginx/html nginx:latest
**從 Bind Mount 到 Volume Mount,實質上是容器發展過程中對存儲抽象能力提升的外在表現。**我們根據 “Bind” 這個名字,以及 Bind Mount 的實際功能,其實可以合理地推測,Docker 最初認爲 “Volume” 就只是一種“外部宿主機的磁盤存儲到內部容器存儲的映射關係”,但後來它眉頭一皺,發現事情並沒有那麼簡單:存儲的位置並不侷限只在外部宿主機,存儲的介質並不侷限只是物理磁盤,存儲的管理也並不侷限只有映射關係。
我給你舉幾個例子。
比如,Bind Mount 只能讓容器與本地宿主機之間建立某個目錄的映射,那麼如果想要在不同宿主機上的容器共享同一份存儲,就必須先把共享存儲掛載到每一臺宿主機操作系統的某個目錄下,然後才能逐個掛載到容器內使用,這種跨宿主機共享存儲的場景如下圖所示:
圖片來自 Docker 官方文檔
這種存儲範圍超越了宿主機的共享存儲,配置過程卻要涉及到大量與宿主機環境相關的操作,只能由管理員人工地去完成,不僅繁瑣,而且由於每臺宿主機環境的差異,還會導致主機很難實現自動化。
再比如,即使只考慮單臺宿主機的情況,基於可管理性的需求,Docker 也完全有支持 Volume Mount 的必要。爲什麼這麼說呢?
實際上,在 Bind Mount 的設計裏,Docker 只有容器的控制權,存放容器生產數據的主機目錄是完全獨立的,與 Docker 沒有任何關係,它既不受 Docker 保護,也不受 Docker 管理。所以這就使得數據很容易被其他進程訪問到,甚至是被修改和刪除。如果用戶想對掛載的目錄進行備份、遷移等管理運維操作,也只能在 Docker 之外靠管理員人工進行,而這些都增加了數據安全與操作意外的風險。
因此,Docker 希望能有一種抽象的資源,來代表在宿主機或網絡中存儲的區域,以便讓 Docker 能管理這些資源,這樣就很自然地聯想到了操作系統裏的 Volume。
提出 Volume 最核心的一個目的,是爲了提升 Docker 對不同存儲介質的支撐能力,這同時也是爲了減輕 Docker 本身的工作量。
要知道,存儲並不是只有掛載在宿主機上的物理存儲這一種介質。磁盤是這種介質,各種雲服務廠商提供的存儲產品也可以是這種介質。(在雲計算時代,網絡存儲逐漸成爲了數據中心的主流選擇,不同的網絡存儲都有各自的協議和交互接口。而且,並不是所有的存儲系統都適合先掛載到操作系統,然後再掛載到容器的,如果 Docker 想要越過操作系統去支持掛載某種存儲系統,首先必須要知道該如何訪問它,然後才能把容器中的讀寫操作自動轉移到該位置。)
Docker 把解決如何訪問存儲的功能模塊叫做存儲驅動(Storage Driver)。通過 docker info 命令,你能查看到當前 Docker 所支持的存儲驅動。雖然 Docker 已經內置了市面上主流的 OverlayFS 驅動,比如 Overlay、Overlay2、AUFS、BTRFS、ZFS 等等,但面對雲計算的快速迭代,只靠 Docker 自己來支持全部雲計算廠商的存儲系統是完全不現實的。
爲此,Docker 就提出了與 Storage Driver 相對應的 Volume Driver(卷驅動)的概念。
我們可以通過 docker plugin install 命令安裝外部的卷驅動,並在創建 Volume 時,指定一個與其存儲系統相匹配的卷驅動。比如,我們希望數據存儲在 AWS Elastic Block Store 上,就找一個 AWS EBS 的驅動;如果想存儲在 Azure File Storage 上,也是找一個對應的 Azure File Storage 驅動即可。
而如果在創建 Volume 時,不指定卷驅動,那默認就是 local 類型,在 Volume 中存放的數據就會存儲在宿主機的 / var/lib/docker/volumes / 目錄之中。
Static Provisioning
好了,瞭解了 Mount 和 Volume 的概念含義之後,現在我們把討論主角轉回容器編排系統上。
這裏,我們會從存儲如何分配、持久存儲與非持久存儲的差異出發,來具體學習下 Static Provisioning 的設計。
首先我們可以明確一件事,即 Kubernetes 同樣是把操作系統和 Docker 的 Volume 概念延續了下來,並對其進行了進一步的細化。
Kubernetes 把 Volume 分爲了持久化的 PersistentVolume 和非持久化的普通 Volume 兩類,這裏爲了不跟我前面定義的 Volume 這個概念產生混淆,後面課程我提到的 Kubernetes 中非持久化的 Volume 時,都會帶着 “普通” 這個前綴。
普通 Volume 的設計目標並不是爲了持久地保存數據,而是爲同一個 Pod 中多個容器提供可共享的存儲資源,所以普通 Volume 的生命週期非常明確,也就是與掛載它的 Pod 有着相同的生命週期。
這樣,就意味着儘管普通 Volume 不具備持久化的存儲能力,但至少比 Pod 中運行的任何容器的存活期都更長,Pod 中不同的容器能共享相同的普通 Volume,當容器重新啓動時,普通 Volume 中的數據也能夠得到保留。
當然,一旦整個 Pod 被銷燬,普通 Volume 也就不復存在了,數據在邏輯上也會被銷燬掉。至於實際中是否會真正刪除數據,就取決於存儲驅動具體是如何實現 Unmount、Detach、Delete 接口的(這個小章節的主題是 “持久化存儲”,所以關於無持久化能力的普通 Volume,我就不再展開了)。
如此一來,從操作系統裏傳承下來的 Volume 概念,就在 Docker 和 Kubernetes 中繼續按照一致的邏輯延伸拓展了,只不過 Kubernetes 爲了把它跟普通 Volume 區別開來,專門取了 PersistentVolume 這個名字。我們從 Persistent 這個單詞的意思,就能大致瞭解 PersistentVolume 的含義,它是指能夠將數據進行持久化存儲的一種資源對象。
PersistentVolume 可以獨立於 Pod 存在,生命週期與 Pod 無關,所以也就決定了 PersistentVolume 不應該依附於任何一個宿主機節點,否則必然會對 Pod 調度產生干擾限制。我們在前面 “Docker 的三種掛載類型” 圖例中,可以看到 “Persistent” 一列裏都是網絡存儲,這便是很好的印證。
那麼,在把 PersistentVolume 與 Pod 分離後,就需要專門考慮 PersistentVolume 該如何被 Pod 所引用的問題了。
實際上,**原本在 Pod 中引用其他資源是常有的事,要麼是通過資源名稱直接引用,要麼是通過標籤選擇器(Selectors)間接引用。但是類似的方法在這裏卻都不太妥當,**至於原因,你可以先思考一下:“Pod 該使用何種存儲” 這件事情,應該是系統管理員(運維人員)說的算,還是由用戶(開發人員)說的算?
要我看,最合理的答案是他們一起說的纔算,因爲只有開發能準確評估 Pod 運行需要消耗多大的存儲空間,只有運維能清楚地知道當前系統可以使用的存儲設備狀況。
所以,爲了讓這二者能夠各自提供自己擅長的信息,Kubernetes 又額外設計出了 PersistentVolumeClaim 資源。
其實在 Kubernetes 官方給出的概念定義中,也特別強調了 PersistentVolume 是由管理員(運維人員)負責維護的,用戶(開發人員)通過 PersistentVolumeClaim,來匹配到合乎需求的 PersistentVolume。
說人話就是
PersistentVolume 系統管理員分配的具體大小的存儲空間
PersistentVolumeClaim 開發人員指定需要存儲空間的大小
實際上管理員和用戶並不是誰引用誰的固定關係,而是根據實際情況動態匹配的。
下面我們就來看看這兩者配合工作的具體過程:
-
管理員準備好要使用的存儲系統,它應該是某種網絡文件系統(NFS)或者雲儲存系統,一般來說應該具備跨主機共享的能力。
-
管理員會根據存儲系統的實際情況,手工預先分配好若干個 PersistentVolume,並定義好每個 PersistentVolume 可以提供的具體能力。如下面例子所示:
apiVersion: v1
kind: PersistentVolume
metadata:
name: nginx-html
spec:
capacity:
storage: 5Gi # 最大容量爲5GB
accessModes:
- ReadWriteOnce # 訪問模式爲RXO
persistentVolumeReclaimPolicy: Retain # 回收策略是Retain
nfs: # 存儲驅動是NFS
path: /html
server: 172.17.0.2
這裏我們來簡單分析下以上 YAML 中定義的存儲能力:
-
存儲的最大容量是 5GB。
-
存儲的訪問模式是 “只能被一個節點讀寫掛載”(ReadWriteOnce,RWO),另外兩種可選的訪問模式是 “可以被多個節點以只讀方式掛載”(ReadOnlyMany,ROX)和 “可以被多個節點讀寫掛載”(ReadWriteMany,RWX)。
-
存儲的回收策略是 Retain,即在 Pod 被銷燬時並不會刪除數據。另外兩種可選的回收策略分別是 Recycle ,即在 Pod 被銷燬時,由 Kubernetes 自動執行 rm -rf /volume/* 這樣的命令來自動刪除資料;以及 Delete,它讓 Kubernetes 自動調用 AWS EBS、GCE PersistentDisk、OpenStack Cinder 這些雲存儲的刪除指令。
-
存儲驅動是 NFS,其他常見的存儲驅動還有 AWS EBS、GCE PD、iSCSI、RBD(Ceph Block Device)、GlusterFS、HostPath,等等。
- 用戶根據業務系統的實際情況,創建 PersistentVolumeClaim,聲明 Pod 運行所需的存儲能力。如下面例子所示:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nginx-html-claim
spec:
accessModes:
- ReadWriteOnce # 支持RXO訪問模式
resources:
requests:
storage: 5Gi # 最小容量5GB
可以看到,在以上 YAML 中,聲明瞭要求容量不得小於 5GB,必須支持 RWO 的訪問模式。
4.Kubernetes 在創建 Pod 的過程中,會根據系統中 PersistentVolume 與 PersistentVolumeClaim 的供需關係,對兩者進行撮合,如果系統中存在滿足 PersistentVolumeClaim 聲明中要求能力的 PersistentVolume,就表示撮合成功,它們將會被綁定。而如果撮合不成功,Pod 就不會被繼續創建,直到系統中出現新的、或讓出空閒的 PersistentVolume 資源。
- 以上幾步都順利完成的話,意味着 Pod 的存儲需求得到滿足,進而繼續 Pod 的創建過程。
以上的整個運作過程如下圖所示:
PersistentVolumeClaim 與 PersistentVolume 運作過程
Kubernetes 對 PersistentVolumeClaim 與 PersistentVolume 撮合的結果是產生一對一的綁定關係,“一對一” 的意思是 PersistentVolume 一旦綁定在某個 PersistentVolumeClaim 上,直到釋放以前都會被這個 PersistentVolumeClaim 所獨佔,不能再與其他 PersistentVolumeClaim 進行綁定。
這意味着即使 PersistentVolumeClaim 申請的存儲空間比 PersistentVolume 能夠提供的要少,依然要求整個存儲空間都爲該 PersistentVolumeClaim 所用,這有可能會造成資源的浪費。
比如開發要 3g 空間,最小的 PersistentVolume 是 5g,就浪費了 2g。
Dynamic Provisioning
對於中小規模的 Kubernetes 集羣,PersistentVolume 已經能夠滿足有狀態應用的存儲需求。PersistentVolume 依靠人工介入來分配空間的設計雖然簡單直觀,卻算不上是先進,一旦應用規模增大,PersistentVolume 很難被自動化的問題就會凸顯出來。
針對這種情況,在 2017 年 Kubernetes 發佈 1.6 版本後,終於提供了今天被稱爲 Dynamic Provisioning 的動態存儲解決方案,讓系統管理員擺脫了人工分配的 PersistentVolume 的窘境,並把此前的分配方式稱爲 Static Provisioning。
那 Dynamic Provisioning 方案是如何解放系統管理員的呢?我們先來看概念,Dynamic Provisioning 方案是指在用戶聲明存儲能力的需求時,不是期望通過 Kubernetes 撮合來獲得一個管理員人工預置的 PersistentVolume,而是由特定的資源分配器(Provisioner)自動地在存儲資源池或者雲存儲系統中分配符合用戶存儲需要的 PersistentVolume,然後掛載到 Pod 中使用,完成這項工作的資源被命名爲 StorageClass,它的具體工作過程如下:
-
管理員根據儲系統的實際情況,先準備好對應的 Provisioner。Kubernetes 官方已經提供了一系列預置的 In-Tree Provisioner,放置在 kubernetes.io 的 API 組之下。其中部分 Provisioner 已經有了官方的 CSI 驅動,如 vSphere 的 Kubernetes 自帶驅動爲 kubernetes.io/vsphere-volume,VMware 的官方驅動爲 csi.vsphere.vmware.com。
-
管理員不再是手工去分配 PersistentVolume,而是根據存儲去配置 StorageClass。Pod 是可以動態擴縮的,而存儲則是相對固定的,哪怕使用的是具有擴展能力的雲存儲,也會將它們視爲存儲容量、IOPS 等參數可變的固定存儲來看待,比如你可以將來自不同雲存儲提供商、不同性能、支持不同訪問模式的存儲配置爲各種類型的 StorageClass,這也是它名字中 “Class”(類型)的由來,如下面這個例子:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs #AWS EBS的Provisioner
parameters:
type: gp2
reclaimPolicy: Retain
- 用戶依然通過 PersistentVolumeClaim 來聲明所需的存儲,但是應在聲明中明確指出該由哪個 StorageClass 來代替 Kubernetes 處理該 PersistentVolumeClaim 的請求,如下面這個例子:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: standard-claim
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard #明確指出該由哪個StorageClass來處理該PersistentVolumeClaim的請求
resource:
requests:
storage: 5Gi
- 如果 PersistentVolumeClaim 中要求的 StorageClass 及它用到的 Provisioner 均是可用的話,那這個 StorageClass 就會接管掉原本由 Kubernetes 撮合的 PersistentVolume 和 PersistentVolumeClaim 的操作,按照 PersistentVolumeClaim 中聲明的存儲需求,自動產生出滿足該需求的 PersistentVolume 描述信息,併發送給 Provisioner 處理。
5.Provisioner 接收到 StorageClass 發來的創建 PersistentVolume 請求後,會操作其背後存儲系統去分配空間,如果分配成功,就生成並返回符合要求的 PersistentVolume 給 Pod 使用。
- 前面這幾步都順利完成的話,就意味着 Pod 的存儲需求得到了滿足,會繼續 Pod 的創建過程,整個過程如下圖所示。
好了,通過剛剛的講述,相信你可以看出 Dynamic Provisioning 與 Static Provisioning 並不是各有用途的互補設計,而是對同一個問題先後出現的兩種解決方案。你完全可以只用 Dynamic Provisioning 來實現所有的 Static Provisioning 能夠實現的存儲需求,包括那些不需要動態分配的場景,甚至之前例子裏使用 HostPath 在本地靜態分配存儲,都可以指定 no-provisioner 作爲 Provisioner 的 StorageClass,以 Local Persistent Volume 來代替,比如下面這個例子:
apiVersion: v1
kind: PersistentVolume
metadata:
name: nginx-html
spec:
capacity:
storage: 5Gi # 最大容量爲5GB
accessModes:
- ReadWriteOnce # 訪問模式爲RXO
persistentVolumeReclaimPolicy: Retain # 回收策略是Retain
nfs: # 存儲驅動是NFS
path: /html
server: 172.17.0.2
################對比####################
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
所以說,相較於 Static Provisioning,使用 Dynamic Provisioning 來分配存儲無疑是更合理的設計,不僅省去了管理員的人工操作的中間層,也不再需要將 PersistentVolume 這樣的概念暴露給最終用戶,因爲 Dynamic Provisioning 裏的 PersistentVolume 只是處理過程的中間產物,用戶不再需要接觸和理解它,只需要知道由 PersistentVolumeClaim 去描述存儲需求,由 StorageClass 去滿足存儲需求即可。只描述意圖而不關心中間具體的處理過程是聲明式編程的精髓,也是流程自動化的必要基礎。
除此之外,由 Dynamic Provisioning 來分配存儲還能獲得更高的可管理性。如前面提到的回收策略,當希望 PersistentVolume 跟隨 Pod 一同被銷燬時,以前經常會配置回收策略爲 Recycle 來回收空間,即讓系統自動執行 rm -rf /volume/* 命令。
但是這種方式往往過於粗暴,要是遇到更精細的管理需求,如 “刪除到回收站” 或者 “敏感信息粉碎式徹底刪除” 這樣的功能,實現起來就很麻煩。而 Dynamic Provisioning 中由於有 Provisioner 的存在,如何創建、如何回收都是由 Provisioner 的代碼所管理的,這就帶來了更高的靈活性。所以,現在 Kubernetes 官方已經明確建議廢棄掉 Recycle 策略,如果有這類需求就改由 Dynamic Provisioning 去實現了。
另外,相較於 Dynamic Provisioning,Static Provisioning 的主要使用場景就侷限於管理員能夠手工管理存儲的小型集羣,它符合很多小型系統,尤其是私有化部署系統的現狀,但並不符合當今運維自動化所提倡的思路。Static Provisioning 的存在,某種意義上也可以視爲是對歷史的一種兼容,在可見的將來,Kubernetes 肯定還是會把 Static Provisioning 作爲用戶分配存儲的一種主要方案,來供用戶選用。
小結
容器是鏡像的運行時實例,爲了保證鏡像能夠重複地產生出具備一致性的運行時實例,必須要求鏡像本身是持久而穩定的,這就決定了在容器中發生的一切數據變動操作,都不能真正寫入到鏡像當中,否則必然會破壞鏡像穩定不變的性質。
爲此,容器中的數據修改操作,大多是基於寫入時複製(Copy-on-Write)策略來實現的,容器會利用疊加式文件系統(OverlayFS)的特性,在用戶意圖對鏡像進行修改時,自動將變更的內容寫入到獨立區域,再與原有數據疊加到一起,使其外觀上看起來像是 “覆蓋” 了原有內容。這種改動通常都是臨時的,一旦容器終止運行,這些存儲於獨立區域中的變動信息也將被一併移除,不復存在。所以可見,如果不去進行額外的處理,容器默認是不具備持久化存儲能力的。
而另一方面,容器作爲信息系統的運行載體,必定會產生出有價值的、應該被持久保存的信息,比如扮演數據庫角色的容器,大概沒有什麼系統能夠接受數據庫像緩存服務一樣,重啓之後會丟失全部數據;多個容器之間也經常需要通過共享存儲來實現某些交互操作,比如之前曾經舉過的例子,Nginx 容器產生日誌、Filebeat 容器收集日誌,兩者就需要共享同一塊日誌存儲區域才能協同工作。
而正因爲鏡像的穩定性與生產數據持久性存在矛盾,所以我們才需要去重點了解這個問題:如何實現容器的持久化存儲。
一課一思
不知你是否察覺,這節課裏,還埋藏了一條暗線的邏輯,以 Kubernetes 的存儲爲樣例,討論當新的更好的解決方案出來之後,系統對既有舊方案和舊功能的兼容。這是很多場景中都會遇到的問題,系統設計必須考慮現實情況,必須有所妥協,很難單純去追求理論上的最優解。越大規模的應用,通常都帶着更大的現實牽絆。如果你也有這樣的經歷,不妨留言與我分享一下。
如果你覺得有收穫,也歡迎把今天的內容分享給更多的朋友。感謝你的閱讀,我們下一講再見。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/vtkA00ajEUgrNLaV_263vQ