本文已发表一年多。较早的文章可能包含过时内容。请检查页面中的信息自发布以来是否已失效。

Kubernetes 1.28:Beta 支持在 Linux 上使用 swap

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 Node) 在 Beta 版中为支持 Linux 节点上的交换投入了大量精力。与 Alpha 版相比,kubelet 对启用交换运行的支持更加稳定和健壮,对用户更友好,并解决了许多已知缺点。这次升级到 Beta 版是朝着完全支持 Kubernetes 中的交换内存这一目标迈出的关键一步。

如何使用它?

已配置交换内存的节点上,可以通过激活 kubelet 上的 NodeSwap feature gate 来启用交换内存的使用。此外,你必须禁用 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 的配置但启用了 feature gate,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 创建单节点集群。在 init 过程中,会有一条警告提示节点上已启用交换内存,并且如果 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 应可配置为:

  • 它可以在启用交换时启动。
  • 它将指示容器运行时接口 (CRI) 默认不为 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 中的工作负载使用更多无法预测的内存,这也增加了吵闹的邻居和意外的打包配置的风险,因为调度器无法考虑交换内存的使用。

启用交换内存的节点的性能取决于底层物理存储。当使用交换内存时,在 IOPS 受限的环境中(例如带 I/O 限流的云虚拟机),性能将明显不如固态硬盘或 NVMe 等速度更快的存储介质。

因此,我们不建议对性能受限的工作负载或环境使用交换内存。此外,建议使用 LimitedSwap,因为这能显著减轻对节点造成的风险。

集群管理员和开发者在生产环境场景中使用交换内存之前应对其节点和应用进行基准测试,为此我们需要你的帮助

安全风险

在没有加密的系统上启用交换内存会带来安全风险,因为关键信息,例如代表 Kubernetes Secrets 的卷,可能会被换出到磁盘。如果未经授权的个人访问了磁盘,他们可能会获取这些机密数据。为了减轻此风险,Kubernetes 项目强烈建议你加密你的交换空间。然而,处理加密交换不在 kubelet 的范围之内;这是一个一般的操作系统配置问题,应在该级别处理。管理员有责任配置加密交换以减轻此风险。

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

展望未来

Kubernetes 1.28 版本引入了对 Linux 节点上交换内存的 Beta 支持,我们将继续努力使此功能达到正式可用状态。我希望这包括:

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

如何了解更多?

你可以查阅当前关于在 Kubernetes 中使用交换内存的文档

如需了解更多信息,并协助测试和提供反馈,请参阅KEP-2400 及其设计提案

如何参与?

随时欢迎你的反馈!SIG Node 定期开会,并且可以通过 Slack(频道 #sig-node)或 SIG 的邮件列表联系到。还有一个专门用于交换内存的 Slack 频道:#sig-node-swap

如果你想提供帮助或提出更多问题,请随时联系我,Itamar Holder(Slack 和 GitHub 上的 @iholder101)。