当前位置: 首页 > news >正文

Kubernetes 使用自定义资源(CRD)扩展API

K8s CRD 即 Kubernetes CustomResourceDefinition,是 Kubernetes 提供的一种扩展机制,允许用户在 Kubernetes 集群中定义和使用自定义的资源类型。通过定义 CRD,用户可以在 Kubernetes 集群中创建、读取、更新和删除自定义资源对象,就像使用原生的 Pod、Service 等资源一样。

本文主要介绍如何使用kubebuilder快速创建自定义资源类型。完成guestbook资源类型自定义,并通过CRD Controller创建deloyment对象,通过deployment运行管理pod

前提条件

  • 安装go https://go.dev/doc/install
  • 安装k8s(可查看上一篇文章)

安装kubebuilder

参考文档步骤:https://book.kubebuilder.io/quick-start

# download kubebuilder and install locally.
curl -L -o kubebuilder "https://go.kubebuilder.io/dl/latest/$(go env GOOS)/$(go env GOARCH)"
chmod +x kubebuilder && sudo mv kubebuilder /usr/local/bin/

创建CRD

创建Project & CRD API

mkdir -p ~/projects/guestbook
cd ~/projects/guestbook
kubebuilder init --domain my.domain --repo my.domain/guestbook
kubebuilder create api --group webapp --version v1 --kind Guestbook

执行完上面两个命令之后,会初始化一个k8s控制器项目,并且创建自定义资源及相关代码。

安装CRD

执行make manifests生成资源配置文件

[root@master guestbook]# make manifests 
/root/crd/guestbook/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases

根据需要编辑api/v1/guestbook_types.go文件


// GuestbookSpec defines the desired state of Guestbook.
type GuestbookSpec struct {// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster// Important: Run "make" to regenerate code after modifying this file// Foo is an example field of Guestbook. Edit guestbook_types.go to remove/updateFoo      string `json:"foo,omitempty"`Replicas int32  `json:"replicas,omitempty"`Image    string `json:"image,omitempty"`
}// GuestbookStatus defines the observed state of Guestbook.
type GuestbookStatus struct {// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster// Important: Run "make" to regenerate code after modifying this fileServiceStatus string `json:"serviceStatus"`Replicas      int32  `json:"replicas,omitempty"`
}

编写CRD Controller代码internal/controller/guestbook_controller.go
前面只是定义了guestbook的资源类型,当创建guestbook类型时需要做什么操作是通过CRD Controller来完成的, 本示例用controller创建一个deployment类型的资源运行两个Nginx Pod。

kubebuilder已经帮我们生成了代码框架guestbook_controller.go,只需要在Reconcile方法添加相关的逻辑即可。

