连错集群、用错账号、命名空间莫名其妙——多半是 kubeconfig 的合并和覆盖规则没搞清。这篇不看文档,用两份内容故意冲突的文件和两个假 apiserver,把环境变量顺序、命令行参数覆盖、相对路径解析都跑成可以直接对照的结果。
current-context=ctx-a
clusters:{'c-a': 'https://127.0.0.1:9821', 'c-b': 'https://127.0.0.1:9822', 'c-shared': 'https://127.0.0.1:9821'}
users(token 在默认视图里被遮掉,这里取自 --raw):{'u-a': 'token-from-A', 'u-b': 'token-from-B'}
contexts:{'ctx-a': ('c-a', 'u-a', 'ns-a'), 'ctx-b': ('c-b', 'u-b', 'ns-b'), 'ctx-shared': ('c-shared', 'u-a', None)}
规则:同名的 cluster / user / context,先出现的文件胜出(a 里的 c-shared、u-a、ctx-shared 生效,b 里的被忽略);不同名的合并;current-context 取第一个设了它的文件a.yaml 和 b.yaml 里都有 c-shared 集群、u-a 用户、ctx-shared context,内容不同。KUBECONFIG=a.yaml:b.yaml 合并后:current-context=ctx-a(第一个设了它的文件),c-shared 指向 a 的服务器,u-a 的令牌是 token-from-A;只在 b 里有的 c-b、u-b、ctx-b 被并进来。规则:同名条目先出现的文件胜出,后面的整条被忽略;不同名的合并。
current-context=ctx-b
clusters:{'c-a': 'https://127.0.0.1:9821', 'c-b': 'https://127.0.0.1:9822', 'c-shared': 'https://127.0.0.1:9822'}
users:{'u-a': 'token-from-B-for-u-a', 'u-b': 'token-from-B'}
contexts:{'ctx-a': ('c-a', 'u-a', 'ns-a'), 'ctx-b': ('c-b', 'u-b', 'ns-b'), 'ctx-shared': ('c-shared', 'u-b', None)}
--minify(只留当前 context 用到的部分):server+namespace = https://127.0.0.1:9822 ns-b
文件的位置不同,最终的集群地址 / 用户凭据就不同——KUBECONFIG 里的顺序是有意义的KUBECONFIG=b.yaml:a.yaml 之后:current-context=ctx-b,c-shared 变成 b 的服务器,u-a 的令牌变成 token-from-B-for-u-a,ctx-shared 引用的用户也变成 u-b。同样的两个文件,顺序不同,实际连到哪、用谁的令牌就不同——排查“怎么连到别的集群了”,先看 KUBECONFIG 里的顺序,再用 kubectl config view --minify 看实际生效的那一份。
默认(a.yaml:b.yaml,当前 context=ctx-a):请求打到端口 9821,路径 /api/v1/namespaces/ns-a/pods,Authorization=Bearer token-from-A --context=ctx-b:请求打到端口 9822,路径 /api/v1/namespaces/ns-b/pods,Authorization=Bearer token-from-B --cluster=c-b(只换集群):请求打到端口 9822,路径 /api/v1/namespaces/ns-a/pods,Authorization=Bearer token-from-A --user=u-b(只换用户):请求打到端口 9821,路径 /api/v1/namespaces/ns-a/pods,Authorization=Bearer token-from-B --namespace=other(只换命名空间):请求打到端口 9821,路径 /api/v1/namespaces/other/pods,Authorization=Bearer token-from-A --cluster=c-b --user=u-b --namespace=other:请求打到端口 9822,路径 /api/v1/namespaces/other/pods,Authorization=Bearer token-from-B --token=cli-token(命令行直接给令牌):请求打到端口 9821,路径 /api/v1/namespaces/ns-a/pods,Authorization=Bearer cli-token --kubeconfig=b.yaml(环境变量里的 a.yaml:b.yaml 被整个忽略):请求打到端口 9822,路径 /api/v1/namespaces/ns-b/pods,Authorization=Bearer token-from-B --context=no-such:退出码 1;Error in configuration: context was not found for specified context: no-such
真的发一次 kubectl get pods,看假 apiserver 收到什么:默认是 9821、/api/v1/namespaces/ns-a/pods、Bearer token-from-A。--context=ctx-b 整套换;--cluster 只换服务器(命名空间和令牌不变),--user 只换令牌,--namespace 只换路径里的命名空间,--token 直接覆盖令牌。--kubeconfig 不是“再合并一个文件”,而是让环境变量里的 KUBECONFIG 被整个忽略。注意:kubectl config view --minify --cluster=… 这类命令只是打印文件内容,不会应用这些覆盖,验证覆盖要看真实请求。
默认视图里的 c-a 集群与用户(a.yaml 的 ctx-a):insecure-skip-tls-verify: true | server: https://127.0.0.1:9821 | token: REDACTED ctx-shared(CA 写的是相对路径 sub/ca.pem):certificate-authority: sub/ca.pem | server: https://127.0.0.1:9821 --flatten 把引用的文件内容嵌进去:certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJmYWtlLWNh 工作目录是 /(与 kubeconfig 不在同一目录)时上面的路径仍然被正确解析:是——解析基准是 a.yaml 所在目录 k22/ 删掉 sub/ca.pem 之后 kubectl get nodes:退出码 1;error: unable to read certificate-authority <ktmp>/k22/sub/ca.pem for c-shared due to open <ktmp>/k22/sub/ca.pem: no such file or directory 对照:kind 给 kx-main 生成的 kubeconfig:CURRENT NAME CLUSTER AUTHINFO NAMESPACE | * kind-kx-main kind-kx-main kind-kx-main
kubeconfig 里的相对路径(这里是 certificate-authority: sub/ca.pem)以 kubeconfig 文件所在的目录为基准,不是当前工作目录;--flatten 把引用的文件内容嵌成 certificate-authority-data,搬到别的机器上不会失效。文件缺了,报 unable to read certificate-authority … for c-shared,错误里带着解析后的绝对路径。kubectl config view 默认把令牌显示成 REDACTED,要看原文得加 --raw。