K8s二开之 client-go 初探

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 近期有需求要对k8s的一些数据进行自定义整合,利用client-go可以快速方便的实现需求,在K8s运维中,我们可以使用kubectl、客户端库或者REST请求来访问K8S API。而实际上,无论是kubectl还是客户端库,都是封装了REST请求的工具。client-go作为一个客户端库,能够调用K8S API,实现对K8S集群中资源对象(包括deployment、service、ingress、replicaSet、pod、namespace、node等)的增删改查等操作。

一 client-go简介

近期有需求要对k8s的一些数据进行自定义整合,利用client-go可以快速方便的实现需求,在K8s运维中,我们可以使用kubectl、客户端库或者REST请求来访问K8S API。而实际上,无论是kubectl还是客户端库,都是封装了REST请求的工具。client-go作为一个客户端库,能够调用K8S API,实现对K8S集群中资源对象(包括deployment、service、ingress、replicaSet、pod、namespace、node等)的增删改查等操作。

二 简介

2.1 结构图

从上图可以看到client-go 中包含四种client,ClientSetDynamicClientDiscoveryClient都是RestClient的具体实现。

2.2 目录结构

# tree client-go/ -L 1
client-go/
  ├── discovery
  ├── dynamic
  ├── informers
  ├── kubernetes
  ├── listers
  ├── plugin
  ├── rest
  ├── scale
  ├── tools
  ├── transport
  └── util
  • discovery:提供 DiscoveryClient 发现客户端
  • dynamic:提供 DynamicClient 动态客户端
  • informers:每种 kubernetes 资源的 Informer 实现
  • kubernetes:提供 ClientSet 客户端
  • listers:为每一个 Kubernetes 资源提供 Lister 功能,该功能对 Get 和 List 请求提供只读的缓存数据
  • plugin:提供 OpenStack、GCP 和 Azure 等云服务商授权插件
  • rest:提供 RESTClient 客户端,对 Kubernetes API Server 执行 RESTful 操作
  • scale:提供 ScaleClient 客户端,用于扩容或缩容 Deployment、ReplicaSet、Relication Controller 等资源对象
  • tools:提供常用工具,例如 SharedInformer、Reflector、DealtFIFO 及 Indexers。提供 Client 查询和缓存机制,以减少向 kube-apiserver 发起的请求数等
  • transport:提供安全的 TCP 连接,支持 Http Stream,某些操作需要在客户端和容器之间传输二进制流,例如 exec、attach 等操作。该功能由内部的 spdy 包提供支持
  • util:提供常用方法,例如 WorkQueue 功能队列、Certificate 证书管理等

三 认证

这里值得一提的是go mod通过go client 对接k8s的时候有个小坑
那么就是我们需要在go mod文件中指定k8s版本 不然会默认拉去最新的k8s版本的包 我们也知道不同的k8s版本的api会出现差异

3.1 认证

3.1.1 token

# APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
# TOKEN=$(kubectl get secret $(kubectl get serviceaccount default -o jsonpath='{.secrets[0].name}') -o # jsonpath='{.data.token}' | base64 --decode )
# curl $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure

四 client-go四种类型

4.1 RestClient

RestClient是最基础的客户端,RestClient基于http request进行了封装,实现了restful的api,可以直接通过 是RESTClient提供的RESTful方法如Get(),Put(),Post(),Delete()进行交互,同时支持Json 和 protobuf,支持所有原生资源和CRDs,但是,一般而言,为了更为优雅的处理,需要进一步封装,通过Clientset封装RESTClient,然后再对外提供接口和服务。

package main

import (
    "fmt"
    corev1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes/scheme"
    "k8s.io/client-go/rest"
    "k8s.io/client-go/tools/clientcmd"
)

var configFile = "../config"
var ApiPath = "api"
var nameSpace = "kube-system"
var resouce = "pods"

