本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

Kubernetes 1.27:關於加速 Pod 啟動的更新

如何加速大型叢集中節點上的 Pod 啟動?這是叢集管理員可能面臨的常見問題。

這篇部落格文章重點介紹從 kubelet 側加速 Pod 啟動的方法。它不涉及 controller-manager 透過 kube-apiserver 建立 Pod 的時間,也不包括 Pod 的排程時間或在其上執行的 webhook 的時間。

我們在此提到了從 kubelet 的角度需要考慮的一些重要因素,但這並非詳盡無遺的列表。隨著 Kubernetes v1.27 的釋出,這篇部落格重點介紹了 v1.27 中有助於加速 Pod 啟動的重大變化。

並行拉取容器映象

拉取映象總是需要一些時間,更糟糕的是,預設情況下映象是序列拉取的。換句話說,kubelet 一次只向映象服務傳送一個映象拉取請求。其他映象拉取請求必須等到正在處理的請求完成後才能開始。

要啟用並行映象拉取,請在 kubelet 配置中將 serializeImagePulls 欄位設定為 false。當 serializeImagePulls 被停用時,映象拉取請求會立即傳送到映象服務,多個映象可以同時被拉取。

最大並行映象拉取數量將有助於保護你的節點免於因映象拉取而過載

我們在 kubelet 中引入了一項新功能,用於在節點級別設定並行映象拉取的數量限制。此限制規定了可以同時拉取的最大映象數量。如果映象拉取請求超出此限制,它將被阻塞,直到其中一個正在進行的映象拉取完成。在啟用此功能之前,請確保你的容器執行時的映象服務能夠有效處理並行映象拉取。

要限制同時進行的映象拉取數量,你可以配置 kubelet 中的 maxParallelImagePulls 欄位。透過將 maxParallelImagePulls 設定為值 n,最多隻能有 n 個映象被同時拉取。任何超出此限制的額外映象拉取都將等待,直到至少一個正在進行的拉取完成。

你可以在相關的 KEP 中找到更多詳細資訊:限制 Kubelet 並行映象拉取數量 (KEP-3673)。

提高了 kubelet 的預設 API 每秒查詢數限制

為了在節點上有多個 Pod 的場景中改善 Pod 啟動,特別是在突發擴容的情況下,kubelet 必須同步 Pod 狀態並準備 ConfigMap、Secret 或卷。這需要較大的頻寬來訪問 kube-apiserver。

在 v1.27 之前的版本中,預設的 kubeAPIQPS 是 5,kubeAPIBurst 是 10。然而,v1.27 中的 kubelet 已將這些預設值分別增加到 50 和 100,以在 Pod 啟動期間獲得更好的效能。值得注意的是,這並非我們提高 Kubelet API QPS 限制的唯一原因。

  1. 現在它有可能被嚴重節流(預設 QPS = 5)
  2. 在大型叢集中,由於數量眾多,它們無論如何都會產生巨大的負載
  3. 它們有專用的 PriorityLevel 和 FlowSchema,我們可以輕鬆控制

以前,我們經常在 Pod 啟動期間,在擁有超過 50 個 Pod 的節點上遇到 kubelet 的 volume mount timeout(卷掛載超時)問題。我們建議叢集運營商將 kubeAPIQPS 提高到 20,kubeAPIBurst 提高到 40,尤其是在使用裸金屬節點時。

更多細節可以在 KEP https://kep.k8s.io/1040 和 PR #116121 中找到。

事件觸發的容器狀態更新

Evented PLEG(PLEG 是“Pod 生命週期事件生成器”的縮寫)在 v1.27 中進入 Beta 階段。Kubernetes 為 kubelet 提供了兩種檢測 Pod 生命週期事件的方式,例如容器中最後一個程序關閉。在 Kubernetes v1.27 中,**基於事件的**機制已升級為 Beta 版,但預設仍為停用。如果你明確切換到基於事件的生命週期變化檢測,kubelet 能夠比依賴輪詢的預設方法更快地啟動 Pod。預設的輪詢生命週期變化的機制會增加明顯的開銷;這會影響 kubelet 並行處理不同任務的能力,並導致效能和可靠性問題。因此,我們建議你將節點切換為使用基於事件的 Pod 生命週期變化檢測。

更多細節可以在 KEP https://kep.k8s.io/3386從輪詢切換到基於 CRI 事件的容器狀態更新中找到。

如果需要,提高你的 Pod 資源限制

在啟動過程中,一些 Pod 可能會消耗大量的 CPU 或記憶體。如果 CPU 限制較低,這會顯著減慢 Pod 的啟動過程。為了改善記憶體管理,Kubernetes v1.22 在 kubelet 中引入了一個名為 MemoryQoS 的特性門控。此功能使 kubelet 能夠在容器、Pod 和 QoS 級別設定記憶體 QoS,以便在使用 cgroups v2 執行時提供更好的記憶體保護和質量保證。儘管它有好處,但如果 Pod 啟動時消耗大量記憶體,啟用此特性門控可能會影響 Pod 的啟動速度。

Kubelet 配置現在包含 memoryThrottlingFactor。此因子乘以記憶體限制或節點可分配記憶體,以設定 cgroupv2 的 memory.high 值來強制執行 MemoryQoS。降低此因子會為容器 cgroup 設定較低的 high 限制,從而增加回收壓力。增加此因子會減少回收壓力。預設值最初為 0.8,在 Kubernetes v1.27 中將變為 0.9。此引數調整可以減少此功能對 Pod 啟動速度的潛在影響。

更多細節可以在 KEP https://kep.k8s.io/2570 中找到。

還有什麼?

在 Kubernetes v1.26 中,新增了一個直方圖指標 pod_start_sli_duration_seconds,用於提供 Pod 啟動延遲 SLI/SLO 的詳細資訊。此外,kubelet 日誌現在將顯示更多關於 Pod 啟動相關時間戳的資訊,如下所示

Dec 30 15:33:13.375379 e2e-022435249c-674b9-minion-group-gdj4 kubelet[8362]: I1230 15:33:13.375359 8362 pod_startup_latency_tracker.go:102] "Observed pod startup duration" pod="kube-system/konnectivity-agent-gnc9k" podStartSLOduration=-9.223372029479458e+09 pod.CreationTimestamp="2022-12-30 15:33:06 +0000 UTC" firstStartedPulling="2022-12-30 15:33:09.258791695 +0000 UTC m=+13.029631711" lastFinishedPulling="0001-01-01 00:00:00 +0000 UTC" observedRunningTime="2022-12-30 15:33:13.375009262 +0000 UTC m=+17.145849275" watchObservedRunningTime="2022-12-30 15:33:13.375317944 +0000 UTC m=+17.146157970"

“使用掛載選項進行 SELinux 重打標”功能在 v1.27 中進入 Beta 階段。此功能透過使用正確的 SELinux 標籤掛載捲來加速容器啟動,而不是遞迴地更改捲上的每個檔案。更多細節可以在 KEP https://kep.k8s.io/1710 中找到。

要確定 Pod 啟動緩慢的原因,分析指標和日誌會很有幫助。可能影響 Pod 啟動的其他因素包括容器執行時、磁碟速度、節點上的 CPU 和記憶體資源。

SIG Node 負責確保快速的 Pod 啟動時間,而解決大型叢集中的問題也屬於 SIG Scalability 的職責範圍。