kubernetesのAPIオブジェクトタイプ定義の詳細な分析

目次

 

1.背景

2.分析

2.1api

2.2metav1

2.2.1MetaType

2.2.3ListMeta

2.3ランタイム

2.3.1スケジュール

2.3.2オブジェクト

3.まとめ


1.背景

私がkuberentesを学んでいたとき、著者はコードファーマーとして、そのコードの実装に非常に興味を持っていました。そこで、コードのgit cloneを開始しました。まず、kuberentesのコードウェアハウスに混乱しました。kuberentesプロジェクトには、kubernetes、client-go、api、apimachineryなどの多くのウェアハウスがあります。どこから始めればよいですか?kubernetesのAPIオブジェクトの定義から始めてください。api関連のウェアハウスには2つのapiとapimachineryがあります。同時に、apimachineryウェアハウスにはapiとapisの2つのパッケージがあります。これらはすべてtypes.goを持っているようです。およびmeta.go。、Interface.go。現時点では、作者の気分は本当に言葉では言い表せませんが、好奇心が私に原理を理解するように促しているので、私は同様の要約でこの記事を持っています。この記事が、読者がkubernetesコードの予備的な理解を深め、より基本的な入門記事になるのに役立つことを願っています。

2.分析

以前、著者の印象では、APIはあらゆる種類のインターフェースであり、最も典型的なものはオペレーティングシステムAPIでした。APIに関しては、デフォルトは関数定義です。RESTAPIが普及するまで、APIは形式の関数ではなくなりますが、インターフェースのサーバー側がローカルからリモートに変更されたことを除いて、原則は同じです。実際、作成者はAPIのもう1つの重要なポイント、つまりインターフェイスタイプ、つまりAPIの一部でもあるインターフェイス関数のパラメータタイプを常に無視してきました。著者は、オペレーティングシステムのAPIがメソッドを強調し、ほとんどのパラメータータイプがメソッド用に設計されているのに対し、REST APIはリソースを強調しており、メソッドはごくわずかであると考えています。システムのRestAPIを理解するときは、最初に、使用可能なリソース、これらのリソースの定義方法、サポートされている操作などを確認する必要があります。

kubernetesが外部で提供するのはRestAPIですが、この部分はclient-goプロジェクトによってSDKと同様の形式にパッケージ化されています。また、apiseverは、APIオブジェクトに基づいてさまざまな操作を提供します。この記事の目的は、APIオブジェクトがkubernetesでどのように定義および実装されるかを調べることです。

2.1api

kubernetesには多くのAPIオブジェクトが用意されており、それらはk8s.io/apiリポジトリで定義されているため、この章の名前はapiです。ポッドは最も基本的なオブジェクトの1つである必要があります。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']

myapp-podという名前のポッドオブジェクトは、コマンドkubectl create -f xxx.yamlを使用してkubernetesに作成されます(名前空間はここでは無視されます)。

プログラミングの観点から上記のプロセスを分析します。kubernetesにポッドタイプが必要です。kubectlcreate-fxxx.yamlを実行してポッドオブジェクトを作成するたびに、ポッドをインスタンス化し、xxx.yamlでパラメーターを割り当てる必要があります。ポッドオブジェクトに。

次に、ポッドタイプが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"`
}

