API 类型定义

参考:

深入剖析kubernetes的API对象类型定义

K8s源码分析(2)-Resource Meta

在kubernetes里提供了非常多的API对象,它们被定义在k8s.io/api这个仓库中,这也是本章节命名为api的原因。Pod应该是最为基础的对象之一,在初学kubernetes时我相信大部分同学都写过类似下面的代码:

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
  labels:
    app: myapp
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo Hello Kubernetes! && sleep 3600']

通过命令kubectl create -f xxx.yaml在kubernetes中创建了一个名字为myapp-pod的Pod对象(此处忽略namespace)。

用编程的角度分析上面的流程:在kubernetes中需要有一个Pod的类型,每次执行kubectl create -f xxx.yaml创建Pod对象的时候需要实例化Pod,并把xxx.yaml中的参数赋值到Pod对象中。

现在就来看看kubernetes中Pod类型是如何定义的:

// 代码源自k8s.io/api/core/v1/types.go
// kubernetes的API对象是单独的git仓库(https://github.com/kubernetes/api.git),可见API对象
// 在kubernetes项目中的重要程度。
type Pod struct {
    // metav1是"k8s.io/apimachinery/pkg/apis/meta/v1"的重命名。额...,apimachinery又是
    // 什么鬼?apis包又是干啥的?起初笔者被这些名字搞得云里雾里,但所有的这些迷雾都会在本文揭开,此处
    // 读者只需要知道这个是类型的meta。那什么又是类型的meta呢?以普通类型int32为例,类型名称
    // “int32”、类型占用内存空间4字节就是类型的meta,简单的说就是类型属性的描述。而kubernetes的
    // API对象的类型meta是如何定义的,后面会有单独章节详细说明。
    metav1.TypeMeta `json:",inline"`
    // 同样是metav1包,这回是对象的meta。同样以int32为例,对象的地址就属于对象meta。在kubernetes
    // 中,API对象都有自己的属性,并且他们都有相同的属性,例如名字、命名空间、标签等等。kuberentes把
    // 这些公共的属性提取出来就是metav1.ObjectMeta,成为了API对象类型的父类。
    metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
    // 从名字上看还是比较好理解的,就是Pod规格,最为代表性的就是CPU、内存的资源使用。它和xxx.yaml中
    // spec是关联的。PodSpec不作为本文的说明重点,所以不再详细解释。
    Spec PodSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
    // Pod的状态,比如是运行还是挂起、Pod的IP、启动时间等等。
    Status PodStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}

kubernetes全部API对象的基类

  • 类型的meta:就是类型的属性描述(占用实际的物理空间多少等信息)
  • 如类型名称为:“int32”、类型占用内存空间4字节就是类型的meta
  • 因此 metav1.TypeMeta 就是kubernetes 的 API 对象的类型的类型meta
  • metav1是"k8s.io/apimachinery/pkg/apis/meta/v1"的重命名
  • 个人理解:以 pod 为例, metav1.TypeMeta 表示创建一个 pod 所需的物理空间大小
  • 可能有人会困惑此部分大小怎么确定?—— 编译器负责处理
  • 对象的meta:公共属性的集合,用于记录实际这些属性分配的地址,以int32为例,对象的地址就属于对象meta
  • 可以这么理解,类型meta是虚拟概念(表达我需要多少空间),对象meta是实际概念(表达我被分配到哪了)
  • API对象都有自己的属性,并且他们都有相同的属性,例如名字、命名空间、标签等等。kuberentes把这些公共的属性提取出来就是metav1.ObjectMeta,成为了API对象类型的父类
  • 个人理解:对象的meta 是一个公共属性集合(比如 label,name,namespace,annotation 等),是要保证所有 API 对象都可以使用,用于记录这些公共属性的具体地址信息
  • 在kubernetes中
  • 每个API对象都需要metav1.TypeMeta字段用于描述自己是什么类型,这样才能构造相应类型的对象
  • 所以相同类型的所有对象的metav1.TypeMeta字段都是相同的
  • 个人理解:创建一个 Pod 分配的空间大小是固定的,也就是都需要 metav1.TypeMeta 来描述该大小
  • 但是metav1.ObjectMeta则不同,它是定义对象的公共属性,即所有对象都应该具备的属性
  • 这部分就是和对象本身相关,和类型无关,所以相同类型的所有对象的metav1.ObjectMeta可能是不同
  • 个人理解:比如创建多个 pod ,可能有的需要 InitContianer 部分,有的不需要(所以此部分不需要用到所有metav1.ObjectMeta 的属性),就是 metav1.ObjectMeta 定义的 公有属性 不是必须全部使用

