You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kubernetes client-go Informer监听Deployment镜像变更生产集群失效求助

问题描述

作为Golang新手,我开发了一款部署在K8s集群的应用,核心需求是检测Deployment的镜像变更。使用client-go Informer实现的代码在本地K3s集群能正常捕获镜像变更,但部署到生产集群后,Informer完全无法识别镜像变更,日志仅输出"Starting stopper"。已验证容器内可通过curl获取Deployment资源,ClusterRole、ClusterRoleBinding及ServiceAccount配置与本地环境完全一致,目前无法定位问题,请求帮助排查。

代码片段
func main() {
    clientset, err := createKubernetesClient()
    if err != nil {
        log.Fatalf("Error creating Kubernetes client: %v", err)
    }

    gitlabClient, err := createGitLabClient()
    if err != nil {
        log.Fatalf("Failed to create GitLab client: %v", err)
    }

    updateGitLabFileAndFetchProject(clientset, gitlabClient)

    factory := informers.NewSharedInformerFactoryWithOptions(clientset, 0)
    informer := factory.Apps().V1().Deployments().Informer()
    stopper := make(chan struct{})
    defer close(stopper)
    defer runtime.HandleCrash()
    informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
        UpdateFunc: func(oldObj, newObj interface{}) {
            onUpdate(clientset, gitlabClient, oldObj, newObj)
        },
        AddFunc: func(obj interface{}) {
            onAdd(clientset, gitlabClient, obj)
        },
    })
    go informer.Run(stopper)
    fmt.Println("Starting stopper")
    if !cache.WaitForCacheSync(stopper, informer.HasSynced) {
        runtime.HandleError(fmt.Errorf("Timed out waiting for caches to sync"))
        return
    }
    <-stopper
}

func onUpdate(clientset *kubernetes.Clientset, gitlabClient *gitlab.Client, oldObj, newObj interface{}) {
    oldDepl := oldObj.(*v1.Deployment)
    newDepl := newObj.(*v1.Deployment)

    updateMutex.Lock()
    defer updateMutex.Unlock()

    for oldContainerID := range oldDepl.Spec.Template.Spec.Containers {
        for newContainerID := range newDepl.Spec.Template.Spec.Containers {
            if oldDepl.Spec.Template.Spec.Containers[oldContainerID].Name == newDepl.Spec.Template.Spec.Containers[newContainerID].Name {
                if oldDepl.Spec.Template.Spec.Containers[oldContainerID].Image != newDepl.Spec.Template.Spec.Containers[newContainerID].Image {
                    fmt.Printf("OLD DEPLOYMENT %s IN NS %s UPDATED FROM IMAGE %s to NEW DEPLOYMENT %s IN NS %s TO IMAGE %s", oldDepl.Name, oldDepl.Namespace,
                        oldDepl.Spec.Template.Spec.Containers[oldContainerID].Image, newDepl.Name, newDepl.Namespace, newDepl.Spec.Template.Spec.Containers[newContainerID].Image)

                    updateGitLabFileForSingleDeployment(clientset, gitlabClient, newDepl.Name, newDepl.Namespace, newDepl.Spec.Template.Spec.Containers[newContainerID].Image)
                }
            }
        }
    }
}
排查建议
  • 确认Informer监听范围:当前代码未指定命名空间参数,默认监听所有命名空间。检查生产集群目标Deployment所在命名空间是否正常,再次验证ClusterRole是否包含list、watch权限。若只需监听特定命名空间,修改Factory初始化代码:

    factory := informers.NewSharedInformerFactoryWithOptions(clientset, 0, informers.WithNamespace("your-target-namespace"))
    
  • 排查缓存同步阻塞:日志停在"Starting stopper"说明程序卡在缓存同步步骤,添加日志输出同步状态:

    fmt.Println("Waiting for cache sync...")
    if !cache.WaitForCacheSync(stopper, informer.HasSynced) {
        log.Fatalf("Timed out waiting for caches to sync")
    }
    fmt.Println("Cache synced successfully")
    

    也可设置明确超时避免无限等待:

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
    defer cancel()
    if !cache.WaitForCacheSync(ctx.Done(), informer.HasSynced) {
        log.Fatalf("Timed out waiting for caches to sync")
    }
    
  • 验证版本兼容性:本地K3s与生产集群K8s版本可能存在差异,client-go版本需与集群API Server版本兼容(建议client-go版本≤集群版本,差距不超过1个小版本),检查并调整依赖版本。

  • 测试Watch连接可用性:Informer依赖Watch长连接,在容器内执行命令测试:

    curl -v "https://kubernetes.default.svc/apis/apps/v1/deployments?watch=true"
    

    若连接中断或无响应,说明生产集群存在网络策略、防火墙限制,导致Informer无法接收事件。

  • 增强日志排查:在事件处理函数中添加基础日志,确认Informer是否接收到事件:

    AddFunc: func(obj interface{}) {
        depl := obj.(*v1.Deployment)
        log.Printf("Received Add event for Deployment %s/%s", depl.Namespace, depl.Name)
        onAdd(clientset, gitlabClient, obj)
    },
    UpdateFunc: func(oldObj, newObj interface{}) {
        oldDepl := oldObj.(*v1.Deployment)
        newDepl := newObj.(*v1.Deployment)
        log.Printf("Received Update event for Deployment %s/%s (old resourceVersion: %s, new: %s)", oldDepl.Namespace, oldDepl.Name, oldDepl.ResourceVersion, newDepl.ResourceVersion)
        onUpdate(clientset, gitlabClient, oldObj, newObj)
    },
    

    若启动后无Add日志,说明Informer未获取到Deployment资源,重点排查权限或集群连接问题。

  • 检查Deployment更新逻辑:确认生产集群中镜像变更确实修改了spec.template.spec.containers.image字段,且触发了Deployment的resourceVersion变化(可通过kubectl get deploy <name> -o yaml对比),若resourceVersion未变化,Informer不会触发Update事件。

内容的提问来源于stack exchange,提问作者roman5595

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 01:54:54