Kubernetes operator(一)client-go篇【更新中】

云原生学习路线导航页(持续更新中)

  • 本文是 Kubernetes operator学习 系列第一篇,主要对client-go进行学习,从源码阅读角度,学习client-go各个组件的实现原理、如何协同工作等
  • 参考视频:Bilibili 2022年最新k8s编程operator篇,UP主:白丁云原生
  • 本文引用声明
    • 部分内容来自 白丁云原生 所提供 资料:链接: https://pan.baidu.com/s/1BibLAishAFJLeTyYCLnlbA 提取码: en2p
    • 部分来自:https://zhuanlan.zhihu.com/p/573982128
    • 并根据个人理解进行了汇总和修改

1.为什么要学习 client-go

  • 为了适应更多的业务场景,k8s提供了很多的扩展点,用于满足更复杂的需求
  • K8s的扩展点如下:
    在这里插入图片描述
  • ① kubectl
    • 用户通过kubectl与ApiServer进行交互,kubectl提供了插件,可以扩展kubectl的行为,但是这些插件只能影响用户本地的环境
  • ② API Server
    • 处理所有的请求,可以对用户请求进行 身份认证、基于其内容阻止请求、编辑请求内容、处理删除操作等等。
    • 这个扩展点应该说的是:用户可以 自定义 API Server
  • ③ k8s提供的内置资源
    • 我们无法修改,只能通过 annotation、label 控制他们
  • ④ CRD
    • 自定义资源,配合 自定义控制器Custom Controller,扩展k8s的特定业务场景
  • ⑤ scheduler
    • 调度器,决定k8s把Pod放到哪个节点执行。k8s提供了多种方式扩展调度行为
  • ⑥ Controller Manager
    • 实际上也是k8s的一个客户端,通过与API Server交互。k8s的每种资源都有对应的控制器,都属于ControllerManager
    • client-go本质上就是一个与apiserver交互的库,所以Controller Manager也是通过 client-go 库与 API Server交互的
  • ⑦ Custom Controller
    • 自定义控制器,可以控制 内置资源,也可以控制自定义资源CRD
  • ⑧ kubelet
    • 使用CNI:使得k8s可以使用不同技术,连接Pod网络
    • 使用CSI:使得k8s可以支持不同的存储类型
    • 使用CRI:使得k8s可以支持不同的容器运行时
  • ⑨ client-go
    • 一个通用的Golang库,用于和 apiserver 交互
    • 不管是k8s的各个组件,还是我们自己为CRD开发Custom Controller,都需要使用 client-go 与 API Server 进行通信

综上所述,要想学习 Operator,使用 CRD + Custom Controller 扩展kubernetes功能,必须先学习 Client-go 库,学会如何与APIServer进行交互

2.client-go与kubernetes版本对应关系

我们假设前提:kubernetes版本为 v1.x.y

  • kubernetes版本 >= v1.17.0时,client-go 版本使用 v0.x.y
  • kubernetes版本 < v1.17.0时,client-go 版本使用 v1.x.y

3.client-go架构

3.1.client-go 源代码目录介绍

  • github地址:https://github.com/kubernetes/client-go
    在这里插入图片描述
  • discovery:用于发现API Server都是支持哪些API。kubectl apiversions使用了同样的机制
  • dynamic:包含了kubernetes dynamic client的逻辑,可以操作任意的k8s资源API对象,包括内置的、自定义的资源对象
  • informers:包含了所有内置资源的informer,便于操作k8s的资源对象
  • kubernetes:包含了访问Kubernetes API的 所有ClientSet
  • listers:包含了所有内置资源的lister,用于读取缓存中k8s资源对象的信息
  • plugin/pkg/client/auth:包含所有可选的认证插件,用于从外部获取credential(凭证)
  • tools:包含一系列工具,编写控制器时会用到很多里面的工具方法
  • transport:包含了创建连接、认证的逻辑,会被上层的ClientSet使用

3.2.client-go 架构

