client-go支持4种Client客户端对象与Kubernetes API Server交互的方式,Client交互对象如图所示。
image.png

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

  1. func (rules *ClientConfigLoadingRules) Load() (*clientcmdapi.Config, error) {
  2. if err := rules.Migrate(); err != nil {
  3. return nil, err
  4. }
  5. errlist := []error{}
  6. missingList := []string{}
  7. kubeConfigFiles := []string{}
  8. // Make sure a file we were explicitly told to use exists
  9. if len(rules.ExplicitPath) > 0 {
  10. if _, err := os.Stat(rules.ExplicitPath); os.IsNotExist(err) {
  11. return nil, err
  12. }
  13. kubeConfigFiles = append(kubeConfigFiles, rules.ExplicitPath)
  14. } else {
  15. kubeConfigFiles = append(kubeConfigFiles, rules.Precedence...)
  16. }
  17. kubeconfigs := []*clientcmdapi.Config{}
  18. // read and cache the config files so that we only look at them once
  19. for _, filename := range kubeConfigFiles {
  20. if len(filename) == 0 {
  21. // no work to do
  22. continue
  23. }
  24. config, err := LoadFromFile(filename)
  25. if os.IsNotExist(err) {
  26. // skip missing files
  27. // Add to the missing list to produce a warning
  28. missingList = append(missingList, filename)
  29. continue
  30. }
  31. if err != nil {
  32. errlist = append(errlist, fmt.Errorf("error loading config file \"%s\": %v", filename, err))
  33. continue
  34. }
  35. kubeconfigs = append(kubeconfigs, config)
  36. }
  37. if rules.WarnIfAllMissing && len(missingList) > 0 && len(kubeconfigs) == 0 {
  38. klog.Warningf("Config not found: %s", strings.Join(missingList, ", "))
  39. }
  40. // first merge all of our maps
  41. mapConfig := clientcmdapi.NewConfig()
  42. for _, kubeconfig := range kubeconfigs {
  43. mergo.MergeWithOverwrite(mapConfig, kubeconfig)
  44. }
  45. // merge all of the struct values in the reverse order so that priority is given correctly
  46. // errors are not added to the list the second time
  47. nonMapConfig := clientcmdapi.NewConfig()
  48. for i := len(kubeconfigs) - 1; i >= 0; i-- {
  49. kubeconfig := kubeconfigs[i]
  50. mergo.MergeWithOverwrite(nonMapConfig, kubeconfig)
  51. }
  52. // since values are overwritten, but maps values are not, we can merge the non-map config on top of the map config and
  53. // get the values we expect.
  54. config := clientcmdapi.NewConfig()
  55. mergo.MergeWithOverwrite(config, mapConfig)
  56. mergo.MergeWithOverwrite(config, nonMapConfig)
  57. if rules.ResolvePaths() {
  58. if err := ResolveLocalPaths(config); err != nil {
  59. errlist = append(errlist, err)
  60. }
  61. }
  62. return config, utilerrors.NewAggregate(errlist)
  63. }

获取配置文件以及合并配置文件都在同一个方法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自定义资源。

代码示例如下:

  1. package main
  2. import (
  3. "fmt"
  4. apiv1 "k8s.io/api/core/v1"
  5. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  6. "k8s.io/client-go/kubernetes"
  7. "k8s.io/client-go/tools/clientcmd"
  8. )
  9. func main() {
  10. config, err := clientcmd.BuildConfigFromFlags("", "./config")
  11. if err != nil {
  12. panic(err)
  13. }
  14. clientset, err := kubernetes.NewForConfig(config)
  15. if err != nil {
  16. panic(err)
  17. }
  18. podClient := clientset.CoreV1().Pods(apiv1.NamespaceDefault)
  19. podList, err := podClient.List(metav1.ListOptions{Limit: 10})
  20. if err != nil {
  21. panic(err)
  22. }
  23. for _,pod := range podList.Items{
  24. fmt.Printf("NAMESPACE: %v \nNAME: %v \nSTATUS: %v \n",pod.Namespace,pod.Name,pod.Status)
  25. }
  26. }

通过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{}转换的。

示例如下:

  1. package main
  2. import (
  3. "fmt"
  4. apiv1 "k8s.io/api/core/v1"
  5. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  6. "k8s.io/apimachinery/pkg/runtime"
  7. "k8s.io/apimachinery/pkg/runtime/schema"
  8. "k8s.io/client-go/dynamic"
  9. "k8s.io/client-go/tools/clientcmd"
  10. )
  11. func main() {
  12. config, err := clientcmd.BuildConfigFromFlags("", "./config")
  13. if err != nil {
  14. panic(err)
  15. }
  16. dynamicClient, err := dynamic.NewForConfig(config)
  17. if err != nil {
  18. panic(err)
  19. }
  20. resource := schema.GroupVersionResource{
  21. Version: "v1",
  22. Resource: "pods",
  23. }
  24. unstructObj, err := dynamicClient.Resource(resource).Namespace(apiv1.NamespaceDefault).List(metav1.ListOptions{Limit: 10})
  25. if err != nil {
  26. panic(err)
  27. }
  28. podList := &apiv1.PodList{}
  29. err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructObj.UnstructuredContent(), podList)
  30. if err != nil {
  31. panic(err)
  32. }
  33. for _, pod := range podList.Items {
  34. fmt.Printf("NAMESPACE: %v \nNAME: %v \nSTATUS: %v \n", pod.Namespace, pod.Name, pod.Status)
  35. }
  36. }

首先加载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实现的。

示例代码:

  1. package main
  2. import (
  3. "fmt"
  4. "k8s.io/apimachinery/pkg/runtime/schema"
  5. "k8s.io/client-go/discovery"
  6. "k8s.io/client-go/tools/clientcmd"
  7. )
  8. func main() {
  9. config, err := clientcmd.BuildConfigFromFlags("", "./config")
  10. if err != nil {
  11. panic(err)
  12. }
  13. discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
  14. if err != nil {
  15. panic(err)
  16. }
  17. _, APIResourceLists, err := discoveryClient.ServerGroupsAndResources()
  18. if err != nil {
  19. panic(err)
  20. }
  21. for _,list := range APIResourceLists{
  22. groupVersion, err := schema.ParseGroupVersion(list.GroupVersion)
  23. if err != nil {
  24. panic(err)
  25. }
  26. for _, resource := range list.APIResources{
  27. fmt.Printf("name:%v,group:%v,version:%v \n",resource.Name,groupVersion.Group,groupVersion.Version)
  28. }
  29. }
  30. }

运行以上代码,列出Kubernetes API Server所支持的资源组、资源版本、资源信息。首先加载kubeconfig配置信息,discovery.NewDiscoveryClientForConfig通过kubeconfig配置信息实例化discoveryClient对象,该对象是用于发现Kubernetes API Server所支持的资源组、资源版本、资源信息的客户端。

discoveryClient.ServerGroupsAndResources函数会返回Kubernetes APIServer所支持的资源组、资源版本、资源信息(即APIResourceList),通过遍历APIResourceList输出信息。