如何優雅的在 Kubernetes 集群中緩存容器鏡像
介紹
當容器化應用部署到Kubernetes 集群時,K8s控制平面會將 Pod調度到集群中的工作節點。運行在工作節點中的節點代理(Kubelet)與安裝在節點中的容器運行時(例如 containerd)協調,并從鏡像registry中拉取必要的容器鏡像。根據鏡像的大小和可用的網絡帶寬,將所有鏡像拉取到節點需要時間。因此,在任何容器化應用程序中,我們都應該意識到由于從registry中獲取鏡像而引入的延遲。然而,作為進程運行的傳統應用程序(例如由 systemd管理)不會受到這種延遲的影響,因為所有必需的文件都已經安裝在機器中。
想象一下,您的容器化應用程序遇到了突然的流量激增,它需要立即橫向擴展(即需要創建額外的實例)。如果您配置了 Horizontal Pod Autoscaler (HPA),K8s控制平面會創建額外的 Pod 副本。但是,這些 Pod 將無法用于處理增加的流量,直到所需的鏡像被拉取,容器啟動并運行?;蛘呒僭O您的應用程序需要處理高速實時數據。此類應用程序對其啟動和擴展的速度有嚴格的要求,因為它實現的目的的本質。
簡而言之,在一些用例中,由于從registry中提取鏡像而引入的延遲是不可接受的。此外,集群和鏡像registry之間的網絡連接可能會受到帶寬不足的影響,或者連接可能會完全丟失。在某些情況下,尤其是在邊緣計算中,應用程序必須優雅地容忍間歇性網絡連接。
這些挑戰可以通過不同的方式來解決。在這些場景中非常有用的一種解決方案是將容器鏡像直接緩存在集群工作節點上,這樣 Kubelet 不需要拉取這些鏡像,而是立即使用已經緩存在節點中的鏡像。在這篇博客中,我將解釋如何使用開源項目kube-fledged 在 Kubernetes 集群中構建和管理容器鏡像的緩存。
現有解決方案
在向您介紹 kube-fledged 之前,讓我簡要介紹一下解決此問題的現有解決方案。廣泛使用的方法是在集群內運行一個 Registry 鏡像。兩種廣泛使用的解決方案是
- 集群內自托管registry
- 直通緩存
在前一種解決方案中,本地注冊中心在 k8s集群中運行,并在容器運行時配置為鏡像注冊中心。
任何鏡像拉取請求都被定向到集群內registry。如果失敗,請求將被定向到主注冊中心。在后一種解決方案中,本地registry具有緩存功能。第一次拉取鏡像時,它會緩存在本地registry中。對鏡像的后續請求由本地registry提供服務。
現有解決方案的缺點
設置和維護本地registry鏡像會消耗大量計算資源和人力資源。
對于跨越多個區域的龐大集群,我們需要有多個本地registry鏡像。當應用程序實例跨越多個區域時,這會引入不必要的復雜性。您可能需要有多個部署清單,每個清單都指向該區域的本地 registry鏡像。
這些方法并不能完全解決Pod快速啟動的需求,因為從本地鏡像拉取鏡像仍然存在明顯的延遲。有幾個用例不能容忍這種延遲。
節點可能會失去與本地registry鏡像的網絡連接,因此 Pod 將卡住,直到連接恢復。
kube-fledged 概述
kube-fledged是一個 kubernetes插件或operator,用于直接在 kubernetes 集群的工作節點上創建和管理容器鏡像的緩存。
它允許用戶定義鏡像列表以及這些鏡像應該緩存(即拉取)到哪些工作節點上。因此,應用程序 pod幾乎立即啟動,因為不需要從registry中提取鏡像。kube-fledged提供了 CRUD API來管理鏡像緩存的生命周期,并支持多個可配置的參數來根據需要自定義功能。
https : //github.com/senthilrch/kube-fledged)
kube-fledged 被設計和構建為用于管理Kubernetes 中的鏡像緩存的通用解決方案。盡管主要用例是實現快速 Pod 啟動和擴展,但該解決方案支持多種用例,如下所述
用例
- 需要快速啟動的應用程序。例如,由于數據量激增,執行實時數據處理的應用程序需要快速擴展。
- 無服務器函數,因為它們需要對傳入的事件立即做出反應。
- 在邊緣設備上運行的 IoT 應用程序,因為邊緣設備和鏡像registry之間的網絡連接是間歇性的。
- 如果需要從私有registry中拉取鏡像,并且無法授予每個人從該registry中拉取鏡像的訪問權限,則可以在集群節點上提供這些鏡像。
- 如果集群管理員或操作員需要對應用程序進行升級,并希望事先驗證是否可以成功拉取新鏡像。
kube-fledged 的工作原理
Kubernetes允許開發人員通過自定義資源擴展 kubernetes api。kube-fledged定義了一個類型為“ ImageCache ”的自定義資源并實現了一個自定義控制器(名為 kubefledged-controller)。
kubefledged-controller負責管理鏡像緩存。用戶可以使用 kubectl命令來創建和刪除 ImageCache 資源。
kubefledged-controller有一個內置的 Image Manager 例程,負責拉取和刪除鏡像。使用 kubernetes job拉取或刪除鏡像。如果啟用,刷新工作者會定期刷新鏡像緩存。kubefledged-controller 在 ImageCache 資源的 status 字段中更新鏡像拉取、刷新和鏡像刪除的狀態。kubefledged-webhook-server負責驗證 ImageCache資源的字段。
如果您需要在集群中創建鏡像緩存,則只需ImageCache通過指定要拉取的鏡像列表以及nodeSelector. 將nodeSelector用于指定在其上的鏡像應該被高速緩存的節點。如果您希望鏡像緩存在集群的所有節點中,則省略nodeSelector. 當您將清單提交到集群時,API 服務器將向 kubefledged-webhook-server 發布驗證webhook事件。Webhook 服務器驗證cacheSpec的清單。在收到來自 webhook 服務器的成功響應后,API 服務器將 ImageCache 資源持久保存在etcd 中。這會觸發對kubefledged-controller 的 Informer 通知,該通知將請求排隊。該請求由鏡像緩存工作器接收,它創建多個鏡像拉取請求(每個節點每個鏡像一個請求)并將它們放入鏡像拉取/刪除隊列中。
這些請求由鏡像管理器例程處理。對于每個請求,鏡像管理器都會創建一個 k8s job,負責將鏡像拉入緩存。鏡像管理器會跟蹤它創建的job,一旦job完成,它就會將響應放在一個單獨的隊列中。然后鏡像緩存工作器聚合來自鏡像管理器的所有結果,最后更新 ImageCache資源的狀態部分。
kube-fledged 有一個刷新工作例程,它會定期運行以保持鏡像緩存刷新。如果它發現緩存中缺少任何鏡像(可能被 kubelet 的鏡像垃圾收集刪除了),它會重新將鏡像拉入緩存。帶有:latest標簽的鏡像總是在刷新周期中被重新拉出。默認情況下,刷新周期每5m. 用戶可以在部署 kube-fledged 時將其修改為不同的值或完全禁用自動刷新機制。還支持按需刷新機制,用戶可以使用該機制請求 kube-fledged 立即刷新鏡像緩存。
kube-fledged 支持的鏡像緩存操作
kube-fledged 支持以下鏡像緩存操作。所有這些操作都可以使用 kubectl 或通過直接向 Kubernetes API服務器提交 REST API 請求來執行:
- 創建鏡像緩存
- 修改鏡像緩存
- 刷新鏡像緩存
- 清除鏡像緩存
- 刪除鏡像緩存
支持的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:具有延遲拉動功能的快速容器鏡像分發插件
(https://github.com/containerd/stargz-snapshotter)
Uber Kraken:Kraken 是一個 P2P Docker registry,能夠在幾秒鐘內分發 TB數據
(https://github.com/uber/kraken)
Imagewolf:ImageWolf 是一種 PoC,它提供了一種將 Docker 鏡像加載到集群上的極快方式,從而可以更快地推送更新
https://github.com/ContainerSolutions/ImageWolf)
結論
有些應用程序和用例需要快速啟動和擴展。在這種情況下,從registry中拉取鏡像所帶來的延遲可能是不可接受的。此外,與registry的網絡連接可能不穩定/間歇性。不授予所有用戶訪問安全registry的權限可能是出于安全原因。Kube-fledged 是一個簡單而有用的解決方案,可以直接在集群工作節點上構建和管理容器鏡像的緩存