go json 自定义_使用结构化数据访问k8s自定义资源

在上文中对k8s中自定义资源进行了介绍,同时也介绍了如何使用client-go通过非结构化的数据类型来访问自定义资源。使用非结构化的数据类型并不是十分友好,因此本文将介绍如何使用结构化的数据结构来访问自定义资源

准备

参考如何使用CustomResourceDefinition介绍的方式,在k8s上创建自定义资源,同时创建一个实例,以方便下文使用

使用结构化数据访问自定义资源

简介

对k8s的资源访问都是通过k8s的API Server来进行的,client-go就是对API Server的一层封装,也就是说client-go通过访问API Server来获取数据,并将获取到的数据解析成结构化的数据类型,如PodNode等,方便用户使用。对于自定义资源类型,我们也可以通过访问API Server来获取到相关数据,参考如下步骤

  1. 建立本地到API Server的映射

    kubectl proxy
  2. 访问http://127.0.0.1:8001/apis/test.wuming.com/v1/namespaces/default/crontabs即可获取到自定义资源的相关数据

    6227d0311db18c17cc79abc9ba3c08f2.png

从结果中可以看出,所获取到的数据为json结构,将其按照特定的格式进行解析便可获取到结构化的数据类型了

构建结构化的数据类型

  1. 创建文件api\types\v1\crontab.go,该文件主要就是将获取到的json数据解析成结构化的数据

    package v1

    import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

    type CrontabSpec struct {
      Replicas int    `json:"replicas"`
      Spec     string `json:"spec"`
      Image    string `json:"Image"`
    }

    //+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
    type CronTab struct {
      metav1.TypeMeta   `json:",inline"`
      metav1.ObjectMeta `json:"metadata,omitempty"`
      Spec CrontabSpec `json:"spec"`
    }

    //+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
    type CronTabList struct {
      metav1.TypeMeta `json:",inline"`
      metav1.ListMeta `json:"metadata,omitempty"`
      Items []CronTab `json:"items"`
    }
  2. 实现接口k8s.io/apimachinery/pkg/runtime.Object, 该接口是所有API类型都要实现的,主要是考虑到对资源的修改需要写回到API Server,详细信息可参考文档2。该接口可通过工具controller-gen自动实现,我们只需给类型加上注释+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

    # Install controller-gen
    go get -u github.com/kubernetes-sigs/controller-tools/cmd/controller-gen
    # Implement interface runtime.Object automatically
    controller-gen object paths=.\api\types\v1\crontab.go
  3. 创建文件api\types\v1\register.go,该文件主要用于将上面定义的数据类型注册到client-go,之后便可使用client-go对获取到的CronTab类型进行解析。通过方法v1.AddToScheme(scheme.Scheme)完成注册

    package v1

    import (
      metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
      "k8s.io/apimachinery/pkg/runtime"
      "k8s.io/apimachinery/pkg/runtime/schema"
    )

    const GroupName = "test.wuming.com"
    const GroupVersion = "v1"
    var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: GroupVersion}

    var (
      SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
      AddToScheme   = SchemeBuilder.AddToScheme
    )

    func addKnownTypes(scheme *runtime.Scheme) error {
      scheme.AddKnownTypes(SchemeGroupVersion,
        &CronTab{},
        &CronTabList{},
      )
      metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
      return nil
    }

