client-go如何监听自定义资源

news2025/4/9 9:31:06

如何使用 client-go 监听自定义资源

在 Kubernetes 中使用 client-go 监听自定义资源(Custom Resource,简称 CR)需要借助 Dynamic ClientCustom Informer,因为 client-go 的标准 Clientset 只支持内置资源(如 Pod、Deployment)。自定义资源由 CustomResourceDefinition(CRD)或 Operator 定义,监听它们需要动态处理其 Group、Version 和 Resource(GVR)。以下是详细步骤和实现方法。


前提条件

  • CRD 已部署:确保你的自定义资源定义(CRD)已在集群中注册。
    • 示例:myresource.example.com/v1,Kind 为 MyResource
  • 依赖
    • client-go(推荐与集群版本匹配,例如 v0.28.0 对应 Kubernetes 1.28)。
    • 添加依赖:
      go get k8s.io/client-go@v0.28.0
      
  • 权限:确保 ServiceAccount 有权访问 CRD(通过 RBAC 配置)。

方法 1:使用 Dynamic Client 和 Informer

Dynamic Clientclient-go 提供的通用客户端,支持任意资源类型。结合 SharedInformer,可以监听自定义资源。

步骤

  1. 初始化 Dynamic Client

    package main
    
    import (
        "context"
        "log"
        "time"
    
        "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
        "k8s.io/apimachinery/pkg/runtime/schema"
        "k8s.io/client-go/dynamic"
        "k8s.io/client-go/rest"
        "k8s.io/client-go/tools/cache"
        "k8s.io/client-go/tools/clientcmd"
    )
    
    func getDynamicClient() dynamic.Interface {
        config, err := rest.InClusterConfig()
        if err != nil {
            config, err = clientcmd.BuildConfigFromFlags("", "/path/to/kubeconfig")
            if err != nil {
                log.Fatalf("Failed to create config: %v", err)
            }
        }
        client, err := dynamic.NewForConfig(config)
        if err != nil {
            log.Fatalf("Failed to create dynamic client: %v", err)
        }
        return client
    }
    
  2. 定义 GVR

    • 指定自定义资源的 Group、Version 和 Resource。
    • 示例:myresource.example.com/v1,资源名为 myresources
      gvr := schema.GroupVersionResource{
          Group:    "example.com",
          Version:  "v1",
          Resource: "myresources",
      }
      
  3. 创建 Dynamic Informer

    func main() {
        client := getDynamicClient()
    
        // 创建 Dynamic Informer Factory
        factory := dynamicinformer.NewDynamicSharedInformerFactory(client, time.Minute*30)
        informer := factory.ForResource(gvr).Informer()
    
        // 添加事件处理函数
        informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
            AddFunc: func(obj interface{}) {
                unstructuredObj := obj.(*unstructured.Unstructured)
                name := unstructuredObj.GetName()
                namespace := unstructuredObj.GetNamespace()
                log.Printf("CR Added: %s/%s", namespace, name)
            },
            UpdateFunc: func(oldObj, newObj interface{}) {
                oldUnstructured := oldObj.(*unstructured.Unstructured)
                newUnstructured := newObj.(*unstructured.Unstructured)
                log.Printf("CR Updated: %s/%s", newUnstructured.GetNamespace(), newUnstructured.GetName())
            },
            DeleteFunc: func(obj interface{}) {
                unstructuredObj := obj.(*unstructured.Unstructured)
                log.Printf("CR Deleted: %s/%s", unstructuredObj.GetNamespace(), unstructuredObj.GetName())
            },
        })
    
        // 启动 Informer
        ctx, cancel := context.WithCancel(context.Background())
        defer cancel()
    
        factory.Start(ctx.Done())
        factory.WaitForCacheSync(ctx.Done())
    
        // 保持运行
        <-ctx.Done()
    }
    
  4. 获取缓存数据

    lister := factory.ForResource(gvr).Lister()
    items, err := lister.List(labels.Everything())
    if err != nil {
        log.Printf("Failed to list CRs: %v", err)
    } else {
        for _, item := range items {
            unstructuredObj := item.(*unstructured.Unstructured)
            log.Printf("Current CR: %s/%s", unstructuredObj.GetNamespace(), unstructuredObj.GetName())
        }
    }
    

说明

  • GVR:通过 kubectl api-resources 查看自定义资源的准确 GVR。
  • Unstructured:自定义资源以 unstructured.Unstructured 类型返回,需手动解析字段。
  • 依赖:需要导入 k8s.io/client-go/dynamic/informer

