01-client-go

打印 上一主题 下一主题

主题 534|帖子 534|积分 1602

想学习K8S源码,可以加 :mkjnnm
1、先容

client-go 是用来和 k8s 集群交互的go语言客户端库,地点为:https://github.com/kubernetes/client-go client-go 的版本有两种标识方式:


  • v0.x.y (For each v1.x.y Kubernetes release, the major version (first digit) would remain 0)
  • kubernetes-1.x.y
ps: k8s 发布v1.30.0 版本时,client-go 会同步发布两个版本 v0.30.0 (保举利用)和 kubernetes-1.30.0
如果你想利用最新版本的客户端库,你可以运行如下下令:
go get k8s.io/client-go@latest
如果你想利用特定版本,保举利用如下下令:
go get k8s.io/client-go@v0.20.4
2、目录布局

client-go 包罗以下几部门:


  • The kubernetes package contains the clientset to access Kubernetes API.
  • The discovery package is used to discover APIs supported by a Kubernetes API server.
  • The dynamic package contains a dynamic client that can perform generic operations on arbitrary Kubernetes API objects.
  • The plugin/pkg/client/auth packages contain optional authentication plugins for obtaining credentials from external sources.
  • The transport package is used to set up auth and start a connection.
  • The tools/cache package is useful for writing controllers.
3、利用

1.初始化



  • 集群内初始化
  • 集群外初始化
如果你的应用跑在集群中的pod上,保举利用集群内初始化,否则利用集群外初始化。
  1. // 集群外初始化 client
  2. // 需要集群的 kubeconfig 配置文件
  3. func main() {
  4.         var kubeconfig *string
  5.         if home := homedir.HomeDir(); home != "" {
  6.                 kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
  7.         } else {
  8.                 kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
  9.         }
  10.         flag.Parse()
  11.         // use the current context in kubeconfig
  12.         config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
  13.         if err != nil {
  14.                 panic(err.Error())
  15.         }
  16.         // create the clientset
  17.         clientset, err := kubernetes.NewForConfig(config)
  18.         if err != nil {
  19.                 panic(err.Error())
  20.         }
  21. }
复制代码
2. 列出集群内pod资源

  1. pods, err := clientset.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{})
  2.                 if err != nil {
  3.                         panic(err.Error())
  4.                 }
  5.                 fmt.Printf("There are %d pods in the cluster\n", len(pods.Items))
复制代码
上述代码在client-
go仓库下examples目录
你可以运行该代码:
  1. cd out-of-cluster-client-configuration
  2. go build -o app .
  3. ./app -kubeconfig=/path/to/xxx
复制代码
3. deployment资源CRUD - typed (clientset)方式

