本地开发需用 kubeconfig 文件而非 in-cluster 模式,调用 rest.setkubernetesdefaults(cfg) 补全默认参数,client 须用 corev1.newforconfig(cfg),pod 名需符合 dns-1123 规则,watch 需手动实现指数退避重连。

用 client-go 连接集群并列出 Pod 列表
直接连不上集群,八成是 rest.InClusterConfig() 失败或 rest.InClusterConfig() 与 rest.KubeConfig 混用。本地开发必须用 kubeconfig 文件,Pod 内运行才走 in-cluster 模式。
实操建议:
- 先确认
KUBECONFIG环境变量是否指向有效文件,或显式传入路径:clientcmd.BuildConfigFromFlags("", "/path/to/kubeconfig") - 别直接用
rest.InClusterConfig()测试本地代码——它只读/var/run/secrets/kubernetes.io/serviceaccount/,本地根本没这目录 - 拿到
*rest.Config后,务必调用rest.SetKubernetesDefaults(cfg)补全默认参数,否则可能因 timeout 或 version 不匹配静默失败 - 构造 client 时用
corev1.NewForConfig(cfg),不是corev1.New(...)—— 后者不带认证和序列化支持
创建 Pod 时字段填写容易出错的几个地方
常见现象:Pod 创建成功但状态一直是 Pending,或者报错 Invalid value: "xxx": a DNS-1123 subdomain must consist of lower case alphanumeric characters...。
关键点:
-
ObjectMeta.Name必须符合 DNS-1123 规则(小写字母、数字、中划线),且不能以中划线开头或结尾;GenerateName可留空或设为前缀(如"nginx-"),让 API server 自动生成完整名 -
Spec.Containers[0].Name是容器名,不是镜像名,也不能含斜杠;Image字段要写全(如"nginx:1.25",不能只写"nginx",否则可能拉取到旧版或失败 - 若 Pod 需访问 Secret/ConfigMap,记得在
Spec.Volumes和Spec.Containers[].VolumeMounts中配对声明,漏一个就挂载失败,且不会报错,只是路径为空 - 不设
Spec.RestartPolicy会默认为"Always",但 Job/CronJob 场景下通常要设成"OnFailure"或"Never"
Watch Pod 状态变化时连接中断和重连逻辑怎么写
原生 Watch() 返回的 watch.Interface 不自动重连,网络抖动或 apiserver 重启后 watch 就卡死,日志里只看到 EOF 或 i/o timeout。
正确做法是自己包一层重试:
- 用
context.WithTimeout(ctx, 30*time.Second)包住每次Watch()调用,避免单次阻塞太久 - 监听
watch.Interface.ResultChan(),遇到watch.Event.Type == watch.Error时检查err.(*errors.StatusError).ErrStatus.Reason是否为"Expired"或"Gone",这类错误需重建 watch - 不要在循环里反复
time.Sleep(1 * time.Second)后重试——应使用指数退避(如backoff := time.Second * 1 ) - 每次新建
Watch()前,确保老的watch.Interface已调用Stop(),否则 goroutine 泄漏
删除 Pod 时如何避免“正在终止中”卡住
调用 clientset.CoreV1().Pods(ns).Delete(ctx, name, metav1.DeleteOptions{}) 后,Pod 进入 Terminating 状态却迟迟不消失,常见于 preStop hook 卡住、finalizer 未清理、或容器进程没响应 SIGTERM。
应对方式:
- 加
GracePeriodSeconds控制宽限期:metav1.DeleteOptions{GracePeriodSeconds: &seconds},设为0强制立即删除(注意:会跳过 preStop 和 graceful shutdown) - 检查 Pod 的
Finalizers字段,若有自定义 finalizer(如"example.com/finalizer"),必须有对应 controller 清理它,否则删除永远阻塞 - 用
PropagationPolicy控制级联行为:metav1.DeletePropagationBackground(默认)不等子资源删完就返回,DeletePropagationForeground会等所有依赖资源(如 PVC)也进入 terminating - 调试时可加
FieldSelector查看 pending 删除的 Pod:clientset.CoreV1().Pods(ns).List(ctx, metav1.ListOptions{FieldSelector: "metadata.deletionTimestamp!="})
真正麻烦的不是调哪个函数,而是每个操作背后都绑着 RBAC 权限、命名空间隔离、资源版本(resourceVersion)、ownerReferences 清理这些隐性约束。少设一个 ResourceVersion 在 list-watch 场景可能丢事件,RBAC 缺一个 verbs: ["patch"] 就会让 status 更新失败——这些都不报编译错误,只在 runtime 静默失效。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











