Análisis en profundidad de la definición del tipo de objeto API de kubernetes

Tabla de contenido

 

1. Antecedentes

2. Análisis

2.1api

2.2metav1

2.2.1MetaType

2.2.3ListMeta

2.3tiempo de ejecución

2.3.1 horario

2.3.2 Objeto

3. Resumen


1. Antecedentes

Cuando estaba aprendiendo kuberentes, el autor, como productor de código, tenía mucha curiosidad sobre su implementación de código. Entonces comencé a clonar el código. Primero que nada, estaba confundido por el almacén de código de kuberentes. El proyecto kuberentes tiene muchos almacenes, incluidos kubernetes, client-go, api, apimachinery ..., ¿por dónde empezar? Simplemente comience con la definición del objeto API de kubernetes. El almacén relacionado con api tiene dos api y una apimachinery. Al mismo tiempo, hay dos paquetes de api y apis en el almacén de apimachinery. Parece que todos tienen types.go y meta.go., Interface.go. En este momento, el estado de ánimo del autor es realmente indescriptible, pero la curiosidad me impulsa a entender el principio, por eso tengo este artículo con un resumen similar. Espero que este artículo pueda ayudar a los lectores a obtener una comprensión preliminar del código de Kubernetes y convertirse en un artículo introductorio más básico.

2. Análisis

En el pasado, según la impresión del autor, las API eran todo tipo de interfaces, y la más típica era la API del sistema operativo. Cuando se trata de API, el valor predeterminado son las definiciones de funciones. Hasta que las API REST se vuelvan populares, las API ya no son funciones en forma, pero los principios son los mismos, excepto que el lado del servidor de la interfaz ha cambiado de local a remoto. De hecho, el autor siempre ha ignorado otro punto importante de la API, es decir, el tipo de interfaz, es decir, el tipo de parámetro de la función de interfaz, que también forma parte de la API. El autor cree que la API del sistema operativo enfatiza los métodos y la mayoría de los tipos de parámetros están diseñados para el método, mientras que la API Rest enfatiza los recursos, y solo hay unos pocos métodos. Al comprender la API Rest de un sistema, primero debemos observar qué recursos están disponibles, cómo se definen estos recursos, qué operaciones son compatibles, etc.

Lo que kubernetes proporciona externamente es la API Rest, pero el proyecto client-go empaqueta esta parte en un formato similar al SDK. Y apisever proporciona varias operaciones basadas en objetos API. El objetivo de este artículo es explorar cómo se definen e implementan los objetos API en kubernetes.

2.1api

Hay muchos objetos API proporcionados en kubernetes, que se definen en el repositorio k8s.io/api, por lo que este capítulo se llama api. Pod debería ser uno de los objetos más básicos. Cuando comencé a aprender kubernetes, creo que la mayoría de los estudiantes han escrito un código similar al siguiente:

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']

Un objeto Pod llamado myapp-pod se crea en kubernetes mediante el comando kubectl create -f xxx.yaml (aquí se ignora el espacio de nombres).

Analiza el proceso anterior desde una perspectiva de programación: debe haber un tipo de Pod en kubernetes. Cada vez que ejecutas kubectl create -f xxx.yaml para crear un objeto Pod, necesitas crear una instancia del Pod y asignar los parámetros en xxx.yaml al objeto Pod.

Ahora echemos un vistazo a cómo se define el tipo de pod en kubernetes:

// 代码源自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"`
}

De la definición de Pod, hereda dos tipos, metav1.TypeMeta y metav1.ObjectMeta, y define dos variables miembro, Spec y Status. De hecho, la mayoría de los tipos de objetos API de kubernetes son de esta estructura, todos heredan metav1.TypeMeta y metav1.ObjectMeta, el primero se usa para definir los atributos del tipo, el segundo se usa para definir los atributos públicos del object; Spec se usa para definir el tipo de objeto API Las propiedades privadas de los objetos API también son la diferencia entre los objetos API (por ejemplo, aunque Pod y Deployment heredan dos clases principales, la diferencia entre ellas se logra a través de Spec. Es como dos hijos del mismo padre, hay lugares similares, lugares más o menos similares los hacen dos individuos independientes, este es el encanto de la herencia); el estado se usa para describir el estado de cada objeto, este y el tipo de cada objeto de cerca relacionada. Los lectores cuidadosos pueden encontrar fácilmente que metav1.TypeMeta y metav1.ObjectMeta corresponden a los campos kind, apiVersion y metadata en xxx.yaml, y Spec corresponde al campo spec en xxx.yaml. Esto se puede confirmar en el comentario de código `json: ...`, y aquí se puede sacar otra conclusión, es decir, xxx.yaml es la serialización del tipo de Pod yaml. Por lo tanto, kubectl create -f xxx.yaml es equivalente a new (Pod).

