Go中用JSON服务账号密钥创建Kubernetes Clientset遇ADC报错求解
问题:显式提供Token创建K8s Clientset仍触发ADC查找崩溃?
我从JSON服务账号密钥文件提取Token,想用来创建Kubernetes Clientset。已经在配置里显式指定了Token,但程序还是在找Google默认应用凭据(ADC),找不到就崩溃了。
我的代码
package main import ( "context" "encoding/base64" "fmt" "io/ioutil" "golang.org/x/oauth2" "golang.org/x/oauth2/google" gke "google.golang.org/api/container/v1" "google.golang.org/api/option" "k8s.io/client-go/kubernetes" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd/api" ) const ( projectID = "my_project_id" clusterName = "my_cluster_name" scope = "https://www.googleapis.com/auth/cloud-platform" ) func main() { ctx := context.Background() // 读取JSON密钥并提取token data, err := ioutil.ReadFile("sa_key.json") if err != nil { panic(err) } creds, err := google.CredentialsFromJSON(ctx, data, scope) if err != nil { panic(err) } token, err := creds.TokenSource.Token() if err != nil { panic(err) } fmt.Println("token", token.AccessToken) // 创建GKE客户端 tokenSource := oauth2.StaticTokenSource(token) gkeClient, err := gke.NewService(ctx, option.WithTokenSource(tokenSource)) if err != nil { panic(err) } // 创建内存中的kube配置 inMemKubeConfig, err := createInMemKubeConfig(ctx, gkeClient, token, projectID) if err != nil { panic(err) } // 转换为rest.Config config, err := clientcmd.NewNonInteractiveClientConfig(*inMemKubeConfig, clusterName, &clientcmd.ConfigOverrides{CurrentContext: clusterName}, nil).ClientConfig() if err != nil { panic(err) } // 创建Clientset(此处崩溃,提示找不到Google ADC) clientset, err := kubernetes.NewForConfig(config) if err != nil { panic(err) } fmt.Printf("clientset %+v\n", clientset) } func createInMemKubeConfig(ctx context.Context, client *gke.Service, token *oauth2.Token, projectID string) (*api.Config, error) { k8sConf := api.Config{ APIVersion: "v1", Kind: "Config", Clusters: map[string]*api.Cluster{}, AuthInfos: map[string]*api.AuthInfo{}, Contexts: map[string]*api.Context{}, } // 列出项目下所有可用区的集群 resp, err := client.Projects.Zones.Clusters.List(projectID, "-").Context(ctx).Do() if err != nil { return nil, err } for _, f := range resp.Clusters { name := fmt.Sprintf("gke_%s_%s_%s", projectID, f.Zone, f.Name) // 自定义集群命名规则 cert, err := base64.StdEncoding.DecodeString(f.MasterAuth.ClusterCaCertificate) if err != nil { return nil, err } k8sConf.Clusters[name] = &api.Cluster{ CertificateAuthorityData: cert, Server: "https://" + f.Endpoint, } k8sConf.Contexts[name] = &api.Context{ Cluster: name, AuthInfo: name, } k8sConf.AuthInfos[name] = &api.AuthInfo{ Token: token.AccessToken, AuthProvider: &api.AuthProviderConfig{ Name: "gcp", Config: map[string]string{ "scopes": scope, }, }, } } return &k8sConf, nil }
报错信息
panic: 无法构造google默认token源: google: 找不到默认凭据。
解决方案
问题出在你给AuthInfo同时设置了Token和AuthProvider:当AuthProvider存在时,client-go会优先执行它的认证逻辑,而非直接使用你提供的Token。gcp类型的AuthProvider默认会尝试加载ADC,这就是程序仍在查找ADC的根本原因。
修复步骤
在createInMemKubeConfig函数中,删除AuthInfo里的AuthProvider配置,只保留Token字段:
k8sConf.AuthInfos[name] = &api.AuthInfo{ Token: token.AccessToken, }
修改后,client-go会直接使用你提供的Token完成认证,不会再触发ADC查找逻辑。
进阶优化(Token自动刷新)
如果程序需要长期运行,要注意Token的过期问题。可以直接将TokenSource集成到rest.Config中,实现Token自动刷新:
// 替换原有的ClientConfig创建逻辑,直接构建rest.Config // 注意:根据实际情况选择目标集群 targetCluster := resp.Clusters[0] cert, _ := base64.StdEncoding.DecodeString(targetCluster.MasterAuth.ClusterCaCertificate) config := &rest.Config{ Host: "https://" + targetCluster.Endpoint, TLSClientConfig: rest.TLSClientConfig{ CAData: cert, }, // 设置TokenSource,Token过期时自动刷新 BearerTokenSource: creds.TokenSource, } // 直接用该config创建clientset clientset, err := kubernetes.NewForConfig(config)
这样就不需要手动管理Token的过期和刷新了。
内容的提问来源于stack exchange,提问作者Emre Chomko
相关产品推荐
相关产品推荐

