本文发布已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已失效。
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 limit of Parallel Image Pulls (KEP-3673)。
提高 kubelet 的默认 API 每秒查询数限制
为了改进节点上存在多个 Pod,特别是在突然扩缩容场景下的 Pod 启动速度,Kubelet 需要同步 Pod 状态并准备 ConfigMaps、Secrets 或 Volumes。这需要大量的带宽来访问 kube-apiserver。
在 v1.27 之前的版本中,默认的 kubeAPIQPS
是 5,kubeAPIBurst
是 10。然而,v1.27 中的 kubelet 已将这些默认值分别增加到 50 和 100,以在 Pod 启动期间获得更好的性能。值得注意的是,这并不是我们提高 Kubelet API QPS 限制的唯一原因。
- 现在它有可能受到很大的限制(默认 QPS = 5)
- 在大型集群中,由于数量众多,它们无论如何都会产生显著的负载
- 它们有专用的 PriorityLevel 和 FlowSchema,我们可以轻松控制
之前,在节点上运行超过 50 个 Pod 时,我们在 Pod 启动期间经常遇到 kubelet 上的 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 设置较低的 high 限制,从而增加回收压力。增加此因子会减少回收压力。默认值最初为 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 的职责范围。