方法 2:生成类型化客户端和 Informer(推荐生产环境)

如果你的 CRD 有明确的 Go 类型(通过代码生成器生成),可以使用类型化的客户端和 Informer。这种方法需要更多前期工作,但更安全和直观。

步骤

  1. 生成代码

    • 使用 controller-toolsk8s.io/code-generator 生成 CRD 的客户端代码。
    • 示例 CRD 文件(myresource_v1.yaml):
      apiVersion: apiextensions.k8s.io/v1
      kind: CustomResourceDefinition
      metadata:
        name: myresources.example.com
      spec:
        group: example.com
        names:
          kind: MyResource
          plural: myresources
        scope: Namespaced
        versions:
        - name: v1
          served: true
          storage: true
          schema:
            openAPIV3Schema:
              type: object
              properties:
                spec:
                  type: object
                  properties:
                    replicas:
                      type: integer
      
    • 生成命令:
      mkdir -p pkg/apis/example.com/v1
      controller-gen crd paths=./pkg/apis/example.com/v1 output:crd:dir=./manifests
      controller-gen object paths=./pkg/apis/example.com/v1
      k8s.io/code-generator/generate-groups.sh all ./pkg/client ./pkg/apis example.com:v1
      
  2. 注册类型

    • pkg/apis/example.com/v1/types.go 中定义类型:
      package v1
      
      import (
          metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
      )
      
      type MyResourceSpec struct {
          Replicas int32 `json:"replicas"`
      }
      
      type MyResource struct {
          metav1.TypeMeta   `json:",inline"`
          metav1.ObjectMeta `json:"metadata,omitempty"`
          Spec              MyResourceSpec `json:"spec,omitempty"`
      }
      
      type MyResourceList struct {
          metav1.TypeMeta `json:",inline"`
          metav1.ListMeta `json:"metadata,omitempty"`
          Items           []MyResource `json:"items"`
      }
      
  3. 创建 Informer

    package main
    
    import (
        "context"
        "log"
        "time"
    
        "k8s.io/client-go/tools/cache"
        examplev1 "your/module/pkg/apis/example.com/v1"
        exampleclientset "your/module/pkg/client/clientset/versioned"
        exampleinformers "your/module/pkg/client/informers/externalversions"
    )
    
    func main() {
        config, err := rest.InClusterConfig()
        if err != nil {
            log.Fatalf("Failed to create config: %v", err)
        }
        client, err := exampleclientset.NewForConfig(config)
        if err != nil {
            log.Fatalf("Failed to create clientset: %v", err)
        }
    
        factory := exampleinformers.NewSharedInformerFactory(client, time.Minute*30)
        informer := factory.Example().V1().MyResources().Informer()
    
        informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
            AddFunc: func(obj interface{}) {
                myResource := obj.(*examplev1.MyResource)
                log.Printf("MyResource Added: %s/%s, Replicas: %d", 
                    myResource.Namespace, myResource.Name, myResource.Spec.Replicas)
            },
            UpdateFunc: func(oldObj, newObj interface{}) {
                newResource := newObj.(*examplev1.MyResource)
                log.Printf("MyResource Updated: %s/%s", newResource.Namespace, newResource.Name)
            },
            DeleteFunc: func(obj interface{}) {
                myResource := obj.(*examplev1.MyResource)
                log.Printf("MyResource Deleted: %s/%s", myResource.Namespace, myResource.Name)
            },
        })
    
        ctx, cancel := context.WithCancel(context.Background())
        defer cancel()
        factory.Start(ctx.Done())
        factory.WaitForCacheSync(ctx.Done())
    
        <-ctx.Done()
    }
    

说明

  • 类型安全:使用生成的类型(如 *examplev1.MyResource),避免手动解析。
  • 依赖:需要自定义的客户端包(pkg/client)。
  • 复杂度:前期生成代码较繁琐,但长期维护更方便。

注意事项

  1. CRD 注册
    • 确保 CRD 已应用(kubectl apply -f myresource_v1.yaml)。
    • 检查:
      kubectl get crd myresources.example.com
      
  2. 权限
    • 为 ServiceAccount 配置 RBAC:
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRole
      metadata:
        name: myresource-reader
      rules:
      - apiGroups: ["example.com"]
        resources: ["myresources"]
        verbs: ["get", "list", "watch"]
      ---
      apiVersion: rbac.authorization.k8s.io/v1
      kind: ClusterRoleBinding
      metadata:
        name: myresource-reader-binding
      subjects:
      - kind: ServiceAccount
        name: default
        namespace: default
      roleRef:
        kind: ClusterRole
        name: myresource-reader
        apiGroup: rbac.authorization.k8s.io
      
  3. 性能
    • 使用 WithNamespace 或标签过滤减少监听范围。
  4. 错误处理
    • Watch 失败时,Informer 会自动重试,需关注日志。

