元鉴
返回中文阅读流

Kubernetes Blog

Kubernetes v1.36:控制器陈旧性缓解与可观测性

Kubernetes 控制器中的陈旧性问题影响众多控制器,并可能以微妙方式影响控制器行为。通常直到为时已晚,即生产环境中的控制器已执行错误操作后,人们才会发现因控制器作者的某些底层假设,陈旧性已成为问题。陈旧性引发的问题包括:控制器执行错误操作、该行动时未行动,以及行动耗时过长。我很高兴宣布 Kubernetes v1.36 包含新功能 t

中文内容

已翻译official company source英文原文2026-04-28

Kubernetes v1.36:控制器的陈旧性缓解与可观测性

By Michael Aspinwall (Google) | Tuesday, April 28, 2026

Kubernetes 控制器中的陈旧性是一个影响许多控制器的问题,并且可能以微妙的方式影响控制器行为。通常直到为时已晚,也就是生产环境中的控制器已经采取了错误操作之后,才会发现由于控制器作者所做的某些底层假设,陈旧性成了一个问题。由陈旧性引发的一些问题包括:控制器采取错误操作、控制器在应当采取操作时没有采取操作,以及控制器花费过长时间才采取操作。我很高兴地宣布,Kubernetes v1.36 包含了一些新功能,有助于缓解控制器中的陈旧性,并为控制器行为提供更好的可观测性。

什么是陈旧性?

控制器中的陈旧性源于控制器缓存内部对现实状态的过时视图。为了提供快速的用户体验,控制器通常会维护一个本地缓存,用于保存集群的状态。该缓存通过监听 Kubernetes API 服务器中控制器所关注对象的变更来填充。当控制器需要采取行动时,它会首先检查自己的缓存,以确认是否拥有最新信息。如果没有,它随后会通过监听 API 服务器中控制器所关注对象的变更来更新其缓存。这个过程称为调谐。

然而,在某些情况下,控制器的缓存可能会过时。例如,如果控制器重新启动,它需要通过监听 API 服务器中控制器所关注对象的变更来重建其缓存。在此期间,控制器的缓存将是过时的,并且无法采取行动。此外,如果 API 服务器宕机,控制器的缓存将无法更新,也将无法采取行动。这些只是控制器缓存可能过时的一些示例。

1.36 中的改进

Kubernetes v1.36 在 client-go 以及 kube-controller-manager 中高竞争控制器的实现方面都包含了改进,并且这些实现使用了 client-go 的这些改进。

client-go 改进

在 client-go 中,该项目新增了原子 FIFO 处理(特性门控名称为 AtomicFIFO),它构建在现有 FIFO 队列实现之上。新方法允许队列以原子方式处理批量接收的操作,例如 informer 用于填充其缓存的 list 操作所返回的初始对象集合。这可确保队列始终处于一致状态,即使事件乱序到达也是如此。在此之前,事件会按照接收顺序被添加到队列中,这可能导致缓存处于不一致状态,无法准确反映集群的状态。

通过这一变更,现在可以确保队列始终处于一致状态,即使事件乱序到达也是如此。为了利用这一点,使用 client-go 的客户端现在可以内省缓存,以确定控制器缓存已看到的最新资源版本。这是通过在 Store 接口上新添加的函数 LastStoreSyncResourceVersion() 实现的。该函数是 kube-controller-manager 中过期缓解功能的基础。

kube-controller-manager 改进

在 kube-controller-manager 中,v1.36 版本新增了让 4 个不同控制器使用这一新功能的能力。这些控制器是:

  1. DaemonSet 控制器
  2. StatefulSet 控制器
  3. ReplicaSet 控制器
  4. Job 控制器

这些控制器都作用于 Pod,而在大多数情况下,Pod 是集群中竞争最激烈的资源。这些变更对这些控制器默认启用,并且可以通过将特定控制器对应的功能门控 StaleControllerConsistency<API type> 设置为 false 来禁用。例如,要为 DaemonSet 控制器禁用该功能,可以将功能门控 StaleControllerConsistencyDaemonSet 设置为 false。

启用相关功能门控后,控制器会在采取操作前先检查缓存的最新资源版本。如果缓存的最新资源版本低于控制器已为其尝试协调的对象写入 API 服务器的版本,控制器将不会采取操作。这是因为控制器的缓存已过期,并且没有关于集群状态的最新信息。