图片参考来源:https://zhuanlan.zhihu.com/p/573982128
在这里插入图片描述
下面先介绍各组件整体的运转流程,然后对 client-go 和 一个 CRDController 应该包含哪些组件进行详细介绍。

  • 整体流程简介
    • Reflector会持续监听k8s集群中指定资源类型的API,当发现变动和更新时,就会创建一个发生变动的 对象副本,并将其添加到队列DeltaFIFO中
    • Informer监听DeltaFIFO队列,取出对象,做两件事:
      • (1)将对象加入Indexer,Indexer 会将 [对象key, 对象] 存入一个线程安全的Cache中
      • (2)根据对象的 资源类型和操作,找到对应 Controller 预先提供的 Resource Event Handler,调用Handler,将对象的Key加入该 Controller 的 Workqueue
    • Controller 的循环函数 ProcessItem,监听到 Workqueue 有数据了,就会取出一个key,交给处理函数Worker,Worker 会根据 Key,使用 Indexer reference 从 Cache 中 获取 该key对应的 真实对象。然后就可以进行调谐了。
    • 注意点
      • DeltaFIFO 中 存的是 对象副本
      • Cache 中 存的是 [对象key, 对象] 的映射
      • Workqueue 中存的是 对象Key
      • CRDController 中,使用Informer对象,是为了向其中添加一些 Resource Event Handlers
      • CRDController 中,使用Indexer对象,是为了根据对象Key,获取对象实例
  • client-go组件
    • Reflector
      • reflector会一直监听kubernetes中指定资源类型的API,实现监听的函数就是ListAndWatch。这种监听机制既适用于k8s的内建资源,也适用于自定义资源。
      • 当reflector通过监听API发现资源对象实例存在新的 notification 时,它就会使用 listing API 获取这个新的实例对象,并将其放入 watchHandler 函数内的 DeltaFIFO 中;
    • Informer
      • Informer 会从 Delta FIFO 中取出对象。实现这个功能的方法对应源码中的 processLoop;
      • Informer 取出对象后,根据Resource类型,调用对应的 Resource Event Handler 回调函数,该函数实际上由某个具体的 Controller 提供,函数中会获取对象的 key,并将 key 放入到 该Controller 内部的 Workqueue 中,等候处理。
    • Indexer 和 Thread Safe Store
      • Indexer 会提供对象的索引功能,通常是基于对象Key来创建索引。默认索引函数是MetaNamespaceKeyFunc, 它生成的索引键为/格式。
      • Indexer 维护着一个线程安全的 Cache,即 Thread Safe Store。存储的是[对象key, 对象],用对象Key可以进行获取对象实例。
    • Resource Event Handlers reference
      • 这实际上是所有Controller的Resource Event Handlers的引用。
      • 这些 handlers 由具体的Controller提供,就是 Informer 的回调函数。Informer 会根据资源的类型,调用对应Controller的 handler 方法
      • handler 通常都是用于将资源对象的key放入到 该Controller 内部的 Workqueue 中,等候处理。
  • 自定义控制器组件
    • Informer reference
      • Informer reference 是 Informer 实例对象的引用,用于操作和处理自定义资源对象
      • 我们编写自定义控制器时,需要引用自己需要的Informer,向其中加入一系列 Resource Event Handlers
    • Indexer reference
      • Indexer reference 是 Indexer实例对象的引用,用于根据对象Key索引资源对象
      • 我们编写自定义控制器时,应该创建Indexer的引用,将对象Key传给它,就可以获取想要处理的对象
      • NewIndexerInformer函数
        • client-go中的基本控制器提供了 NewIndexerInformer 函数,用于创建Informer和Indexer。
        • 可以直接使用NewIndexerInformer 函数,或者也可以使用工厂方法来创建Informer
    • Resource Event Handlers
      • 由具体的 Controller 给 Client-go 的Informer 提供的回调函数,获取待处理对象的key,并将key放入到Workqueue中。
    • Workqueue
      • 此队列是 具体的Controller 内部创建的队列,用于暂时存储从Resource event handler 中 传递过来的,待处理对象的Key。
      • Resource event handler 函数通常会获取待处理对象的key,并将key放入到这个workqueue中。
    • Process Item
      • 这个函数为循环函数,它不断从 Work queue 中取出对象的key,并使用 Indexer Reference 获取这个key对应的具体资源对象,然后根据资源的变化,做具体的调谐 Reconcile 动作。

3.3.使用client-go编写Controller的步骤

  • 根据2.2中所述,编写一个 自定义Controller,需要实现如下功能。
    • 先从client-go中获取对应资源的 Informer
    • 提供 一系列的 Resource event handlers,并加入对应的Informer,供该informer回调
    • 提供一个 Workqueue 队列,存储待处理的对象的Key
    • 提供一个 循环函数 ProcessItem,不断从 Workqueue 中取出对象的key,交给 处理函数 Worker
      • 提供一个 处理函数 Worker,根据对象Key,使用对应资源的Indexer,获取到该对象的实例,根据对象的属性变化,做真正的调谐过程。

4.client-go的client组件

4.1.Client的4种类型

  • 我们知道,client-go 可以实现与 kubernetes 的通信。如何实现的呢?
  • client-go 主要提供了4种 client 组件:
    • RESTClient:最基础的客户端,提供最基本的封装,可以通过它组装与API Server即时通讯时 的 url
    • Clientset:是一个Client的集合,在Clientset中包含了所有K8S内置资源 的 Client,通过Clientset便可以很方便的操作如Pod、Service这些资源
    • dynamicClient:动态客户端,可以操作任意K8S的资源,包括CRD定义的资源
    • DiscoveryClient:用于发现K8S提供的资源组、资源版本和资源信息,比如:kubectl api-resources
  • 4种client分别对应源码目录:
    在这里插入图片描述