构建对API Server的访问接口

  1. 创建文件clientset\v1\api.go,该文件主要用于对k8s配置文件进行解析,创建访问API Server的客户端

    package v1

    import (
      "k8s.io/apimachinery/pkg/runtime/schema"
      "k8s.io/client-go/kubernetes/scheme"
      "k8s.io/client-go/rest"
      v1 "main.go/api/types/v1"
    )

    type CrontabV1Interface interface {
      Crontabs(namespace string) CronTabInterface
    }

    type CrontabV1Client struct {
      restClient rest.Interface
    }

    func NewForConfig(c *rest.Config) (*CrontabV1Client, error) {
      config := *c
      config.ContentConfig.GroupVersion = &schema.GroupVersion{Group: v1.GroupName, Version: v1.GroupVersion}
      config.APIPath = "/apis"
      config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
      config.UserAgent = rest.DefaultKubernetesUserAgent()

      client, err := rest.RESTClientFor(&config)
      if err != nil {
        return nil, err
      }

      return &CrontabV1Client{restClient: client}, nil
    }

    func (c *CrontabV1Client) Crontabs(namespace string) CronTabInterface {
      return &CronTabClient{
        restClient: c.restClient,
        ns: namespace,
      }
    }
  2. 创建文件clientset\v1\crontabs.go,该文件主要用于访问API Server,并将返回的数据解析成已定义的结构化数据类型

    package v1

    import (
      metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
      "k8s.io/apimachinery/pkg/watch"
      "k8s.io/client-go/kubernetes/scheme"
      "k8s.io/client-go/rest"
      v1 "main.go/api/types/v1"
    )

    type CronTabInterface interface {
      List(opts metav1.ListOptions) (*v1.CronTabList, error)
      Get(name string, options metav1.GetOptions) (*v1.CronTab, error)
    }

    type CronTabClient struct {
      restClient rest.Interface
      ns         string
    }

    func (c *CronTabClient) List(opts metav1.ListOptions) (*v1.CronTabList, error) {
      result := v1.CronTabList{}
      err := c.restClient.
        Get().
        Namespace(c.ns).
        Resource("crontabs").
        VersionedParams(&opts, scheme.ParameterCodec).
        Do().
        Into(&result)
      return &result, err
    }

    func (c *CronTabClient) Get(name string, opts metav1.GetOptions) (*v1.CronTab, error) {
      result := v1.CronTab{}
      err := c.restClient.
        Get().
        Namespace(c.ns).
        Resource("crontabs").
        Name(name).
        VersionedParams(&opts, scheme.ParameterCodec).
        Do().
        Into(&result)
      return &result, err
    }

构建主程序

上述程序完成了自定义资源的结构化解析,以及访问API Server获取到相关的数据,接下来的程序将使用已创建好的接口来完成对自定义资源的访问,同时所获取到的资源信息将以结构化的数据类型呈现

package main

import (
 "flag"
 "fmt"
 "os"
 v1 "main.go/api/types/v1"
 clientV1 "main.go/clientset/v1"
 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 "k8s.io/client-go/kubernetes/scheme"
 "k8s.io/client-go/rest"
 "k8s.io/client-go/tools/clientcmd"
)

func buildConfig() (*rest.Config, error) {
 config, err := rest.InClusterConfig()
 if err == nil {
  return config, nil
 }
 var kubeconfig = flag.String("kubeconfig", "C:/Users/wumin/.kube/config", "kubeconfig file")
 flag.Parse()
 return clientcmd.BuildConfigFromFlags("", *kubeconfig)
}

func main() {
 config, err := buildConfig()
 if err != nil {
  fmt.Printf("The kubeconfig cannot be loaded: %v\n", err)
  os.Exit(1)
 }

 v1.AddToScheme(scheme.Scheme)

 clientSet, err := clientV1.NewForConfig(config)
 if err != nil {
  panic(err)
 }

 crontabs, err := clientSet.Crontabs("default").List(metav1.ListOptions{})
 if err != nil {
  panic(err)
 }
 for _, crontab := range crontabs.Items {
  item, err := clientSet.Crontabs("default").Get(crontab.Name, metav1.GetOptions{})
  if err != nil {
   panic(err)
  }
  fmt.Printf("crontab : %+v\n", item)
 }
 fmt.Printf("crontabs found: %+v\n", crontabs)
}

结果如下:

e7b7d20dc948df770c2f288e250b970f.png

Q&A

  • Q:直接写代码访问API Server获取到所需数据,之后将获取到的数据结构化不也可以吗?为什么还要使用client-go,按照它的规范来实现?

    A: 访问API Server是需要证书密钥等信息的,这些信息配置在k8s的config文件中,直接码代码访问API Server首先需要对该文件进行解析,之后才能对API Server进行访问。而这个工作已经在client-go中做好了,使用client-go可以减少该部分工作量。当然如果想自己写代码访问API Server也是可以的

参考

  • https://www.martin-helmich.de/en/blog/kubernetes-crd-client.html
  • https://pkg.go.dev/k8s.io/apimachinery@v0.17.0/pkg/runtime?tab=doc#Object
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值