> 技术文档 > 【云原生开发】如何通过client-go来操作K8S集群_client-go开发

【云原生开发】如何通过client-go来操作K8S集群_client-go开发

在这里插入图片描述

✨✨ 欢迎大家来到景天科技苑✨✨

🎈🎈 养成好习惯,先赞后看哦~🎈🎈

🏆 作者简介:景天科技苑
🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,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
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

如果是其他语言的客户端工具,可以通过https://github.com/kubernetes-client 来查看
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

我们看下client-go几个比较重要的目录
【云原生开发】如何通过client-go来操作K8S集群_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来操作K8S集群_client-go开发
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

建议:client-go我们直接用最新版本

3. client-go客户端分类

【云原生开发】如何通过client-go来操作K8S集群_client-go开发

restclient: 一般我们不会使用restclient,因为它需要把整个资源的yaml文件或json数据都传过去,显得比较臃肿,一般我们不用这个discoverclient: 比如我们创建deployment时的apiversion: apps/v1 apps就是资源组Group v1就是资源版本Version 资源信息 就是kind 。我们一般也不会用这个客户端工具ClientSet: 只能针对K8S内置的资源进行操作,不能操作自定义的资源DyanmicClient: 我们经常使用这个客户端,但是对于内置资源,我们还是习惯使用ClientSet,因为它更好用,自定义资源我们使用DyanmicClient。

我们可以通过命令 kubectl api-resources 查看每种资源的资源组
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

4. client-go客户端工具依赖关系

【云原生开发】如何通过client-go来操作K8S集群_client-go开发

5. 安装client-go

client-go是一个Go模块,可以通过Go Module的方式进行安装。在你的Go项目中,执行以下命令:

go get k8s.io/client-go@latest

【云原生开发】如何通过client-go来操作K8S集群_client-go开发

这将安装最新版本的client-go。此外,你还需要安装一些相关的依赖库,例如apimachinery,用于处理Kubernetes API对象。

go get k8s.io/apimachinery@latest

【云原生开发】如何通过client-go来操作K8S集群_client-go开发

安装完还需要运行go mod tidy 加载依赖包
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

二、使用client-go进行基本操作

创建Kubernetes客户端
在使用client-go之前,首先需要创建一个Kubernetes客户端。client-go提供了两种创建客户端的方式:in-cluster配置和out-of-cluster配置。

我们根据我们之前写好的脚手架,改个名字,在此基础上开发我们的项目
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

并不是说在此改了就可以了,因为很多包用的还是原来的名字,

我们可以批量替换
在Goland IDE中想要替换某一段特定的字符串,可以使用Find and Replace 功能来实现。这是一种全局性的操作,将会在你的整个项目或指定的文件/文件夹中进行。

使用Ctrl + Shift + R 打开Find and Repalce对话框
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

我们测试client-go,要用到k8s集群,得有~/.kube/config 这个文件
里面是加载集群的配置信息
【云原生开发】如何通过client-go来操作K8S集群_client-go开发
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

将这个文件复制到我们的项目中
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

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上面看用法举例
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

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 clientset clientset, 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)}

【云原生开发】如何通过client-go来操作K8S集群_client-go开发

2.3 client-go 查询列表功能使用

我们看下List方法的参数,包含两个,一个context,一个是ListOptions。
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

这个ListOptions就可以在里面做些筛选条件,比如传json串,标签等
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

我们看下List的返回值
【云原生开发】如何通过client-go来操作K8S集群_client-go开发
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

所以我们要查询具体的pod里面的信息,可以在Items字段中获取到所有的pod
跟我们通过在k8s集群中通过kubectl … -ojson的得到的信息是一样的
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

如果要取其中某个pod,可以通过下标来获取
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

如果忘记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 clientset clientset, 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)}

下面,我们探讨下,我们怎么知道我们要操作的资源是属于CoreV1()或者是其他什么组呢?
之前,我们说过,在K8S集群中,可以通过命令 kubectl api-resources查看
【云原生开发】如何通过client-go来操作K8S集群_client-go开发
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

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()
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

如果不想通过K8S命令来查,也可以在代码中查看
点进来
【云原生开发】如何通过client-go来操作K8S集群_client-go开发
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

这里可看看到个各种方法,不过我们用的时候要把首字母大写
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

比如查询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))

【云原生开发】如何通过client-go来操作K8S集群_client-go开发

完整代码:

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 clientset clientset, 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 查询详情
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

// 查询资源详情 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)

【云原生开发】如何通过client-go来操作K8S集群_client-go开发

完整代码

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 clientset clientset, 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的字段,就不能被修改
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

注意:如果修改的字段在资源中不存在,比如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-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)

【云原生开发】如何通过client-go来操作K8S集群_client-go开发

完整代码:

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 clientset clientset, 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-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)}

2.6 client-go删除资源

删除pod,比如我们将下列的pod删除
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

