【云原生开发】如何通过client-go来操作K8S集群
✨✨ 欢迎大家来到景天科技苑✨✨
🎈🎈 养成好习惯,先赞后看哦~🎈🎈
🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。
🏆《博客》:Python全栈,Golang开发,云原生开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。所属的专栏:云原生开发
景天的主页:景天科技苑
文章目录
- client-go
- 一、client-go介绍
- 1. 什么是client-go?
- 2. client-go版本的演变
- 3. client-go客户端分类
- 4. client-go客户端工具依赖关系
- 5. 安装client-go
- 二、使用client-go进行基本操作
- 2.1 in-cluster配置
- 2.2 out-of-cluster配置
- 2.3 client-go 查询列表功能使用
- 2.4 client-go查询资源详情
- 2.5 client-go更新资源功能
- 2.6 client-go删除资源
- 2.7 client-go创建资源
- 2.8 client-go使用json串创建资源
- 三、总结
client-go
一、client-go介绍
1. 什么是client-go?
client-go是Kubernetes官方提供的,用于操作kubernetes资源的Go语言客户端库,通过它,开发者可以非常方便地在Go项目中与Kubernetes集群进行交互,实现对Kubernetes资源以及自定义CRD的增删改查和事件监听等操作。
同时,可以通过client-go实现kubernetes的二次开发。自定义资源开发。
源码:
github下载地址:https://github.com/kubernetes/client-go
如果是其他语言的客户端工具,可以通过https://github.com/kubernetes-client 来查看
我们看下client-go几个比较重要的目录
2. client-go版本的演变
左边是client-go的版本。右边是k8s的版本
在client-go 1.17版本之前,client-go的版本与k8s版本保持一致,1.17之后,client-go的版本多了一个v的tag。是由于go语言的包是带v的版本
建议:client-go我们直接用最新版本
3. client-go客户端分类
restclient: 一般我们不会使用restclient,因为它需要把整个资源的yaml文件或json数据都传过去,显得比较臃肿,一般我们不用这个
discoverclient: 比如我们创建deployment时的apiversion: apps/v1 apps就是资源组Group v1就是资源版本Version 资源信息 就是kind 。我们一般也不会用这个客户端工具
ClientSet: 只能针对K8S内置的资源进行操作,不能操作自定义的资源
DyanmicClient: 我们经常使用这个客户端,但是对于内置资源,我们还是习惯使用ClientSet,因为它更好用,自定义资源我们使用DyanmicClient。
我们可以通过命令 kubectl api-resources 查看每种资源的资源组
4. client-go客户端工具依赖关系
5. 安装client-go
client-go是一个Go模块,可以通过Go Module的方式进行安装。在你的Go项目中,执行以下命令:
go get k8s.io/client-go@latest
这将安装最新版本的client-go。此外,你还需要安装一些相关的依赖库,例如apimachinery,用于处理Kubernetes API对象。
go get k8s.io/apimachinery@latest
安装完还需要运行go mod tidy 加载依赖包
二、使用client-go进行基本操作
创建Kubernetes客户端
在使用client-go之前,首先需要创建一个Kubernetes客户端。client-go提供了两种创建客户端的方式:in-cluster配置和out-of-cluster配置。
我们根据我们之前写好的脚手架,改个名字,在此基础上开发我们的项目
并不是说在此改了就可以了,因为很多包用的还是原来的名字,
我们可以批量替换
在Goland IDE中想要替换某一段特定的字符串,可以使用Find and Replace 功能来实现。这是一种全局性的操作,将会在你的整个项目或指定的文件/文件夹中进行。
使用Ctrl + Shift + R 打开Find and Repalce对话框
我们测试client-go,要用到k8s集群,得有~/.kube/config 这个文件
里面是加载集群的配置信息
将这个文件复制到我们的项目中
2.1 in-cluster配置
在Kubernetes 集群内部运行时,可以使用in-cluster配置。这种方式不需要手动指定kubeconfig文件路径,client-go会自动使用集群中的服务账户进行身份验证。
2.2 out-of-cluster配置
测试client-go,我们使用out-of-cluster方式来测试,发布项目的时候,我们使用in-cluster方式配置
在本地电脑开发环境或其他非Kubernetes集群中运行时,可以使用out-of-cluster配置。这需要指定kubeconfig文件的路径。kubeconfig文件通常位于$HOME/.kube/config,它包含了访问Kubernetes集群所需的配置信息。
这是github上面看用法举例
package mainimport ("context""fmt"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/client-go/kubernetes""k8s.io/client-go/tools/clientcmd"
)func main() {//1. 初始化config实例//var kubeconfig *string// 通过家目录找到kubeconfig文件。我们的路径是已知的,所以不用此项配置//if home := homedir.HomeDir(); home != "" {// kubeconfig = flag.String("meta.kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")//} else {// kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")//}//flag.Parse()// 1. 初始化config实例// 因为我们的路径是已知的,所以不用上面的配置。use the current context in kubeconfig// masterUrl就是离我们主节点的ip地址和端口号,我们在kubeconfig文件中有了,所以可以省略config, err := clientcmd.BuildConfigFromFlags("", "meta.kubeconfig")//要想正常应用我们的服务,必须能够实例化成功kubeconfig,要不然后面所有的功能都无法使用,所以这里直接报panic即可if err != nil {panic(err.Error())}// 2. 创建客户端工具 create the clientsetclientset, err := kubernetes.NewForConfig(config)//这个客户端工具如果生成失败的话,后面的操作也无法完成,所以这里也报panic即可if err != nil {panic(err.Error())}//3. 操作集群pods, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{})//此时报错的话,不应该是panic了,但是这里官方用的还是panic。后期需要优化,我么可以返回个错误信息if err != nil {panic(err.Error())}//打印pod的数量fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))// 获取指定名称空间下的pod数量,如果namespace不传值,默认查的是所有命名空间下的podnamespace := "h5-web"pods, err = clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})if err != nil {panic(err.Error())}//打印pod的数量fmt.Printf("%s namespce has %d pods in the cluster\n", namespace, len(pods.Items))//看下返回的pod是什么fmt.Println("pods是什么:", pods)
}
2.3 client-go 查询列表功能使用
我们看下List方法的参数,包含两个,一个context,一个是ListOptions。
这个ListOptions就可以在里面做些筛选条件,比如传json串,标签等
我们看下List的返回值
所以我们要查询具体的pod里面的信息,可以在Items字段中获取到所有的pod
跟我们通过在k8s集群中通过kubectl … -ojson的得到的信息是一样的
如果要取其中某个pod,可以通过下标来获取
如果忘记pod的层级关系,可以使用k8s命令的-ojson 查看一下
完整代码:
package mainimport ("context""fmt"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/client-go/kubernetes""k8s.io/client-go/tools/clientcmd"
)func main() {// 1. 初始化config实例// masterUrl就是离我们主节点的ip地址和端口号,我们在kubeconfig文件中有了,所以可以省略config, err := clientcmd.BuildConfigFromFlags("", "meta.kubeconfig")//要想正常应用我们的服务,必须能够实例化成功kubeconfig,要不然后面所有的功能都无法使用,所以这里直接报panic即可if err != nil {panic(err.Error())}// 2. 创建客户端工具 create the clientsetclientset, err := kubernetes.NewForConfig(config)//这个客户端工具如果生成失败的话,后面的操作也无法完成,所以这里也报panic即可if err != nil {panic(err.Error())}//3. 操作集群pods, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{})//此时报错的话,不应该是panic了,但是这里官方用的还是panic。后期需要优化,我么可以返回个错误信息if err != nil {panic(err.Error())}//打印pod的数量fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))// 获取指定名称空间下的pod数量,如果namespace不传值,默认查的是所有命名空间下的podnamespace := "h5-web"pods, err = clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})if err != nil {panic(err.Error())}//打印pod的数量fmt.Printf("%s namespce has %d pods in the cluster\n", namespace, len(pods.Items))//看下返回的pod是什么fmt.Println("pods是什么:", pods)//获取到某个podfmt.Println(pods.Items[0].Spec.NodeName)//获取到某个容器的镜像fmt.Println(pods.Items[0].Spec.Containers[0].Image)}
下面,我们探讨下,我们怎么知道我们要操作的资源是属于CoreV1()或者是其他什么组呢?
之前,我们说过,在K8S集群中,可以通过命令 kubectl api-resources查看
deployment 的apiversion是 apps/v1 对应的client-go里面的方法就是 clientset.AppsV1()
crontabs 的apiversion是batch/v1 对应的client-go里面的方法就是clientset.BatchV1()
ingresses的apiversion是networking.k8s.io/v1 对应client-go里面的方法就是clientset.NetworkingV1()
…
以此类推,由此我们就知道了个汇总资源对应的操作方法
这种V1的apiversion的资源,对应的就是clientset.CoreV1()
如果不想通过K8S命令来查,也可以在代码中查看
点进来
这里可看看到个各种方法,不过我们用的时候要把首字母大写
比如查询deployment
//查询deployment列表,用法与pod类似
deploy, _ := clientset.AppsV1().Deployments("").List(context.TODO(), metav1.ListOptions{})
//查看所有名称空间下deploy的数量
fmt.Println("deployment的数量", len(deploy.Items))
//打印deploy名称,由于是多个,我们循环打印
for _, i := range deploy.Items {fmt.Printf("当前资源的名称空间: %s, deployment名称是: %s\n", i.Namespace, i.Name)
}//查询没有名称空间限制的资源,比如名称空间,工作节点,clusterrole,clusterrolebinding等
//查的都是集群的资源
//比如我们查询集群有多少个名称空间
ns, _ := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
fmt.Printf("There are %d namespaces in the cluster\n", len(ns.Items))
完整代码:
package mainimport ("context""fmt"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/client-go/kubernetes""k8s.io/client-go/tools/clientcmd"
)func main() {// 1. 初始化config实例// masterUrl就是离我们主节点的ip地址和端口号,我们在kubeconfig文件中有了,所以可以省略config, err := clientcmd.BuildConfigFromFlags("", "meta.kubeconfig")//要想正常应用我们的服务,必须能够实例化成功kubeconfig,要不然后面所有的功能都无法使用,所以这里直接报panic即可if err != nil {panic(err.Error())}// 2. 创建客户端工具 create the clientsetclientset, err := kubernetes.NewForConfig(config)//这个客户端工具如果生成失败的话,后面的操作也无法完成,所以这里也报panic即可if err != nil {panic(err.Error())}//3. 操作集群pods, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{})//此时报错的话,不应该是panic了,但是这里官方用的还是panic。后期需要优化,我么可以返回个错误信息if err != nil {panic(err.Error())}//打印pod的数量fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))// 获取指定名称空间下的pod数量,如果namespace不传值,默认查的是所有命名空间下的pod//namespace := "h5-web"//pods, err = clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})//if err != nil {// panic(err.Error())//}打印pod的数量//fmt.Printf("%s namespce has %d pods in the cluster\n", namespace, len(pods.Items))看下返回的pod是什么//fmt.Println("pods是什么:", pods)//获取到某个pod//fmt.Println(pods.Items[0].Spec.NodeName)获取到某个容器的镜像//fmt.Println(pods.Items[0].Spec.Containers[0].Image)//查询deployment列表,用法与pod类似deploy, _ := clientset.AppsV1().Deployments("").List(context.TODO(), metav1.ListOptions{})//查看所有名称空间下deploy的数量fmt.Println("deployment的数量", len(deploy.Items))//打印deploy名称,由于是多个,我们循环打印for _, i := range deploy.Items {fmt.Printf("当前资源的名称空间: %s, deployment名称是: %s\n", i.Namespace, i.Name)}//查询没有名称空间限制的资源,比如名称空间,工作节点,clusterrole,clusterrolebinding等//查的都是集群的资源//比如我们查询集群有多少个名称空间ns, _ := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})fmt.Printf("There are %d namespaces in the cluster\n", len(ns.Items))
}
2.4 client-go查询资源详情
Get()方法,可以获取单个资源的详情,获取详情之后,我们可以传给前端展示,或者根据查询出来的数据进行更改
比如说,我们对K8S集群中h5-web名称空间下的 pods 查询详情
// 查询资源详情 Get()方法
// Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Pod, error)
poddetail, _ := clientset.CoreV1().Pods("h5-web").Get(context.TODO(), "web-864f4c6988-95sw4", metav1.GetOptions{})
//fmt.Println("pod详情:", poddetail)
//打印pod的镜像名称
fmt.Println("pod第一个容器的镜像名称", poddetail.Spec.Containers[0].Image)//获取名称空间的详情
namespace, _ := clientset.CoreV1().Namespaces().Get(context.TODO(), "h5-web", metav1.GetOptions{})
fmt.Println("名称空间详情:", namespace)
完整代码
package mainimport ("context""fmt"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/client-go/kubernetes""k8s.io/client-go/tools/clientcmd"
)func main() {// 1. 初始化config实例// masterUrl就是离我们主节点的ip地址和端口号,我们在kubeconfig文件中有了,所以可以省略config, err := clientcmd.BuildConfigFromFlags("", "meta.kubeconfig")//要想正常应用我们的服务,必须能够实例化成功kubeconfig,要不然后面所有的功能都无法使用,所以这里直接报panic即可if err != nil {panic(err.Error())}// 2. 创建客户端工具 create the clientsetclientset, err := kubernetes.NewForConfig(config)//这个客户端工具如果生成失败的话,后面的操作也无法完成,所以这里也报panic即可if err != nil {panic(err.Error())}//3. 操作集群// 查询资源详情 Get()方法// Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Pod, error)poddetail, _ := clientset.CoreV1().Pods("h5-web").Get(context.TODO(), "web-864f4c6988-95sw4", metav1.GetOptions{})//fmt.Println("pod详情:", poddetail)//打印pod的镜像名称fmt.Println("pod第一个容器的镜像名称", poddetail.Spec.Containers[0].Image)//获取名称空间的详情namespace, _ := clientset.CoreV1().Namespaces().Get(context.TODO(), "h5-web", metav1.GetOptions{})fmt.Println("名称空间详情:", namespace)}
其他资源查询方式类似,感兴趣的朋友可以尝试下
2.5 client-go更新资源功能
更新的前提是该字段是可更改的
比如这种can’t be updated的字段,就不能被修改
注意:如果修改的字段在资源中不存在,比如labels 。修改时会报空指针错误,此时就要初始化下才能修改
//更新资源操作 Update()
//先获取资源详情,再修改
//比如,我们修改service的暴露的端口号
service, _ := clientset.CoreV1().Services("h5-web").Get(context.TODO(), "web", metav1.GetOptions{})
fmt.Printf("service对外的端口号是 %d\n", service.Spec.Ports[0].NodePort)
// 修改端口号
// service-node-port-range 默认可以设置的范围 30000-32767
service.Spec.Ports[0].NodePort = 32050
// 修改暴露的端口号
// Update(ctx context.Context, service *v1.Service, opts metav1.UpdateOptions) (*v1.Service, error)
_, err = clientset.CoreV1().Services("h5-web").Update(context.TODO(), service, metav1.UpdateOptions{})
if err != nil {panic(err.Error())
}
fmt.Printf("修改后service对外的端口号是 %d\n", service.Spec.Ports[0].NodePort)//修改deploy的副本数
deploy, _ := clientset.AppsV1().Deployments("h5-web").Get(context.TODO(), "web", metav1.GetOptions{})
//查看当前deploy的副本数
fmt.Println("当前deploy的副本数是:", *deploy.Spec.Replicas)
//修改副本数
replacs := int32(3)
//注意Replicas 是int32的指针类型
deploy.Spec.Replicas = &replacs_, err = clientset.AppsV1().Deployments("h5-web").Update(context.TODO(), deploy, metav1.UpdateOptions{})
//查看修改后deploy的副本数
fmt.Println("修改后deploy的副本数是:", *deploy.Spec.Replicas)
完整代码:
package mainimport ("context""fmt"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/client-go/kubernetes""k8s.io/client-go/tools/clientcmd"
)func main() {// 1. 初始化config实例// masterUrl就是离我们主节点的ip地址和端口号,我们在kubeconfig文件中有了,所以可以省略config, err := clientcmd.BuildConfigFromFlags("", "meta.kubeconfig")//要想正常应用我们的服务,必须能够实例化成功kubeconfig,要不然后面所有的功能都无法使用,所以这里直接报panic即可if err != nil {panic(err.Error())}// 2. 创建客户端工具 create the clientsetclientset, err := kubernetes.NewForConfig(config)//这个客户端工具如果生成失败的话,后面的操作也无法完成,所以这里也报panic即可if err != nil {panic(err.Error())}//3. 操作集群//更新资源操作 Update()//先获取资源详情,再修改//比如,我们修改service的暴露的端口号service, _ := clientset.CoreV1().Services("h5-web").Get(context.TODO(), "web", metav1.GetOptions{})fmt.Printf("service对外的端口号是 %d\n", service.Spec.Ports[0].NodePort)// 修改端口号// service-node-port-range 默认可以设置的范围 30000-32767service.Spec.Ports[0].NodePort = 32050// 修改暴露的端口号// Update(ctx context.Context, service *v1.Service, opts metav1.UpdateOptions) (*v1.Service, error)_, err = clientset.CoreV1().Services("h5-web").Update(context.TODO(), service, metav1.UpdateOptions{})if err != nil {panic(err.Error())}fmt.Printf("修改后service对外的端口号是 %d\n", service.Spec.Ports[0].NodePort)//修改deploy的副本数deploy, _ := clientset.AppsV1().Deployments("h5-web").Get(context.TODO(), "web", metav1.GetOptions{})//查看当前deploy的副本数fmt.Println("当前deploy的副本数是:", *deploy.Spec.Replicas)//修改副本数replacs := int32(3)//注意Replicas 是int32的指针类型deploy.Spec.Replicas = &replacs_, err = clientset.AppsV1().Deployments("h5-web").Update(context.TODO(), deploy, metav1.UpdateOptions{})//查看修改后deploy的副本数fmt.Println("修改后deploy的副本数是:", *deploy.Spec.Replicas)
}
2.6 client-go删除资源
删除pod,比如我们将下列的pod删除
//删除资源 Delete()
//删除pod
err = clientset.CoreV1().Pods("h5-web").Delete(context.TODO(), "web-864f4c6988-r456g", metav1.DeleteOptions{})
if err != nil {panic(err.Error())
可见pod已被删除
2.7 client-go创建资源
创建namespace
//创建名称空间
var namespace corev1.Namespace
//创建namespace只需要传个名字就可以了
namespace.Name = "test1"
// Create(ctx context.Context, namespace *v1.Namespace, opts metav1.CreateOptions) (*v1.Namespace, error)
//传的是指针
_, err = clientset.CoreV1().Namespaces().Create(context.TODO(), &namespace, metav1.CreateOptions{})
if err != nil {panic(err.Error())
}
注意,这个corev1的导包,我们要根据Create()这个方法里面的导包,导过来,不要导错了,因为很多v1的包
创建deployment
注意,这个deployment的v1,
导包的时候,不要导错
传参时,要把必须得参数都传进去
可以通过这个命令来查看哪些是必须传的参数
kubectl create deployment mynginx --image="nginx" --dry-run=client -oyaml
它会导出一份yaml文件
package mainimport ("context""fmt"deployv1 "k8s.io/api/apps/v1"corev1 "k8s.io/api/core/v1"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/client-go/kubernetes""k8s.io/client-go/tools/clientcmd"
)func main() {// 1. 初始化config实例// masterUrl就是离我们主节点的ip地址和端口号,我们在kubeconfig文件中有了,所以可以省略config, err := clientcmd.BuildConfigFromFlags("", "meta.kubeconfig")//要想正常应用我们的服务,必须能够实例化成功kubeconfig,要不然后面所有的功能都无法使用,所以这里直接报panic即可if err != nil {panic(err.Error())}// 2. 创建客户端工具 create the clientsetclientset, err := kubernetes.NewForConfig(config)//这个客户端工具如果生成失败的话,后面的操作也无法完成,所以这里也报panic即可if err != nil {panic(err.Error())}//3. 操作集群//创建deploymentvar deploy deployv1.Deployment//给deployment传参,要把必须传的参数都传进去,不然创建会报错deploy.Name = "mydeploy"deploy.Namespace = "test1"//副本数replicas := int32(1)deploy.Spec.Replicas = &replicas//mathlabelslabels := make(map[string]string)labels["app"] = "nginx"//Selector 是个指针类型,需要先初始化//Selector *metav1.LabelSelector `json:"selector" protobuf:"bytes,2,opt,name=selector"`deploy.Spec.Selector = &metav1.LabelSelector{}deploy.Spec.Selector.MatchLabels = labels//deployment label metadata会将里面的资源发布出去,metadata可以省略掉deploy.Labels = labels// 创建template 这个template模版就是pod的模板// Template v1.PodTemplateSpec `json:"template" protobuf:"bytes,3,opt,name=template"`// 此时的labels要和selector的labels一样,否则deployment就无法管理到poddeploy.Spec.Template.ObjectMeta.Labels = labels//创建容器,容器是个切片,可以创建多个容器var containers []corev1.Containervar container corev1.Containercontainer.Name = "nginx"container.Image = "nginx:1.7.9"containers = append(containers, container)container.Name = "redis"container.Image = "redis:6-alpine"containers = append(containers, container)deploy.Spec.Template.Spec.Containers = containers_, err = clientset.AppsV1().Deployments("test1").Create(context.TODO(), &deploy, metav1.CreateOptions{})}
查看创建的deploy
查看yaml文件,两个容器都创建成功
[root@master01 svc ]#kubectl get deploy -n test1 -oyaml
apiVersion: v1
items:
- apiVersion: apps/v1kind: Deploymentmetadata:annotations:deployment.kubernetes.io/revision: "1"creationTimestamp: "2024-11-05T09:58:43Z"generation: 1labels:app: nginxname: mydeploynamespace: test1resourceVersion: "1079640"uid: 8df3654a-71c6-45d5-888d-6329ed81dad7spec:progressDeadlineSeconds: 600replicas: 1revisionHistoryLimit: 10selector:matchLabels:app: nginxstrategy:rollingUpdate:maxSurge: 25%maxUnavailable: 25%type: RollingUpdatetemplate:metadata:creationTimestamp: nulllabels:app: nginxspec:containers:- image: nginx:1.7.9imagePullPolicy: IfNotPresentname: nginxresources: {}terminationMessagePath: /dev/termination-logterminationMessagePolicy: File- image: redis:6-alpineimagePullPolicy: IfNotPresentname: redisresources: {}terminationMessagePath: /dev/termination-logterminationMessagePolicy: FilednsPolicy: ClusterFirstrestartPolicy: AlwaysschedulerName: default-schedulersecurityContext: {}terminationGracePeriodSeconds: 30status:conditions:- lastTransitionTime: "2024-11-05T09:58:43Z"lastUpdateTime: "2024-11-05T09:58:43Z"message: Deployment does not have minimum availability.reason: MinimumReplicasUnavailablestatus: "False"type: Available- lastTransitionTime: "2024-11-05T09:58:43Z"lastUpdateTime: "2024-11-05T09:58:43Z"message: ReplicaSet "mydeploy-68dcc7d46d" is progressing.reason: ReplicaSetUpdatedstatus: "True"type: ProgressingobservedGeneration: 1replicas: 1unavailableReplicas: 1updatedReplicas: 1
kind: List
metadata:resourceVersion: ""
2.8 client-go使用json串创建资源
上面使用手动填值的方式创建,还是比较麻烦的,稍微有不注意的地方还容易犯错,因此,在前后端分离的项目中,在web页面,一般我们不悔通过手动填值进行创建资源。
一般我们会根据json串来创建资源
首先我们通过先通过kubectl命令导出json串
–dry-run 选项只能为 “none”、“server”、"client"三者中的一个,默认是none;当不加该参数,或者为none的时候,该操作后资源会生效 ,请求会被发送到kube-apiserver并做实际更改;
当该参数为client的时候,只打印该对象并不会发送请求且并不会实际创建该对象;
当该参数为server的时候,会发送请求到服务端,但是并不会实际创建该对象。
比如我们拿到一个创建deploy的json串
kubectl create deployment myredis --image="redis" --dry-run=client -ojson
我们将json串拿出来
{"kind": "Deployment","apiVersion": "apps/v1","metadata": {"name": "myredis","creationTimestamp": null,"labels": {"app": "myredis"}},"spec": {"replicas": 1,"selector": {"matchLabels": {"app": "myredis"}},"template": {"metadata": {"creationTimestamp": null,"labels": {"app": "myredis"}},"spec": {"containers": [{"name": "redis","image": "redis","resources": {}}]}},"strategy": {}},"status": {}
}
使用json创建deploy完整代码:
package mainimport ("context""encoding/json""fmt"deployv1 "k8s.io/api/apps/v1"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/client-go/kubernetes""k8s.io/client-go/tools/clientcmd"
)func main() {// 1. 初始化config实例// masterUrl就是离我们主节点的ip地址和端口号,我们在kubeconfig文件中有了,所以可以省略config, err := clientcmd.BuildConfigFromFlags("", "meta.kubeconfig")//要想正常应用我们的服务,必须能够实例化成功kubeconfig,要不然后面所有的功能都无法使用,所以这里直接报panic即可if err != nil {panic(err.Error())}// 2. 创建客户端工具 create the clientsetclientset, err := kubernetes.NewForConfig(config)//这个客户端工具如果生成失败的话,后面的操作也无法完成,所以这里也报panic即可if err != nil {panic(err.Error())}//3. 操作集群//通过json串创建k8s资源,注意多行字符串用反引号包裹deployJson := `{"kind": "Deployment","apiVersion": "apps/v1","metadata": {"name": "myredis","creationTimestamp": null,"labels": {"app": "myredis"}},"spec": {"replicas": 1,"selector": {"matchLabels": {"app": "myredis"}},"template": {"metadata": {"creationTimestamp": null,"labels": {"app": "myredis"}},"spec": {"containers": [{"name": "redis","image": "redis","resources": {}}]}},"strategy": {}},"status": {}
}`//我们需要将json串转换成deployv1类型的资源var redisdeploy deployv1.Deployment//将json转换成struct// func Unmarshal(data []byte, v any) errorerr = json.Unmarshal([]byte(deployJson), &redisdeploy)if err != nil {panic(err.Error())}fmt.Println("将json转换成的struct:", redisdeploy)//创建deploy_, err = clientset.AppsV1().Deployments("default").Create(context.TODO(), &redisdeploy, metav1.CreateOptions{})if err != nil {panic(err.Error())}}
在K8S集群查看下,创建成功
三、总结
client-go是Kubernetes官方提供的Go客户端库,它封装了与Kubernetes API服务器的交互,提供了便捷的方式进行各种资源的管理。通过创建客户端并使用相应的API客户端进行操作,你可以轻松地进行Pod、Deployment、Service等资源的增删改查。
本文详细介绍了client-go的安装、配置和使用方法,并通过示例代码展示了如何进行常见的Kubernetes操作。希望这些内容能帮助大家更好地理解和使用client-go,从而提高你的Kubernetes开发效率。
相关文章:

【云原生开发】如何通过client-go来操作K8S集群
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...

CSS基础知识六(浮动的高度塌陷问题及解决方案)
目录 1.浮动高度塌陷概念 2.下面是几种解决高度塌陷的几种方案: 解决方案一: 解决方案二: 解决方案三: 1.浮动高度塌陷概念 在CSS中,高度塌陷问题指的是父元素没有正确地根据其内部的浮动元素或绝对定位元素来计…...

开源模型应用落地-glm模型小试-glm-4-9b-chat-vLLM集成(四)
一、前言 GLM-4是智谱AI团队于2024年1月16日发布的基座大模型,旨在自动理解和规划用户的复杂指令,并能调用网页浏览器。其功能包括数据分析、图表创建、PPT生成等,支持128K的上下文窗口,使其在长文本处理和精度召回方面表现优异&a…...

.net为什么要在单独的项目中定义扩展方法?C#
使用 扩展方法(Extension Methods) 和创建 扩展类(Extension Class) 在 C# 中有几个特定的目的,主要是为了提高代码的可扩展性、灵活性和可读性。让我们来详细解释这些概念以及为什么扩展类需要是静态的。 为什么使用…...

动态规划 —— dp 问题-打家劫舍II
1.打家劫舍II 题目链接: 213. 打家劫舍 II - 力扣(LeetCode)https://leetcode.cn/problems/house-robber-ii/ 2. 题目解析 通过分类讨论,将环形问题转换为两个线性的“打家劫舍|” 当偷第一个位置的时候,rob1在&#…...

Java基础-组件及事件处理(上)
(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 Swing 概述 MVC 架构 Swing 特点 控件 SWING UI 元素 JFrame SWING 容器 说明 常用方法 示例&a…...

Python实例:爱心代码
前言 在编程的奇妙世界里,代码不仅仅是冰冷的指令集合,它还可以成为表达情感、传递温暖的独特方式。今天,我们将一同探索用 Python 语言绘制爱心的神奇之旅。 爱心,这个象征着爱与温暖的符号,一直以来都在人类的情感世界中占据着特殊的地位。而通过 Python 的强大功能,…...

图解大模型训练系列:序列并行3,Ring Attention
在序列并行系列中,我们将详细介绍下面四种常用的框架/方法: Megatron Sequence Parallelism:本质是想通过降低单卡激活值大小的方式,尽可能多保存激活值,少做重计算,以此提升整体训练速度,一般…...

pyspark基础准备
1.前言介绍 学习目标:了解什么是Speak、PySpark,了解为什么学习PySpark,了解课程是如何和大数据开发方向进行衔接 使用pyspark库所写出来的代码,既可以在电脑上简单运行,进行数据分析处理,又可以把代码无缝…...

Netty报错
问题:因客户反馈Netty版本低,影响性能,建议提升。于是,我将所有Netty版本从4.1.82.Final到4.1.114.Final后,报下面的错误,java.lang.NoClassDefFoundError: io/netty/util/Recycler$EnhancedHandle…...

Kafka 之顺序消息
前言: 在分布式消息系统中,消息的顺序性是一个重要的问题,也是一个常见的业务场景,那 Kafka 作为一个高性能的分布式消息中间件,又是如何实现顺序消息的呢?本篇我们将对 Kafka 的顺序消息展开讨论。 Kafk…...

Kafka 之批量消息发送消费
前言: 前面我们分享了 Kafka 的一些基础知识,以及 Spring Boot 集成 Kafka 完成消息发送消费,本篇我们来分享一下 Kafka 的批量消息发送消费。 Kafka 系列文章传送门 Kafka 简介及核心概念讲解 Spring Boot 整合 Kafka 详解 Kafka Kafka…...

【大数据学习 | kafka】kafka的偏移量管理
1. 偏移量的概念 消费者在消费数据的时候需要将消费的记录存储到一个位置,防止因为消费者程序宕机而引起断点消费数据丢失问题,下一次可以按照相应的位置从kafka中找寻数据,这个消费位置记录称之为偏移量offset。 kafka0.9以前版本将偏移量信…...

实景三维赋能森林防灭火指挥调度智慧化
森林防灭火工作是保护森林资源和生态环境的重要任务。随着信息技术的发展,实景三维技术在森林防灭火指挥调度中的应用日益广泛,为提升防灭火工作的效率和效果提供了有力支持。 一、森林防灭火面临的挑战 森林火灾具有突发性强、破坏性大、蔓延速度快、…...

【C++课程学习】:string的模拟实现
🎁个人主页:我们的五年 🔍系列专栏:C课程学习 🎉欢迎大家点赞👍评论📝收藏⭐文章 目录 一.string的主体框架: 二.string的分析: 🍔构造函数和析构函数&a…...

Linux(VMware + CentOS )设置固定ip
需求:设置ip为 192.168.88.130 先关闭虚拟机 启动虚拟机 查看当前自动获取的ip 使用 FinalShell 通过 ssh 服务远程登录系统,更换到 root 用户 修改ip配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33 重启网卡 systemctl restart network …...

安卓 android studio各版本下载地址(官方)
https://developer.android.google.cn/studio/archive 别用中文,右上角的语言切换成英文...

如何在一个 Docker 容器中运行多个进程 ?
在容器化的世界里,Docker 彻底改变了开发人员构建、发布和运行应用程序的方式。Docker 容器封装了运行应用程序所需的所有依赖项,使其易于跨不同环境一致地部署。然而,在单个 Docker 容器中管理多个进程可能具有挑战性,这就是 Sup…...

poetry 配置多个cuda环境心得
操作系统:ubuntu22.04 LTS python版本:3.12.7 最近学习了用poetry配置python虚拟环境,当为不同的项目配置cuda时,会遇到不同的项目使用的cuda版本不一致的情况。 像torch 这样的库,它们会对cuda-toolkit有依赖&…...

网络编程入门
目录 1.网络编程入门 1.1 网络编程概述【理解】 1.2 网络编程三要素【理解】 1.3 IP地址【理解】 1.4InetAddress【应用】 1.5端口和协议【理解】 2.UDP通信程序 2.1 UDP发送数据【应用】 2.2UDP接收数据【应用】 2.3UDP通信程序练习【应用】 3.TCP通信程序 3.1TCP…...

Linux-socket详解
Linux-socket详解_socket linux-CSDN博客...

SQL Server 2022安装要求(硬件、软件、操作系统等)
SQL Server 2022安装要求 1、硬件要求2、软件要求3、操作系统支持4、Server Core 支持5、跨语言支持6、磁盘空间要求 1、硬件要求 以下内存和处理器要求适用于所有版本的 SQL Server: 组件要求存储SQL Server 要求最少 6 GB 的可用硬盘驱动器空间。 磁盘空间要求随…...

“众店模式”:创新驱动下的商业新生态
在数字化浪潮的推动下,传统商业模式正经历着前所未有的转型。“众店模式”作为一种新兴的商业模式,以其独特的商业逻辑和创新的玩法,为商家和消费者构建了一个共赢的商业新生态。 一、“众店模式”的核心构成 “众店模式”的成功࿰…...

54. 螺旋矩阵
https://leetcode.cn/problems/spiral-matrix/description/?envTypestudy-plan-v2&envIdtop-100-liked观察示例中的输出轨迹我们可以想到如下设计: 1.在朝某一方向行进到头后的改变方向是确定的,左->下,下->右,右->…...

剧本杀小程序,市场发展下的新机遇
剧本杀作为休闲娱乐的一种游戏方式,在短时间内进入了大众视野中,受到了广泛关注。近几年,剧本杀行业面临着创新挑战,商家需求寻求新的发展机遇,在市场饱和度下降的趋势下,获得市场份额。 随着科技的不断进…...

【系统架构设计师】论文:论基于 ABSD 的软件开发
更多内容请见: 备考系统架构设计师-专栏介绍和目录 文章目录 摘要正文摘要 2022年5月,我就职的公司承接了xx的智慧党建工作,建设“党建红云” 系统,为xx公司的党组织提供觉务管理、服务功能,促进党员学习和党组织交流。我在该项目中承担架构设计师的职责,主导需求分析和…...

为什么OLED透明屏在同类产品中显示效果最好
说起OLED透明屏,这家伙在同类产品里那真的是“一枝独秀”啊!为啥这么说呢?且听我细细道来。 首先,OLED透明屏的透明度那是杠杠的!它不像传统显示屏那样有个固定的背景,而是可以实现像素级的透明效果。这样一…...

深度学习基础知识-Batch Normalization(BN)超详细解析
一、背景和问题定义 在深层神经网络(Deep Neural Networks, DNNs)中,层与层之间的输入分布会随着参数更新不断发生变化,这种现象被称为内部协变量偏移(Internal Covariate Shift)。具体来说,由…...

基于单片机的燃气报警阀门系统
本设计基于单片机的燃气报警阀门系统,燃气报警阀门系统采用STM32主控制器为核心芯片,外围电路由燃气传感器、OLED液晶显示模块、按键模块、蜂鸣器报警模块、电磁阀以及SIM800模块等模块组成。燃气传感器模块负责采集燃气浓度数据,采集完成由S…...

watch与computed的区别、运用的场景
computed和watch都是响应式数据变化的重要机制,但它们在功能、使用场景和性能表现上有显著的区别。 主要区别 功能和用途 1、computed:计算属性,用于基于其他数据属性进行计算,并返回一个结果。它具有缓存机制,只有当…...