Aquí quiero decir algunas palabras sobre metav1.TypeMeta y metav1.ObjectMeta. Pueden considerarse como las clases base de todos los objetos API en kubernetes, similar a la clase Object en java. Debido a que el lenguaje tiene un compilador, cosas como metav1.TypeMeta están bloqueadas de la compilación, por lo que todas las clases que ven los desarrolladores heredan de Object. Pero en kubernetes, cada objeto API necesita el campo metav1.TypeMeta para describir de qué tipo es, de modo que se pueda construir el tipo de objeto correspondiente, por lo que el campo metav1.TypeMeta de todos los objetos del mismo tipo es el mismo. Pero metav1.ObjectMeta es diferente, es una propiedad pública que define un objeto, es decir, una propiedad que deben tener todos los objetos. Esta parte está relacionada con el objeto en sí y no tiene nada que ver con el tipo, por lo que metav1.ObjectMeta de todos los objetos del mismo tipo puede ser diferente.

Además del objeto único en el objeto API de kubernetes, también hay un tipo de lista de objetos, que se usa para describir un grupo de objetos, que es equivalente a slice en golang. El escenario de aplicación típico de la lista de objetos es la enumeración, y la lista de objetos puede expresar un grupo de objetos. Algunos lectores pueden preguntar por qué no usas segmentos de objetos, como [] Pod. Con la explicación del autor de la lista de objetos, los lectores entenderán. Aquí tomamos PodList como un ejemplo para el análisis:

// 代码源自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"`
}

La definición de Pod se ha explicado antes, pero PodList no explicará mucho. He aquí un resumen:

  1. metav1.TypeMeta y metav1.ObjectMeta son las clases principales de todos los objetos monómeros API;
  2. metav1.TypeMeta y metav1.ListMeta son las clases principales de todos los objetos de lista de API;
  3. metav1.TypeMeta es la clase principal de todos los objetos API. Esto también es fácil de entender. Después de todo, todos los objetos deben explicar de qué tipo son;

2.2metav1

metav1 es la abreviatura de k8s.io/apimachinery/pkg/apis/meta/v1, y se denominará metav1 a continuación.

2.2.1MetaType

Como clase principal de todos los objetos de la API, es hora de revelar sus verdaderos colores:

// 代码源自:k8s.io/apimachinery/pkg/apis/meta/v1/types.go
// 同样来自apimachinery仓库,ObjectMeta是xxx.yaml中metadata字段,平时我们填写的metadata
// 一般只有name、label,其实ObjectMeta字段还是有很多内容了,让笔者逐一介绍一下。
type ObjectMeta struct {
    // 对象的名字应该不用介绍了。
    Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"`
    // 如果Name为空,系统这为该对象生成一个唯一的名字。
    GenerateName string `json:"generateName,omitempty" protobuf:"bytes,2,opt,name=generateName"`
    // 命名空间,在平时学习、调试的时候很少用,但是在发布的时候会经常用。
    Namespace string `json:"namespace,omitempty" protobuf:"bytes,3,opt,name=namespace"`
    // 对象的URL,由系统生成。
    SelfLink string `json:"selfLink,omitempty" protobuf:"bytes,4,opt,name=selfLink"`
    // 对象的唯一ID,由系统生成。
    UID types.UID `json:"uid,omitempty" protobuf:"bytes,5,opt,name=uid,casttype=k8s.io/kubernetes/pkg/types.UID"`
    // 资源版本,这是一个非常有意思且变量,版本可以理解为对象在时间轴上的一个时间节点,代表着对象最后
    // 一次更新的时刻。如果说Name是在Namespace空间下唯一,那么ResourceVersion则是同名、同类型
    // 对象时间下唯一。因为同名对象在不同时间可能会更新、删除再添加,在比较两个对象谁比较新的情况
    // 非常有用,比如Watch。
    ResourceVersion string `json:"resourceVersion,omitempty" protobuf:"bytes,6,opt,name=resourceVersion"`
    // 笔者很少关注这个值,所以也不太了解是干什么的,读者感兴趣可以自己了解一下。
    Generation int64 `json:"generation,omitempty" protobuf:"varint,7,opt,name=generation"`
    // 对象创建时间,由系统生成。
    CreationTimestamp Time `json:"creationTimestamp,omitempty" protobuf:"bytes,8,opt,name=creationTimestamp"`
    // 对象删除时间,指针类型说明是可选的,当指针不为空的时候说明对象被删除了,也是由系统生成
    DeletionTimestamp *Time `json:"deletionTimestamp,omitempty" protobuf:"bytes,9,opt,name=deletionTimestamp"`
    // 对象被删除前允许优雅结束的时间,单位为秒。
    DeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty" protobuf:"varint,10,opt,name=deletionGracePeriodSeconds"`
    // 对象标签,这个是我们经常用的,不用多解释了
    Labels map[string]string `json:"labels,omitempty" protobuf:"bytes,11,rep,name=labels"`
    // 批注,这个和标签很像,但是用法不同,比如可以用来做配置。
    Annotations map[string]string `json:"annotations,omitempty" protobuf:"bytes,12,rep,name=annotations"`
    // 该对象依赖的对象类表,如果这些依赖对象全部被删除了,那么该对象也会被回收。如果该对象对象被
    // 某一controller管理,那么类表中有一条就是指向这个controller的。例如Deployment对象的
    // OwnerReferences有一条就是指向DeploymentController的。
    OwnerReferences []OwnerReference `json:"ownerReferences,omitempty" patchStrategy:"merge" patchMergeKey:"uid" protobuf:"bytes,13,rep,name=ownerReferences"`
    // 下面这几个变量笔者没有了解过,等笔者知道了再来更新文章吧。
    Finalizers []string `json:"finalizers,omitempty" patchStrategy:"merge" protobuf:"bytes,14,rep,name=finalizers"`
    ClusterName string `json:"clusterName,omitempty" protobuf:"bytes,15,opt,name=clusterName"`
    ManagedFields []ManagedFieldsEntry `json:"managedFields,omitempty" protobuf:"bytes,17,rep,name=managedFields"`
}

