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

06-01 1638阅读

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

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

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

🏆 作者简介:景天科技苑

🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。

🏆《博客》:Python全栈,Golang开发,云原生开发,PyQt5和Tkinter桌面开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生K8S,linux,shell脚本等实操经验,网站搭建,数据库等分享。

所属的专栏:云原生开发

景天的主页:景天科技苑

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

文章目录

  • 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集群

          如果是其他语言的客户端工具,可以通过https://github.com/kubernetes-client 来查看

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

          我们看下client-go几个比较重要的目录

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

          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来操作K8S集群

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

          3. client-go客户端分类

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

          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集群

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

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

          5. 安装client-go

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

          go get k8s.io/client-go@latest
          

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

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

          go get k8s.io/apimachinery@latest
          

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

          安装完还需要运行go mod tidy 加载依赖包

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

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

          创建Kubernetes客户端

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

          我们根据我们之前写好的脚手架,改个名字,在此基础上开发我们的项目

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

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

          我们可以批量替换

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

          使用Ctrl + Shift + R 打开Find and Repalce对话框

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

          我们测试client-go,要用到k8s集群,得有~/.kube/config 这个文件

          里面是加载集群的配置信息

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

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

          将这个文件复制到我们的项目中

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

          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集群

          package main
          import (
              "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集群

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

          我们看下List方法的参数,包含两个,一个context,一个是ListOptions。

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

          这个ListOptions就可以在里面做些筛选条件,比如传json串,标签等

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

          我们看下List的返回值

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

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

          所以我们要查询具体的pod里面的信息,可以在Items字段中获取到所有的pod

          跟我们通过在k8s集群中通过kubectl … -ojson的得到的信息是一样的

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

          如果要取其中某个pod,可以通过下标来获取

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

          如果忘记pod的层级关系,可以使用k8s命令的-ojson 查看一下

          完整代码:

          package main
          import (
              "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来操作K8S集群

          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集群

          如果不想通过K8S命令来查,也可以在代码中查看

          点进来

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

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

          这里可看看到个各种方法,不过我们用的时候要把首字母大写

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

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

          完整代码:

          package main
          import (
              "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集群

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

          完整代码

          package main
          import (
              "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集群

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

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

          完整代码:

          package main
          import (
              "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集群

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

          可见pod已被删除

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

          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来操作K8S集群

          创建deployment

          注意,这个deployment的v1,

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

          导包的时候,不要导错

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

          传参时,要把必须得参数都传进去

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

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

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

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

          它会导出一份yaml文件

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

          package main
          import (
              "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集群

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

          [root@master01 svc ]#kubectl get deploy -n test1 -oyaml
          apiVersion: v1
          items:
          - 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: 1
          kind: List
          metadata:
            resourceVersion: ""
          

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

          上面使用手动填值的方式创建,还是比较麻烦的,稍微有不注意的地方还容易犯错,因此,在前后端分离的项目中,在web页面,一般我们不悔通过手动填值进行创建资源。

          一般我们会根据json串来创建资源

          首先我们通过先通过kubectl命令导出json串

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

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

          –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集群

          我们将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 main
          import (
              "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是Kubernetes官方提供的Go客户端库,它封装了与Kubernetes API服务器的交互,提供了便捷的方式进行各种资源的管理。通过创建客户端并使用相应的API客户端进行操作,你可以轻松地进行Pod、Deployment、Service等资源的增删改查。

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

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

目录[+]

取消
微信二维码
微信二维码
支付宝二维码