client-go如何监听自定义资源
如何使用 client-go 监听自定义资源
在 Kubernetes 中使用 client-go 监听自定义资源(Custom Resource,简称 CR)需要借助 Dynamic Client 或 Custom 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 Client 是 client-go 提供的通用客户端,支持任意资源类型。结合 SharedInformer,可以监听自定义资源。
步骤
-
初始化 Dynamic Client:
package mainimport ("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 } -
定义 GVR:
- 指定自定义资源的 Group、Version 和 Resource。
- 示例:
myresource.example.com/v1,资源名为myresources。gvr := schema.GroupVersionResource{Group: "example.com",Version: "v1",Resource: "myresources", }
-
创建 Dynamic Informer:
func main() {client := getDynamicClient()// 创建 Dynamic Informer Factoryfactory := 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())},})// 启动 Informerctx, cancel := context.WithCancel(context.Background())defer cancel()factory.Start(ctx.Done())factory.WaitForCacheSync(ctx.Done())// 保持运行<-ctx.Done() } -
获取缓存数据:
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。这种方法需要更多前期工作,但更安全和直观。
步骤
-
生成代码:
- 使用
controller-tools或k8s.io/code-generator生成 CRD 的客户端代码。 - 示例 CRD 文件(
myresource_v1.yaml):apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata:name: myresources.example.com spec:group: example.comnames:kind: MyResourceplural: myresourcesscope: Namespacedversions:- name: v1served: truestorage: trueschema:openAPIV3Schema:type: objectproperties:spec:type: objectproperties: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
- 使用
-
注册类型:
- 在
pkg/apis/example.com/v1/types.go中定义类型:package v1import (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"` }
- 在
-
创建 Informer:
package mainimport ("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)。 - 复杂度:前期生成代码较繁琐,但长期维护更方便。
注意事项
- CRD 注册:
- 确保 CRD 已应用(
kubectl apply -f myresource_v1.yaml)。 - 检查:
kubectl get crd myresources.example.com
- 确保 CRD 已应用(
- 权限:
- 为 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: ServiceAccountname: defaultnamespace: default roleRef:kind: ClusterRolename: myresource-readerapiGroup: rbac.authorization.k8s.io
- 为 ServiceAccount 配置 RBAC:
- 性能:
- 使用
WithNamespace或标签过滤减少监听范围。
- 使用
- 错误处理:
- Watch 失败时,Informer 会自动重试,需关注日志。
验证
-
创建自定义资源:
apiVersion: example.com/v1 kind: MyResource metadata:name: test-resourcenamespace: default spec:replicas: 3kubectl apply -f test-resource.yaml -
运行程序,观察日志输出:
MyResource Added: default/test-resource, Replicas: 3
总结
- Dynamic Client:
- 适合快速实现,无需生成代码。
- 使用
unstructured.Unstructured处理数据。
- 类型化客户端:
- 适合生产环境,类型安全,需生成代码。
- 使用特定类型(如
*MyResource)操作。
- 选择建议:
- 测试或简单场景:Dynamic Client。
- 长期项目或 Operator:类型化客户端。
如果你有具体的 CRD 定义或需求(例如监听特定字段),可以告诉我,我会进一步定制代码!
---相关文章:
client-go如何监听自定义资源
如何使用 client-go 监听自定义资源 在 Kubernetes 中使用 client-go 监听自定义资源(Custom Resource,简称 CR)需要借助 Dynamic Client 或 Custom Informer,因为 client-go 的标准 Clientset 只支持内置资源(如 Pod…...
安装gpu版本的dgl
1.先去网址,找到对应版本的dgl,然后下载到本地。 dgl-whl下载地址 我的是python 3.8 ,cuda 11.6. windows 2.在虚拟环境里 输入 pip install E:\dgl-1.0.2cu116-cp38-cp38-win_amd64.whl (因为我下载到E盘里了) 这样GPU版本的d…...
AI比人脑更强,因为被植入思维模型【43】蝴蝶效应思维模型
giszz的理解:蝴蝶效应我们都熟知,就是说一个微小的变化,能带动整个系统甚至系统的空间和时间的远端,产生巨大的链式反应。我学习后的启迪,简单的说,就是不要忽视任何微小的问题,更多时候&#x…...
Libevent UDP开发指南
UDP 与 TCP 的核心区别 无连接:不需要建立/维护连接 不可靠:不保证数据包顺序和到达 高效:头部开销小,没有连接管理负担 支持广播/多播:可以向多个目标同时发送数据 一、基础UDP服务器实现 1. 创建 UDP 套接字 #include <event2/event.h> #include <event2/lis…...
Android View事件分发机制深度解析
在Android面试中,关于View事件分发机制的考察往往不仅限于基础流程,更关注底层原理、性能优化和实际应用场景。以下是针对面试的全面回答策略: 一、基础回答框架 核心三要素: 传递流程 "事件分发遵循Activity → Window →…...
如何在 GitHub 上开源一个小项目:从创建到长期维护的完整指南
如何在 GitHub 上开源一个小项目:从创建到长期维护的完整指南 适用于 个人开发者、团队合作、企业开源,涵盖 Git 基础、GitHub 配置、最佳实践、社区互动、自动化 CI/CD 及长期维护策略。 📌 1. 注册 GitHub 账户 如果你还没有 GitHub 账户&…...
autoconf 笔记250404
autoconf autoconf 是 Linux 系统中控制 IPv6 无状态地址自动配置(SLAAC) 的关键参数,位于 /proc/sys/net/ipv6/conf/<接口>/ 目录下。它决定接口是否根据接收到的 路由通告(Router Advertisement, RA) 自动生成…...
5天速成ai agent智能体camel-ai之第1天:camel-ai安装和智能体交流消息讲解(附源码,零基础可学习运行)
嗨,朋友们!👋 是不是感觉AI浪潮铺天盖地,身边的人都在谈论AI Agent、大模型,而你看着那些密密麻麻的代码,感觉像在读天书?🤯 别焦虑!你不是一个人。很多人都想抓住AI的风…...
FPGA——FPGA状态机实现流水灯
一、引言 在FPGA开发中,状态机是一种重要的设计工具,用于处理具有时间顺序的事件。本文将详细介绍如何使用状态机实现一个LED流水灯的效果。 二、状态机概述 状态机(FSM)是一种行为模型,用于表示系统在不同状态下的…...
晶晨S905-S905L-S905LB_S905M2通刷_安卓6.0.1_16S极速开机_线刷固件包
晶晨S905-S905L-S905LB_S905M2通刷_安卓6.0.1_16S极速开机_线刷固件包 线刷方法:(新手参考借鉴一下) 刷机工具版本请用2.2.0以上,导入固件后,刷机工具右侧两个擦除打勾,然后点开始。插上刷机神器…...
构建第一个ArkTS应用:Hello World之旅
# 构建第一个ArkTS应用:Hello World之旅 在鸿蒙应用开发的领域中,ArkTS语言为我们提供了强大而便捷的开发方式。今天,就让我们一起踏上构建第一个ArkTS应用——Hello World的奇妙旅程。 ## 一、创建ArkTS工程 1. 首先,我们要使用…...
第十五届单片机模拟考试III
题目 题目不长 ,功能也不难,一道水题 按键功能 S4界面切换,S5 功能切换,在不同界面转换不同的功能,定义两个标志位记录即可。 S9复位,回到初始状态,记得界面也得回到初始的信号界面࿰…...
测试:正交法设计测试用例
目录 一、什么是正交法 二、利用正交表设计测试用例 正交法设计测试用例的步骤 一、什么是正交法 正交法的目的是为了减少测试用例的数量,让尽可能少的用例覆盖两两组合。认识正交表。 最简单的正交表是L4(2^3),含意如下: “L”代表正…...
生成 SSH Key 并配置 GitHub/GitLab 详细教程
🔑 生成 SSH Key 并配置 GitHub/GitLab 详细教程 🟢 第 1 步:检查是否已有 SSH Key 在 Git Bash (Windows)、终端 (Linux/macOS) 运行以下命令: ls -al ~/.ssh🔹 可能的输出: 如果已有 SSH Key…...
[ctfshow web入门] web5
前置知识 引用博客:phps的利用 当服务器配置了 .phps 文件类型时,访问 .phps 文件会以语法高亮的形式直接显示 PHP 源代码,而不是执行它。.phps被作为辅助开发者的一种功能,开发者可以通过网站上访问xxx.phps直接获取高亮源代码 …...
Qt基本框架(2)
本篇主要介绍如何设置窗口,以及在窗口中添加按钮 本文部分ppt、视频截图原链接:[萌马工作室的个人空间-萌马工作室个人主页-哔哩哔哩视频] 1. Qt简单框架 2. 通过QMainWindow实现简单界面 QMainWindow是构建主窗口应用的核心类,通过合理设计…...
基于javaweb的SpringBoot图片管理系统图片相册系统设计与实现(源码+文档+部署讲解)
技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...
用HTML.CSS.JavaScript实现一个贪吃蛇小游戏
目录 一、引言二、实现思路1. HTML 结构2. CSS 样式3. JavaScript 逻辑 三、代码实现四、效果展示 一、引言 贪吃蛇是一款经典的小游戏,曾经风靡一时。今天,我们将使用 HTML、CSS 和 JavaScript 来实现一个简单的贪吃蛇小游戏。通过这个项目,…...
[特殊字符] Pandas 常用操作对比:Python 运算符 vs Pandas 函数
在 Pandas 中,许多操作可以直接使用 Python 的比较运算符(如 、!、>、< 等),而不需要调用 Pandas 的专门函数(如 eq()、ne()、gt() 等)。这些运算符在 Pandas 中已经被重载,代码更简洁。以…...
Java 实现插入排序:[通俗易懂的排序算法系列之三]
引言 大家好!欢迎继续关注我的排序算法系列。今天,我们要学习的是另一种非常基础且重要的排序算法——插入排序 (Insertion Sort)。 插入排序的思路非常贴近我们日常整理扑克牌的方式,理解起来相对自然。虽然它在最坏情况下的效率不高,但在某些特定场景下,它的表现甚至优…...
使用MATIO库写入MATLAB结构体(struct)数据的示例程序
使用MATIO库写入MATLAB结构体(struct)数据的示例程序 MATIO是一个用于读写MATLAB数据文件(.mat)的开源C库。下面是一个完整的示例程序,展示如何使用MATIO库创建一个包含结构体数据的MAT文件。 示例程序 #include <stdio.h> #include <stdlib.h> #inc…...
JVM——模型分析、回收机制
方法区:存储已被虚拟机加载的类元数据信息(元空间) 堆:存放对象实例,几乎所有的对象实例都在这里分配内存 虚拟机栈:虚拟机栈描述的是|ava方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局…...
7. 记忆(Memory)机制:让AI拥有“短期记忆”与“长期记忆”
引言:当AI学会"记住你" 2025年某银行智能客服因无法记住用户身份,每次对话都要求重复验证,引发大量投诉。引入LangChain 记忆系统后,客户满意度提升62%。本文将基于MemorySaver与FAISS本地存储,教你构建符合…...
前后端分离下,Spring Boot 请求从发起到响应的完整执行流程
以下是前后端分离架构下,Spring Boot 请求从发起到响应的完整执行流程,结合你提出的所有问题,按真实执行顺序和职责链条重新整理所有核心概念、结构、关键类、数据转换点和典型代码示例: 一、前端发起请求(步骤1-2&…...
【文献阅读】Vision-Language Models for Vision Tasks: A Survey
发表于2024年2月 TPAMI 摘要 大多数视觉识别研究在深度神经网络(DNN)训练中严重依赖标注数据,并且通常为每个单一视觉识别任务训练一个DNN,这导致了一种费力且耗时的视觉识别范式。为应对这两个挑战,视觉语言模型&am…...
【BFS最小步数】魔板题解
魔板题解 题目传送门 题目传送门 一、题目描述 Rubik先生发明了魔板的二维版本,这是一个有8个格子的板子,初始状态为: 1 2 3 4 8 7 6 5我们可以用三种操作来改变魔板状态: A:交换上下两行B:将最右边一…...
搭建K8S-1.23
0、简介 这里只用3台服务器来做一个简单的集群 地址主机名192.168.160.40kuber-master-1192.168.160.41kuber-master-2192.168.160.42kuber-node-1 1、关闭三个服务 (1)防火墙 systemctl stop firewalld (2)Selinux setenf…...
AOP在SpringBoot项目中的简单使用场景
SpringBoot AOP的简单使用 添加DTO添加controller(同包不同类)控制器1控制器2 AOP场景演示1. 对某package下的所有接口进行方法执行前逻辑校验新增切面,编写处理逻辑 2. 对某controller类下的所有接口进行方法执行前逻辑校验新增切面,编写处理逻辑 3. 对…...
windows如何安装wkhtmltoimage 给PHP使用根据HTML生成图片
windows如何安装wkhtmltoimage 给PHP使用 在Windows系统上安装wkhtmltoimage以便在PHP中使用,通常涉及到以下几个步骤: 下载wkhtmltoimage 首先,你需要从wkhtmltopdf的官方网站( https://wkhtmltopdf.org/downloads.html …...
代码仓库使用git lfs上传模型文件
一 Git LFS是什么 它主要是用来处理大文件的,比如模型文件通常都很大,超过100MB的话,用普通的Git上传可能会出问题,所以必须用LFS。 二 具体步骤 Windows环境下使用Git LFS上传大模型文件到代码仓库: 2.1ÿ…...
