Kubernetes Operator控制器自定义指标删除功能失效求助
Kubernetes Operator自定义指标删除失效的排查与解决
排查方向与解决方案
1. 验证标签匹配的一致性
删除指标时必须完全匹配注册时使用的所有标签键和值,任何拼写、大小写或维度缺失都会导致删除失败:
- 检查注册指标时的标签定义,比如如果注册是:
那删除时必须包含所有3个标签,不能只传custom_metric_name.With(prometheus.Labels{ "cr_name": cr.Name, "namespace": cr.Namespace, "cluster": "default", })name和namespace。 - 直接查询Prometheus确认指标的实际标签:执行
curl http://<prometheus-addr>:9090/api/v1/query?query=custom_metric_name,对比返回的标签键值对和删除代码中的参数。
2. 确认指标实例的全局唯一性
如果custom_metric_name不是全局单例(比如在函数内局部初始化),删除操作会针对错误的指标实例生效,导致实际暴露的指标不受影响:
- 确保
custom_metric_name是全局变量,且只初始化一次:var custom_metric_name = prometheus.NewGaugeVec( prometheus.GaugeOpts{Name: "custom_metric_name"}, []string{"name", "namespace"}, ) - 初始化后立即注册到Prometheus:
prometheus.MustRegister(custom_metric_name)
3. 改用Finalizer处理删除逻辑
仅在errors.IsNotFound(err)分支处理删除不可靠——CR被删除时,Kubernetes会先标记DeletionTimestamp,此时CR还存在,直到所有Finalizer被移除。用Finalizer确保指标删除逻辑必执行:
func (r *cr) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { cr := &CR{} err := r.Get(ctx, req.NamespacedName, cr) if err != nil { if errors.IsNotFound(err) { return ctrl.Result{}, nil } return ctrl.Result{}, err } // 处理CR删除流程 if !cr.DeletionTimestamp.IsZero() { // 执行指标删除 DeleteMetric(cr, true) // 移除自定义Finalizer cr.Finalizers = slices.DeleteFunc(cr.Finalizers, func(f string) bool { return f == "cr.example.com/metric-cleanup" }) if err := r.Update(ctx, cr); err != nil { return ctrl.Result{}, err } return ctrl.Result{}, nil } // 为CR添加Finalizer(首次创建时) if !slices.Contains(cr.Finalizers, "cr.example.com/metric-cleanup") { cr.Finalizers = append(cr.Finalizers, "cr.example.com/metric-cleanup") if err := r.Update(ctx, cr); err != nil { return ctrl.Result{}, err } return ctrl.Result{Requeue: true}, nil } // 正常业务逻辑... return ctrl.Result{}, nil }
4. 修复Predicate的Delete事件过滤
如果使用Predicate,确保它不会拦截Delete事件:
// 配置Predicate,允许接收Delete事件 pred := predicates.NewPredicateFuncs(func(obj client.Object) bool { // 始终允许Delete事件 if obj.GetDeletionTimestamp() != nil { return true } // 其他事件的过滤逻辑 return true }) // 在SetupWithManager中使用 err = r.SetupWithManager(mgr, ctrl.NewControllerManagedBy(mgr). For(&CR{}). WithEventFilter(pred). // 其他子资源... )
5. 增加日志排查细节
在DeleteMetric中添加更详细的日志,验证删除操作的执行状态:
func DeleteMetric(cr *CR, condition bool) { l := logf.Log.WithName("CR Metric deletion") l.Info("Deleting metric for CR", "instance", cr.Name, "namespace", cr.Namespace) if condition { // 删除前检查指标是否存在 gauge := custom_metric_name.With(prometheus.Labels{ "name": cr.Name, "namespace": cr.Namespace, }) l.Info("Current metric value before deletion", "value", gauge.Get()) // 执行删除 custom_metric_name.Delete(prometheus.Labels{ "name": cr.Name, "namespace": cr.Namespace, }) // 删除后再次检查 l.Info("Metric exists after deletion?", "exists", gauge.Get() != 0) } }
内容的提问来源于stack exchange,提问作者unbox-us
相关产品推荐
相关产品推荐