4.2.RESTClient详解

4.2.1.RESTClient结构体

type RESTClient struct {
	// base is the root URL for all invocations of the client
	base *url.URL
	
	// versionedAPIPath is a path segment connecting the base URL to the resource root
	versionedAPIPath string

	// content describes how a RESTClient encodes and decodes responses.
	content ClientContentConfig

	// creates BackoffManager that is passed to requests.
	createBackoffMgr func() BackoffManager

	// rateLimiter is shared among all requests created by this client unless specifically
	// overridden.
	rateLimiter flowcontrol.RateLimiter

	// warningHandler is shared among all requests created by this client.
	// If not set, defaultWarningHandler is used.
	warningHandler WarningHandler

	// Set specific behavior of the client.  If not set http.DefaultClient will be used.
	Client *http.Client
}

4.2.2.RESTClient常用方法

  • RESTClientFor()
    • 位置:rest/config.go 文件
    • 函数签名:func RESTClientFor(config *Config) (*RESTClient, error),直接 rest点 调用
    • 该方法是用于 创建一个 RESTClient 实例
    • 接收一个 rest.Config 类型参数,Config中包含了 限速器、编解码器 等
      • RESTClientFor 方法内部会从 Config 中取出这些配置,设置给RESTClient 实例
      • 这样RESTClient 实例就具有了 限速、编解码 等多种功能
      • 因此,我们创建Config的时候,可以手动设置这些功能,下面的示例中会展示。
  • RESTClient实例的常用方法
    • /rest/client.go 中有一个接口 Interface
      // Interface captures the set of operations for generically interacting with Kubernetes REST apis.
      type Interface interface {
      	GetRateLimiter() flowcontrol.RateLimiter
      	Verb(verb string) *Request
      	Post() *Request
      	Put() *Request
      	Patch(pt types.PatchType) *Request
      	Get() *Request
      	Delete() *Request
      	APIVersion() schema.GroupVersion
      }
      
    • RESTClient 实现了这个接口,因此具有所有的方法,用于发送各种类型的请求
    • 另外,Interface 每个方法的返回值都是 Request 类型,Request 类型的各种方法,很多的返回值也是 Request,这样就可以实现 链式编程

4.2.3.RESTClient的一些其他知识点(建议看一遍)

4.2.3.1.Request 和 Result 常用方法
  • Request 位于 /rest/request.go
    • func (r *Request) Namespace(namespace string) *Request:设置 当前Resquest 访问的 namespace
    • func (r *Request) Resource(resource string) *Request:设置 当前Resquest 想要访问的资源类型
    • func (r *Request) Name(resourceName string) *Request:设置 当前Resquest 想要访问的资源的名称
    • func (r *Request) Do(ctx context.Context) Result:格式化并执行请求。返回一个 Result 对象,以便于处理响应。
  • Result 也位于 /rest/request.go
    在这里插入图片描述
4.2.3.2.rest.Config 结构体
  • 位于 rest/config.go 中,用于描述 kubernetes客户端的通用属性
    type Config struct {
    	// API 服务器的主机地址,格式为 https://<hostname>:<port>。默认情况下,它为空字符串,表示使用当前上下文中的集群配置。
    	Host string
    	
    	// 指定 API 服务器的路径,目前只有两种取值:/api、/apis
    	// - /api:访问core API 组资源时,其实group值为空
    	// - /apis:访问其他 API 组资源时,都是apis,他们都有group值
    	APIPath string
    
    	// 对请求内容的配置,会影响对象在发送到服务器时的转换方式
    	// - ContentConfig中有两个重要属性:
    	//   - NegotiatedSerializer:用于序列化和反序列化请求和响应的接口
    	//   - GroupVersion:请求资源的 API 组和版本
    	ContentConfig
    
    	// 用于进行基本身份验证的用户名的字符串
    	Username string
    	
    	// 用于进行基本身份验证的密码的字符串
    	Password string `datapolicy:"password"`
    
    	// 用于进行身份验证的令牌的字符串
    	BearerToken string `datapolicy:"token"`
    
    	// 包含身份验证令牌的文件的路径
    	BearerTokenFile string
    
    	// TLS 客户端配置,包括证书和密钥
    	TLSClientConfig
    
    	// 每秒允许的请求数(Queries Per Second)。默认为 5.0。
    	QPS float32
    
    	// 突发请求数。默认为 10
    	Burst int
    
    	// 速率限制器,用于控制向 API 服务器发送请求的速率
    	RateLimiter flowcontrol.RateLimiter
    
    	// 与 API 服务器建立连接的超时时间
    	Timeout time.Duration
    
    	// 用于创建网络连接的 Dial 函数
    	Dial func(ctx context.Context, network, address string) (net.Conn, error)
    
    	// ......
    }
    