Podの定義から、metav1.TypeMetaとmetav1.ObjectMetaの2つのタイプを継承し、SpecとStatusの2つのメンバー変数を定義します。実際、kubernetes APIオブジェクトのほとんどのタイプはこの構造であり、すべてmetav1.TypeMetaとmetav1.ObjectMetaを継承します。前者はタイプの属性を定義するために使用され、後者はのパブリック属性を定義するために使用されます。オブジェクト; SpecはAPIオブジェクトタイプを定義するために使用されますAPIオブジェクトのプライベートプロパティはAPIオブジェクト間の違いでもあります(たとえば、PodとDeploymentは両方とも2つの親クラスを継承しますが、それらの違いはSpecによって実現されます。同じ親の2人の子供、同じような場所があります、多かれ少なかれ同じような場所はそれらを2つの独立した個人にします、これは継承の魅力です);ステータスは各オブジェクトの状態、これと各オブジェクトのタイプを密接に説明するために使用されます関連。注意深い読者は、metav1.TypeMetaとmetav1.ObjectMetaがxxx.yamlのkind、apiVersion、metadataフィールドに対応し、Specがxxx.yamlのspecフィールドに対応していることを簡単に見つけることができます。これはコードコメント `json:...`で確認でき、ここで別の結論を引き出すことができます。つまり、xxx.yamlはポッドタイプyamlのシリアル化です。したがって、kubectl create -f xxx.yamlはnew(Pod)と同等です。

ここで、metav1.TypeMetaとmetav1.ObjectMetaについて簡単に説明します。これらは、javaのObjectクラスと同様に、kubernetesのすべてのAPIオブジェクトの基本クラスと見なすことができます。言語にはコンパイラがあるため、metav1.TypeMetaなどはコンパイルがブロックされ、開発者が見るすべてのクラスはObjectから継承されます。ただし、kubernetesでは、各APIオブジェクトはそれがどのタイプであるかを記述するmetav1.TypeMetaフィールドを必要とします。これにより、対応するタイプのオブジェクトを構築できるため、同じタイプのすべてのオブジェクトのmetav1.TypeMetaフィールドは同じになります。ただし、me​​tav1.ObjectMetaは異なります。これは、オブジェクトを定義するパブリックプロパティ、つまり、すべてのオブジェクトが持つ必要のあるプロパティです。この部分はオブジェクト自体に関連しており、タイプとは関係がないため、同じタイプのすべてのオブジェクトのmetav1.ObjectMetaが異なる場合があります。

kubernetes APIオブジェクトの単一のオブジェクトに加えて、オブジェクトのグループを記述するために使用されるオブジェクトリストタイプもあります。これは、golangのスライスに相当します。オブジェクトリストの一般的なアプリケーションシナリオは列挙型であり、オブジェクトリストはオブジェクトのグループを表すことができます。一部の読者は、[] Podなどのオブジェクトのスライスを使用しない理由を尋ねる場合があります。オブジェクトリストの作成者の説明により、読者は理解できます。ここでは、分析の例としてPodListを取り上げます。

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

Podの定義は以前に説明されていますが、PodListはあまり説明しません。要約は次のとおりです。

  1. metav1.TypeMetaおよびmetav1.ObjectMetaは、すべてのAPIモノマーオブジェクトの親クラスです。
  2. metav1.TypeMetaおよびmetav1.ListMetaは、すべてのAPIリストオブジェクトの親クラスです。
  3. metav1.TypeMetaは、すべてのAPIオブジェクトの親クラスです。これも理解しやすいです。結局のところ、すべてのオブジェクトは、それらがどのタイプであるかを説明する必要があります。

2.2metav1

metav1はk8s.io/apimachinery/pkg/apis/meta/v1の略語であり、以下ではmetav1と呼びます。

2.2.1MetaType

すべてのAPIオブジェクトの親クラスとして、その真の色を明らかにする時が来ました。

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

ObjectMetaの各メンバー変数の目的は、この記事を理解するのに役立ちません。読者は、これらのプロパティがすべてのAPIオブジェクトに共通のプロパティであることを知っておく必要があります。したがって、各メンバー変数に関する作成者のコメントは、表面の定義にのみ残り、詳細な説明はありませんでした。

この時点で、結論を導き出すことができます。ObjectMetaはObjectとMetaAccessorの2つのインターフェースを実装し、kubernetesのすべてのモノリシックオブジェクトはObjectMetaを継承し、すべてのAPIオブジェクトはObjectとMetaAccessorを実装します。kubernetesには、APIオブジェクトのメタ情報にアクセスし、オブジェクトタイプを区別しない場所がたくさんあります。オブジェクトは良い選択です。