func main() {
    // 生成config
    config, err := clientcmd.BuildConfigFromFlags("", configFile)
    if err != nil {
        panic(err)
    }
    config.APIPath = ApiPath
    config.GroupVersion = &corev1.SchemeGroupVersion
    config.NegotiatedSerializer = scheme.Codecs

    // 生成restClient
    restClient, err := rest.RESTClientFor(config)
    if err != nil {
        panic(err)
    }
    // 声明空结构体
    rest := &corev1.PodList{}
    if err = restClient.Get().Namespace(nameSpace).Resource("pods").VersionedParams(&metav1.ListOptions{Limit: 500},
        scheme.ParameterCodec).Do().Into(rest); err != nil {
        panic(err)
    }
    for _, v := range rest.Items {
        fmt.Printf("NameSpace: %v  Name: %v  Status: %v \n", v.Namespace, v.Name, v.Status.Phase)
    }
}

4.2 ClientSet

ClientSet在RestClient的基础上封装了对Resouorce和Version的管理方法一个Resource可以理解为一个客户端,而ClientSet是多个客户端的集合

其操作资源对象时需要指定Group、指定Version,然后根据Resource获取,但是clientset不支持自定义crd。

package main

import (
    "flag"
    "fmt"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"
    "path/filepath"
)

// ~/.kube/config
func ParseConfig(configPath string) (*kubernetes.Clientset, error) {
    var kubeconfigPath *string
    if home := homedir.HomeDir(); home != "" {
        kubeconfigPath = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
    } else {
        kubeconfigPath = flag.String("kubeconfig", configPath, "absolute path to the kubeconfig file")
    }
    flag.Parse()
    config, err := clientcmd.BuildConfigFromFlags("", *kubeconfigPath)
    if err != nil {
        return nil, err
    }
    // 生成clientSet
    clientSet, err := kubernetes.NewForConfig(config)
    if err != nil {
        return clientSet, err
    }
    return clientSet, nil
}

func ListCm(c *kubernetes.Clientset, ns string) error {
    configMaps, err := c.CoreV1().ConfigMaps(ns).List(metav1.ListOptions{})
    if err != nil {
        return err
    }
    for _, cm := range configMaps.Items {
        fmt.Printf("configName: %v, configData: %v \n", cm.Name, cm.Data)
    }
    return nil
}

func ListNodes(c *kubernetes.Clientset) error {
    nodeList, err := c.CoreV1().Nodes().List(metav1.ListOptions{})
    if err != nil {
        return err
    }
    for _, node := range nodeList.Items {
        fmt.Printf("nodeName: %v, status: %v", node.GetName(), node.GetCreationTimestamp())
    }
    return nil
}

func ListPods(c *kubernetes.Clientset, ns string) {
    pods, err := c.CoreV1().Pods(ns).List(metav1.ListOptions{})
    if err != nil {
        panic(err)
    }
    for _, v := range pods.Items {
        fmt.Printf("namespace: %v podname: %v podstatus: %v \n", v.Namespace, v.Name, v.Status.Phase)
    }
}

func ListDeployment(c *kubernetes.Clientset, ns string) error {
    deployments, err := c.AppsV1().Deployments(ns).List(metav1.ListOptions{})
    if err != nil {
        return err
    }
    for _, v := range deployments.Items {
        fmt.Printf("deploymentname: %v, available: %v, ready: %v", v.GetName(), v.Status.AvailableReplicas, v.Status.ReadyReplicas)
    }
    return nil
}

func main() {
    var namespace = "kube-system"
    configPath := "../config"
    config, err := ParseConfig(configPath)
    if err != nil {
        fmt.Printf("load config error: %v\n", err)
    }
    fmt.Println("list pods")
    ListPods(config, namespace)
    fmt.Println("list cm")
    if err = ListCm(config, namespace); err != nil {
        fmt.Printf("list cm error: %v", err)
    }
    fmt.Println("list nodes")
    if err = ListNodes(config); err != nil {
        fmt.Printf("list nodes error: %v", err)
    }
    fmt.Println("list deployment")
    if err = ListDeployment(config, namespace); err != nil {
        fmt.Printf("list deployment error: %v", err)
    }
}

