如何防止重复协调呼叫

时间:2021-07-13 05:26:33

标签: kubernetes

我正在开发 Kubernetes 控制器。这个控制器的期望状态在 CRD-A 中被捕获,然后它创建一个部署和 statefulset 来实现实际状态。目前我正在使用服务器端申请来创建/更新这些部署和状态集。

控制器在 CRD-A 和部署 statefulset 上建立监视。这是为了确保如果部署/状态集发生变化,则 reconcile() 会收到通知并采取行动修复它。目前,reconcile() 总是调用服务器端应用来创建/更新,这会导致另一个监视事件(每个服务器端应用的资源版本更改)导致对 reconcile() 的重复/无限调用

我一直在考虑的一种方法是在部署/状态集上利用“生成”,即控制器将维护(k8s 对象 -> 生成)的内存映射,并在 reconcile() 上比较该映射中的值索引通知者缓存中存在的内容;你觉得这种方法有什么问题吗?是否有更好的替代方法来防止重复/无限 reconcile() 调用?

2 个答案:

答案 0 :(得分:1)

如果没有要应用的更改,一个想法可能是不应用对象。 这给您带来了如何检测对象是否已经是最新的问题,但很难判断这在您的情况下是否可行。

答案 1 :(得分:1)

理想情况下,如果您在服务器端应用中提供的对象未更改,则对象的生成和资源版本都不应更改。

但有时并非如此,请参阅此 github 问题:https://github.com/kubernetes/kubernetes/issues/95460

幸运的是,世代始终保持不变,所以是的,您可以通过向控制器添加 GenerationChangedPredicate 过滤器来利用此字段来避免协调死循环,如果世代不变,它将跳过协调,它通常与 LabelChangedPredicate 结合使用,当对象的标签没有改变时,它会过滤事件。

以下是使用这两个谓词设置控制器的方法:

ctrl.NewControllerManagedBy(mgr).
    For(&Object{}).
    Owns(&appsv1.StatefulSet{}).
    Owns(&appsv1.Deployment{}).
    // together with Server Side Apply
    // this predicates prevents meaningless reconcilations from being triggered
    WithEventFilter(predicate.Or(predicate.GenerationChangedPredicate{}, predicate.LabelChangedPredicate{})).
    Complete(r)