// 代码源自k8s.io/apimachinery/pkg/apis/meta/v1/meta.go,GetObjectMeta是MetaAccessor
// 的接口函数,这个函数说明了ObjectMeta实现了MetaAccessor。
func (obj *ObjectMeta) GetObjectMeta() Object { return obj }

// 下面所有的函数是接口Object的ObjectMeta实现,可以看出来基本就是setter/getter方法。纳尼?
// 又一个Object(这个Object是metav1.Object,本章节简写为Object)?Object是API对象公共属性
// (meta信息)的抽象,下面的函数是Object所有函数的实现,因为功能比较简单,笔者就不一一注释了。
func (meta *ObjectMeta) GetNamespace() string                { return meta.Namespace }
func (meta *ObjectMeta) SetNamespace(namespace string)       { meta.Namespace = namespace }
func (meta *ObjectMeta) GetName() string                     { return meta.Name }
func (meta *ObjectMeta) SetName(name string)                 { meta.Name = name }
func (meta *ObjectMeta) GetGenerateName() string             { return meta.GenerateName }
func (meta *ObjectMeta) SetGenerateName(generateName string) { meta.GenerateName = generateName }
func (meta *ObjectMeta) GetUID() types.UID                   { return meta.UID }
func (meta *ObjectMeta) SetUID(uid types.UID)                { meta.UID = uid }
func (meta *ObjectMeta) GetResourceVersion() string          { return meta.ResourceVersion }
func (meta *ObjectMeta) SetResourceVersion(version string)   { meta.ResourceVersion = version }
func (meta *ObjectMeta) GetGeneration() int64                { return meta.Generation }
func (meta *ObjectMeta) SetGeneration(generation int64)      { meta.Generation = generation }
func (meta *ObjectMeta) GetSelfLink() string                 { return meta.SelfLink }
func (meta *ObjectMeta) SetSelfLink(selfLink string)         { meta.SelfLink = selfLink }
func (meta *ObjectMeta) GetCreationTimestamp() Time          { return meta.CreationTimestamp }
func (meta *ObjectMeta) SetCreationTimestamp(creationTimestamp Time) {
    meta.CreationTimestamp = creationTimestamp
}
func (meta *ObjectMeta) GetDeletionTimestamp() *Time { return meta.DeletionTimestamp }
func (meta *ObjectMeta) SetDeletionTimestamp(deletionTimestamp *Time) {
    meta.DeletionTimestamp = deletionTimestamp
}
func (meta *ObjectMeta) GetDeletionGracePeriodSeconds() *int64 { return meta.DeletionGracePeriodSeconds }
func (meta *ObjectMeta) SetDeletionGracePeriodSeconds(deletionGracePeriodSeconds *int64) {
    meta.DeletionGracePeriodSeconds = deletionGracePeriodSeconds
}
func (meta *ObjectMeta) GetLabels() map[string]string                 { return meta.Labels }
func (meta *ObjectMeta) SetLabels(labels map[string]string)           { meta.Labels = labels }
func (meta *ObjectMeta) GetAnnotations() map[string]string            { return meta.Annotations }
func (meta *ObjectMeta) SetAnnotations(annotations map[string]string) { meta.Annotations = annotations }
func (meta *ObjectMeta) GetFinalizers() []string                      { return meta.Finalizers }
func (meta *ObjectMeta) SetFinalizers(finalizers []string)            { meta.Finalizers = finalizers }
func (meta *ObjectMeta) GetOwnerReferences() []OwnerReference         { return meta.OwnerReferences }
func (meta *ObjectMeta) SetOwnerReferences(references []OwnerReference) {
    meta.OwnerReferences = references
}
func (meta *ObjectMeta) GetClusterName() string                 { return meta.ClusterName }
func (meta *ObjectMeta) SetClusterName(clusterName string)      { meta.ClusterName = clusterName }
func (meta *ObjectMeta) GetManagedFields() []ManagedFieldsEntry { return meta.ManagedFields }
func (meta *ObjectMeta) SetManagedFields(managedFields []ManagedFieldsEntry) {
    meta.ManagedFields = managedFields
}