4.3 DynamicClient

DynamicClient是一种动态客户端它可以对任何资源进行restful操作包括crd自定义资源,不同于 clientset,dynamic client 返回的对象是一个 map[string]interface{},如果一个 controller 中需要控制所有的 API,可以使用dynamic client,目前它在 garbage collector 和 namespace controller中被使用。
DynamicClient的处理过程将Resource例如podlist转换为unstructured类型,k8s的所有resource都可以转换为这个结构类型,处理完之后在转换为podlist,整个转换过程类似于接口转换就是通过interface{}的断言。

Dynamic client 是一种动态的 client,它能处理 kubernetes 所有的资源,只支持JSON。

package main

import (
    "fmt"
    apiv1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/runtime"
    "k8s.io/apimachinery/pkg/runtime/schema"
    "k8s.io/client-go/dynamic"
    "k8s.io/client-go/tools/clientcmd"
)

var namespace = "kube-system"

func main() {

    config, err := clientcmd.BuildConfigFromFlags("", "../config")
    if err != nil {
        panic(err)
    }

    dynamicClient, err := dynamic.NewForConfig(config)
    if err != nil {
        panic(err)
    }
    // 定义组版本资源
    gvr := schema.GroupVersionResource{Version: "v1", Resource: "pods"}
    unStructObj, err := dynamicClient.Resource(gvr).Namespace(namespace).List(metav1.ListOptions{})
    if err != nil {
        panic(err)
    }
    podList := &apiv1.PodList{}

    if err = runtime.DefaultUnstructuredConverter.FromUnstructured(unStructObj.UnstructuredContent(), podList); err != nil {
        panic(err)
    }

    for _, v := range podList.Items {
        fmt.Printf("namespaces:%v  name:%v status:%v \n", v.Namespace, v.Name, v.Status.Phase)
    }
}

4.4 DiscoveryClient

DiscoveryClient是发现客户端,主要用于发现api server支持的资源组 资源版本 资源信息,k8s api server 支持很多资源组 资源版本,资源信息,此时可以通过DiscoveryClient来查看

kubectl的api-version和api-resource也是通过DiscoveryClient来实现的,还可以将信息缓存在本地cache,以减轻api的访问压力,默认在./kube/cache和./kube/http-cache下。

package main

import (
    "fmt"
    "k8s.io/apimachinery/pkg/runtime/schema"
    "k8s.io/client-go/discovery"
    "k8s.io/client-go/tools/clientcmd"
)

func main() {
    config, err := clientcmd.BuildConfigFromFlags("", "../config")
    if err != nil {
        panic(err)
    }
    discoverClient, err := discovery.NewDiscoveryClientForConfig(config)
    if err != nil {
        panic(err)
    }
    _, apiResourceList, err := discoverClient.ServerGroupsAndResources()
    for _, v := range apiResourceList {
        gv, err := schema.ParseGroupVersion(v.GroupVersion)
        if err != nil {
            panic(err)
        }
        for _, resource := range v.APIResources {
            fmt.Println("name:", resource.Name, "    ", "group:", gv.Group, "    ", "version:", gv.Version)
        }
    }

}

五 其他

学习client-go,可以非常方便的利用其对k8s集群资源进行操作,kubeconfig→rest.config→clientset→具体的client(CoreV1Client)→具体的资源对象(pod)→RESTClient→http.Client→HTTP请求的发送及响应

通过clientset中不同的client和client中不同资源对象的方法实现对kubernetes中资源对象的增删改查等操作,常用的client有CoreV1Client、AppsV1beta1Client、ExtensionsV1beta1Client等。

本篇为简单利用client-go 实现简单的k8s资源操作,后期利用例如 kubebuilder 和 operator-SDK 编写operator也需要深入的理解和学习client-go。后期继续继续深入学习。