以下代码创建一个有2个副本数的deployment,然后更新副本数为1,升级nginx镜像版本,最后删除
  1.         deploymentsClient := clientset.AppsV1().Deployments(apiv1.NamespaceDefault)
  2.         deployment := &appsv1.Deployment{
  3.                 ObjectMeta: metav1.ObjectMeta{
  4.                         Name: "demo-deployment",
  5.                 },
  6.                 Spec: appsv1.DeploymentSpec{
  7.                         Replicas: int32Ptr(2),
  8.                         Selector: &metav1.LabelSelector{
  9.                                 MatchLabels: map[string]string{
  10.                                         "app": "demo",
  11.                                 },
  12.                         },
  13.                         Template: apiv1.PodTemplateSpec{
  14.                                 ObjectMeta: metav1.ObjectMeta{
  15.                                         Labels: map[string]string{
  16.                                                 "app": "demo",
  17.                                         },
  18.                                 },
  19.                                 Spec: apiv1.PodSpec{
  20.                                         Containers: []apiv1.Container{
  21.                                                 {
  22.                                                         Name:  "web",
  23.                                                         Image: "nginx:1.12",
  24.                                                         Ports: []apiv1.ContainerPort{
  25.                                                                 {
  26.                                                                         Name:          "http",
  27.                                                                         Protocol:      apiv1.ProtocolTCP,
  28.                                                                         ContainerPort: 80,
  29.                                                                 },
  30.                                                         },
  31.                                                 },
  32.                                         },
  33.                                 },
  34.                         },
  35.                 },
  36.         }
  37.         // Create Deployment
  38.         fmt.Println("Creating deployment...")
  39.         result, err := deploymentsClient.Create(context.TODO(), deployment, metav1.CreateOptions{})
  40.         if err != nil {
  41.                 panic(err)
  42.         }
  43.         fmt.Printf("Created deployment %q.\n", result.GetObjectMeta().GetName())
  44.         // Update Deployment
  45.         prompt()
  46.         fmt.Println("Updating deployment...")
  47.         //    You have two options to Update() this Deployment:
  48.         //
  49.         //    1. Modify the "deployment" variable and call: Update(deployment).
  50.         //       This works like the "kubectl replace" command and it overwrites/loses changes
  51.         //       made by other clients between you Create() and Update() the object.
  52.         //    2. Modify the "result" returned by Get() and retry Update(result) until
  53.         //       you no longer get a conflict error. This way, you can preserve changes made
  54.         //       by other clients between Create() and Update(). This is implemented below
  55.         //                         using the retry utility package included with client-go. (RECOMMENDED)
  56.         //
  57.         // More Info:
  58.         // https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
  59.         retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
  60.                 // Retrieve the latest version of Deployment before attempting update
  61.                 // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver
  62.                 result, getErr := deploymentsClient.Get(context.TODO(), "demo-deployment", metav1.GetOptions{})
  63.                 if getErr != nil {
  64.                         panic(fmt.Errorf("Failed to get latest version of Deployment: %v", getErr))
  65.                 }
  66.                 result.Spec.Replicas = int32Ptr(1)                           // reduce replica count
  67.                 result.Spec.Template.Spec.Containers[0].Image = "nginx:1.13" // change nginx version
  68.                 _, updateErr := deploymentsClient.Update(context.TODO(), result, metav1.UpdateOptions{})
  69.                 return updateErr
  70.         })
  71.         if retryErr != nil {
  72.                 panic(fmt.Errorf("Update failed: %v", retryErr))
  73.         }
  74.         fmt.Println("Updated deployment...")
  75.         // List Deployments
  76.         prompt()
  77.         fmt.Printf("Listing deployments in namespace %q:\n", apiv1.NamespaceDefault)
  78.         list, err := deploymentsClient.List(context.TODO(), metav1.ListOptions{})
  79.         if err != nil {
  80.                 panic(err)
  81.         }
  82.         for _, d := range list.Items {
  83.                 fmt.Printf(" * %s (%d replicas)\n", d.Name, *d.Spec.Replicas)
  84.         }
  85.         // Delete Deployment
  86.         prompt()
  87.         fmt.Println("Deleting deployment...")
  88.         deletePolicy := metav1.DeletePropagationForeground
  89.         if err := deploymentsClient.Delete(context.TODO(), "demo-deployment", metav1.DeleteOptions{
  90.                 PropagationPolicy: &deletePolicy,
  91.         }); err != nil {
  92.                 panic(err)
  93.         }
  94.         fmt.Println("Deleted deployment.")
  95. }
  96. func prompt() {
  97.         fmt.Printf("-> Press Return key to continue.")
  98.         scanner := bufio.NewScanner(os.Stdin)
  99.         for scanner.Scan() {
  100.                 break
  101.         }
  102.         if err := scanner.Err(); err != nil {
  103.                 panic(err)
  104.         }
  105.         fmt.Println()
  106. }
  107. func int32Ptr(i int32) *int32 { return &i }
复制代码
4.deployment资源CRUD - dynamic方式

利用typed方式创建资源固然方便,但是必要事先利用client-gen天生且会与某个特定版本耦合,不敷通用,所以我们可以利用 unstructured.Unstructured 来表现集群中恣意对象。
  1.         client, err := dynamic.NewForConfig(config)
  2.         if err != nil {
  3.                 panic(err)
  4.         }
  5.        
  6.         deploymentRes := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}
  7.         deployment := &unstructured.Unstructured{
  8.                 Object: map[string]interface{}{
  9.                         "apiVersion": "apps/v1",
  10.                         "kind":       "Deployment",
  11.                         "metadata": map[string]interface{}{
  12.                                 "name": "demo-deployment",
  13.                         },
  14.                         "spec": map[string]interface{}{
  15.                                 "replicas": 2,
  16.                                 "selector": map[string]interface{}{
  17.                                         "matchLabels": map[string]interface{}{
  18.                                                 "app": "demo",
  19.                                         },
  20.                                 },
  21.                                 "template": map[string]interface{}{
  22.                                         "metadata": map[string]interface{}{
  23.                                                 "labels": map[string]interface{}{
  24.                                                         "app": "demo",
  25.                                                 },
  26.                                         },
  27.                                         "spec": map[string]interface{}{
  28.                                                 "containers": []map[string]interface{}{
  29.                                                         {
  30.                                                                 "name":  "web",
  31.                                                                 "image": "nginx:1.12",
  32.                                                                 "ports": []map[string]interface{}{
  33.                                                                         {
  34.                                                                                 "name":          "http",
  35.                                                                                 "protocol":      "TCP",
  36.                                                                                 "containerPort": 80,
  37.                                                                         },
  38.                                                                 },
  39.                                                         },
  40.                                                 },
  41.                                         },
  42.                                 },
  43.                         },
  44.                 },
  45.         }
  46.         // Create Deployment
  47.         fmt.Println("Creating deployment...")
  48.         result, err := client.Resource(deploymentRes).Namespace(apiv1.NamespaceDefault).Create(context.TODO(), deployment, metav1.CreateOptions{})
  49.         if err != nil {
  50.                 panic(err)
  51.         }
  52.         fmt.Printf("Created deployment %q.\n", result.GetName())