4.2.3.3.tools/clientcmd 工具
  • 源码位于 client-go/tools/clientcmd 包下
  • clientcmd 是 Kubernetes Go 客户端库(client-go)中的一个包,用于加载和解析 Kubernetes 配置文件,并辅助创建与 Kubernetes API 服务器进行通信的客户端。
  • clientcmd 提供了一些功能,使得在客户端应用程序中处理 Kubernetes 配置变得更加方便。主要包含以下几个方面的功能:
    • 加载配置文件:clientcmd 可以根据指定的路径加载 Kubernetes 配置文件,例如 kubeconfig 文件。
    • 解析配置文件:一旦加载了配置文件,clientcmd 提供了解析配置文件的功能,可以获取各种配置信息,如集群信息、认证信息、上下文信息等。
    • 辅助创建客户端:clientcmd 可以使用配置文件中的信息,辅助创建与 Kubernetes API 服务器进行通信的客户端对象。这些客户端对象可以用来执行对 Kubernetes 资源的增删改查操作。
    • 切换上下文:clientcmd 还支持在多个上下文之间进行切换。上下文表示一组命名空间、集群和用户的组合,用于确定客户端与哪个Kubernetes 环境进行通信。

4.2.4.RESTClient使用示例

  • 需求:获取default命名空间下的所有pod,并打印所有pod的name
  • 首先到kubernetes的官方API文档中,查看 请求url、响应
    • https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#pod-v1-core
    • 或者:https://v1-24.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#list-pod-v1-core
      在这里插入图片描述
  • 代码编写
    package main
    
    import (
    	"context"
    	v1 "k8s.io/api/core/v1"
    	"k8s.io/client-go/kubernetes/scheme"
    	"k8s.io/client-go/rest"
    	"k8s.io/client-go/tools/clientcmd"
    )
    
    func main() {
    	// 在你机器的homeDir下,放入集群的config文件,用于连接集群(可以直接从集群master的~/.kube/config拷贝过来)
    	// clientcmd是位于client-go/tools/clientcmd目录下的工具
    	config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
    	if err != nil {
    		panic(err)
    	}
    	// 设置默认 GroupVersion(我要操作的是pod,不属于任何的group,所以使用了SchemeGroupVersion。你要操作什么,就写什么GroupVersion即可)
    	config.GroupVersion = &v1.SchemeGroupVersion
    
    	// 设置序列化/反序列化器(后面的 Into方法 就是使用它完成 反序列化 的)
    	config.NegotiatedSerializer = scheme.Codecs
    
    	// 设置 API 根的子路径(我们操作的是pod,属于core资源,所以设置为/api)
    	config.APIPath = "/api"
    	
    	// 创建一个 RESTClient
    	restClient, err := rest.RESTClientFor(config)
    	if err != nil {
    		panic(err)
    	}
    
    	// 创建一个Pod,用于接收请求结果
    	pods := v1.PodList{}
    	
    	// 链式编程 发送请求,并反序列化结果到pod中
    	err = restClient.Get().Namespace(v1.NamespaceDefault).Resource("pods").Do(context.TODO()).Into(&pods)
    	if err != nil {
    		panic(err)
    	}
    	
    	// 打印pod名称
    	for _, pod := range pods.Items {
    		println(pod.Name)
    	}
    }
    
  • 输出结果
    cassandra-5hbf7
    liveness-exec
    mysql-87pgn
    myweb-7f8rh
    myweb-rjblc
    nginx-pod-node1
    

4.3.Clientset详解

4.3.1.Clientset是什么

  • 结论:Clientset 是 一系列 RESTClient 的 集合。
  • 从4.2.4的 RESTClient 使用示例来看,使用 RESTClient 操作kubernetes资源,太麻烦了
    • 要操作 pods,需要指定config,给config设置 APIPath 为 “/api”、设置序列化器、设置 GroupVersion,最后还要调用 rest.RESTClientFor(config) 得到一个 用于操作pods的Clientset
    • 而如果我要操作 deployment,这个过程又需要写一遍,然后又得到一个 用于操作deployment的Clientset
    • 代码冗余,不优雅,而且到处创建Clientset,耗时又浪费资源
  • 因此,就有了事先创建 各种资源的RESTClient,存起来备用的需求。Clientset就是这样封装起来的一个set集合。

