欢迎访问我的GitHub
关于《Kubernetes对象深入学习》系列
- 在client-go的学习和使用过程中,不可避免涉及到对象相关的代码,经常面临一个尴尬的现象:平时代码能读懂七七八八,一旦写的时候就感觉无从下手,甚至抄都不知道去哪抄,例如:拿到一个runtime.Object类型的接口该如何处理,它的具体实现可能有哪些?如何取得它的name、label、annonation等信息?
- 为了解决这些问题,必须对kubernetes的对象及其相关的代码有足够了解,然而面对大量代码和知识点,如何将其梳理清晰,合理拆分为多个重点,进行系统的学习,这就是《Kubernetes对象深入学习》系列的主要任务
- 写这个系列的过程,也是欣宸自己的学习过程,整个系列会包含丰富的图示、表格、实战等元素加入,这些都是欣宸原创的特色,总之就是手段齐出,尽可能将知识点清晰立体的传达给您
本篇概览
- 本文是《Kubernetes对象深入学习》系列的开篇,咱们先从整体上说清楚这个系列讲的是哪些内容,涉及哪些知识点,还要理清它们之间的关系,后续的文章会聚焦这些知识点深入学习,如此一来,从入门到精通也不是没有可能[dog]
- 接下来会从对象定义开始,再展开与之相关的接口和实现类进行分析,最后结合实际的kubernetes资源来分析,这样就完成了对kubernetes对象的初步了解
核心知识点
- 为了便于理解,这里将核心知识浓缩为几下几点
- 与对象有关的大部分源码在k8s.io/apimachinery这个module中
- 对象的根源是runtime.Object,官方描述如下
- 这里将对象相关的知识按照不同侧重点梳理出三条线,以便咱们逐个击破,避免那种面对大量知识点无从下手的困境,具体的三条线如下图所示,分别是:对象类型、属性、列表属性,每个知识点都有明确的接口和实现
-
从上图可见,runtime.Object是个接口,其真实的实现可能是单个对象,也可能是列表对象,但无论是哪种都实现了类型接口schema.ObjectKind,然后就是它们各自的特有接口:单个对象有metav1.Object,列表对象有metav1.Listinterface
-
注意:上图是学习路线,不是UML!
关于metav1
- 在kubernetes源码中,metav1是k8s.io/apimachinery/pkg/apis/meta/v1这个package的别名,如下所示,因此文中都用metav1来表示完整的包
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
源码位置
- 为了便于翻阅源码,这里用列表将其整理好以便随时用到(可以看出内容确实不少,这些kubernetes的基础知识,是不推荐速成的,还是认真深入学习逐个掌握吧)
- 有了上面的表格,那么多interface和struct终于不显得混乱了,再捋一捋会更清晰:
- 除了类型接口比较特殊,属于schema包,其余所有接口和实现类都在metav1包中
- 实现类的名字都是xxxMeta
runtime.Object和metav1.TypeMeta的关系(非常重要!)
- runtime.Object和metav1.TypeMeta的关系需要尽早理清楚,后面的学习会顺利很多
- 先看runtime.Object的源码,如下所示,非常简单的接口,只定义了两个方法
type Object interface {
GetObjectKind() schema.ObjectKind
DeepCopyObject() Object
}
- 再看metav1.TypeMeta的方法
func (obj *TypeMeta) GetObjectKind() schema.ObjectKind { return obj }
-
也就是说metav1.TypeMeta实现了runtime.Object的GetObjectKind方法,至于另一个方法DeepCopyObject,咱们来看看Pod的源码就一目了然了
-
关于上图黄色箭头1指向的deepcopy-gen,涉及到代码生成工具,此工具在编译时会把代码生成在kubernetes源码目录中,再用于编译,举个例子,pod有关的生成代码如下
-
通过上面对Pod代码的分析,得到这么一个规律:如果一个数据结构内嵌了TypeMeta,并且用deepcopy-gen工具生成DeepCopyObject方法,那么这个数据结构就是runtime.Object接口的实现类(非常重要!)
-
按照这个规则去找一个列表对象看看,就选PodList吧,这是kubernetes用来表达Pod对象列表的数据结构,如下图所示,和Pod一样的套路
-
现在对最基础的runtime.Ojbect算是有了一定的了解,接下来分别观察单个对象和列表对象,即要看它们和通用接口TypeMeta的关系,也要看它们各自特有的接口:ObjectMeta和ListMeta
单个对象实现的接口:TypeMeta和ObjectMeta
- 虽然用表格和关系图做了梳理,但还是有些抽象,所以这里来举个具体的例子,把前面那些对象、接口、实现的关系做个说明
- 在kubernetes开发中,pod应该是最常见的对象了,它的数据结构源码在kubernetes仓库中的apis/core/types.go文件
// 1. 代码生成器来生成runtime.Object接口的实现
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Pod is a collection of containers, used as either input (create, update) or as output (list, get).
type Pod struct {
// 2. 这样就实现了schema.ObjectKind接口
metav1.TypeMeta
// 3. 这样就实现了metav1.Object接口
// +optional
metav1.ObjectMeta
// Spec defines the behavior of a pod.
// +optional
Spec PodSpec
// Status represents the current information about a pod. This data may not be up
// to date.
// +optional
Status PodStatus
}
- 从上述代码可见,Pod数据结构嵌入了metav1.TypeMeta、metav1.ObjectMeta,这就实现了schema.ObjectKind和metav1.Object接口
- 如果上面对Pod源码的分析还不够具体,您依然对TypeMeta和ObjectMeta没有形象具体的认识,那就再找个更具体例子吧
- 在kubernetes环境执行kubectl get pod kube-apiserver-hedy -n kube-system -o yaml,作用是以yaml格式的名义查看api-server的pod详情,内容如下图所示,属于TypeMeta和ObjectMeta部分的内容用黄色箭头标识出来了
- 现在您应该对metav1.TypeMeta、metav1.ObjectMeta有了大致认识,也发现了一个问题:不是分了三条学习线路吗?还有个metav1.ListInterface呢?
列表对象实现的接口:TypeMeta和ListMeta
- 为了说清楚metav1.ListInterface,还是以Pod为例吧,它有自己专属的列表对象PodList,源码如下
type PodList struct {
metav1.TypeMeta
// +optional
metav1.ListMeta
Items []Pod
}
- 也就是说,kubernetes在表达Pod列表的时候,并不是简单的使用Pod切片,而是使用了PodList对象,列表的真实数据存储在Items字段中
- PodList内嵌了metav1.TypeMeta,这和Pod是一致的,因此这里得出一个重要结论:PodList也是runtime.Object接口的的具体实现,这很重要!
- 请务必注意:当一段代码中出现runtime.Object时,它的真实对象可能是一个资源实例,例如Pod,也可能是个列表对象,例如PodList
- 还剩一个问题:PodList和ListInterface有啥关系呢?很简答:PodList内嵌了metav1.ListMeta,metav1.ListMeta又是ListInterface的实现类,因此PodList也是ListInterface的实现类
- 至此,本篇算是完成了,咱们算是对kubernetes的对象和相关接口有了基本的了解,至少它们关系已经理清楚,读kubernetes源码的时候可以对的上号了,接下来的内容就会聚焦到每个知识点的深度上,再配上丰富的编码实战,咱们有信心学好kubernetes知识