2.2.3ListMeta

ObjectMeta関数と同様に、ListMetaはすべてのリストオブジェクトの共通プロパティを定義します。

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

簡単な要約を次に示します。metav1パッケージでは、API単一オブジェクトのパブリックプロパティ(meta)とオブジェクトリストが抽象化されています。これらはそれぞれmetav1.Objectとmetav1.ListInterfaceです。同時に、metav1パッケージはこれらの2つの抽象化を実装します。それぞれmetav1.ObjectMetaとmetav.listMetaです。APIオブジェクトタイプは、これらのクラスを継承することで抽象化できます。で定義されているように、「type」と「basic」が少しありますか。 apimachinery「施設」とはどういう意味ですか?

2.3ランタイム

2.3.1スケジュール

上記のように、metav1.TypeMetaはschema.ObjectKind(このセクションではObjectKindの略)を実装し、metav1.TypeMetaはxxx.yamlの対応するフィールドに対応するために非常に直感的ですが、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)
    }
}

そのため、デプロイメントのapiVersionはapps / v1またはextension / v1beta1です。これまでのところ、次のように要約できます。

  1. schema.ObjecKindは、すべてのAPIオブジェクトタイプメタを抽象化したものです。
  2. metav1.TypeMetaは、schema.ObjecKindの実装です。APIオブジェクトタイプは、metav1.TypeMetaを継承することによってschema.ObjecKindを実装します。

2.3.2オブジェクト

schema.ObjecKindがすべてのAPIオブジェクトタイプの抽象化であり、metav1.ObjectがすべてのAPIモノマーオブジェクトの共通プロパティの抽象化である場合、すべてのAPIオブジェクトのルートが見つかったようです。しかし、奇妙に感じますか?基本クラスのポインターを介してAPIモノマーオブジェクトをポイントしたい場合、アクセスできるドメインが制限されているため、schema.ObjecKindとmetav1.Objectは不適切だと感じます。APIオブジェクトの型とパブリックプロパティにアクセスする必要がある関数がある場合は、同じオブジェクトへの2つのポインター(schema.ObjecKindとmetav1.Object)を渡す必要がありますが、これは受け入れられません。APIモノマーオブジェクトの統一された基本クラスとしてのタイプはありますか?これは、このセクションで説明する内容です:runtime.Object(このセクションではオブジェクトと呼ばれます)。

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

待って、APIオブジェクトがruntime.Object.DeepCopyObject()を実装しているのを見てみませんか?これは、特定のAPIオブジェクトタイプに対してディープコピーを実装する必要があり、APIオブジェクトタイプの親クラスとして実装できないタイプ依存関係があるためです。ここでは、Podを例として取り上げ、Podが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.まとめ

この時点で、前の章の要約は忘れられる可能性があります。これらの要約は当時の知識の背景に基づいており、誤った結論を出すための全体的な考慮が不足している可能性があるため、図に示すように、ここに包括的な要約があります。下に表示:

 

  1. runtime.Objectは、すべてのAPIモノマーオブジェクトのルートクラス(インターフェイス)です。
  2. schema.ObjectKindは、APIオブジェクトタイプ(インターフェイス)を抽象化したものです。
  3. metav1.Objectは、APIオブジェクトのパブリックプロパティの抽象化(インターフェイス)です。
  4. metav1.ListInterfaceは、APIオブジェクトリストのパブリックプロパティの抽象化(インターフェイス)です。
  5. metav1.TypeMetaはschema.ObjectKindの実装であり、APIオブジェクトタイプはそれを継承します。
  6. metav1.ObjectMetaはmetav1.Objectの実装であり、APIオブジェクトタイプはそれを継承します。
  7. metav1.ListMetaはmetav1.ListInterfaceの実装であり、APIオブジェクトリストはそれを継承します。

 

おすすめ

転載: blog.csdn.net/weixin_42663840/article/details/102558455