You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用client-go枚举Kubernetes所有资源速度过慢,求优化方案

优化Kubernetes全资源枚举代码的执行速度

你的代码执行慢的核心原因是串行遍历并调用每个资源的List接口,每个请求都要等待前一个完成,累积起来耗时就很长。以下是具体的优化手段:

核心优化手段

1. 并行执行资源查询

将串行的List请求改为并行处理,利用goroutine同时发起多个资源查询,这能大幅降低总耗时。使用sync.WaitGroup来等待所有goroutine完成,同时加锁避免打印输出混乱。

2. 修正API资源发现与GVR处理逻辑

原代码中GVR的构建存在错误:

  • group.GroupVersion是group/version格式的字符串(比如apps/v1),直接赋值给gvr.Group会导致GVR格式错误,需要拆分Group和Version
  • 原containsSlash函数判断逻辑错误,子资源是形如pod/logs的格式(斜杠在中间),不是开头,导致没跳过子资源,产生大量无效请求

3. 过滤不必要的资源

跳过不需要的资源类型(比如events这类数据量大但非必需的资源,以及所有带斜杠的子资源),减少无效API调用。可根据需求添加更多过滤规则。

4. 精简List请求返回数据

通过metav1.ListOptions指定只返回必要字段(比如仅获取资源名称),减少数据传输量和序列化开销,进一步提升请求速度。

5. 添加上下文超时

使用带超时的上下文,避免某个资源请求卡住导致整体耗时过长。

优化后的代码示例

package main

import (
    "context"
    "fmt"
    "strings"
    "sync"
    "time"

    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    "k8s.io/apimachinery/pkg/runtime/schema"
    "k8s.io/client-go/dynamic"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
)

func main() {
    loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
    configOverrides := &clientcmd.ConfigOverrides{}
    kubeconfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)

    config, err := kubeconfig.ClientConfig()
    if err != nil {
        panic(err.Error())
    }

    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }

    dynClient, err := dynamic.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }

    discoveryClient := clientset.Discovery()

    // 获取所有API资源
    serverResources, err := discoveryClient.ServerPreferredResources()
    if err != nil {
        panic(err.Error())
    }

    // 创建带超时的上下文,防止请求无限阻塞
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    var wg sync.WaitGroup
    var printMu sync.Mutex // 保证打印输出不混乱

    for _, group := range serverResources {
        // 拆分GroupVersion为Group和Version
        gvParts := strings.Split(group.GroupVersion, "/")
        var groupName, version string
        if len(gvParts) == 2 {
            groupName = gvParts[0]
            version = gvParts[1]
        } else {
            // 核心v1资源,Group为空
            version = gvParts[0]
        }

        for _, resource := range group.APIResources {
            // 跳过子资源(名称包含斜杠)
            if strings.Contains(resource.Name, "/") {
                continue
            }
            // 跳过非必需的资源,比如events
            if resource.Name == "events" {
                continue
            }

            gvr := schema.GroupVersionResource{
                Group:    groupName,
                Version:  version,
                Resource: resource.Name,
            }

            wg.Add(1)
            // 启动goroutine并行查询
            go func(gvr schema.GroupVersionResource, resName string, namespaced bool) {
                defer wg.Done()

                var list *unstructured.UnstructuredList
                var err error

                // 精简返回字段,只获取metadata.name,减少数据传输
                listOpts := metav1.ListOptions{
                    FieldSelector: "metadata.name",
                }

                if namespaced {
                    list, err = dynClient.Resource(gvr).List(ctx, listOpts)
                } else {
                    list, err = dynClient.Resource(gvr).List(ctx, listOpts)
                }

                if err != nil {
                    printMu.Lock()
                    fmt.Printf("..Error listing %s: %v. group %q version %q resource %q\n", resName, err,
                        gvr.Group, gvr.Version, gvr.Resource)
                    printMu.Unlock()
                    return
                }

                printMu.Lock()
                fmt.Printf("Found %d resources of type %s. group %q version %q resource %q\n", len(list.Items), resName, gvr.Group, gvr.Version, gvr.Resource)
                printMu.Unlock()
            }(gvr, resource.Name, resource.Namespaced)
        }
    }

    // 等待所有并行任务完成
    wg.Wait()
}

额外优化建议

  • 若担心并行请求对API Server压力过大,可添加限流逻辑(比如用带缓冲的channel控制并发数)
  • 可缓存Discovery的API资源列表结果,避免每次运行都重新获取
  • 针对自定义CRD,可根据需求添加过滤规则,只枚举需要的CRD资源

内容的提问来源于stack exchange,提问作者guettli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 13:11:03