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

Kubernetes 1.28:在 Linux 上使用交換分割槽的 Beta 支援

1.22 版本引入了 Alpha 支援,用於為在 Linux 上執行的 Kubernetes 工作負載按節點配置交換記憶體使用。現在,在 1.28 版本中,Linux 節點上的交換支援已升級到 Beta 版,並帶來了許多新的改進。

在 1.22 版本之前,Kubernetes 不支援 Linux 系統上的交換記憶體。這是因為在涉及交換記憶體時,很難保證和核算 Pod 的記憶體利用率。因此,在 Kubernetes 的初始設計中,交換支援被認為超出了範圍,kubelet 的預設行為是在節點上檢測到交換記憶體時啟動失敗。

在 1.22 版本中,Linux 的交換功能最初以 Alpha 階段引入。這代表了一項重大進步,為 Linux 使用者提供了首次試用交換功能的機會。然而,作為一個 Alpha 版本,它並未完全開發,存在一些問題,包括對 cgroup v2 的支援不足、指標和摘要 API 統計資料不足、測試不充分等等。

Kubernetes 中的交換對廣泛的使用者有許多用例。因此,Kubernetes 專案中的節點特別興趣小組(SIG)投入了大量精力來支援 Linux 節點上的交換功能進入 Beta 階段。與 Alpha 版本相比,kubelet 對啟用交換執行的支援更加穩定和健壯,對使用者更加友好,並解決了許多已知的缺點。這次升級到 Beta 版是實現 Kubernetes 中完全支援交換目標的關鍵一步。

我該如何使用它?

在已配置交換記憶體的節點上使用交換記憶體,可以透過在 kubelet 上啟用 NodeSwap 特性門控來實現。此外,你必須停用 failSwapOn 配置設定,或者必須停用已棄用的 --fail-swap-on 命令列標誌。

可以配置 memorySwap.swapBehavior 選項來定義節點使用交換記憶體的方式。例如,

# this fragment goes into the kubelet's configuration file
memorySwap:
  swapBehavior: UnlimitedSwap

swapBehavior 的可用配置選項有:

  • UnlimitedSwap(預設):Kubernetes 工作負載可以使用其請求的任意數量的交換記憶體,最高可達系統限制。
  • LimitedSwap:Kubernetes 工作負載對交換記憶體的利用受到限制。只有 Burstable QoS 的 Pod 才允許使用交換。

如果未指定 memorySwap 的配置並且特性門控已啟用,則 kubelet 預設會應用與 UnlimitedSwap 設定相同的行為。

請注意,NodeSwap 僅支援 cgroup v2。對於 Kubernetes v1.28,不再支援將交換與 cgroup v1 一起使用。

使用 kubeadm 安裝一個啟用交換的叢集

開始之前

此演示要求安裝 kubeadm 工具,請遵循 kubeadm 安裝指南中的步驟。如果節點上已啟用交換,則可以繼續建立叢集。如果未啟用交換,請參閱提供的說明以啟用交換。

建立交換檔案並開啟交換

我將演示建立 4GiB 的未加密交換。

dd if=/dev/zero of=/swapfile bs=128M count=32
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
swapon -s # enable the swap file only until this node is rebooted

要在啟動時啟用交換檔案,請將類似 /swapfile swap swap defaults 0 0 的行新增到 /etc/fstab 檔案中。

設定一個使用啟用交換節點的 Kubernetes 叢集

為了更清楚地說明,這裡是一個啟用交換的叢集的示例 kubeadm 配置檔案 kubeadm-config.yaml

---
apiVersion: "kubeadm.k8s.io/v1beta3"
kind: InitConfiguration
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
failSwapOn: false
featureGates:
  NodeSwap: true
memorySwap:
  swapBehavior: LimitedSwap

然後使用 kubeadm init --config kubeadm-config.yaml 建立一個單節點叢集。在 init 期間,會有一個警告,提示節點上已啟用交換,以防 kubelet 的 failSwapOn 設定為 true。我們計劃在未來的版本中移除此警告。

使用 LimitedSwap 時如何確定交換限制?

交換記憶體的配置,包括其限制,是一個重大的挑戰。它不僅容易配置錯誤,而且作為一個系統級屬性,任何配置錯誤都可能危及整個節點,而不僅僅是某個特定的工作負載。為了降低這種風險並確保節點的健康,我們在 Beta 版的交換功能中實現了限制的自動配置。

使用 LimitedSwap 時,不屬於 Burstable QoS 分類的 Pod(即 BestEffort/Guaranteed QoS Pods)被禁止使用交換記憶體。BestEffort QoS Pods 表現出不可預測的記憶體消耗模式,並且缺乏關於其記憶體使用的資訊,這使得難以確定一個安全的交換記憶體分配。相反,Guaranteed QoS Pods 通常用於依賴工作負載指定的精確資源分配的應用程式,記憶體需要立即可用。為了維持上述安全性和節點健康保證,當 LimitedSwap 生效時,這些 Pod 不允許使用交換記憶體。