参考链接

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
目录
相关文章
|
Kubernetes Cloud Native jenkins
下篇:使用jenkins发布go项目到k8s,接上篇的手工体验改造为自动化发布
下篇:使用jenkins发布go项目到k8s,接上篇的手工体验改造为自动化发布
575 1
|
12天前
|
Kubernetes Go Docker
在K8s编程中如何使用Go
一文带你了解在K8s编程中如何使用Go
33 3
|
1月前
|
Kubernetes 监控 Cloud Native
"解锁K8s新姿势!Cobra+Client-go强强联手,打造你的专属K8s监控神器,让资源优化与性能监控尽在掌握!"
【8月更文挑战第14天】在云原生领域,Kubernetes以出色的扩展性和定制化能力引领潮流。面对独特需求,自定义插件成为必要。本文通过Cobra与Client-go两大利器,打造一款监测特定标签Pods资源使用的K8s插件。Cobra简化CLI开发,Client-go则负责与K8s API交互。从初始化项目到实现查询逻辑,一步步引导你构建个性化工具,开启K8s集群智能化管理之旅。
35 2
|
1月前
|
运维 Kubernetes Go
"解锁K8s二开新姿势!client-go:你不可不知的Go语言神器,让Kubernetes集群管理如虎添翼,秒变运维大神!"
【8月更文挑战第14天】随着云原生技术的发展,Kubernetes (K8s) 成为容器编排的首选。client-go作为K8s的官方Go语言客户端库,通过封装RESTful API,使开发者能便捷地管理集群资源,如Pods和服务。本文介绍client-go基本概念、使用方法及自定义操作。涵盖ClientSet、DynamicClient等客户端实现,以及lister、informer等组件,通过示例展示如何列出集群中的所有Pods。client-go的强大功能助力高效开发和运维。
87 1
|
4月前
|
Kubernetes Cloud Native Go
Golang深入浅出之-Go语言中的云原生开发:Kubernetes与Docker
【5月更文挑战第5天】本文探讨了Go语言在云原生开发中的应用,特别是在Kubernetes和Docker中的使用。Docker利用Go语言的性能和跨平台能力编写Dockerfile和构建镜像。Kubernetes,主要由Go语言编写,提供了方便的客户端库与集群交互。文章列举了Dockerfile编写、Kubernetes资源定义和服务发现的常见问题及解决方案,并给出了Go语言构建Docker镜像和与Kubernetes交互的代码示例。通过掌握这些技巧,开发者能更高效地进行云原生应用开发。
130 1
|
Kubernetes 监控 Cloud Native
Go微服务架构实战 中篇:2. 基于k8s部署服务和注册中心,验证服务注册和发现
Go微服务架构实战 中篇:2. 基于k8s部署服务和注册中心,验证服务注册和发现
Go微服务架构实战 中篇:2. 基于k8s部署服务和注册中心,验证服务注册和发现
|
JSON Kubernetes 测试技术
在 Go 中使用 Kubernetes 对象
通常,在某些情况下,我们需要通用的方法去使用 Kubernetes 资源对象,而不是编写代码来处理特定类型。
162 0
|
运维 Kubernetes 负载均衡
Go微服务架构实战 中篇:5. k8s基于ingress和service实现金丝雀发布和蓝绿发布
Go微服务架构实战 中篇:5. k8s基于ingress和service实现金丝雀发布和蓝绿发布
|
Kubernetes 监控 负载均衡
Go微服务架构实战-中篇 1. k8s架构介绍
Go微服务架构实战-中篇 1. k8s架构介绍
|
Kubernetes Go 开发工具
开发 k8s 管理平台 - k8sailor 03. 使用 client-go sdk 链接集群
开发 k8s 管理平台 - k8sailor 03. 使用 client-go sdk 链接集群
258 0
开发 k8s 管理平台 - k8sailor 03. 使用 client-go sdk 链接集群