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

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、密碼或磁碟區。這需要大量頻寬才能存取 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 的 volume mount timeout。我們建議叢集操作員將 kubeAPIQPS 提高到 20,將 kubeAPIBurst 提高到 40,尤其是在使用裸機節點的情況下。

更多詳細資訊可以在 KEP https://kep.k8s.io/1040 和 pull request #116121 中找到。

事件觸發的容器狀態更新

Evented PLEG (PLEG 是「Pod Lifecycle Event Generator」的縮寫) 在 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 設定較低的上限,從而增加回收壓力。增加此因子會減少回收壓力。預設值最初為 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 的職責範圍。