istio用的k8s版本 k8s的apiversion_docker

自定义部分(独特性)

  • 若编写 CRD ,需要自己定义下面两部分
  • Spec 设置此 API 对象需要的属性,用于定义目标状态
  • 也就是私有属性
  • 私有属性,也是API对象之间的区别所在(例如Pod和Deployment虽然都继承了两个父类,但是他们二者的区别就是通过Spec实现的。就像是同一对父母的两个孩子,有像的地方,更多的还是不像的地方让他们成为了两个独立的个体,这就是继承的魅力所在)
  • Status 设置运行中需要监控的 API 对象的属性,用于获取当前状态
  • 用于描述每个对象的状态的,这和每个对象的类型紧密相关的

对象列表类型 List

// 代码源自k8s.io/api/core/v1/types.go
type PodList struct {
    // PodList同样需要继承metav1.TypeMeta,毕竟对象列表也好、单体对象也好都需要类型属性。
    // PodList比[]Pod类型在yaml或者json表达上多了类型描述,当需要根据yaml构建对象列表的时候,
    // 就可以根据类型描述反序列成为PodList。而[]Pod则不可以,他必须确保yaml就是[]Pod序列化的
    // 结果,否则就会报错。这就无法实现一个通用的对象序列化/反序列化。
    metav1.TypeMeta `json:",inline"`
    // 与Pod不同,PodList继承了metav1.ListMeta,metav1.ListMeta是所有对象类表类型的父类,
    // 他定义了所有列表类型公共属性。
    metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
    // Items就是PodList定义的本质了,其实就是Pod的slice。说白了PodList就是[]Pod基础上加了一些
    // 跟类型和类表相关的信息,这些信息的作用会在后面的章节做详细解释。
    Items []Pod `json:"items" protobuf:"bytes,2,rep,name=items"`
}
  • 可能有些读者会问为什么不用对象的slice,例如[]Pod
  • 因为利用 yaml 创建多个 Pod 时,由于 PodList 具有类型描述metav1.TypeMeta,就告诉了处理器,我是这种类型,该怎么处理,所以很方便做对象序列化/反序列化,提交请求
  • 而采用 []Pod 形式,利用 yaml 创建多个 Pod 时,提交的请求 apiserver 不理解是什么类型,所以必须将 yaml 写为 []Pod序列化后的结果,apiserver 处理器才有可能理解,这增加了书写 yaml 的复杂度
  • metav1.ListMeta 是所有对象类表类型的父类,定义了所有列表类型公共属性
  • Items就是PodList定义的本质了,其实就是Pod的slice
  • 说白了PodList就是[]Pod基础上加了一些跟类型和列表相关的信息
  • 简单理解为:
  • 我突然给你一堆东西 []Pod,我说起来费劲,你解释也费劲,因此我就再封装一起,把这些叫做 PodList,你听着简短多了
  • 也就是我说我带来 苹果、橘子、梨、香蕉等等,太费劲,改为——我带来了一个果篮

小结

前面已经解释了Pod的定义,PodList就不多解释了。此处做一个小结:

  1. metav1.TypeMeta和metav1.ObjectMeta是所有API单体对象的父类;
  2. metav1.TypeMeta和metav1.ListMeta是所有API列表对象的父类;
  3. metav1.TypeMeta才是所有API对象的父类,这也很好理解,毕竟所有的对象都要说明自己是什么类型;