必须显式加载 REST 配置并设置 QPS/Burst,List 操作需分页+超时控制,FieldSelector 仅支持白名单字段,CRD 查询须注册 Scheme。

用 client-go 连接集群并初始化 clientset
不配置好认证和 REST 配置,后续所有查询都会报 Unauthorized 或 connection refused。本地开发时默认读 $HOME/.kube/config,但硬编码路径或忽略上下文切换会导致在 CI/多集群环境直接失败。
- 务必显式加载 config:
config, err := rest.InClusterConfig() // Pod 内运行 // 或 config, err := clientcmd.BuildConfigFromFlags("", "/path/to/kubeconfig") - 若 kubeconfig 含多个 context,需手动指定:
config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig( &clientcmd.ClientConfigLoadingRules{ExplicitPath: "/path/to/kubeconfig"}, &clientcmd.ConfigOverrides{CurrentContext: "prod-cluster"}, ).ClientConfig() - 别漏掉设置
QPS和Burst,尤其在高频轮询场景,否则容易触发 apiserver 限流:config.QPS = 50 config.Burst = 100
查 Pod 列表时如何避免 TooManyRequests 和超时
直接调用 clientset.CoreV1().Pods(namespace).List() 默认不带分页,大命名空间(如上百 Pod)可能卡住或被限流。Kubernetes 1.22+ 对未分页请求更敏感,且默认 timeout 是 30 秒,容易在弱网络下中断。
- 强制加
context.WithTimeout,别依赖 clientset 默认行为:ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() list, err := clientset.CoreV1().Pods("default").List(ctx, metav1.ListOptions{ Limit: 500, Continue: "", // 首次请求留空 }) - 需要全量数据?必须循环处理
list.Continue字段,否则只拿到第一页:for list.Continue != "" { opts := metav1.ListOptions{Limit: 500, Continue: list.Continue} list, err = clientset.CoreV1().Pods("default").List(ctx, opts) // ... 处理 list.Items } - 非必要别用
Watch替代List—— Watch 持久连接更耗资源,且断连重试逻辑复杂得多
按 label 或 field selector 查询时字段名必须严格匹配
labelSelector 看似简单,但写错一个连字符或大小写就返回空列表,且无报错;fieldSelector 更脆弱——比如想查 Pending 状态的 Pod,写成 status.phase=Pending 会静默失败,正确写法是 status.phase=Pending(注意:这个字段名是对的,但实际必须用小写 status.phase,且值区分大小写)。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- Label 查询示例(支持
=、!=、in):metav1.ListOptions{ LabelSelector: "app.kubernetes.io/name in (nginx,redis),env=prod" } - Field 查询仅支持有限字段,常见可用的有:
metadata.name、metadata.namespace、status.phase、spec.nodeName;status.conditions这类嵌套结构不支持 - 多个 field selector 必须用逗号拼接,不能用空格或分号:
status.phase=Pending,spec.nodeName=ip-10-0-1-123
处理自定义资源(CRD)时必须注册 Scheme
直接用 clientset 查不到 CRD,因为默认 scheme 不知道你的类型。不注册就会 panic:“no kind is registered for the type”。这不是权限问题,是 Go 类型系统层面的缺失。
立即学习“go语言免费学习笔记(深入)”;
- 先用
scheme.Scheme注册你的 CRD 类型:import mycrd "github.com/example/my-operator/api/v1" ... scheme := runtime.NewScheme() _ = mycrd.AddToScheme(scheme)
- 再基于该 scheme 构建 dynamic client:
dynamicClient := dynamic.NewForConfigOrDie(config) gvr := schema.GroupVersionResource{ Group: "example.com", Version: "v1", Resource: "widgets", } list, err := dynamicClient.Resource(gvr).Namespace("default").List(ctx, metav1.ListOptions{}) - 如果已有生成的 clientset(如用
controller-gen),优先用它而非 dynamic client —— 类型安全、IDE 可跳转、字段名编译期校验

