/*
Copyright 2025.Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/package controllerimport ("context""fmt""k8s.io/apimachinery/pkg/api/errors""k8s.io/apimachinery/pkg/runtime"ctrl "sigs.k8s.io/controller-runtime""sigs.k8s.io/controller-runtime/pkg/client""sigs.k8s.io/controller-runtime/pkg/log"corev1 "k8s.io/api/core/v1"appsv1 "k8s.io/api/apps/v1"webappv1 "my.domain/guestbook/api/v1"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)// GuestbookReconciler reconciles a Guestbook object
type GuestbookReconciler struct {client.ClientScheme *runtime.Scheme
}// +kubebuilder:rbac:groups=webapp.my.domain,resources=guestbooks,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=webapp.my.domain,resources=guestbooks/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=webapp.my.domain,resources=guestbooks/finalizers,verbs=update// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the Guestbook object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.1/pkg/reconcile//资源对象创建/更新/删除/变化时触发调用
func (r *GuestbookReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {logger := log.FromContext(ctx)fmt.Printf("Guestbook Reconcile called....%v...%v \n",req.Name,req.Namespace)// 获取当前已存在的Deployment对象(如果有的话)existingDeployment := &appsv1.Deployment{}err1 := r.Get(ctx, client.ObjectKey{Namespace: req.Namespace,Name:      fmt.Sprintf("%s-deployment", req.Name),}, existingDeployment)var guestbook webappv1.Guestbookif err := r.Get(ctx, req.NamespacedName, &guestbook); err != nil {//如果guestbook资源不存在,删除已有的deploymentif errors.IsNotFound(err) {return r.handleGuestbookDeleted(existingDeployment,ctx,req)}}desiredDeployment := r.buildDeploymentForGuestbook(&guestbook,req)if err1!=nil && errors.IsNotFound(err1) {// 如果不存在,则创建Deploymentif err := r.Create(ctx, desiredDeployment); err != nil {return ctrl.Result{}, fmt.Errorf("failed to create Deployment: %v", err)}logger.Info("Deployment created successfully")} else {// 对比期望的Deployment和已存在的Deployment,若有差异则更新if !r.deploymentsEqual(desiredDeployment, existingDeployment) {existingDeployment.Spec = desiredDeployment.Specif err := r.Update(ctx, existingDeployment); err != nil {return ctrl.Result{}, fmt.Errorf("failed to update Deployment: %v", err)}logger.Info("Deployment updated successfully")}}// 更新Guestbook资源的状态(这里简单示例,可根据实际情况完善状态更新逻辑)fmt.Printf("guestbook spec replicas: %v \n",guestbook.Spec.Replicas)guestbook.Status.Replicas = guestbook.Spec.Replicasguestbook.Status.ServiceStatus = "Running"if err := r.Status().Update(ctx, &guestbook); err != nil {return ctrl.Result{}, fmt.Errorf("failed to update Guestbook status: %v", err)}return ctrl.Result{}, nil
}// handleGuestbookDeleted处理Guestbook资源被删除的情况,删除对应的Deployment
func (r *GuestbookReconciler) handleGuestbookDeleted(existedDeployment *appsv1.Deployment,ctx context.Context, req ctrl.Request) (ctrl.Result, error) {if (existedDeployment != nil && existedDeployment.Name != "") {err := r.Delete(ctx, existedDeployment)if err != nil {log.FromContext(ctx).Error(err, "failed to delete Deployment")return ctrl.Result{}, err}return ctrl.Result{}, nil}//logger := log.FromContext(ctx) 获取当前已存在的Deployment对象(如果有的话)//existingDeployment := &appsv1.Deployment{}////err := r.Get(ctx, client.ObjectKey{// Namespace: req.Namespace,// Name:      fmt.Sprintf("%s-deployment", req.Name),// Name:      "guestbook-sample-deployment",//}, existingDeployment)//logger.Error(err, "handleGuestbookDeleted err is not null")// If GuestBook does not exist, remove the Deployment if it exists//if err == nil {//// logger.Info("GuestBook resource not found, removing the associated Deployment")// err = r.Delete(ctx, existingDeployment)// if err != nil {//    logger.Error(err, "failed to delete Deployment")//    return ctrl.Result{}, err// }// return ctrl.Result{}, nil//} else {// logger.Error(err, "handleGuestbookDeleted err is not null")// //fmt.Println("handleGuestbookDeleted err is not null")//}return ctrl.Result{}, nil
}// buildDeploymentForGuestbook根据Guestbook资源构建期望的Deployment对象
func (r *GuestbookReconciler) buildDeploymentForGuestbook(guestbook *webappv1.Guestbook,req ctrl.Request) *appsv1.Deployment {labels := map[string]string{"app": guestbook.Name,}replicas := guestbook.Spec.Replicasreturn &appsv1.Deployment{ObjectMeta: metav1.ObjectMeta{Name:      fmt.Sprintf("%s-deployment", req.Name),Namespace: req.Namespace,Labels:    labels,},Spec: appsv1.DeploymentSpec{Replicas: &replicas,Selector: &metav1.LabelSelector{MatchLabels: labels,},Template: corev1.PodTemplateSpec{ObjectMeta: metav1.ObjectMeta{Labels: labels,},Spec: corev1.PodSpec{Containers: []corev1.Container{{Name:  "guestbook-container",Image: guestbook.Spec.Image,Ports: []corev1.ContainerPort{{Name:          "http",ContainerPort: 80,},},},},},},},}
}// deploymentsEqual比较两个Deployment对象是否相等(简单比较主要属性)
func (r *GuestbookReconciler) deploymentsEqual(d1, d2 *appsv1.Deployment) bool {return d1.Spec.Replicas == d2.Spec.Replicas && d1.Spec.Template.Spec.Containers[0].Image == d2.Spec.Template.Spec.Containers[0].Image
}// SetupWithManager sets up the controller with the Manager.
func (r *GuestbookReconciler) SetupWithManager(mgr ctrl.Manager) error {return ctrl.NewControllerManagedBy(mgr).For(&webappv1.Guestbook{}).Named("guestbook").Complete(r)
}

执行make install安装命令

[root@master guestbook]# make install
/root/crd/guestbook/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
/root/crd/guestbook/bin/kustomize build config/crd | kubectl apply -f -
customresourcedefinition.apiextensions.k8s.io/guestbooks.webapp.my.domain created

验证资源是否存在
执行 kubectl api-resources,可以看到guestbooks资源已经被创建。

[root@master guestbook]# kubectl api-resources---前面省略---
priorityclasses                   pc           scheduling.k8s.io/v1                   false        PriorityClass
csidrivers                                     storage.k8s.io/v1                      false        CSIDriver
csinodes                                       storage.k8s.io/v1                      false        CSINode
csistoragecapacities                           storage.k8s.io/v1                      true         CSIStorageCapacity
storageclasses                    sc           storage.k8s.io/v1                      false        StorageClass
volumeattachments                              storage.k8s.io/v1                      false        VolumeAttachment
guestbooks                                     webapp.my.domain/v1                    true         Guestbook

创建guestbook资源对象

先执行make run命令,将前面创建的Controller运行起来

[root@master guestbook]# make run
/root/crd/guestbook/bin/controller-gen rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
/root/crd/guestbook/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
go fmt ./...
go vet ./...
go run ./cmd/main.go
2025-01-09T07:36:11-05:00	INFO	setup	starting manager
2025-01-09T07:36:11-05:00	INFO	starting server	{"name": "health probe", "addr": "[::]:8081"}
2025-01-09T07:36:11-05:00	INFO	Starting EventSource	{"controller": "guestbook", "controllerGroup": "webapp.my.domain", "controllerKind": "Guestbook", "source": "kind source: *v1.Guestbook"}
2025-01-09T07:36:11-05:00	INFO	Starting Controller	{"controller": "guestbook", "controllerGroup": "webapp.my.domain", "controllerKind": "Guestbook"}
2025-01-09T07:36:11-05:00	INFO	Starting workers	{"controller": "guestbook", "controllerGroup": "webapp.my.domain", "controllerKind": "Guestbook", "worker count": 1}

创建刚定义的CRD资源
kubebuilder已经生成了一个yaml文件样例
/config/samples/webapp_v1_guestbook.yaml

修改下相关参数

apiVersion: webapp.my.domain/v1
kind: Guestbook
metadata:labels:app.kubernetes.io/name: guestbookapp.kubernetes.io/managed-by: kustomizename: guestbook-sample
spec:replicas: 2image: nginx

执行创建命令

[root@master guestbook]# kubectl apply -k config/samples
guestbook.webapp.my.domain/guestbook-sample created
# 验证是否创建成功
[root@master guestbook]# kubectl get guestbook
NAME               AGE
guestbook-sample   17s
[root@master guestbook]# kubectl get deployment
NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
guestbook-sample-deployment   2/2     2            2           22s
tomcat-deployment             2/2     2            2           17d
wordpress                     0/1     1            0           12d
# 两个Nginx Pod已经被创建
[root@master guestbook]# kubectl get pod
NAME                                           READY   STATUS    RESTARTS     AGE
guestbook-sample-deployment-654b67bc8f-kkpdr   1/1     Running   0            25s
guestbook-sample-deployment-654b67bc8f-sf6t5   1/1     Running   0            25s# 如果要查看guestbook更详细信息,执行
kubectl get guestbook -o yaml

如果需要删除 guestbook资源类型,可以执行

kubectl delete -k config/samples

相关文章:

Kubernetes 使用自定义资源(CRD)扩展API

K8s CRD 即 Kubernetes CustomResourceDefinition,是 Kubernetes 提供的一种扩展机制,允许用户在 Kubernetes 集群中定义和使用自定义的资源类型。通过定义 CRD,用户可以在 Kubernetes 集群中创建、读取、更新和删除自定义资源对象&#xff0…...

用户使用LLM模型都在干什么?

Anthropic 对用户与 Claude 3.5 Sonnet 的大量匿名对话展开分析,主要发现及相关情况如下: 使用用途分布 软件开发主导:在各类使用场景中,软件开发占比最高,其中编码占 Claude 对话的 15% - 25%,网页和移动应…...

MySQL常用命令之汇总(Summary of Commonly Used Commands in MySQL)

MySQL常用命令汇总 简介 ‌MySQL是一个广泛使用的开源关系型数据库管理系统,由瑞典的MySQL AB公司开发,现属于Oracle公司。‌ MySQL支持SQL(结构化查询语言),这是数据库操作的标准语言,用户可以使用SQL进…...

六年之约day10

今日开心∶今天部门开了个颁奖大会,看着别人收获的荣誉,还真有些羡慕,什么时候,我也能拥有属于自己的荣誉啊. 今日不开心∶活没干多少,对业务也不是很懂 今日思考∶很多事情,存在即合理.工作,…...

springboot和vue配置https请求

项目场景: 代码发布到线上使用https请求需要配置ssl证书,前后端都需要修改。 问题描述 如图,我们在调用接口时报如下错误,这就是未配置ssl但是用https请求产生的问题。 解决方案: 前端:在vite.config.js文…...

selenium遇见伪元素该如何处理?

🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 问题发生 在很多前端页面中,大家会见到很多::before、::after 元素,比如【百度流量研究院】: 比如【百度疫情大数…...

慧集通(DataLinkX)iPaaS集成平台-数据质量

1.什么是数据质量 介绍: 数据质量的主要作用就是记录组件写入的数据,及执行时的相关信息,如执行的最终状态(成功,失败,进行中等),执行的时间(创建时间,修改时…...

微软发布AIOpsLab:一个开源的全面AI框架,用于AIOps代理

在当今这个云计算技术迅猛发展的时代,企业面临着前所未有的挑战与机遇。随着云基础设施的日益复杂化,它们成为了企业运营不可或缺的支柱。网站可靠性工程师(Site Reliability Engineers,简称SRE)和DevOps团队肩负着关键…...

ElasticSearch | Elasticsearch与Kibana页面查询语句实践

关注:CodingTechWork 引言 在当今大数据应用中,Elasticsearch(简称 ES)以其高效的全文检索、分布式处理能力和灵活的查询语法,广泛应用于各类日志分析、用户行为分析以及实时数据查询等场景。通过 ES,用户…...

12.C语言中的struct详解:定义、赋值、指针、嵌套与位字段

目录 1.简介2.struct 的复制3.struct 指针4.struct 的嵌套5.位字段6.弹性数组成员 1.简介 本篇原文为:C语言中的struct详解:定义、赋值、指针、嵌套与位字段。 更多C进阶、rust、python、逆向等等教程,可点击此链接查看:酷程网 …...

文件读写到SQLite数据库的方法

在 SQLite 数据库中,将文件读写到数据库的常见方法主要有以下几种: 1. 将文件以 BLOB 类型存储 BLOB(Binary Large Object) 是 SQLite 中的二进制数据类型,可以直接用来存储文件内容。 步骤: 创建表 创建一…...

springboot项目部署至linux

1.修改pom.xml 确认是否有以下代码&#xff0c;没有请进行添加&#xff0c;mainClass改成你的启动类 <plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.ve…...

使用sed命令封装自定义dos2unix脚本

使用sed命令封装自定义dos2unix脚本 创建 `dos2unix` 脚本使用自定义的 `dos2unix` 脚本注意事项要将 sed -i 封装为一个简单的 dos2unix 脚本,你可以创建一个 Bash 脚本文件,该文件接受文件名作为参数,并使用 sed 命令来删除文件中的 DOS 回车符(\r)。以下是一个基本的实…...

调整Python+Pytest+Allure+Yaml+Pymysql框架中需要执行的用例顺序

当pytest框架中有时时候会因为用例的前后关联关系需要调整用例执行顺序时则可以跟进具体的要求调整pytest.ini配置文件中执行用例文件夹的前后顺序 当如果是需要调整某个文件夹中用例的执行顺序时&#xff0c;则跟进具体的文件调整对应testcases中test_*.py文件中的执行顺序...

带内管理和带外管理

带内管理&#xff08;In-Band Management&#xff09; 概述 带内管理是一种借助生产网络来传输管理数据的网络管理方式&#xff0c;其管理流量与业务流量共享相同的网络路径。 特点 共享网络路径&#xff1a;管理数据和业务数据一同使用现有的网络基础设施&#xff0c;在同…...

【操作系统】阻塞非阻塞I/O、同步异步I/O

阻塞I/O&#xff1a;程序发起I/O操作时&#xff0c;程序被挂起&#xff0c;直到I/O操作完成并返回结果。在这个过程中&#xff0c;程序会被阻塞无法执行其他任务。适用于简单、低并发的场景。 非阻塞I/O&#xff1a;程序发起I/O操作时&#xff0c;不会等待&#xff0c;立即返回…...

spring cloud alibaba-dubbo3 rpc运行原理

Dubbo3 运行原理 Dubbo3 是 Apache Dubbo 的最新版本&#xff0c;是一个高性能、轻量级的分布式服务框架&#xff0c;支持微服务架构。相比 Dubbo2&#xff0c;它在协议、扩展性、服务治理、流控等方面做了大量改进&#xff0c;特别是引入了 Triple 协议&#xff0c;使其更加适…...

【Uniapp-Vue3】computed计算属性用法及方法对比

如果我们想要将两个响应式变量进行某种运算&#xff0c;就可以使用computed计算属性。 比如下面这个例子中&#xff0c;输入名和姓合成全名&#xff0c;可以用直接显示的方法&#xff1a; 我们也可以使用computed属性&#xff1a; import {computed} from "vue"; le…...

web实操10——Filter和Listener

Filter介绍 web三大组件&#xff1a;servlet&#xff0c;filter, lisenter。 Filter快速入门 步骤 拦截路径&#xff1a;你访问什么样的资源&#xff0c;过滤器会生效&#xff0c;包括静态资源&#xff0c;动态资源。 配置&#xff1a;两种配置方式 代码实现 代码&#…...

Spring中,出现依赖不完全注入后才执行逻辑

1. Bean生命周期机制 Spring管理的Bean是通过生命周期回调进行初始化和依赖注入的。以下是典型的生命周期阶段&#xff1a; 实例化&#xff08;Instantiation&#xff09;&#xff1a; 创建Bean对象。依赖注入&#xff08;Dependency Injection&#xff09;&#xff1a; 向Be…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

业务系统对接大模型的基础方案:架构设计与关键步骤

业务系统对接大模型&#xff1a;架构设计与关键步骤 在当今数字化转型的浪潮中&#xff0c;大语言模型&#xff08;LLM&#xff09;已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中&#xff0c;不仅可以优化用户体验&#xff0c;还能为业务决策提供…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

Java 二维码

Java 二维码 **技术&#xff1a;**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...