复制代码
5. discoveryClient

3-4末节我们学习了 typed client 和 dynamic client ,这两个client利用来操作集群中资源,比如创建 deployment,删除pod。discovery client 差别,他是用来发现服务端支持的组、版本、资源类型:
  1. // Package discovery provides ways to discover server-supported
  2. // API groups, versions and resources.
复制代码
我们可以查询服务端支持的组与版本、某个组的资源列表
  1. func main() {
  2.         var kubeconfig *string
  3.         if home := homedir.HomeDir(); home != "" {
  4.                 kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
  5.         } else {
  6.                 kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
  7.         }
  8.         flag.Parse()
  9.         // use the current context in kubeconfig
  10.         config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
  11.         if err != nil {
  12.                 panic(err.Error())
  13.         }
  14.         // *查询服务端支持的组列表
  15.         discoveryClient := discovery.NewDiscoveryClientForConfigOrDie(config)
  16.         gs, err := discoveryClient.ServerGroups()
  17.         if err != nil {
  18.                 panic(err.Error())
  19.         }
  20.         spew.Dump(gs.Groups)
  21.        
  22.         // *查询core/v1 组下的资源列表
  23.         rs, err := discoveryClient.ServerResourcesForGroupVersion("v1")
  24.         if err != nil {
  25.                 panic(err.Error())
  26.         }
  27.         for _, r := range rs.APIResources {
  28.                 fmt.Println(r.Name)
  29.         }
  30. }
  31. // 输出支持的组列表
  32. /*
  33. (v1.APIGroup) &APIGroup{Name:apps,Versions:[]GroupVersionForDiscovery{GroupVersionForDiscovery{GroupVersion:apps/v1,Version:v1,},},PreferredVersion:GroupVersionForDiscovery{GroupVersion:apps/v1,Version:v1,},ServerAddressByClientCIDRs:[]ServerAddressByClientCIDR{},},
  34. (v1.APIGroup) &APIGroup{Name:events.k8s.io,Versions:[]GroupVersionForDiscovery{GroupVersionForDiscovery{GroupVersion:events.k8s.io/v1,Version:v1,},},PreferredVersion:GroupVersionForDiscovery{GroupVersion:events.k8s.io/v1,Version:v1,},ServerAddressByClientCIDRs:[]ServerAddressByClientCIDR{},},
  35. ...
  36. */
  37. // 输出core/v1组下的资源列表
  38. /*
  39. pods/status
  40. podtemplates
  41. replicationcontrollers
  42. replicationcontrollers/scale
  43. replicationcontrollers/status
  44. resourcequotas
  45. resourcequotas/status
  46. secrets
  47. serviceaccounts
  48. ...
  49. */
复制代码
6. restClient

上面三种客户端都是基于 restClient 封装的,restClient 是 client-go 最底子的客户端,对http request 举行了封装,更加灵活,一般我们用不到。
  1. // 根据配置信息构建restClient实例
  2.         restClient, err := rest.RESTClientFor(config)
  3.         if err!=nil {
  4.                 panic(err.Error())
  5.         }
  6.         // 保存pod结果的数据结构实例
  7.         result := &corev1.PodList{}
  8.         //  指定namespace
  9.         namespace := "kube-system"
  10.         // 设置请求参数,然后发起请求
  11.         // GET请求
  12.         err = restClient.Get().
  13.                 //  指定namespace,参考path : /api/v1/namespaces/{namespace}/pods
  14.                 Namespace(namespace).
  15.                 // 查找多个pod,参考path : /api/v1/namespaces/{namespace}/pods
  16.                 Resource("pods").
  17.                 // 指定大小限制和序列化工具
  18.                 VersionedParams(&metav1.ListOptions{Limit:100}, scheme.ParameterCodec).
  19.                 // 请求
  20.                 Do(context.TODO()).
  21.                 // 结果存入result
  22.                 Into(result)
复制代码
4、范围

利用 client 操作集群中资源会导致频繁的轮询,k8s client-go 包提供了更加高效的方式:informer 。
informer 提供了一种机制来监视 Kubernetes 集群内资源的变化并做出反应。它使开辟职员能够接收有关各种 Kubernetes 对象(比方 Pod、服务、部署等)状态的实时更新。
Informer 将集群中的资源缓存在当地来减少频繁的API调用,提高性能并优化资源利用率。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

光之使者

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表