在詳細說明交換限制的計算之前,有必要定義以下術語:

  • nodeTotalMemory:節點上可用的物理記憶體總量。
  • totalPodsSwapAvailable:節點上可供 Pod 使用的交換記憶體總量(一些交換記憶體可能為系統使用而保留)。
  • containerMemoryRequest:容器的記憶體請求。

交換限制配置為:(containerMemoryRequest / nodeTotalMemory) × totalPodsSwapAvailable

換句話說,一個容器能夠使用的交換量與其記憶體請求、節點的總物理記憶體以及節點上可供 Pod 使用的總交換記憶體量成正比。

需要注意的是,對於 Burstable QoS Pods 中的容器,可以透過將記憶體請求指定為等於記憶體限制來選擇不使用交換。以這種方式配置的容器將無法訪問交換記憶體。

它是如何工作的?

人們可以設想在節點上使用交換的多種可能方式。當交換在節點上已經配置並可用時,SIG Node 提議 kubelet 應該能夠被配置成:

  • 它可以在交換開啟的情況下啟動。
  • 預設情況下,它將指示容器執行時介面(Container Runtime Interface)為 Kubernetes 工作負載分配零交換記憶體。

節點上的交換配置透過 KubeletConfiguration 中的 memorySwap 向叢集管理員公開。作為叢集管理員,你可以透過設定 memorySwap.swapBehavior 來指定節點在存在交換記憶體時的行為。

kubelet 利用 CRI(容器執行時介面)API 來指示 CRI 配置特定的 cgroup v2 引數(例如 memory.swap.max),以實現容器所需的交換配置。然後,CRI 負責將這些設定寫入容器級別的 cgroup。

如何監控交換?

Alpha 版本的一個顯著缺陷是無法監控和內省交換使用情況。這個問題在 Kubernetes 1.28 中引入的 Beta 版本中得到了解決,現在它提供了通過幾種不同方法監控交換使用情況的能力。

Beta 版本的 kubelet 現在收集節點級指標統計資料,可以透過 /metrics/resource/stats/summary kubelet HTTP 端點訪問。這使得能夠直接查詢 kubelet 的客戶端在使用 LimitedSwap 時可以監控交換使用情況和剩餘交換記憶體。此外,cadvisor 中增加了一個 machine_swap_bytes 指標,以顯示機器的總物理交換容量。

注意事項

系統上可用交換會降低可預測性。交換的效能比常規記憶體差,有時差幾個數量級,這可能導致意外的效能迴歸。此外,交換會改變系統在記憶體壓力下的行為。由於啟用交換允許 Kubernetes 中的工作負載使用更多無法可預測地核算的記憶體,這也增加了“吵鬧鄰居”和意外打包配置的風險,因為排程器無法核算交換記憶體的使用情況。

啟用交換記憶體的節點的效能取決於底層的物理儲存。當使用交換記憶體時,在 I/O 操作每秒(IOPS)受限的環境中(例如具有 I/O 節流的雲虛擬機器),與固態驅動器或 NVMe 等更快的儲存介質相比,效能會顯著下降。

因此,我們不主張對受效能限制的工作負載或環境使用交換記憶體。此外,建議使用 LimitedSwap,因為這能顯著減輕對節點構成的風險。

叢集管理員和開發人員在生產場景中使用交換之前,應對其節點和應用程式進行基準測試,並且我們需要你的幫助來完成這項工作!

安全風險

在未加密的系統上啟用交換會帶來安全風險,因為關鍵資訊,例如代表 Kubernetes Secret 的卷,可能會被交換到磁碟上。如果未經授權的個人獲得對磁碟的訪問許可權,他們可能會獲取這些機密資料。為了降低這種風險,Kubernetes 專案強烈建議你加密交換空間。然而,處理加密交換不在 kubelet 的範圍之內;相反,這是一個通用的作業系統配置問題,應該在該級別上解決。管理員有責任配置加密交換以減輕此風險。

此外,如前所述,使用 LimitedSwap 時,使用者可以選擇透過將記憶體請求指定為等於記憶體限制來完全停用容器的交換使用。這將阻止相應的容器訪問交換記憶體。

展望未來

Kubernetes 1.28 版本為 Linux 節點引入了對交換記憶體的 Beta 支援,我們將繼續努力使該功能達到正式釋出(General Availability)。我希望這將包括:

  • 新增從 kubelet 在主機上檢測到的交換中設定系統保留量的能力。
  • 增加透過 cgroups 在 Pod 級別控制交換消耗的支援。
    • 這一點仍在討論中。
  • 收集測試使用者案例的反饋。
    • 我們將考慮為交換引入新的配置模式,例如為工作負載設定節點範圍的交換限制。

我如何瞭解更多資訊?

你可以檢視當前關於在 Kubernetes 中使用交換的文件

要獲取更多資訊、協助測試並提供反饋,請參閱 KEP-2400 及其設計提案

我如何參與?

我們隨時歡迎你的反饋!SIG Node 定期開會,並可以透過 Slack(頻道 #sig-node)或 SIG 的郵件列表聯絡到。還有一個專門討論交換的 Slack 頻道:#sig-node-swap

如果你想提供幫助或有進一步問題,請隨時聯絡我,Itamar Holder(Slack 和 GitHub 上的 @iholder101)。