k8s编程- 基础介绍及client-go架构 代码实践

477 阅读3分钟

教程:www.bilibili.com/video/BV1aY… 笔记摘自如上视频,如有侵权,请联系本人删除

k8s的扩展点

image.png

  1. kubectl: 用户使用kubectl与apiserver交互,只能影响用户本地的环境。
  2. api server: 处理所有的请求。身份认证,处理请求等
  3. 内置资源:Pods/server/dp等,一般无法修改
  4. CRD: 自定义资源,配合自定义控制器进行修改。一般也被叫做operator
  5. scheduler: 调度器,决定pod在哪个Node执行。
  6. controller manager: 控制器管理。很多行为都是通过它来进行控制。是apiserver的客户端。k8s内置资源的控制器都在其中。
  7. custom controller: 自定义控制器,可以控制CRD也可以控制内置资源
  8. kubelet: a. 通过CNI: 实现不同网络连接模式 b. 通过csi: 支持更多存储类型 c. 通过cri: 支持更多的runtime
  9. client-go: 通用golang库,各个组件都通过它与apiserver通信。

k8s控制器模式

控制器的含义是通过监控集群的公共状态,并致力于将当前状态转变为期望的状态。至于如何转变,由控制器的控制循环处理相应的逻辑。一个控制器至少追踪一种类型的Kubernetes资源。该资源的控制器负责确保其当前状态(Status)接近期望状态(Spec) 。不同的控制器可以相互配合完成项复杂的任务。 不论是内置资源的控制器还是自定义资源的控制器,我们都会通过 client-go来于API Server进行交互。而在client-go中,为我们提供了控制器的大部分实现,我们只需要在此基础上通过少量代码便可以写出符合K8S设计原则的控制器。

  • Reflector:
  • Delta FIFO Queue:
  • EventHandler
  • WorkQueue
  • Indexer/Cache
  • Worker: 我们需要主要实现的逻辑在这里,根据spec和status进行比对和逻辑处理
  • API Server

逻辑抽象:

  • 观察:通过监控Kubernetes资源对象变化的事件来获取当前对象状态,我们只需要注入EventHandler让client-go将变化的事件对象信息放入WorkQueue中。
  • 分析:确定当前状态和期望状态的不同,由Worker完成。
  • 执行:执行能够驱动对象当前状态变化的操作,由Worker完成。
  • 更新:更新对象的当前状态,由Worker完成。

Client类型

  • RESTClient: 最基础的客户端,提供最基本的封装。 Restful访问
  • Clientset:是一个Client的集合,在Clientset中包含了所有K8S内置资源的Client,通过Clientset便可以很方便的操作如Pod、Service这些资源
  • dynamicClient:动态客户端,可以操作任意K8S的资源,包括CRD定义的资源。
  • DiscoveryClient:用于发现K8S提供的资源组、资源版本和资源信息,比如:kubectl api-resources

RESTClient

  • RESTClientFor: 为创建RESTClient准备config,比如限速器、编解码器等
  • UnversionedRESTClientFor: 与RESTClientFor类似,只是允许config.GroupVersion为空

代码

import (
	"context"

	"k8s.io/api/core/v1"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

func main() {
	// config
	config, err := clientcmd.BuildConfigFromFlags("", clientcmd.RecommendedHomeFile)
	if err != nil {
		panic(err)
	}
	config.GroupVersion = &v1.SchemeGroupVersion
	config.NegotiatedSerializer = scheme.Codecs
	config.APIPath = "/api"

	// client
	restClient, err := rest.RESTClientFor(config)
	if err != nil {
		panic(err)
	}

	// get data of pod
	pod := v1.Pod{}
	// Do之前的都是在拼接url,
	// do发送执行命令, 实际执行发送的url,返回都在这里完成
	// 获取的结果放到pods中(手动指定的方式)

	err = restClient.Get().Namespace("default").Resource("pods").Name("test").Do(context.TODO()).Into(&pod)
	if err != nil {
		println("\nerr:" + err.Error())
	} else {
		println("\npodName: " + pod.Name)
	}
}

ClientSet

代码:

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)
	}
	// clientSet中会指定config,所以不用手动设置

	// clientSet, 多个client的集合
	clientSet, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err)
	}

	// clientSet找到coreV1
	coreV1 := clientSet.CoreV1()
	pod, err := coreV1.Pods("default").Get(context.TODO(), "test", v1.GetOptions{})
	if err != nil {
		println("\nerr:" + err.Error())
	} else {
		println("\npodName: " + pod.Name)
	}
}

kubernetes.NewForConfig返回了clientSet,具体结构如下。我们到的结构是corev1.CoreV1Client

type Clientset struct {
	*discovery.DiscoveryClient
	admissionregistrationV1      *admissionregistrationv1.AdmissionregistrationV1Client
	admissionregistrationV1beta1 *admissionregistrationv1beta1.AdmissionregistrationV1beta1Client
	internalV1alpha1             *internalv1alpha1.InternalV1alpha1Client
	appsV1                       *appsv1.AppsV1Client
	appsV1beta1                  *appsv1beta1.AppsV1beta1Client
	appsV1beta2                  *appsv1beta2.AppsV1beta2Client
	authenticationV1             *authenticationv1.AuthenticationV1Client
	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
	coordinationV1beta1          *coordinationv1beta1.CoordinationV1beta1Client
	coordinationV1               *coordinationv1.CoordinationV1Client
	coreV1                       *corev1.CoreV1Client
	discoveryV1                  *discoveryv1.DiscoveryV1Client
	discoveryV1beta1             *discoveryv1beta1.DiscoveryV1beta1Client
	eventsV1                     *eventsv1.EventsV1Client
	eventsV1beta1                *eventsv1beta1.EventsV1beta1Client
	extensionsV1beta1            *extensionsv1beta1.ExtensionsV1beta1Client
	flowcontrolV1alpha1          *flowcontrolv1alpha1.FlowcontrolV1alpha1Client
	flowcontrolV1beta1           *flowcontrolv1beta1.FlowcontrolV1beta1Client
	flowcontrolV1beta2           *flowcontrolv1beta2.FlowcontrolV1beta2Client
	networkingV1                 *networkingv1.NetworkingV1Client
	networkingV1beta1            *networkingv1beta1.NetworkingV1beta1Client
	nodeV1                       *nodev1.NodeV1Client
	nodeV1alpha1                 *nodev1alpha1.NodeV1alpha1Client
	nodeV1beta1                  *nodev1beta1.NodeV1beta1Client
	policyV1                     *policyv1.PolicyV1Client
	policyV1beta1                *policyv1beta1.PolicyV1beta1Client
	rbacV1                       *rbacv1.RbacV1Client
	rbacV1beta1                  *rbacv1beta1.RbacV1beta1Client
	rbacV1alpha1                 *rbacv1alpha1.RbacV1alpha1Client
	schedulingV1alpha1           *schedulingv1alpha1.SchedulingV1alpha1Client
	schedulingV1beta1            *schedulingv1beta1.SchedulingV1beta1Client
	schedulingV1                 *schedulingv1.SchedulingV1Client
	storageV1beta1               *storagev1beta1.StorageV1beta1Client
	storageV1                    *storagev1.StorageV1Client
	storageV1alpha1              *storagev1alpha1.StorageV1alpha1Client
}

在每一个NewForConfigAndClient中都能看到刚刚我们手动设置的setConfigDefaults,所以不需要我们再手动设置