4.3.2.Clientset的结构体

  • 位于 /kubernetes/clientset.go
  • Clientset结构体:
    type Clientset struct {
    	......
    	appsV1                        *appsv1.AppsV1Client
    	appsV1beta1                   *appsv1beta1.AppsV1beta1Client
    	appsV1beta2                   *appsv1beta2.AppsV1beta2Client
    	authenticationV1              *authenticationv1.AuthenticationV1Client
    	authenticationV1alpha1        *authenticationv1alpha1.AuthenticationV1alpha1Client
    	authenticationV1beta1         *authenticationv1beta1.AuthenticationV1beta1Client
    	authorizationV1               *authorizationv1.AuthorizationV1Client
    	authorizationV1beta1          *authorizationv1beta1.AuthorizationV1beta1Client
    	autoscalingV1                 *autoscalingv1.AutoscalingV1Client
    	autoscalingV2                 *autoscalingv2.AutoscalingV2Client
    	autoscalingV2beta1            *autoscalingv2beta1.AutoscalingV2beta1Client
    	autoscalingV2beta2            *autoscalingv2beta2.AutoscalingV2beta2Client
    	batchV1                       *batchv1.BatchV1Client
    	batchV1beta1                  *batchv1beta1.BatchV1beta1Client
    	certificatesV1                *certificatesv1.CertificatesV1Client
    	certificatesV1beta1           *certificatesv1beta1.CertificatesV1beta1Client
    	certificatesV1alpha1          *certificatesv1alpha1.CertificatesV1alpha1Client
    	coordinationV1beta1           *coordinationv1beta1.CoordinationV1beta1Client
    	coordinationV1                *coordinationv1.CoordinationV1Client
    	coreV1                        *corev1.CoreV1Client
    	......
    }
    
  • appsv1 的类型 *appsv1.AppsV1Client 举例:可以看到,内部包含了一个 restClient。这也进一步认证,Clientset 就是一系列 RESTClient 的集合。
    type AppsV1Client struct {
    	restClient rest.Interface
    }
    

4.3.3.Clientset的常用方法

4.3.3.1.NewForConfig()方法
  • 位于 /kubernetes/clientset.go 中,所以可以直接使用 kubernetes.NewForConfig() 使用
  • 用于创建一个Clientset,传入一个rest.Config配置对象
    func NewForConfig(c *rest.Config) (*Clientset, error) {
    	configShallowCopy := *c
    
    	if configShallowCopy.UserAgent == "" {
    		configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent()
    	}
    
    	// share the transport between all clients
    	httpClient, err := rest.HTTPClientFor(&configShallowCopy)
    	if err != nil {
    		return nil, err
    	}
    
    	// 这个方法,就完成了所有 RESTClient 的创建
    	return NewForConfigAndClient(&configShallowCopy, httpClient)
    }
    
    func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) {
    	configShallowCopy := *c
    	if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
    		if configShallowCopy.Burst <= 0 {
    			return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
    		}
    		configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
    	}
    
    	var cs Clientset
    	var err error
    	// 下面就是创建各种 RESTClient 了,创建结果,被保存到 cs 中
    	cs.admissionregistrationV1, err = admissionregistrationv1.NewForConfigAndClient(&configShallowCopy, httpClient)
    	if err != nil {
    		return nil, err
    	}
    	cs.admissionregistrationV1alpha1, err = admissionregistrationv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
    	if err != nil {
    		return nil, err
    	}
    	cs.admissionregistrationV1beta1, err = admissionregistrationv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
    	if err != nil {
    		return nil, err
    	}
    	......
    	return &cs, nil
    }
    
