如何優(yōu)雅的在 Kubernetes 集群中緩存容器鏡像
介紹
當容器化應(yīng)用部署到Kubernetes 集群時,K8s控制平面會將 Pod調(diào)度到集群中的工作節(jié)點。運行在工作節(jié)點中的節(jié)點代理(Kubelet)與安裝在節(jié)點中的容器運行時(例如 containerd)協(xié)調(diào),并從鏡像registry中拉取必要的容器鏡像。根據(jù)鏡像的大小和可用的網(wǎng)絡(luò)帶寬,將所有鏡像拉取到節(jié)點需要時間。因此,在任何容器化應(yīng)用程序中,我們都應(yīng)該意識到由于從registry中獲取鏡像而引入的延遲。然而,作為進程運行的傳統(tǒng)應(yīng)用程序(例如由 systemd管理)不會受到這種延遲的影響,因為所有必需的文件都已經(jīng)安裝在機器中。
想象一下,您的容器化應(yīng)用程序遇到了突然的流量激增,它需要立即橫向擴展(即需要創(chuàng)建額外的實例)。如果您配置了 Horizontal Pod Autoscaler (HPA),K8s控制平面會創(chuàng)建額外的 Pod 副本。但是,這些 Pod 將無法用于處理增加的流量,直到所需的鏡像被拉取,容器啟動并運行。或者假設(shè)您的應(yīng)用程序需要處理高速實時數(shù)據(jù)。此類應(yīng)用程序?qū)ζ鋯雍蛿U展的速度有嚴格的要求,因為它實現(xiàn)的目的的本質(zhì)。
簡而言之,在一些用例中,由于從registry中提取鏡像而引入的延遲是不可接受的。此外,集群和鏡像registry之間的網(wǎng)絡(luò)連接可能會受到帶寬不足的影響,或者連接可能會完全丟失。在某些情況下,尤其是在邊緣計算中,應(yīng)用程序必須優(yōu)雅地容忍間歇性網(wǎng)絡(luò)連接。
這些挑戰(zhàn)可以通過不同的方式來解決。在這些場景中非常有用的一種解決方案是將容器鏡像直接緩存在集群工作節(jié)點上,這樣 Kubelet 不需要拉取這些鏡像,而是立即使用已經(jīng)緩存在節(jié)點中的鏡像。在這篇博客中,我將解釋如何使用開源項目kube-fledged 在 Kubernetes 集群中構(gòu)建和管理容器鏡像的緩存。
現(xiàn)有解決方案
在向您介紹 kube-fledged 之前,讓我簡要介紹一下解決此問題的現(xiàn)有解決方案。廣泛使用的方法是在集群內(nèi)運行一個 Registry 鏡像。兩種廣泛使用的解決方案是
- 集群內(nèi)自托管registry
- 直通緩存
在前一種解決方案中,本地注冊中心在 k8s集群中運行,并在容器運行時配置為鏡像注冊中心。
任何鏡像拉取請求都被定向到集群內(nèi)registry。如果失敗,請求將被定向到主注冊中心。在后一種解決方案中,本地registry具有緩存功能。第一次拉取鏡像時,它會緩存在本地registry中。對鏡像的后續(xù)請求由本地registry提供服務(wù)。
現(xiàn)有解決方案的缺點
設(shè)置和維護本地registry鏡像會消耗大量計算資源和人力資源。
對于跨越多個區(qū)域的龐大集群,我們需要有多個本地registry鏡像。當應(yīng)用程序?qū)嵗缭蕉鄠€區(qū)域時,這會引入不必要的復(fù)雜性。您可能需要有多個部署清單,每個清單都指向該區(qū)域的本地 registry鏡像。
這些方法并不能完全解決Pod快速啟動的需求,因為從本地鏡像拉取鏡像仍然存在明顯的延遲。有幾個用例不能容忍這種延遲。
節(jié)點可能會失去與本地registry鏡像的網(wǎng)絡(luò)連接,因此 Pod 將卡住,直到連接恢復(fù)。
kube-fledged 概述
kube-fledged是一個 kubernetes插件或operator,用于直接在 kubernetes 集群的工作節(jié)點上創(chuàng)建和管理容器鏡像的緩存。
它允許用戶定義鏡像列表以及這些鏡像應(yīng)該緩存(即拉取)到哪些工作節(jié)點上。因此,應(yīng)用程序 pod幾乎立即啟動,因為不需要從registry中提取鏡像。kube-fledged提供了 CRUD API來管理鏡像緩存的生命周期,并支持多個可配置的參數(shù)來根據(jù)需要自定義功能。
https : //github.com/senthilrch/kube-fledged)
kube-fledged 被設(shè)計和構(gòu)建為用于管理Kubernetes 中的鏡像緩存的通用解決方案。盡管主要用例是實現(xiàn)快速 Pod 啟動和擴展,但該解決方案支持多種用例,如下所述
用例
- 需要快速啟動的應(yīng)用程序。例如,由于數(shù)據(jù)量激增,執(zhí)行實時數(shù)據(jù)處理的應(yīng)用程序需要快速擴展。
- 無服務(wù)器函數(shù),因為它們需要對傳入的事件立即做出反應(yīng)。
- 在邊緣設(shè)備上運行的 IoT 應(yīng)用程序,因為邊緣設(shè)備和鏡像registry之間的網(wǎng)絡(luò)連接是間歇性的。
- 如果需要從私有registry中拉取鏡像,并且無法授予每個人從該registry中拉取鏡像的訪問權(quán)限,則可以在集群節(jié)點上提供這些鏡像。
- 如果集群管理員或操作員需要對應(yīng)用程序進行升級,并希望事先驗證是否可以成功拉取新鏡像。
kube-fledged 的工作原理
Kubernetes允許開發(fā)人員通過自定義資源擴展 kubernetes api。kube-fledged定義了一個類型為“ ImageCache ”的自定義資源并實現(xiàn)了一個自定義控制器(名為 kubefledged-controller)。
kubefledged-controller負責管理鏡像緩存。用戶可以使用 kubectl命令來創(chuàng)建和刪除 ImageCache 資源。
kubefledged-controller有一個內(nèi)置的 Image Manager 例程,負責拉取和刪除鏡像。使用 kubernetes job拉取或刪除鏡像。如果啟用,刷新工作者會定期刷新鏡像緩存。kubefledged-controller 在 ImageCache 資源的 status 字段中更新鏡像拉取、刷新和鏡像刪除的狀態(tài)。kubefledged-webhook-server負責驗證 ImageCache資源的字段。
如果您需要在集群中創(chuàng)建鏡像緩存,則只需ImageCache通過指定要拉取的鏡像列表以及nodeSelector. 將nodeSelector用于指定在其上的鏡像應(yīng)該被高速緩存的節(jié)點。如果您希望鏡像緩存在集群的所有節(jié)點中,則省略nodeSelector. 當您將清單提交到集群時,API 服務(wù)器將向 kubefledged-webhook-server 發(fā)布驗證webhook事件。Webhook 服務(wù)器驗證cacheSpec的清單。在收到來自 webhook 服務(wù)器的成功響應(yīng)后,API 服務(wù)器將 ImageCache 資源持久保存在etcd 中。這會觸發(fā)對kubefledged-controller 的 Informer 通知,該通知將請求排隊。該請求由鏡像緩存工作器接收,它創(chuàng)建多個鏡像拉取請求(每個節(jié)點每個鏡像一個請求)并將它們放入鏡像拉取/刪除隊列中。
這些請求由鏡像管理器例程處理。對于每個請求,鏡像管理器都會創(chuàng)建一個 k8s job,負責將鏡像拉入緩存。鏡像管理器會跟蹤它創(chuàng)建的job,一旦job完成,它就會將響應(yīng)放在一個單獨的隊列中。然后鏡像緩存工作器聚合來自鏡像管理器的所有結(jié)果,最后更新 ImageCache資源的狀態(tài)部分。
kube-fledged 有一個刷新工作例程,它會定期運行以保持鏡像緩存刷新。如果它發(fā)現(xiàn)緩存中缺少任何鏡像(可能被 kubelet 的鏡像垃圾收集刪除了),它會重新將鏡像拉入緩存。帶有:latest標簽的鏡像總是在刷新周期中被重新拉出。默認情況下,刷新周期每5m. 用戶可以在部署 kube-fledged 時將其修改為不同的值或完全禁用自動刷新機制。還支持按需刷新機制,用戶可以使用該機制請求 kube-fledged 立即刷新鏡像緩存。
kube-fledged 支持的鏡像緩存操作
kube-fledged 支持以下鏡像緩存操作。所有這些操作都可以使用 kubectl 或通過直接向 Kubernetes API服務(wù)器提交 REST API 請求來執(zhí)行:
- 創(chuàng)建鏡像緩存
- 修改鏡像緩存
- 刷新鏡像緩存
- 清除鏡像緩存
- 刪除鏡像緩存
支持的Container Runtime
- Docker
- Containerd
- Cri-o
支持的平臺
- linux/amd64
- linux/arm
- linux/arm64
使用 kube-fledged
使用 kube-fledged 的最快方法是使用項目的 GitHub Repo ( https://github.com/senthilrch/kube-fledged) 中的 YAML 清單來部署它。您還可以使用 helm chart 和 helm operator 部署它。在下面找到使用清單部署 kube-fledged 的步驟:
克隆源代碼存儲庫
- $ mkdir -p $HOME/src/github.com/senthilrch
- $ git clone https://github.com/senthilrch/kube-fledged.git $HOME/src/github.com/senthilrch/kube-fledged
- $ cd $HOME/src/github.com/senthilrch/kube-fledged
將kube-fledged部署到集群
- $ make deploy-using-yaml
驗證kube-fledged是否成功部署
- $ kubectl get pods -n kube-fledged -l app=kubefledged
- $ kubectl get imagecaches -n kube-fledged (Output should be: 'No resources found')
類似解決方案
在下面找到我注意到的類似開源解決方案的列表。這些解決方案嘗試使用替代方法解決問題
Stargz Snapshotter:具有延遲拉動功能的快速容器鏡像分發(fā)插件
(https://github.com/containerd/stargz-snapshotter)
Uber Kraken:Kraken 是一個 P2P Docker registry,能夠在幾秒鐘內(nèi)分發(fā) TB數(shù)據(jù)
(https://github.com/uber/kraken)
Imagewolf:ImageWolf 是一種 PoC,它提供了一種將 Docker 鏡像加載到集群上的極快方式,從而可以更快地推送更新
https://github.com/ContainerSolutions/ImageWolf)
結(jié)論
有些應(yīng)用程序和用例需要快速啟動和擴展。在這種情況下,從registry中拉取鏡像所帶來的延遲可能是不可接受的。此外,與registry的網(wǎng)絡(luò)連接可能不穩(wěn)定/間歇性。不授予所有用戶訪問安全registry的權(quán)限可能是出于安全原因。Kube-fledged 是一個簡單而有用的解決方案,可以直接在集群工作節(jié)點上構(gòu)建和管理容器鏡像的緩存