El propósito de cada variable miembro de ObjectMeta no es útil para comprender este artículo. Los lectores solo necesitan saber que estas propiedades son propiedades comunes de todos los objetos API. Por lo tanto, los comentarios del autor sobre cada variable miembro solo permanecen en la definición superficial y no brindan una explicación detallada.

En este punto, puede sacar una conclusión: ObjectMeta implementa las dos interfaces de Object y MetaAccessor, y todos los objetos monolíticos de kubernetes heredan ObjectMeta, luego todos los objetos API implementan Object y MetaAccessor. Hay muchos lugares en kubernetes para acceder a la metainformación de los objetos de la API y no se distingue entre tipos de objetos. Objeto es una buena opción.

2.2.3ListMeta

Similar a la función ObjectMeta, ListMeta define las propiedades comunes de todos los objetos de lista:

// 代码源自:k8s.io/apimachinery/pkg/apis/meta/v1/types.go
type ListMeta struct {
    // 下面这两个变量在ObjectMeta相同,不多解释
    SelfLink string `json:"selfLink,omitempty" protobuf:"bytes,1,opt,name=selfLink"`
    ResourceVersion string `json:"resourceVersion,omitempty" protobuf:"bytes,2,opt,name=resourceVersion"`
    // 在列举对象的时候可能会有非常多的对象,kubernetes支持分页获取,类似于SQL的limit,当对象总量
    // 多于单页的总量的时候,这个变量就会被设置。它用来告知用户需要继续获取,并且它包含了下次获取的
    // 起始位置。
    Continue string `json:"continue,omitempty" protobuf:"bytes,3,opt,name=continue"`
    // 从字面意思也能理解,就是还剩多少个对象,这个和Continue是配合使用的,当Continue被设置了
    // 这个变量就不会为空,用来告诉用户还有多少对象没有获取。
    RemainingItemCount *int64 `json:"remainingItemCount,omitempty" protobuf:"bytes,4,opt,name=remainingItemCount"`
}

// 代码源自k8s.io/apimachinery/pkg/apis/meta/v1/meta.go
// 下面所有的函数是接口ListInterface的ListMeta实现,ListInterface是API对象列表公共属性(meta)
// 的抽象。
func (meta *ListMeta) GetResourceVersion() string        { return meta.ResourceVersion }
func (meta *ListMeta) SetResourceVersion(version string) { meta.ResourceVersion = version }
func (meta *ListMeta) GetSelfLink() string               { return meta.SelfLink }
func (meta *ListMeta) SetSelfLink(selfLink string)       { meta.SelfLink = selfLink }
func (meta *ListMeta) GetContinue() string               { return meta.Continue }
func (meta *ListMeta) SetContinue(c string)              { meta.Continue = c }
func (meta *ListMeta) GetRemainingItemCount() *int64     { return meta.RemainingItemCount }
func (meta *ListMeta) SetRemainingItemCount(c *int64)    { meta.RemainingItemCount = c }