4.3.3.2.Clientset的实例方法
  • Clientset 实现了 /kubernetes/clientset.go 下的 Interface接口,将自己内部的 私有属性 供外部使用
  • Interface 接口源码
    type Interface interface {
    	......
    	AppsV1() appsv1.AppsV1Interface
    	AppsV1beta1() appsv1beta1.AppsV1beta1Interface
    	AppsV1beta2() appsv1beta2.AppsV1beta2Interface
    	AuthenticationV1() authenticationv1.AuthenticationV1Interface
    	AuthenticationV1alpha1() authenticationv1alpha1.AuthenticationV1alpha1Interface
    	AuthenticationV1beta1() authenticationv1beta1.AuthenticationV1beta1Interface
    	AuthorizationV1() authorizationv1.AuthorizationV1Interface
    	AuthorizationV1beta1() authorizationv1beta1.AuthorizationV1beta1Interface
    	AutoscalingV1() autoscalingv1.AutoscalingV1Interface
    	AutoscalingV2() autoscalingv2.AutoscalingV2Interface
    	AutoscalingV2beta1() autoscalingv2beta1.AutoscalingV2beta1Interface
    	AutoscalingV2beta2() autoscalingv2beta2.AutoscalingV2beta2Interface
    	BatchV1() batchv1.BatchV1Interface
    	BatchV1beta1() batchv1beta1.BatchV1beta1Interface
    	CertificatesV1() certificatesv1.CertificatesV1Interface
    	CertificatesV1beta1() certificatesv1beta1.CertificatesV1beta1Interface
    	CertificatesV1alpha1() certificatesv1alpha1.CertificatesV1alpha1Interface
    	CoordinationV1beta1() coordinationv1beta1.CoordinationV1beta1Interface
    	CoordinationV1() coordinationv1.CoordinationV1Interface
    	CoreV1() corev1.CoreV1Interface
    	......
    }
    
  • AppsV1() 方法为例,返回值是接口 appsv1.AppsV1Interface 的实现类 appsv1.AppsV1Client 的对象
    // 接口
    type AppsV1Interface interface {
    	RESTClient() rest.Interface
    	ControllerRevisionsGetter
    	DaemonSetsGetter
    	DeploymentsGetter
    	ReplicaSetsGetter
    	StatefulSetsGetter
    }
    
    // 实现类
    type AppsV1Client struct {
    	restClient rest.Interface
    }
    
    // AppsV1Client 实现 AppsV1Interface 接口的方法
    func (c *AppsV1Client) RESTClient() rest.Interface {
    	if c == nil {
    		return nil
    	}
    	return c.restClient
    }
    
  • appsv1.AppsV1Client 的其他实例方法
    在这里插入图片描述
  • 以 appsv1.AppsV1Client.Deployments() 方法举例
    • Deployments() 方法源码
      // 返回值是DeploymentInterface 
      func (c *AppsV1Client) Deployments(namespace string) DeploymentInterface {
      	// 实际上,返回值是 DeploymentInterface 的实现类 deployments 的对象
      	return newDeployments(c, namespace)
      }
      
      // 构造一个 deployments 的对象
      func newDeployments(c *AppsV1Client, namespace string) *deployments {
      	return &deployments{
      		client: c.RESTClient(),
      		ns:     namespace,
      	}
      }
      
    • 返回值:DeploymentInterface 接口源码,可以看到包含操作Deployment的各种方法
      type DeploymentInterface interface {
      	Create(ctx context.Context, deployment *v1.Deployment, opts metav1.CreateOptions) (*v1.Deployment, error)
      	Update(ctx context.Context, deployment *v1.Deployment, opts metav1.UpdateOptions) (*v1.Deployment, error)
      	UpdateStatus(ctx context.Context, deployment *v1.Deployment, opts metav1.UpdateOptions) (*v1.Deployment, error)
      	Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
      	DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
      	Get(ctx context.Context, name string, opts metav1.GetOptions) (*v1.Deployment, error)
      	List(ctx context.Context, opts metav1.ListOptions) (*v1.DeploymentList, error)
      	Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
      	Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.Deployment, err error)
      	Apply(ctx context.Context, deployment *appsv1.DeploymentApplyConfiguration, opts metav1.ApplyOptions) (result *v1.Deployment, err error)
      	ApplyStatus(ctx context.Context, deployment *appsv1.DeploymentApplyConfiguration, opts metav1.ApplyOptions) (result *v1.Deployment, err error)
      	GetScale(ctx context.Context, deploymentName string, options metav1.GetOptions) (*autoscalingv1.Scale, error)
      	UpdateScale(ctx context.Context, deploymentName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (*autoscalingv1.Scale, error)
      	ApplyScale(ctx context.Context, deploymentName string, scale *applyconfigurationsautoscalingv1.ScaleApplyConfiguration, opts metav1.ApplyOptions) (*autoscalingv1.Scale, error)
      
      	DeploymentExpansion
      }
      
  • 挑选 DeploymentInterface.Create 方法,查看 实现类 deployments 的 Create实现
    • 可以看出,Create方法的内容,就跟我们4.2.4中使用 RESTClient 的方式差不多
    • 这更加印证了,Clientset 就是 对各种 GroupVersion 的 RESTClient 的封装
    func (c *deployments) Create(ctx context.Context, deployment *v1.Deployment, opts metav1.CreateOptions) (result *v1.Deployment, err error) {
    	result = &v1.Deployment{}
    	err = c.client.Post().
    		Namespace(c.ns).
    		Resource("deployments").
    		VersionedParams(&opts, scheme.ParameterCodec).
    		Body(deployment).
    		Do(ctx).
    		Into(result)
    	return
    }
    
  • 实际上,这些方法都不是人工写的,都是 code-generator 自动生成的
    • code-generator 提供了很多工具用于为k8s中的资源生成相关代码,其中包括一个 client-gen
    • client-gen:可以为资源生成标准的操作方法(get;list;watch;create;update;patch;delete)
    • 比如,在kuberentes源码 staging/src/k8s.io/api/core/v1/types.go 中,可以看到 type Pod struct 注释上,就使用了 genclient 的标记
      // +genclient
      // +genclient:method=UpdateEphemeralContainers,verb=update,subresource=ephemeralcontainers
      // ......
      type Pod struct {
      	......
      }
      
    • client-gen 常用标记
      // +genclient - 生成默认的客户端动作函数(create, update, delete, get, list, update, patch, watch以及 是否生成updateStatus取决于.Status字段是否存在)。
      // +genclient:nonNamespaced - 所有动作函数都是在没有名称空间的情况下生成
      // +genclient:onlyVerbs=create,get - 指定的动作函数被生成.
      // +genclient:skipVerbs=watch - 生成watch以外所有的动作函数.
      // +genclient:noStatus - 即使.Status字段存在也不生成updateStatus动作函数
      

