通过Client-Go自定义LoadBalancer控制器时如何设置Service的EXTERNAL-IP?
解决自定义LoadBalancer Controller设置Service IP未生效的问题
我来帮你排查下这个问题,你的代码里有两个核心问题导致LoadBalancer IP设置没生效,咱们一步步解决:
问题根源
错误使用了
Update方法而非UpdateStatus
Kubernetes对资源的spec(期望状态)和status(实际状态)做了严格区分,普通的Update方法会尝试修改整个Service对象(包括spec),但API Server会对spec的修改做严格校验,而且你的Controller大概率没有修改Servicespec的权限。而status字段需要用专门的UpdateStatus接口来更新,这才是正确的状态更新方式。未处理缓存对象的引用问题与资源版本冲突
你直接修改了从indexer缓存中获取的Service对象,这会污染缓存数据;同时,缓存中的对象resourceVersion可能已经过期,直接提交更新会被API Server以版本冲突为由拒绝。
修正后的代码示例
func (c *Controller) syncToStdout(key string) error { obj, exists, err := c.indexer.GetByKey(key) if err != nil { klog.Errorf("Fetching object with key %s from store failed with %v", key, err) return err } if !exists { fmt.Printf("Pod %s does not exist anymore%s\n", key) } else { // 深拷贝缓存对象,避免污染缓存 service := obj.(*v1.Service).DeepCopy() if service.ObjectMeta.Annotations["service.beta.kubernetes.io/netease-cloud"] == "nlb" { klog.Info("service belong to NLB, name = ", service.GetName()) // 先检查当前状态是否已符合预期,减少不必要的API调用 needUpdate := false if len(service.Status.LoadBalancer.Ingress) == 0 { needUpdate = true } else if service.Status.LoadBalancer.Ingress[0].IP != "10.123.234.213" { needUpdate = true } if needUpdate { // 设置目标LoadBalancer IP service.Status.LoadBalancer.Ingress = []v1.LoadBalancerIngress{{IP: "10.123.234.213"}} // 使用UpdateStatus专门更新status字段 updatedService, err := clientset.CoreV1().Services(service.Namespace).UpdateStatus(context.TODO(), service, metav1.UpdateOptions{}) if err != nil { klog.Errorf("Failed to update service status: %v", err) // 遇到版本冲突时,可以重新获取最新对象再重试 return err } klog.Info("Successfully updated service status, service = ", updatedService) } else { klog.Info("Service already has the target LoadBalancer IP, no update needed") } } else { klog.Info("service not belong to NLB, name = ", service.GetName()) } } return nil }
额外注意事项
- RBAC权限配置:确保你的Controller的ServiceAccount拥有更新
services/status的权限,对应的ClusterRole规则应该包含:
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: loadbalancer-controller-role rules: - apiGroups: [""] resources: ["services/status"] verbs: ["update", "patch"]
- 版本冲突处理:如果更新时遇到
Conflict错误,说明Service对象已被其他进程修改,此时需要重新从API Server拉取最新的Service对象,再执行更新操作。
内容的提问来源于stack exchange,提问作者Bill Jay
相关产品推荐
相关产品推荐