Aquí hay un breve resumen: En el paquete metav1, se abstraen las propiedades públicas (meta) del objeto único de la API y la lista de objetos, que son metav1.Object y metav1.ListInterface respectivamente. Al mismo tiempo, el paquete metav1 implementa estas dos abstracciones. Son metav1.ObjectMeta y metav.listMeta respectivamente. Los tipos de objetos API se pueden abstraer heredando estas clases. ¿Hay un poco de "tipo" y "básico" según lo definido por ¿Qué significa "Instalaciones" de una maquinaria?

2.3tiempo de ejecución

2.3.1 horario

Como se mencionó anteriormente, metav1.TypeMeta implementa schema.ObjectKind (ObjectKind para abreviar en esta sección), y metav1.TypeMeta ha sido muy intuitivo para corresponder a los campos correspondientes de xxx.yaml, entonces, ¿qué hace ObjectKind?

// 代码源自k8s.io/apimachinery/pkg/runtime/schema/interfaces.go
// ObjectKind是接口,两个接口函数是GroupVersionKind类型的setter和getter
type ObjectKind interface {
    SetGroupVersionKind(kind GroupVersionKind)
    GroupVersionKind() GroupVersionKind
}
// GroupVersionKind才是kubernetes的API对象类型真身,他包括Kind、Version和Group。其中Kind和
// Version还比较好理解,Group又是什么?其实Group/Version才是xxx.yaml的apiVersion字段。
// 在kuberentes中API对象是分组的,像Pod、Service、ConfigMap都属于core分组,而core分组的对象
// 无需在apiVersion字段明文写出来,系统会默认将这类的对象归为core分组,正如文章开始那个Pod的例子。
// 详情可以看下面的代码实现。
type GroupVersionKind struct {
    Group   string
    Version string
    Kind    string
}
// 这个函数在metav1.TypeMeta实现GroupVersionKind()接口的时候调用了,该函数调用了ParseGroupVersion
// 实现从apiVersion解析Group和Version。
func FromAPIVersionAndKind(apiVersion, kind string) GroupVersionKind {
    if gv, err := ParseGroupVersion(apiVersion); err == nil {
        return GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind}
    }
    return GroupVersionKind{Kind: kind}
}
// 从apiVersion解析Group和Version。
func ParseGroupVersion(gv string) (GroupVersion, error) {
    // 这种不报错是什么道理?什么情况下会有对象没有Group和Version?
    if (len(gv) == 0) || (gv == "/") {
        return GroupVersion{}, nil
    }
    // 数apiVersion中有几个‘/’
    switch strings.Count(gv, "/") {
    // 没有'/',就像文章开始的Pod的例子,那么Group就是空字符串,系统默认会把空字符串归为core
    case 0:
        return GroupVersion{"", gv}, nil
    // 有一个'/',那么就以'/'分割apiVersion,左边为Group,右边为Version。
    case 1:
        i := strings.Index(gv, "/")
        return GroupVersion{gv[:i], gv[i+1:]}, nil
    // 其他则为格式错误。
    default:
        return GroupVersion{}, fmt.Errorf("unexpected GroupVersion string: %v", gv)
    }
}

Es por eso que la apiVersion de Deployment es apps / v1 o extension / v1beta1. Hasta ahora, se puede resumir de la siguiente manera:

  1. schema.ObjecKind es una abstracción de todos los tipos de objetos de API meta;
  2. metav1.TypeMeta es una implementación de schema.ObjecKind. El tipo de objeto API implementa schema.ObjecKind heredando metav1.TypeMeta;

2.3.2 Objeto

Si schema.ObjecKind es la abstracción de todos los tipos de objetos API, con metav1.Object como abstracción de las propiedades comunes de todos los objetos monómeros API, parece que se ha encontrado la raíz de todos los objetos API. Pero, ¿te sientes raro? Si quieres apuntar a cualquier objeto monómero API a través de un puntero de clase base, schema.ObjecKind y metav1.Object se sienten inapropiados, porque el dominio al que pueden acceder es limitado. Si hay una función que necesita acceder al tipo y las propiedades públicas de cualquier objeto API, entonces se deben pasar dos punteros al mismo objeto (schema.ObjecKind y metav1.Object), lo cual es demasiado inaceptable. ¿Existe un tipo como clase base unificada para objetos de monómero API? Esto es lo que se discutirá en esta sección: runtime.Object (referido como Object en esta sección).