验证

  1. 创建自定义资源

    apiVersion: example.com/v1
    kind: MyResource
    metadata:
      name: test-resource
      namespace: default
    spec:
      replicas: 3
    
    kubectl apply -f test-resource.yaml
    
  2. 运行程序,观察日志输出

    MyResource Added: default/test-resource, Replicas: 3
    

总结

  • Dynamic Client
    • 适合快速实现,无需生成代码。
    • 使用 unstructured.Unstructured 处理数据。
  • 类型化客户端
    • 适合生产环境,类型安全,需生成代码。
    • 使用特定类型(如 *MyResource)操作。
  • 选择建议
    • 测试或简单场景:Dynamic Client。
    • 长期项目或 Operator:类型化客户端。

如果你有具体的 CRD 定义或需求(例如监听特定字段),可以告诉我,我会进一步定制代码!


---

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2329601.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安装gpu版本的dgl

1.先去网址&#xff0c;找到对应版本的dgl,然后下载到本地。 dgl-whl下载地址 我的是python 3.8 &#xff0c;cuda 11.6. windows 2.在虚拟环境里 输入 pip install E:\dgl-1.0.2cu116-cp38-cp38-win_amd64.whl &#xff08;因为我下载到E盘里了&#xff09; 这样GPU版本的d…

5天速成ai agent智能体camel-ai之第1天:camel-ai安装和智能体交流消息讲解(附源码,零基础可学习运行)

嗨&#xff0c;朋友们&#xff01;&#x1f44b; 是不是感觉AI浪潮铺天盖地&#xff0c;身边的人都在谈论AI Agent、大模型&#xff0c;而你看着那些密密麻麻的代码&#xff0c;感觉像在读天书&#xff1f;&#x1f92f; 别焦虑&#xff01;你不是一个人。很多人都想抓住AI的风…

FPGA——FPGA状态机实现流水灯

一、引言 在FPGA开发中&#xff0c;状态机是一种重要的设计工具&#xff0c;用于处理具有时间顺序的事件。本文将详细介绍如何使用状态机实现一个LED流水灯的效果。 二、状态机概述 状态机&#xff08;FSM&#xff09;是一种行为模型&#xff0c;用于表示系统在不同状态下的…

晶晨S905-S905L-S905LB_S905M2通刷_安卓6.0.1_16S极速开机_线刷固件包

晶晨S905-S905L-S905LB_S905M2通刷_安卓6.0.1_16S极速开机_线刷固件包 线刷方法&#xff1a;&#xff08;新手参考借鉴一下&#xff09; 刷机工具版本请用2.2.0以上&#xff0c;导入固件后&#xff0c;刷机工具右侧两个擦除打勾&#xff0c;然后点开始。插上刷机神器&#xf…

构建第一个ArkTS应用:Hello World之旅

# 构建第一个ArkTS应用&#xff1a;Hello World之旅 在鸿蒙应用开发的领域中&#xff0c;ArkTS语言为我们提供了强大而便捷的开发方式。今天&#xff0c;就让我们一起踏上构建第一个ArkTS应用——Hello World的奇妙旅程。 ## 一、创建ArkTS工程 1. 首先&#xff0c;我们要使用…

第十五届单片机模拟考试III

题目 题目不长 &#xff0c;功能也不难&#xff0c;一道水题 按键功能 S4界面切换&#xff0c;S5 功能切换&#xff0c;在不同界面转换不同的功能&#xff0c;定义两个标志位记录即可。 S9复位&#xff0c;回到初始状态&#xff0c;记得界面也得回到初始的信号界面&#xff0…

测试:正交法设计测试用例

目录 一、什么是正交法 二、利用正交表设计测试用例 正交法设计测试用例的步骤 一、什么是正交法 正交法的目的是为了减少测试用例的数量&#xff0c;让尽可能少的用例覆盖两两组合。认识正交表。 最简单的正交表是L4(2^3)&#xff0c;含意如下&#xff1a; “L”代表正…

[ctfshow web入门] web5

前置知识 引用博客&#xff1a;phps的利用 当服务器配置了 .phps 文件类型时&#xff0c;访问 .phps 文件会以语法高亮的形式直接显示 PHP 源代码&#xff0c;而不是执行它。.phps被作为辅助开发者的一种功能&#xff0c;开发者可以通过网站上访问xxx.phps直接获取高亮源代码 …