//删除资源 Delete()//删除poderr = clientset.CoreV1().Pods(\"h5-web\").Delete(context.TODO(), \"web-864f4c6988-r456g\", metav1.DeleteOptions{})if err != nil { panic(err.Error())

可见pod已被删除
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

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的包
【云原生开发】如何通过client-go来操作K8S集群_client-go开发
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

创建deployment
注意,这个deployment的v1,
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

导包的时候,不要导错
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

传参时,要把必须得参数都传进去
【云原生开发】如何通过client-go来操作K8S集群_client-go开发
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

可以通过这个命令来查看哪些是必须传的参数

kubectl create deployment mynginx --image=\"nginx\" --dry-run=client -oyaml

它会导出一份yaml文件
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

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 clientset clientset, err := kubernetes.NewForConfig(config) //这个客户端工具如果生成失败的话,后面的操作也无法完成,所以这里也报panic即可 if err != nil { panic(err.Error()) } //3. 操作集群 //创建deployment var deploy deployv1.Deployment //给deployment传参,要把必须传的参数都传进去,不然创建会报错 deploy.Name = \"mydeploy\" deploy.Namespace = \"test1\" //副本数 replicas := int32(1) deploy.Spec.Replicas = &replicas //mathlabels labels := 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就无法管理到pod deploy.Spec.Template.ObjectMeta.Labels = labels //创建容器,容器是个切片,可以创建多个容器 var containers []corev1.Container var container corev1.Container container.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
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

查看yaml文件,两个容器都创建成功

[root@master01 svc ]#kubectl get deploy -n test1 -oyamlapiVersion: v1items:- apiVersion: apps/v1 kind: Deployment metadata: annotations: deployment.kubernetes.io/revision: \"1\" creationTimestamp: \"2024-11-05T09:58:43Z\" generation: 1 labels: app: nginx name: mydeploy namespace: test1 resourceVersion: \"1079640\" uid: 8df3654a-71c6-45d5-888d-6329ed81dad7 spec: progressDeadlineSeconds: 600 replicas: 1 revisionHistoryLimit: 10 selector: matchLabels: app: nginx strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate template: metadata: creationTimestamp: null labels: app: nginx spec: containers: - image: nginx:1.7.9 imagePullPolicy: IfNotPresent name: nginx resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File - image: redis:6-alpine imagePullPolicy: IfNotPresent name: redis resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File dnsPolicy: ClusterFirst restartPolicy: Always schedulerName: default-scheduler securityContext: {} terminationGracePeriodSeconds: 30 status: conditions: - lastTransitionTime: \"2024-11-05T09:58:43Z\" lastUpdateTime: \"2024-11-05T09:58:43Z\" message: Deployment does not have minimum availability. reason: MinimumReplicasUnavailable status: \"False\" type: Available - lastTransitionTime: \"2024-11-05T09:58:43Z\" lastUpdateTime: \"2024-11-05T09:58:43Z\" message: ReplicaSet \"mydeploy-68dcc7d46d\" is progressing. reason: ReplicaSetUpdated status: \"True\" type: Progressing observedGeneration: 1 replicas: 1 unavailableReplicas: 1 updatedReplicas: 1kind: Listmetadata: resourceVersion: \"\"

2.8 client-go使用json串创建资源

上面使用手动填值的方式创建,还是比较麻烦的,稍微有不注意的地方还容易犯错,因此,在前后端分离的项目中,在web页面,一般我们不悔通过手动填值进行创建资源。
一般我们会根据json串来创建资源
首先我们通过先通过kubectl命令导出json串
【云原生开发】如何通过client-go来操作K8S集群_client-go开发
【云原生开发】如何通过client-go来操作K8S集群_client-go开发

–dry-run 选项只能为 “none”、“server”、\"client\"三者中的一个,默认是none;当不加该参数,或者为none的时候,该操作后资源会生效 ,请求会被发送到kube-apiserver并做实际更改;
当该参数为client的时候,只打印该对象并不会发送请求且并不会实际创建该对象;
当该参数为server的时候,会发送请求到服务端,但是并不会实际创建该对象。
比如我们拿到一个创建deploy的json串

kubectl create deployment myredis --image=\"redis\" --dry-run=client -ojson

【云原生开发】如何通过client-go来操作K8S集群_client-go开发

我们将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 clientset clientset, 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) error err = 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来操作K8S集群_client-go开发

三、总结

client-go是Kubernetes官方提供的Go客户端库,它封装了与Kubernetes API服务器的交互,提供了便捷的方式进行各种资源的管理。通过创建客户端并使用相应的API客户端进行操作,你可以轻松地进行Pod、Deployment、Service等资源的增删改查。

本文详细介绍了client-go的安装、配置和使用方法,并通过示例代码展示了如何进行常见的Kubernetes操作。希望这些内容能帮助大家更好地理解和使用client-go,从而提高你的Kubernetes开发效率。