// 代码源自k8s.io/apimachinery/pkg/runtime/interfaces.go
type Object interface {
    // 有了这个函数,就可以访问对象的类型域
    GetObjectKind() schema.ObjectKind
    // deepcopy是golang深度复制对象的方法,至于什么是深度复制本文就不解释了。这是个不错的函数,
    // 可以通过这个接口复制任何API对象而无需类型依赖。
    DeepCopyObject() Object
    // 就这么两个函数了么?那如果需要访问对象的公共属性域怎么办?不应该有一个类似GetObjectMeta()
    // 的接口么?这一点,kubernetes是通过另一个方式实现的,见下面的代码。
}

// 代码源自k8s.io/apimachinery/pkg/api/meta/meta.go,注意是api包,不是apis
// Accessor()函数可以把obj安全的转换为metav1.Object,这样也就避免了每个API对象类型都需要实现
// 类似GetObjectMeta()的接口了。有的读者肯定会问:所有的API对象都继承了metav1.ObjectMeta,
// 这个类型不是实现了GetObjectMeta()么?笔者就要在这里做出说明:笔者提到是类似GetObjectMeta(),
// 如果接口名字是ObjectMeta(),那岂不是继承metav1.ObjectMeta就没用了?一个顶层的类型抽象定义不
// 应该依赖于相对底层类型的实现。
func Accessor(obj interface{}) (metav1.Object, error) {
    // 使用了golang的switch type语法
    switch t := obj.(type) {
    // 因为API对象类型都继承了metav1.ObjectMeta,也就自然实现了metav1.Object。
    case metav1.Object:
        return t, nil
    // 在ObjectMeta章节笔者提到了,metav1.ObjectMeta实现了metav1.ObjectMetaAccessor,
    // 所以API对象也自然实现了metav1.ObjectMetaAccessor。但是API对象会在上一个case就返回
    // 了,这个case是给谁用的呢?笔者也比较疑惑,笔者感觉是那些没有直接继承metav1.ObjectMeta
    // 却实现了metav1.ObjectMetaAccessor的类型,笔者暂时还没找到相关类型定义。
    case metav1.ObjectMetaAccessor:
        if m := t.GetObjectMeta(); m != nil {
            return m, nil
        }
        return nil, errNotObject
    default:
        return nil, errNotObject
    }
}

Espera, ¿por qué no ves que el objeto API implementa runtime.Object.DeepCopyObject ()? Esto se debe a que se debe implementar una copia profunda para tipos de objetos de API específicos y existe una dependencia de tipos, que no se puede implementar como la clase principal de los tipos de objetos de API. Aquí tomamos Pod como ejemplo para ver cómo Pod implementa DeepCopyObject ().

// +genclient
// +genclient:method=GetEphemeralContainers,verb=get,subresource=ephemeralcontainers,result=EphemeralContainers
// +genclient:method=UpdateEphemeralContainers,verb=update,subresource=ephemeralcontainers,input=EphemeralContainers,result=EphemeralContainers
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// 上面+k8s:deepcopy-gen:....就是告诉代码生成工具为下面的类型生成runtime.Object接口的
// DeepCopyObject()函数实现。因为所有的API对象类型都要实现DeepCopyObject()函数,这是一个相当
// 大量的重复工作,所以kubernetes用代码生成工具来实现。至于如何实现的不作为本文讨论重点,只要读者
// 知道deep copy的目的就可以了。
type Pod struct {
    ......
}

3. Resumen

En este punto, el resumen de los capítulos anteriores puede olvidarse, porque esos resúmenes se basan en los conocimientos previos en ese momento y pueden carecer de la consideración general para sacar conclusiones erróneas, por lo que aquí hay un resumen completo, como se muestra en la figura. a continuación. Mostrar:

 

  1. runtime.Object es la clase raíz (interfaz) de todos los objetos monómeros API;
  2. schema.ObjectKind es una abstracción de tipos de objetos API (interfaz);
  3. metav1.Object es una abstracción (interfaz) de las propiedades públicas de los objetos API;
  4. metav1.ListInterface es una abstracción (interfaz) de las propiedades públicas de la lista de objetos API;
  5. metav1.TypeMeta es una implementación de schema.ObjectKind, y el tipo de objeto API lo hereda;
  6. metav1.ObjectMeta es una implementación de metav1.Object, y el tipo de objeto API lo hereda;
  7. metav1.ListMeta es una implementación de metav1.ListInterface, y la lista de objetos API la hereda;

 

Supongo que te gusta

Origin blog.csdn.net/weixin_42663840/article/details/102558455
Recomendado
Clasificación