英文:
K8s Operator listen to secret change with event filter
问题
我们几个月前创建了一个使用kubebuilder运行良好的控制器。
几周前,我们向一个密钥添加了一个“监听器”,当密钥发生更改(密钥属性)时,应该调用reconcile函数。问题是它有时候工作,有时候不工作(你更改密钥应用它,但reconcile函数没有被调用),我们对于完全相同的密钥文件进行操作。
我们尝试了几天来找到根本原因,但没有成功(我们将k8s.io/client-go v0.23.4
更改为v0.22.3
,现在使用的是v0.22.1
,它才能正常工作)。有没有什么想法是什么问题?任何提示都会有帮助。或者有没有其他我们可以尝试的方法。
func (r *vtsReconciler) SetupWithManager(mgr ctrl.Manager) error {
manager := ctrl.NewControllerManagedBy(mgr).
For(&vts.str).
WithEventFilter(predicate.Or(predicate.AnnotationChangedPredicate{}))
manager = manager.Watches(&source.Kind{Type: &v1.Secret{}}, handler.EnqueueRequestsFromMapFunc(func(a client.Object) []reconcile.Request {
return r.SecretRequests.SecretFinder(a.GetName())
}))
return manager.Complete(r)
}
func (secm *SecretMapper) SecretFinder(name string) []reconcile.Request {
v := cli.ObjectKey{Name: name}
return secm.SecMap[v.String()]
}
英文:
We have created a few month ago controller which runs great using kubebuilder.
Few weeks ago we added a “listener” to a secret which when the secret is changing (secret properties)
The reconcile should be invoked, the problem is that it is sometimes working and sometimes not, (you change the secret apply it and the reconcile doesn’t happens) , we are doing it for the exact same secret file.
We tried few days to find the root cause without success, (we change the k8s.io/client-go v0.23.4
and also to v0.22.3
and now v0.22.1
that is only working.
Any idea what the issue could be? any hint will be helpful. or Any other way to do it that we can try out.
func (r *vtsReconciler) SetupWithManager(mgr ctrl.Manager) error {
manager := ctrl.NewControllerManagedBy(mgr).
For(&vts.str).
WithEventFilter(predicate.Or(predicate.AnnotationChangedPredicate{}))
manager = manager.Watches(&source.Kind{Type: &v1.Secret{}}, handler.EnqueueRequestsFromMapFunc(func(a client.Object) []reconcile.Request {
return r.SecretRequests.SecretFinder(a.GetName())
}))
return manager.Complete(r)
}
func (secm *SecretMapper) SecretFinder(name string) []reconcile.Request {
v := cli.ObjectKey{Name: name}
return secm.SecMap[v.String()]
}
答案1
得分: 4
最可能的问题是WithEventFilter
适用于控制器监视的所有对象。对于CRD,生成是自动递增的,但并不适用于所有资源类型。
从GenerationChangedPredicate文档中可以看到:
// 注意事项:
//
// * 假设生成仅在写入spec时递增,并不适用于所有API。
// 例如,对于Deployment对象,生成也会在写入metadata.annotations字段时递增。
// 对于除自定义资源之外的对象类型,请确保在写入时会触发生成递增的字段。
您可以通过创建或更新一个secret来检查这一点,您会发现没有设置生成(至少在我的本地k3d集群上没有)。
最可能的情况是在创建时它可以工作,因为最初控制器将会将现有资源与集群同步。
要解决这个问题,您可以使用以下代码:
func (r *vtsReconciler) SetupWithManager(mgr ctrl.Manager) error {
manager := ctrl.NewControllerManagedBy(mgr).
For(&vts.str, WithPredicates(predicate.Or(predicate.GenerationChangedPredicate{}, predicate.AnnotationChangedPredicate{}))).
manager = manager.Watches(&source.Kind{Type: &v1.Secret{}}, handler.EnqueueRequestsFromMapFunc(func(a client.Object) []reconcile.Request {
return r.SecretRequests.FindForSecret(a.GetNamespace(), a.GetName())
}))
return manager.Complete(r)
}
这样可以将谓词应用于您的自定义资源。
英文:
Most likely the issue is that the WithEventFIlter
applies to all watched objects by the controller. The generation is auto-incremented for CRDs, but this doesn't hold for all resource types.
From the GenerationChangedPredicate docs:
// Caveats:
//
// * The assumption that the Generation is incremented only on writing to the spec does not hold for all APIs.
// E.g For Deployment objects the Generation is also incremented on writes to the metadata.annotations field.
// For object types other than CustomResources be sure to verify which fields will trigger a Generation increment when they are written to.
You can check this by creating a secret / updating a secret you will see that there is no generation set (at least not on my local k3d cluster).
Most likely it works for the creation as initially the controller will sync existing resources with the cluster.
To solve it you can use:
func (r *vtsReconciler) SetupWithManager(mgr ctrl.Manager) error {
manager := ctrl.NewControllerManagedBy(mgr).
For(&vts.str, WithPredicates(predicate.Or(predicate.GenerationChangedPredicate{}, predicate.AnnotationChangedPredicate{}))).
manager = manager.Watches(&source.Kind{Type: &v1.Secret{}}, handler.EnqueueRequestsFromMapFunc(func(a client.Object) []reconcile.Request {
return r.SecretRequests.FindForSecret(a.GetNamespace(), a.GetName())
}))
return manager.Complete(r)
}
which should apply the predicates only to your custom resource.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论