4.3.4.Clientset使用示例

  • 需求:获取default命名空间下的pod列表,并获取kube-system命名空间下的deploy列表
  • 从下面代码来看,创建了一个 clientset,就可以操作不同 GroupVersion 下的 不同资源,也无需再去手动指定 APIPath 等值了
  • 代码编写
    package main
    
    import (
    	"context"
    	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    	"k8s.io/client-go/kubernetes"
    	"k8s.io/client-go/tools/clientcmd"
    )
    
    func main() {
    	// 同样是先 创建一个客户端配置config
    	config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
    	if err != nil {
    		panic(err)
    	}
    
    	// 使用 kubernetes.NewForConfig(),创建一个ClientSet对象
    	clientSet, err := kubernetes.NewForConfig(config)
    	if err != nil {
    		panic(err)
    	}
    
    	// 1、从 clientSet 中调用操作pod的 RESTClient,获取default命名空间下的pod列表
    	pods, err := clientSet.CoreV1().Pods(v1.NamespaceDefault).List(context.TODO(), v1.ListOptions{})
    	if err != nil {
    		panic(err)
    	}
    	// 打印pod名称
    	for _, pod := range pods.Items {
    		println(pod.Name)
    	}
    
    	println("------")
    
    	// 2、从 clientSet 中调用操作 deploy 的 RESTClient,获取kube-system命名空间下的deploy列表
    	deploys, err := clientSet.AppsV1().Deployments("kube-system").List(context.TODO(), v1.ListOptions{})
    	if err != nil {
    		panic(err)
    	}
    	// 打印 deploy 名称
    	for _, deploy := range deploys.Items {
    		println(deploy.Name)
    	}
    }
    
  • 输出结果
    cassandra-5hbf7
    liveness-exec
    mysql-87pgn
    myweb-7f8rh
    myweb-rjblc
    nginx-pod-node1
    ------
    coredns
    default-http-backend
    metrics-server
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/342519.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

应用app的服务器如何增加高并发

增强服务器的高并发能力是现代网络应用非常关键的需求。面对用户数量的不断增长和数据量的膨胀&#xff0c;服务器必须能够处理大量并发请求。以下是一些提高服务器高并发能力的常用方法和具体实施细节&#xff1a; 优化服务器和操作系统配置 服务器和操作系统的默认配置不一定…

大模型学习与实践笔记(十二)

将RAG生成模型部署到openxlab 平台 代码仓库&#xff1a;https://github.com/AllYoung/LLM4opencv 1&#xff1a;创建代码仓库 在 GitHub 中创建存放应用代码的仓库&#xff0c;其代码大致目录树如下&#xff1a; ├─GitHub repo │ ├─app.py # …

多场景建模:阿里多场景多任务元学习方法M2M

multi-scenario multi-task meta learning approach (M2M) 背景 广告领域大部分是针对用户建模的&#xff0c;像点击率预估&#xff0c;很少有针对广告主需求建模&#xff08;广告消耗预估、活跃率/流失率预估、广告曝光量预估&#xff09;&#xff0c;广告的类型较多&#x…

数据库-分库分表初探

文章目录 分库策略垂直切分垂直分库&#xff08;专库专用&#xff09;垂直分表&#xff08;拆表&#xff09;优点缺点 水平(Sharding)切分水平分表库内分表分库分表优点缺点 分表策略hash取模方案range范围区间取值方案映射表方案 分库分表问题事务一致性问题跨节点关联查询跨节…

隐藏服务器源IP的几种方法

为网络管理员的我们多知道遇到过服务器因为拒绝服务攻击(DDOS攻击)遇到网站瘫痪的情况是很糟心&#xff0c;随着客户信息越来越受到公司企业的重视&#xff0c;网站服务器的安全也越来越受到关注&#xff0c;但无法避免的是会遇到黑客使用DDoS攻击业务。 下面简单介绍一下隐藏i…

PolarDB无感切换特性助力游戏领域高可用实践

❤️作者主页&#xff1a;小虚竹 ❤️作者简介&#xff1a;大家好,我是小虚竹。2022年度博客之星评选TOP 10&#x1f3c6;&#xff0c;Java领域优质创作者&#x1f3c6;&#xff0c;CSDN博客专家&#x1f3c6;&#xff0c;华为云享专家&#x1f3c6;&#xff0c;掘金年度人气作…

前端使用css去除input框的默认样式

关键点&#xff1a; /* 关键点&#xff0c;让输入框无边框 */outline:none; border:none; 1.效果图 2.html <div class"container"><input type"text" placeholder"请输入用户名"><input type"text" placeholder&q…

如何在WordPress中使用 AI 进行 SEO(12 个工具)

您想在 WordPress 中使用 AI 进行 SEO 吗&#xff1f; 人工智能正在对 SEO 行业产生重大影响。已经有优秀的人工智能 SEO 工具&#xff0c;您可以使用它们来提高您的 SEO 排名&#xff0c;而无需付出太多努力。 在本文中&#xff0c;我们将向您展示如何通过我们精心挑选的工具…

