协会地址:上海市长宁区古北路620号图书馆楼309-313室
Kubernetes v1.36:控制器的陈旧性缓解与可观测性
原文链接:https://kubernetes.io/blog/2026/04/28/kubernetes-v1-36-staleness-mitigation-for-controllers/
Kubernetes 控制器中的过时(staleness) 问题会影响许多控制器,并以细微的方式影响控制器的行为。通常,直到生产环境中的控制器已经执行了错误操作、为时已晚时,才会发现由于控制器作者所做的某些底层假设而导致的过时问题。过时引起的问题包括:控制器执行错误操作、控制器在应该操作时不操作,以及控制器操作耗时过长。我很高兴地宣布,Kubernetes v1.36 包含了有助于缓解控制器过时问题,并提供更好控制器行为可观测性的新特性。
什么是过时(staleness)?
控制器的过时源于控制器缓存中对世界状态的过时视图。为了提供快速用户体验,控制器通常会维护集群状态的本地缓存。该缓存通过监听 Kubernetes API 服务器对控制器关心的对象所做的更改来填充。当控制器需要执行操作时,它会首先检查缓存是否拥有最新信息。如果没有,它会通过监听 API 服务器上控制器关心的对象更改来更新缓存。这个过程称为调谐(reconciliation)。
然而,在某些情况下,控制器的缓存可能已经过时。例如,如果控制器重启,它需要通过监听 API 服务器上控制器关心的对象更改来重建缓存。在此期间,控制器的缓存将是过时的,无法执行操作。此外,如果 API 服务器宕机,控制器的缓存将不会更新,也无法执行操作。这些只是控制器缓存可能过时的几个例子。
1.36 中的改进
Kubernetes v1.36 在 client-go 以及 kube-controller-manager 中高争用控制器的实现中均包含了改进,这些控制器使用了 client-go 的改进。
client-go 改进
在 client-go 中,项目新增了原子性 FIFO 处理(atomic FIFO processing)(特性门控名称为 AtomicFIFO),它基于现有的 FIFO 队列实现。新方法允许队列原子性地处理批量接收的操作,例如 Informer 用来填充缓存的 list 操作中的初始对象集合。这确保了队列始终处于一致状态,即使事件顺序错乱。在此之前,事件按接收顺序添加到队列中,可能导致缓存处于不一致状态,无法准确反映集群状态。
通过这一更改,您现在可以确保队列始终处于一致状态,即使事件顺序错乱。要利用此功能,使用 client-go 的客户端现在可以检查缓存,以确定控制器缓存所看到的最新资源版本。这是通过新添加的函数 LastStoreSyncResourceVersion() 实现的,该函数在 Store 接口中实现,详情请见此处。该函数是 kube-controller-manager 中过时缓解特性的基础。
kube-controller-manager 改进
在 kube-controller-manager 中,v1.36 版本已为 4 个不同的控制器添加了使用此新功能的能力。这些控制器是:
- DaemonSet 控制器
- StatefulSet 控制器
- ReplicaSet 控制器
- Job 控制器
这些控制器都作用于 Pod,而在大多数情况下 Pod 是集群中争用最高的对象。这些控制器默认启用此更改,可以通过为要禁用的特定控制器将特性门控 StaleControllerConsistency<API type> 设置为 false 来禁用。例如,要为 DaemonSet 控制器禁用该特性,可设置特性门控 StaleControllerConsistencyDaemonSet 为 false。
当相关特性门控启用时,控制器在采取操作之前会首先检查缓存的最新资源版本。如果缓存的最新资源版本低于控制器已写入 API 服务器、并正在尝试调谐的对象的资源版本,则控制器不会采取操作。这是因为控制器的缓存已经过时,没有关于集群状态的最新信息。
供 Informer 作者使用
使用 client-go 的通知器(informer)作者也可以立即利用这些改进。查看如何在 ReplicaSet 通知器 中使用此功能的示例。该 PR 展示了如何使用新功能在采取操作前检查通知器的缓存是否过时。client-go 库提供了一个 ConsistencyStore 数据结构,用于查询存储并将缓存的最新资源版本与对象的已写入资源版本进行比较。
ReplicaSet 控制器会跟踪 ReplicaSet 的资源版本以及该 ReplicaSet 管理的 Pod 的资源版本。对于特定的 ReplicaSet,它会跟踪该 ReplicaSet 拥有的 Pod 的最新写入资源版本,以及对 ReplicaSet 本身的任何写入。如果缓存的最新资源版本低于控制器为正在尝试协调的对象写入 API 服务器的版本,则控制器不会采取操作。这是因为控制器的缓存已过时,它没有关于集群状态的最新信息。
通知器作者可以使用 ConsistencyStore 来跟踪通知器所关心的对象的最新资源版本。它提供了 3 个主要函数:
type ConsistencyStore interface {
// WroteAt records that the given object was written at the given resource version.
WroteAt(owningObj runtime.Object, uid types.UID, groupResource schema.GroupResource, resourceVersion string)
```go
// EnsureReady 如果缓存对于给定对象是最新的,则返回 true。
// 在协调之前使用,以决定是否进行协调。
EnsureReady(namespacedName types.NamespacedName) bool
// Clear 从一致性存储中移除给定对象。
// 当对象被删除时使用。
Clear(namespacedName types.NamespacedName, uid types.UID)
}
WroteAt:当控制器为某个对象向 API 服务器写入时,会调用此函数。它用于记录控制器已写入 API 服务器的该对象的最新资源版本(resource version)。owningObj是控制器正在协调的对象,uid是该对象的 UID。资源版本和 GroupResource 是控制器已写入 API 服务器的对象的资源版本和组资源(GroupResource)。该对象不会被显式跟踪,因为控制器只关心等待追上已写入对象的最新资源版本。EnsureReady:控制器调用此函数以确保缓存对于该对象是最新的。它在协调之前使用,以决定是否进行协调。如果缓存对于该对象是最新的,则返回 true,否则返回 false。它将使用WroteAt提供的信息来判断缓存是否最新。Clear:当对象被删除时,控制器调用此函数。它用于从一致性存储中移除该对象。这主要用于对象删除时的清理,以防止一致性存储无限增长。
UID 用于区分具有相同名称的不同对象,例如当对象被删除然后重新创建时。EnsureReady 不需要 UID,因为一致性存储只关心追上对象的最新资源版本,而不关心具体是哪个对象。UID 主要用于确保当对象以新 UID 重新创建时,控制器不会删除该对象的条目。
有了这三个函数,通知器(informer)作者可以在其控制器中实现陈旧性缓解(staleness mitigation)。
可观测性(Observability)
除了陈旧性缓解功能外,Kubernetes 项目还在 1.36 版本中为 kube-controller-manager 添加了相关的仪表化(instrumentation)。这些指标也默认启用,并通过同一组特性门控(feature gates)进行控制。
指标(Metrics)
以下 Alpha 指标 已在 1.36 版本中添加到 kube-controller-manager:
stale_sync_skips_total:控制器因缓存陈旧而跳过同步的次数。该指标针对每个使用陈旧性缓解功能的控制器暴露,并带有该控制器的子系统(subsystem)。
该指标通过 kube-controller-manager 的指标端点暴露,可用于监控控制器的健康状况。
与此指标一起,client-go 还会发出指标,这些指标暴露每个共享通知器(shared informer)的最新资源版本,并带有该通知器的子系统。这使你可以查看每个通知器的最新资源版本,并据此判断控制器的缓存是否陈旧,尤其适合与 API 服务器的资源版本进行对比。
该指标名为 store_resource_version,并带有 Group、Version 和 Resource 作为标签。
下一步计划?
Kubernetes SIG API Machinery 很高兴能继续开发此功能,并希望未来将其推广到更多控制器中。我们也期待听到您对此功能的反馈。请在下方评论中告诉我们您的想法,或通过 Kubernetes GitHub 仓库提交 issue。
我们还在与 controller-runtime 合作,为所有使用 controller-runtime 构建的控制器启用这组语义。这将使任何使用 controller-runtime 构建的控制器都能获得“读取自身写入”(read your own writes)的好处,而无需自行实现该逻辑。







