client-go(一)

1,201 阅读2分钟

client-go源码目录结构说明

源码目录说明
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、Replication Controller等资源对象
tools提供常用工具, 例如SharedInformer、Reflector、DeltaFIFO及Indexers. 提供Client查询和缓存机制, 以减少向kube-apiserver发起的请求数等
transport提供安全的TCP连接, 支持Http Stream, 某些操作需要再客户端及容器之间传输二进制流, 例如exec、attach等操作. 该功能由内部的spdy包提供支持
util提供常用方法, 例如WorkQueue工作队列、Certificate证书管理等

Client客户端对象

client-go支持4种Client客户端对象与Kubernetes API Server交互的方式

RESTClient

RESTClient是最基础的客户端. RESTClient对HTTP Request进行了封装, 实现了RESTful风格的API. ClientSet、DynamicClient及DiscoveryClient客户端都是基于RESTClient实现的.

ClientSet

ClientSet再RESTClient的基础上封装了对Resource和Version的管理方法. 每一个Resource可以理解为一个客户端, 而ClientSet则是多个客户端的集合, 每一个Resource和Version都以函数的方式暴露给开发者. ClientSet只能够处理Kubernetes内置资源, 它是通过client-gen代码生成器自动生成的

DynamicClient

DynamicClient与ClientSet最大的不同之处是, ClientSet仅仅能访问Kubernetes机自带的资源(即Client集合内的资源), 不能直接访问CRD自定义资源. DynamicClient能够处理Kubernetes中的所有资源对象, 包括Kubernetes内置资源与CRD自定义资源.

DiscoveryClient

DiscoveryClient发现客户端, 用于发现kube-apiserver所支持的资源组、资源版本、资源信息(即Group、Versions、Resources).

示例

示例1 获取集群所有node

package main

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

func main()  {
	config, err := clientcmd.BuildConfigFromFlags("","/Users/sundongmin/.kube/config")
	if err != nil {
		panic(err.Error())
	}

	config.APIPath = "api"
	config.GroupVersion = &corev1.SchemeGroupVersion
	config.NegotiatedSerializer = scheme.Codecs

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


	result := &corev1.NodeList{}
	err = restClient.Get().Namespace("").Resource("nodes").VersionedParams(&metav1.ListOptions{Limit: 100}, scheme.ParameterCodec).Do().Into(result)
	if err != nil {
		panic(err)
	}

	for _, d := range result.Items {
		fmt.Printf("Node Name %v \n", d.Name)
	}
}

示例2 对某个namespace创建configmap

package main

import (
	apiv1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/informers"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/tools/clientcmd"
	"log"
	"time"
)

const CONFIGMAP_NAME = "simon-test-configmap"

func createConfigmap(namespace string, clientset *kubernetes.Clientset) error {
	configmapClient := clientset.CoreV1().ConfigMaps(namespace)
	_, err := configmapClient.Get(CONFIGMAP_NAME, v1.GetOptions{})
	if errors.IsNotFound(err) {
		configmapObj := &apiv1.ConfigMap{
			TypeMeta: v1.TypeMeta{
				Kind:       "ConfigMap",
				APIVersion: "v1",
			},
			ObjectMeta: v1.ObjectMeta{
				Name: CONFIGMAP_NAME,
			},
			Data: map[string]string{
				"test": "test",
			},
		}

		_, err := configmapClient.Create(configmapObj)
		if err != nil {
			return err
		} else {
			log.Println("create configmap success")
			return nil
		}
	}
	return nil
}


func main() {
	config, err := clientcmd.BuildConfigFromFlags("","/Users/sundongmin/.kube/config")
	if err != nil {
		panic(err.Error())
	}

	clientset, err := kubernetes.NewForConfig(config)
	if err != nil {
		panic(err)
	}

	stopCh := make(chan struct{})
	defer close(stopCh)

	shareInformers := informers.NewSharedInformerFactory(clientset, time.Second)
	informer := shareInformers.Core().V1().Namespaces().Informer()

	informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: func (obj interface{})  {
			nObj := obj.(v1.Object)
			log.Printf("New namespaces add %s", nObj.GetName())

			if nObj.GetName() == "citest" {
				err := createConfigmap(nObj.GetName(), clientset)
				if err != nil {
					log.Println("create configmap fail, fail at %s", err)
				}
			}
		},
	})
	informer.Run(stopCh)
}

参考资料

郑东旭-Kubernetes源码剖析