深入解析互联网医院APP开发流程与源码搭建

本篇文章&#xff0c;深入解析互联网医院APP的开发流程&#xff0c;并提供关于源码搭建的一些建议。 一、确定需求与功能 在开始互联网医院APP的开发之前&#xff0c;首先需要明确项目的需求和功能。这包括用户端的预约挂号、在线咨询、报告查看等功能&#xff0c;以及医生端…

spawn_group_template | spawn_group | linked_respawn

字段介绍 spawn_group | spawn_group_template 用来记录与脚本事件或boss战斗有关的 creatures | gameobjects 的刷新数据linked_respawn 用来将 creatures | gameobjects 和 boss 联系起来&#xff0c;这样如果你杀死boss&#xff0c; creatures | gameobjects 在副本重置之前…

stm32中的SPI

SPI的简介 文章目录 SPI的简介物理层协议层基本通讯过程起始和终止信号数据有效性CPOL/CPHA及通讯模式 STM3的SPI特性及架构通讯引脚时钟控制逻辑数据控制逻辑整体控制逻辑通讯过程 代码配置实现指令集结构体的定义SPI时钟信号的定义SPI端口定义SPI命令 flash驱动代码初始化代码…

白酒:原料选择与品质提升的关键要素

云仓酒庄的豪迈白酒&#xff0c;作为中国白酒的品牌之一&#xff0c;其品质的卓着性深受消费者喜爱。在探究其原料选择与品质提升的关键要素时&#xff0c;我们可以深入了解这款酒的酿造工艺和品质保障。 首先&#xff0c;豪迈白酒的原料选择至关重要。高粱作为主要原料&#…

31、WEB攻防——通用漏洞文件上传JS验证mimeuser.ini语言特性

文章目录 文件上传一、前端验证二、.user.ini 文件上传 检测层面&#xff1a;前端、后端等检测内容&#xff1a;文件头、完整性、二次渲染等检测后缀&#xff1a;黑名单、白名单、MIME检测等绕过技巧&#xff1a;多后缀解析&#xff08;php5、php7&#xff09;、截断、中间件特…

【算法与数据结构】518、LeetCode零钱兑换 II

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题的硬币是无数的&#xff0c;因此本题可以抽象成一个完全背包问题。完全背包和01背包的不同之处在于…

智谱AI官网再升级,GLM-4,智能体,AI作图长文档全部搞定

创建智能体 智能体体验中心 可以看到智谱AI也推出了自己的智能体&#xff0c;并且官方内置了丰富多样的智能体供大家免费体验。 GLM-4 原生支持自动联网、图片生成、数据分析等复杂任务&#xff0c;现开放体验中&#xff0c;快来开启更多精彩。写一篇《繁花》的影评&#xf…

四月在巴黎,首届全球旗舰会议Sui Basecamp诚邀您来

Sui主网于2023年5月成功上线&#xff0c;历经八个月的发展&#xff0c;TVL最高达3.4亿美金跻身非EVM链第二名&#xff0c;整体生态也在不断的调整中&#xff0c;焕发蓬勃生机。随着2024年4月主网上线周年的临近&#xff0c;我们诚挚邀请您参加Sui全球旗舰品牌会议Sui Basecamp&…

darts,一个超强的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个超强的 Python 库 - darts。 Github地址&#xff1a;https://github.com/unit8co/darts 时间序列数据在各行各业中都扮演着重要的角色。无论是股票价格、气象数据、销售记…

浮点数详解

目录 1.概述 2.浮点数的编码方式 2.1.float类型的IEEE编码 2.2.double类型的IEEE编码 2.3.现场问题 2.4.总结 1.概述 计算机也需要运算和存储数学中的实数。在计算机的发展过程中&#xff0c;曾产生过多种存储实数的方式&#xff0c;有的现在已经很少使用了。不管如何存储…

HDMI、VGA、DVI、DB接口的区别

HDMI、VGA、DVI和DB&#xff08;也称为DisplayPort&#xff09;是不同类型的视频接口标准&#xff0c;它们用于连接计算机、显示器、电视和其他视频设备。 HDMI&#xff08;High-Definition Multimedia Interface&#xff0c;高清晰度多媒体接口&#xff09;&#xff1a;HDMI支…

JavaEE进阶(6)SpringBoot 配置文件(作用、格式、properties配置文件说明、yml配置文件说明、验证码案例)

接上次博客&#xff1a;JavaEE进阶&#xff08;5&#xff09;Spring IoC&DI&#xff1a;入门、IoC介绍、IoC详解&#xff08;两种主要IoC容器实现、IoC和DI对对象的管理、Bean存储、方法注解 Bean)、DI详解&#xff1a;注入方式、总结-CSDN博客 目录 配置文件作用 Sprin…