client-go支持4种Client客户端对象与Kubernetes API Server交互的方式,Client交互对象如图所示。
RESTClient是最基础的客户端。RESTClient对HTTP Request进行了封装,实现了RESTful风格的API。ClientSet、DynamicClient及DiscoveryClient客户端都是基于RESTClient实现的。
ClientSet在RESTClient的基础上封装了对Resource和Version的管理方法。每一个Resource可以理解为一个客户端,而ClientSet则是多个客户端的集合,每一个Resource和Version都以函数的方式暴露给开发者。ClientSet只能够处理Kubernetes内置资源,它是通过client-gen代码生成器自动生成的。
DynamicClient与ClientSet最大的不同之处是,ClientSet仅能访问Kubernetes自带的资源(即Client集合内的资源),不能直接访问CRD自定义资源。DynamicClient能够处理Kubernetes中的所有资源对象,包括Kubernetes内置资源与CRD自定义资源。
DiscoveryClient发现客户端,用于发现kube-apiserver所支持的资源组、资源版本、资源信息(即Group、Versions、Resources)。
上面四种客户端都可以通过kubeconfig连接到集群。
一、kubeconfig
kubeconfig用于管理访问集群Kube-apiserver的配置信息。上面介绍的几个客户端都通过kubeconfig来访问集群,其步骤可分为两步:
- 第1步,加载kubeconfig配置信息;
- 第2步,合并多个kubeconfig配置信息
源码位置:staging\src\k8s.io\client-go\tools\clientcmd\loader.go
func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) {if err := rules.Migrate(); err != nil {return nil, err}errlist := []error{}missingList := []string{}kubeConfigFiles := []string{}// Make sure a file we were explicitly told to use existsif len(rules.ExplicitPath) > 0 {if _, err := os.Stat(rules.ExplicitPath); os.IsNotExist(err) {return nil, err}kubeConfigFiles = append(kubeConfigFiles, rules.ExplicitPath)} else {kubeConfigFiles = append(kubeConfigFiles, rules.Precedence...)}kubeconfigs := []*clientcmdapi.Config{}// read and cache the config files so that we only look at them oncefor _, filename := range kubeConfigFiles {if len(filename) == 0 {// no work to docontinue}config, err := LoadFromFile(filename)if os.IsNotExist(err) {// skip missing files// Add to the missing list to produce a warningmissingList = append(missingList, filename)continue}if err != nil {errlist = append(errlist, fmt.Errorf("error loading config file \"%s\": %v", filename, err))continue}kubeconfigs = append(kubeconfigs, config)}if rules.WarnIfAllMissing && len(missingList) > 0 && len(kubeconfigs) == 0 {klog.Warningf("Config not found: %s", strings.Join(missingList, ", "))}// first merge all of our mapsmapConfig := clientcmdapi.NewConfig()for _, kubeconfig := range kubeconfigs {mergo.MergeWithOverwrite(mapConfig, kubeconfig)}// merge all of the struct values in the reverse order so that priority is given correctly// errors are not added to the list the second timenonMapConfig := clientcmdapi.NewConfig()for i := len(kubeconfigs) - 1; i >= 0; i-- {kubeconfig := kubeconfigs[i]mergo.MergeWithOverwrite(nonMapConfig, kubeconfig)}// since values are overwritten, but maps values are not, we can merge the non-map config on top of the map config and// get the values we expect.config := clientcmdapi.NewConfig()mergo.MergeWithOverwrite(config, mapConfig)mergo.MergeWithOverwrite(config, nonMapConfig)if rules.ResolvePaths() {if err := ResolveLocalPaths(config); err != nil {errlist = append(errlist, err)}}return config, utilerrors.NewAggregate(errlist)}
获取配置文件以及合并配置文件都在同一个方法Load中,其中kubeConfigFiles是记录获取到的配置信息,然后会循环它通过LoadFromFile把配置信息读取出来记录到config对象中,然后通过kubeconfigs将所有的config存起来,然后通过mergo.MergeWithOverwrite将所有的config进行合并。
二、RESTClient
RESTClient是最基础的客户端。其他的ClientSet、DynamicClient及DiscoveryClient都是基于RESTClient实现的。RESTClient对HTTP Request进行了封装,实现了RESTful风格的API。它具有很高的灵活性,数据不依赖于方法和资源,因此RESTClient能够处理多种类型的调用,返回不同的数据格式。
三、ClientSet
ClientSet在RESTClient的基础上封装了对Resource和Version的管理方法。每一个Resource可以理解为一个客户端,而ClientSet则是多个客户端的集合,每一个Resource和Version都以函数的方式暴露给开发者。
注意:ClientSet仅能访问Kubernetes自身内置的资源(即客户端集合内的资源),不能直接访问CRD自定义资源。
代码示例如下:
package mainimport ("fmt"apiv1 "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() {config, err := clientcmd.BuildConfigFromFlags("", "./config")if err != nil {panic(err)}clientset, err := kubernetes.NewForConfig(config)if err != nil {panic(err)}podClient := clientset.CoreV1().Pods(apiv1.NamespaceDefault)podList, err := podClient.List(metav1.ListOptions{Limit: 10})if err != nil {panic(err)}for _,pod := range podList.Items{fmt.Printf("NAMESPACE: %v \nNAME: %v \nSTATUS: %v \n",pod.Namespace,pod.Name,pod.Status)}}
通过clientcmd.BuildConfigFromFlags来加载配置文件,然后通过kubernetes.NewForConfig来创建clientset对象。然后通过clientset对象来操作集群,比如上面的获取default命名空间下的pod。
四、DynamicClient
DynamicClient是一种动态客户端,它可以对任意Kubernetes资源进行RESTful操作,包括CRD自定义资源。DynamicClient与ClientSet操作类似,同样封装了RESTClient,同样提供了Create、Update、Delete、Get、List、Watch、Patch等方法。
DynamicClient与ClientSet最大的不同之处是,ClientSet仅能访问Kubernetes自带的资源,而DynamicClient可以。
注意:DynamicClient不是类型安全的,因此在访问CRD自定义资源时需要特别注意。例如,在操作指针不当的情况下可能会导致程序崩溃。
DynamicClient的处理过程将Resource(例如PodList)转换成Unstructured结构类型,Kubernetes的所有Resource都可以转换为该结构类型。处理完成后,再将Unstructured转换成PodList。整个过程类似于Go语言的interface{}断言转换过程。另外,Unstructured结构类型是通过map[string]interface{}转换的。
示例如下:
package mainimport ("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")func main() {config, err := clientcmd.BuildConfigFromFlags("", "./config")if err != nil {panic(err)}dynamicClient, err := dynamic.NewForConfig(config)if err != nil {panic(err)}resource := schema.GroupVersionResource{Version: "v1",Resource: "pods",}unstructObj, err := dynamicClient.Resource(resource).Namespace(apiv1.NamespaceDefault).List(metav1.ListOptions{Limit: 10})if err != nil {panic(err)}podList := &apiv1.PodList{}err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructObj.UnstructuredContent(), podList)if err != nil {panic(err)}for _, pod := range podList.Items {fmt.Printf("NAMESPACE: %v \nNAME: %v \nSTATUS: %v \n", pod.Namespace, pod.Name, pod.Status)}}
首先加载kubeconfig配置信息,dynamic.NewForConfig通过kubeconfig配置信息实例化dynamicClient对象,该对象用于管理Kubernetes的所有Resource的客户端,例如对Resource执行Create、Update、Delete、Get、List、Watch、Patch等操作。
dynamicClient.Resource(resource)函数用于设置请求的资源组、资源版本、资源名称。Namespace函数用于设置请求的命名空间。List函数用于获取Pod列表。得到的Pod列表为unstructured.UnstructuredList指针类型,然后通过runtime.DefaultUnstructuredConverter.FromUnstructured函数将unstructured.UnstructuredList转换成PodList类型。
五、DiscoveryClient
DiscoveryClient是发现客户端,它主要用于发现Kubernetes API Server所支持的资源组、资源版本、资源信息。还可以将这些信息存储到本地,用于本地缓存(Cache),以减轻对Kubernetes API Server访问的压力。在运行Kubernetes组件的机器上,缓存信息默认存储于~/.kube/cache和~/.kube/http-cache下。
kubectl的api-versions和api-resources命令输出也是通过DiscoveryClient实现的。
示例代码:
package mainimport ("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)}discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)if err != nil {panic(err)}_, APIResourceLists, err := discoveryClient.ServerGroupsAndResources()if err != nil {panic(err)}for _,list := range APIResourceLists{groupVersion, err := schema.ParseGroupVersion(list.GroupVersion)if err != nil {panic(err)}for _, resource := range list.APIResources{fmt.Printf("name:%v,group:%v,version:%v \n",resource.Name,groupVersion.Group,groupVersion.Version)}}}
运行以上代码,列出Kubernetes API Server所支持的资源组、资源版本、资源信息。首先加载kubeconfig配置信息,discovery.NewDiscoveryClientForConfig通过kubeconfig配置信息实例化discoveryClient对象,该对象是用于发现Kubernetes API Server所支持的资源组、资源版本、资源信息的客户端。
discoveryClient.ServerGroupsAndResources函数会返回Kubernetes APIServer所支持的资源组、资源版本、资源信息(即APIResourceList),通过遍历APIResourceList输出信息。