供 informer 作者使用

使用 client-go 的 informer 作者也可以立即利用这些改进。请参阅 ReplicaSet informer 中如何使用此功能的示例。此 PR 展示了如何使用这一新功能,在采取操作之前检查 informer 的缓存是否已过时。client-go 库提供了一个 ConsistencyStore 数据结构,用于查询存储,并将缓存的最新资源版本与对象的已写入资源版本进行比较。

ReplicaSet 控制器会同时跟踪 ReplicaSet 的资源版本以及该 ReplicaSet 管理的 Pod 的资源版本。对于某个特定的 ReplicaSet,它会跟踪该 ReplicaSet 拥有的 Pod 的最新已写入资源版本,以及对 ReplicaSet 本身的任何写入。如果缓存的最新资源版本低于控制器已为其尝试调谐的对象写入 API server 的资源版本,控制器将不会采取操作。这是因为控制器的缓存已过时,并且没有关于集群状态的最新信息。

informer 作者可以使用 ConsistencyStore 来跟踪 informer 所关注对象的最新资源版本。它提供 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)

	// EnsureReady returns true if the cache is up to date for the given object.
	// It is used prior to reconciliation to decide whether to reconcile or not.
	EnsureReady(namespacedName types.NamespacedName) bool

	// Clear removes the given object from the consistency store.
	// It is used when an object is deleted.
	Clear(namespacedName types.NamespacedName, uid types.UID)
}
  1. WroteAt:当控制器向 API 服务器写入某个对象时,会调用此函数。它用于记录控制器已写入 API 服务器的该对象的最新资源版本。owningObj 是控制器正在协调的对象,uid 是该对象的 UID。resource version 和 GroupResource 是控制器已写入 API 服务器的对象的资源版本和 GroupResource。该对象不会被显式跟踪,因为控制器只关心等待追上已写入对象的最新资源版本。
  2. EnsureReady:控制器调用此函数以确保该对象的缓存是最新的。它在协调之前使用,用于决定是否进行协调。如果该对象的缓存是最新的,则返回 true;否则返回 false。它将使用 WroteAt 提供的信息来判断缓存是否为最新。
  3. Clear:当对象被删除时,控制器会调用此函数。它用于将该对象从一致性存储中移除。这主要用于在对象被删除时进行清理,以防止一致性存储无限增长。

UID 用于区分具有相同名称的不同对象,例如某个对象被删除后又被重新创建的情况。EnsureReady 不需要它,因为一致性存储只关注追赶到该对象的最新资源版本,而不是特定对象。它主要用于确保控制器不会在对象以新的 UID 重新创建时删除该对象的条目。

借助这 3 个函数,informer 作者可以在其控制器中实现陈旧性缓解。

可观测性

除了陈旧性缓解功能外,Kubernetes 项目还在 1.36 中向 kube-controller-manager 添加了相关检测指标。这些指标也默认启用,并使用同一组功能门控进行控制。

指标

以下 alpha 指标已在 1.36 中添加到 kube-controller-manager:

stale_sync_skips_total:控制器因缓存过期而跳过同步的次数。此指标会针对每个使用过期缓解功能的控制器公开,并带有该控制器的子系统。

该指标由 kube-controller-manager 指标端点公开,可用于监控控制器的健康状况。

除了这一指标之外,client-go 还会发出一些指标,用于通过 informer 的子系统暴露每个共享 informer 的最新资源版本。这使你能够查看每个 informer 的最新资源版本,并据此判断控制器的缓存是否已过期,尤其适合与 API server 的资源版本进行比较。

该指标名为 store_resource_version,并将 Group、Version 和 Resource 作为标签。

接下来是什么?

Kubernetes SIG API Machinery 很高兴继续推进这一功能,并希望未来将其带给更多控制器。我们也很希望听到你对这一功能的反馈。请在下方评论中告诉我们你的想法,或在 Kubernetes GitHub 仓库中提交 issue。

我们也在与 controller-runtime 合作,为所有使用 controller-runtime 构建的控制器启用这套语义。这将使任何使用 controller-runtime 构建的控制器都能获得“读取自己的写入”的好处,而无需自行实现该逻辑。

  • ← 上一篇
  • 下一篇 →

原文标题

Kubernetes v1.36: Staleness Mitigation and Observability for Controllers