本文发布已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。

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 项目中的节点特别兴趣小组投入了大量精力来支持 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

要在启动时启动交换文件,请在 /etc/fstab 文件中添加类似 /swapfile swap swap defaults 0 0 的行。

设置一个使用启用交换内存节点的 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 创建一个单节点集群。在初始化期间,会有一个警告,提示节点上启用了交换内存,并且如果 kubelet failSwapOn 设置为 true。我们计划在未来的版本中删除此警告。

如何使用 LimitedSwap 确定交换限制?

交换内存的配置,包括其限制,提出了一个重大挑战。它不仅容易配置错误,而且作为系统级属性,任何配置错误都可能损害整个节点,而不仅仅是特定的工作负载。为了降低这种风险并确保节点的健康,我们在 Beta 版中实现了交换内存,并自动配置了限制。

使用 LimitedSwap 时,不属于 Burstable QoS 分类(即 BestEffort/Guaranteed Qos Pod)的 Pod 将被禁止使用交换内存。BestEffort QoS Pod 表现出不可预测的内存消耗模式,并且缺乏有关其内存使用情况的信息,因此很难确定交换内存的安全分配。相反,Guaranteed QoS Pod 通常用于依赖于工作负载指定的精确资源分配的应用程序,并且内存会立即可用。为了保持上述安全性和节点健康保证,当 LimitedSwap 生效时,不允许这些 Pod 使用交换内存。

在详细说明交换限制的计算之前,有必要定义以下术语

  • nodeTotalMemory:节点上可用的物理内存总量。
  • totalPodsSwapAvailable:节点上可供 Pod 使用的交换内存总量(某些交换内存可能保留给系统使用)。
  • containerMemoryRequest:容器的内存请求。

交换限制配置为:(containerMemoryRequest / nodeTotalMemory) × totalPodsSwapAvailable

换句话说,容器能够使用的交换内存量与其内存请求、节点的总物理内存以及节点上可供 Pod 使用的交换内存总量成正比。

需要注意的是,对于 Burstable QoS Pod 中的容器,可以通过指定等于内存限制的内存请求来选择不使用交换内存。以这种方式配置的容器将无法访问交换内存。

它是如何工作的?

关于节点上的交换内存使用,有许多可能的方式可以设想。当节点上已配置并可用交换内存时,SIG Node 提议 可以配置 kubelet,使其

  • 可以启动时启用交换内存。
  • 默认情况下,它将指示容器运行时接口为 Kubernetes 工作负载分配零交换内存。

节点上的交换内存配置通过 KubeletConfiguration 中的 memorySwap 向集群管理员公开。作为集群管理员,您可以通过设置 memorySwap.swapBehavior 来指定节点在存在交换内存时的行为。

kubelet 使用 CRI(容器运行时接口)API 来指示 CRI 配置特定的 cgroup v2 参数(例如 memory.swap.max),以便为容器启用所需的交换内存配置。然后,CRI 负责将这些设置写入容器级别的 cgroup。

如何监控交换内存?

Alpha 版本的一个显著缺陷是无法监控和内省交换内存的使用情况。这个问题已在 Kubernetes 1.28 中引入的 Beta 版本中得到解决,该版本现在提供了通过多种不同方法监控交换内存使用情况的功能。

kubelet 的 Beta 版本现在收集节点级指标统计数据,可以通过 /metrics/resource/stats/summary kubelet HTTP 端点访问。这允许可以直接查询 kubelet 的客户端在使用 LimitedSwap 时监控交换内存的使用情况和剩余交换内存。此外,cadvisor 中添加了 machine_swap_bytes 指标,以显示机器的总物理交换容量。

注意事项

在系统上启用交换内存会降低可预测性。交换内存的性能比普通内存差,有时甚至差几个数量级,这可能会导致意外的性能下降。此外,交换内存会改变系统在内存压力下的行为。由于启用交换内存允许 Kubernetes 中的工作负载使用更多无法预测的内存,因此还会增加噪声邻居和意外打包配置的风险,因为调度程序无法计算交换内存的使用情况。

启用交换内存的节点的性能取决于底层的物理存储。当交换内存正在使用时,在每秒 I/O 操作数 (IOPS) 受限的环境中,例如具有 I/O 节流的云虚拟机,与固态驱动器或 NVMe 等更快的存储介质相比,性能会明显更差。

因此,我们不提倡在受性能约束的工作负载或环境中使用交换内存。此外,建议使用 LimitedSwap,因为这可以显著降低对节点造成的风险。

集群管理员和开发人员应在生产场景中使用交换内存之前对其节点和应用程序进行基准测试,并且我们需要您的帮助

安全风险

在没有加密的系统上启用交换内存会带来安全风险,因为关键信息(例如表示 Kubernetes Secrets 的卷)可能会被交换到磁盘。如果未经授权的人员访问磁盘,他们可能会获得这些机密数据。为了降低这种风险,Kubernetes 项目强烈建议您加密交换空间。但是,处理加密交换内存不在 kubelet 的范围内;相反,这是一个通用的操作系统配置问题,应在该级别解决。管理员有责任提供加密的交换内存以降低这种风险。

此外,如前所述,使用 LimitedSwap 时,用户可以选择通过指定等于内存限制的内存请求来完全禁用容器的交换内存使用。这将阻止相应的容器访问交换内存。

展望未来

Kubernetes 1.28 版本引入了对 Linux 节点上的交换内存的 Beta 支持,我们将继续努力实现此功能的全面可用性。我希望这包括

  • 添加从 kubelet 在主机上检测到的交换内存中设置系统保留量的能力。
  • 添加通过 cgroups 控制 Pod 级别交换内存消耗的支持。
    • 这一点仍在讨论中。
  • 收集来自测试用例的反馈。
    • 我们将考虑为交换内存引入新的配置模式,例如工作负载的节点范围交换内存限制。

如何了解更多?

您可以查看当前关于使用 Kubernetes 的交换内存的文档

有关更多信息,以及协助测试和提供反馈,请参阅 KEP-2400 及其设计提案

如何参与?

欢迎您随时提供反馈!SIG Node 定期举行会议,并且可以通过 以下方式联系Slack(频道 #sig-node),或 SIG 的 邮件列表。 此外,还有一个专门用于交换分区的 Slack 频道,频道名为 #sig-node-swap

如果您想提供帮助或有其他问题,请随时联系我,Itamar Holder(在 Slack 和 GitHub 上的用户名是 @iholder101)。