Qt基本框架(2)

本篇主要介绍如何设置窗口&#xff0c;以及在窗口中添加按钮 本文部分ppt、视频截图原链接&#xff1a;[萌马工作室的个人空间-萌马工作室个人主页-哔哩哔哩视频] 1. Qt简单框架 2. 通过QMainWindow实现简单界面 QMainWindow是构建主窗口应用的核心类&#xff0c;通过合理设计…

基于javaweb的SpringBoot图片管理系统图片相册系统设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…

用HTML.CSS.JavaScript实现一个贪吃蛇小游戏

目录 一、引言二、实现思路1. HTML 结构2. CSS 样式3. JavaScript 逻辑 三、代码实现四、效果展示 一、引言 贪吃蛇是一款经典的小游戏&#xff0c;曾经风靡一时。今天&#xff0c;我们将使用 HTML、CSS 和 JavaScript 来实现一个简单的贪吃蛇小游戏。通过这个项目&#xff0c…

JVM——模型分析、回收机制

方法区&#xff1a;存储已被虚拟机加载的类元数据信息(元空间) 堆&#xff1a;存放对象实例&#xff0c;几乎所有的对象实例都在这里分配内存 虚拟机栈&#xff1a;虚拟机栈描述的是|ava方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局…

7. 记忆(Memory)机制:让AI拥有“短期记忆”与“长期记忆”

引言&#xff1a;当AI学会"记住你" 2025年某银行智能客服因无法记住用户身份&#xff0c;每次对话都要求重复验证&#xff0c;引发大量投诉。引入LangChain 记忆系统后&#xff0c;客户满意度提升62%。本文将基于MemorySaver与FAISS本地存储&#xff0c;教你构建符合…

前后端分离下,Spring Boot 请求从发起到响应的完整执行流程

以下是前后端分离架构下&#xff0c;Spring Boot 请求从发起到响应的完整执行流程&#xff0c;结合你提出的所有问题&#xff0c;按真实执行顺序和职责链条重新整理所有核心概念、结构、关键类、数据转换点和典型代码示例&#xff1a; 一、前端发起请求&#xff08;步骤1-2&…

【文献阅读】Vision-Language Models for Vision Tasks: A Survey

发表于2024年2月 TPAMI 摘要 大多数视觉识别研究在深度神经网络&#xff08;DNN&#xff09;训练中严重依赖标注数据&#xff0c;并且通常为每个单一视觉识别任务训练一个DNN&#xff0c;这导致了一种费力且耗时的视觉识别范式。为应对这两个挑战&#xff0c;视觉语言模型&am…

spring-cloud-alibaba-nacos-config使用说明

一、核心功能与定位 Spring Cloud Alibaba Nacos Config 是 Spring Cloud Alibaba 生态中的核心组件之一&#xff0c;专为微服务架构提供动态配置管理能力。它通过整合 Nacos 的配置中心功能&#xff0c;替代传统的 Spring Cloud Config&#xff0c;提供更高效的配置集中化管理…

C# Winform 入门(9)之如何封装并调用dll

封装dll 首先创建 .Net平台 类库 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace _09.Encapsulation_dll {public class Program{/// <summary>/// 求两个double类型的数值的和/// &l…

【嵌入式系统设计师】知识点:第2章 嵌入式系统硬件基础知识

提示:“软考通关秘籍” 专栏围绕软考展开,全面涵盖了如嵌入式系统设计师、数据库系统工程师、信息系统管理工程师等多个软考方向的知识点。从计算机体系结构、存储系统等基础知识,到程序语言概述、算法、数据库技术(包括关系数据库、非关系型数据库、SQL 语言、数据仓库等)…

Vue2_Vue.js教程

目录 一、Vue.js安装 1、独立版本 2、CDN 方法 3、npm 方法 二、Vue Al编程助手 三、Vue.js目录结构 目录解析 四、Vue.js 起步 1.如何定义数据对象和方法并渲染进页面 五、Vue.js 模板语法 插值 文本_{{}} Html_v-html 指令 属性_v-bind (数据传输工具)指令 表…

【工业场景】用YOLOv12实现饮料类别识别

饮料类别识别任务的意义在于帮助人们更快速地识别和区分不同类型的饮料&#xff0c;从而提高消费者的购物体验和满意度。对于商家而言&#xff0c;饮料类别识别可以帮助他们更好地管理库存、优化货架布局和预测销售趋势&#xff0c;从而提高运营效率和利润。此外&#xff0c;饮…