本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
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)。