写点什么

client-go 实战之四:dynamicClient

  • 2022 年 4 月 15 日
  • 本文字数:2780 字

    阅读完需:约 9 分钟

  • 您可能会好奇上述 FromUnstructured 方法究竟是如何实现转换的,咱们去看下此方法的内部实现,如下图所示,其实也没啥悬念了,通过反射可以得到 podList 的字段信息:



  • 至此,Unstructured 的分析就结束了吗?没有,强烈推荐您进入上图红框 2 中的 fromUnstructured 方法去看细节,这里面是非常精彩的,以 podList 为例,这是个数据结构,而 fromUnstructured 只处理原始类型,对于数据结构会调用 structFromUnstructured 方法处理,在 structFromUnstructured 方法中


处理数据结构的每个字段,又会调用 fromUnstructured,这是相互迭代的过程,最终,不论 podList 中有多少数据结构的嵌套都会被处理掉,篇幅所限就不展开相信分析了,下图是一部分关键代码:



  • 小结:Unstructured 转为资源对象的套路并不神秘,无非是用反射取得资源对象的字段类型,然后按照字段名去 Unstructured 的 map 中取得原始数据,再用反射设置到资源对象的字段中即可;

  • 做完了准备工作,接下来该回到本篇文章的主题了:dynamicClient 客户端

[](()关于 dynamicClient

  • deployment、pod 这些资源,其数据结构是明确的固定的,可以精确对应到 Clientset 中的数据结构和方法,但是对于 CRD(用户自定义资源),Clientset 客户端就无能为力了,此时需要有一种数据结构来承载资源对象的数据,也要有对应的方法来处理这些数据;

  • 此刻,前面提到的 Unstructured 可以登场了,没错,把 Clientset 不支持的资源对象交给 Unstructured 来承载,接下来看看 dynamicClient 和 Unstructured 的关系:

  • 先看数据结构定义,和 clientset 没啥区别,只有个 restClient 字段:


type dynamicClient struct {


client *rest.RESTClient


}


  • 这个数据结构只有一个关联方法 Resource,入参为 GVR,返回的是另一个数据结构 dynamicResourceClient:


func (c *dynamicClient) Resource(resource schema.GroupVersionResource) NamespaceableResourceInterface {


return &dynamicResourceClient{client: c, resource: resource}


}


  • 通过上述代码可知,dynamicClient 的关键是数据结构 dynamicResourceClient 及其关联方法,来看看这个 dynamicResourceClient,如下图,果然,dynamicClient 所有和资源相关的操作都是 dynamicResourceClient 在做(代理模式?),选了 create 方法细看,序列化和反序列化都交给 unstructured 的 UnstructuredJSONScheme,与 kubernetes 的交互交给 Restclient:



  • 小结:


  1. 与 Clientset 不同,dynamicClient 为各种类型的资源都提供统一的操作 API,资源需要包装为 Unstructured 数据结构;

  2. 内部使用了 Restclient 与 kubernetes 交互;


  • 对 dynamicClient 的介绍分析就这些吧,可以开始实战了;

[](()需求确认

  • 本次编码实战的需求很简单:查询指定 namespace 下的所有 pod,然后在控制台打印出来,要求用 dynamicClient 实现;

  • 您可能会问:pod 是 kubernetes 的内置资源,更适合 Clientset 来操作,而 dynamicClient 更适合处理 CRD 不是么?—您说得没错,这里用 pod 是因为折腾 CRD 太麻烦了,定义好了还要在 kubernetes 上发布,于是干脆用 pod 来代替 CRD,反正 dynamicClient 都能处理,咱们通过实战掌握 dynamicClient 的用法就行了,以后遇到各种资源都能处理之;

[](()源码下载

  • 本篇实战中的源码可在 GitHub 下载到,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):


| 名称 | 链接 | 备注 |


| :-- | :-- | :-- |


| 项目主页 | https://github.com/zq2599/blog_demos | 该项目在 GitHub 上的主页 |


| git 仓库地址(https) | https://github.com/zq2599/blog_demos.git | 该项目源码的仓库地址,https 协议 |


| git 仓库地址(ssh) | git@github.com:zq2599/blog_demos.git | 该项目源码的仓库地址,ssh 协议 |


  • 这个 git 项目中有多个文件夹,client-go 相关的应用在 client-go-tutorials 文件夹下,如下图红框所示:


![在这里插入图片描述](https://img-blog.csdnimg.cn/20210210175040851.png?x-oss-process=image/waterma 《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》开源 rk,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2JvbGluZ19jYXZhbHJ5,size_16,color_FFFFFF,t_70)


  • client-go-tutorials 文件夹下有多个子文件夹,本篇对应的源码在 dynamicclientdemo 目录下,如下图红框所示:


[](()编码

  • 新建文件夹 dynamicclientdemo,在里面执行以下命令,新建 module:


go mod init dynamicclientdemo


  • 添加 k8s.io/api 和 k8s.io/client-go 这两个依赖,注意版本要匹配 kubernetes 环境:


go get k8s.io/api@v0.20.0


go get k8s.io/client-go@v0.20.0


  • 新建 main.go,内容如下,稍后会说一下要注意的重点:


package main


import (


"context"


"flag"


"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"


"k8s.io/client-go/util/homedir"


"path/filepath"


)


func main() {


var kubeconfig *string


// home 是家目录,如果能取得家目录的值,就可以用来做默认值


if home:=homedir.Ho Java 开源项目【ali1024.coding.net/public/P7/Java/git】 meDir(); home != "" {


// 如果输入了 kubeconfig 参数,该参数的值就是 kubeconfig 文件的绝对路径,


// 如果没有输入 kubeconfig 参数,就用默认路径~/.kube/config


kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")


} else {


// 如果取不到当前用户的家目录,就没办法设置 kubeconfig 的默认目录了,只能从入参中取


kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")


}


flag.Parse()


// 从本机加载 kubeconfig 配置文件,因此第一个参数为空字符串


config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)


// kubeconfig 加载失败就直接退出了


if err != nil {


panic(err.Error())


}


dynamicClient, err := dynamic.NewForConfig(config)


if err != nil {


panic(err.Error())


}


// dynamicClient 的唯一关联方法所需的入参


gvr := schema.GroupVersionResource{Version: "v1", Resource: "pods"}


// 使用 dynamicClient 的查询列表方法,查询指定 namespace 下的所有 pod,


// 注意此方法返回的数据结构类型是 UnstructuredList


unstructObj, err := dynamicClient.


Resource(gvr).


Namespace("kube-system").


List(context.TODO(), metav1.ListOptions{Limit: 100})


if err != nil {


panic(err.Error())


}


// 实例化一个 PodList 数据结构,用于接收从 unstructObj 转换后的结果

最后

总而言之,面试官问来问去,问的那些 Redis 知识点也就这么多吧,复习的不够到位,知识点掌握不够熟练,所以面试才会卡壳。将这些 Redis 面试知识解析以及我整理的一些学习笔记分享出来给大家参考学习


还有更多学习笔记面试资料也分享如下:



用户头像

还未添加个人签名 2022.04.13 加入

还未添加个人简介

评论

发布
暂无评论
client-go实战之四:dynamicClient_Java_爱好编程进阶_InfoQ写作平台