用client-go管理Service需显式指定命名空间,Create要求Name和Namespace非空,Update需带ResourceVersion;Service类型应按环境动态设置,避免硬编码LoadBalancer;Endpoints可绕过kube-proxy但需手动维护;Watch监听时需处理clusterIP延迟就绪问题。
直接调用 Kubernetes API 管理 Service,核心是用 client-go 的 CoreV1().Services() 接口。注意命名空间必须显式指定,空字符串或 default 都会失败 —— 这是新手最常卡住的地方。
关键点:
Create() 要求 ObjectMeta.Name 和 ObjectMeta.Namespace 都非空,否则报错 Service "xxx" is invalid: metadata.name: Required value
Update() 必须带上完整的 ResourceVersion,否则返回 409 Conflict;建议先 Get() 再改字段再 Update()
spec.ports 或 spec.selector,不要覆盖整个 spec,避免意外清空 clusterIP 或 type
svc := &corev1.Service{
ObjectMeta: metav1.ObjectMeta{
Name: "my-app",
Namespace: "production",
},
Spec: corev1.ServiceSpec{
Selector: map[string]string{"app": "my-app"},
Ports: []corev1.ServicePort{{
Port: 80,
TargetPort: intstr.FromInt(8080),
}},
Type: corev1.ServiceTypeClusterIP,
},
}
_, err := clientset.CoreV1().Services("production").Create(ctx, svc, metav1.CreateOptions{})
Go 程序里写死 Type: corev1.ServiceTypeLoadBalancer 很危险 —— 它依赖云厂商控制器,本地 kind 或 m 环境根本不会分配 
ExternalIP,Status.LoadBalancer.Ingress 会长期为空。
更稳妥的做法是按环境动态设置:
ClusterIP + kubectl port-forward 调试NodePort,但需检查 NodePort 范围(默认 30000–32767),避免硬编码冲突LoadBalancer 必须配合云平台注解(如 service.beta.kubernetes.io/aws-load-balancer-type),且 Go 代码里不应等待 Ingress.IP 就绪 —— 它可能几分钟才出现当需要精细控制流量(比如灰度发布、故障注入),可跳过 Service 的 iptables/IPVS 规则,直接操作 Endpoints 对象。但要注意:Endpoints 不是 CRD,不能用 client-go 的泛型客户端,必须用 CoreV1().Endpoints()。
常见陷阱:
Endpoints.Subsets 里每个 Address 必须带 IP 字段,TargetRef 可选;填错格式(如写成 127.0.0.1)会导致连接拒绝Endpoints 时,Service 的 selector 字段会被忽略 —— 即使你删了 selector,kube-controller-manager 也不会自动同步 Endpoints
Service 和 Endpoints,Kubernetes 不会报错,但行为未定义(实际以 Endpoints 为准)用 Watch() 实时响应 Service 变更比轮询高效得多,但要注意事件类型和重连逻辑:
watch.Event.Type 是字符串 "ADDED"/"MODIFIED"/"DELETED",不是枚举,别用 switch event.Type 直接比对常量event.Object 可能是 *unstructured.Unstructured,需用 runtime.DefaultUnstructuredConverter.FromUnstructured() 转为 *corev1.Service
Watch 回调里直接调用阻塞操作(如 HTTP 请求),应发消息到 channel 由 worker 处理,否则会卡住整个 watch stream
真正难处理的是 Service 的 clusterIP 字段:它在 ADDED 事件中可能是 "None"(Headless Service)或空字符串,要等 MODIFIED 事件才稳定。硬编码假设 clusterIP != "" 会导致路由配置失败。