理解 Kubernetes 的 API Schema
詞起源于希臘語(yǔ)中的 ??form?
?? 或 ??figure?
??,但具體應(yīng)該如何定義 ??schema?
?? 取決于應(yīng)用環(huán)境的上下文。??schema?
? 有不同的類(lèi)型,其含義與數(shù)據(jù)科學(xué)、教育、營(yíng)銷(xiāo)和 SEO 以及心理學(xué)等領(lǐng)域密切相關(guān)。
在維基百科中將 schema 解釋為,圖式,在心理學(xué)中主要描述一種思維或行為類(lèi)型,用來(lái)組織資訊的類(lèi)別,以及資訊之間的關(guān)系。它也可以被描述為先入為主思想的心理結(jié)構(gòu),表示世界某些觀點(diǎn)的框架,或是用于組織和感知新資訊的系統(tǒng)。
但在計(jì)算機(jī)中的 schema 其實(shí)與這個(gè)解釋很接近了,從很多地方都可以看到 schema 這個(gè)名詞,例如 database,openldap,programing language 等的。這里可以簡(jiǎn)單的把 _schema_ 理解為 元數(shù)據(jù)集合 (metadata component),主要包含元素及屬性的聲明,與其他數(shù)據(jù)結(jié)構(gòu)組成。
數(shù)據(jù)庫(kù)中的 schema
在數(shù)據(jù)庫(kù)中,??schema?
? 就像一個(gè)骨架結(jié)構(gòu),代表整個(gè)數(shù)據(jù)庫(kù)的邏輯視圖。它設(shè)計(jì)了應(yīng)用于特定數(shù)據(jù)庫(kù)中數(shù)據(jù)的所有約束。當(dāng)在數(shù)據(jù)建模時(shí),就會(huì)產(chǎn)生一個(gè) schema。在談到關(guān)系數(shù)據(jù)庫(kù)]和面向?qū)ο髷?shù)據(jù)庫(kù)時(shí)經(jīng)常使用 schema。有時(shí)也指將結(jié)構(gòu)或文本的描述。
數(shù)據(jù)庫(kù)中 schema 描述數(shù)據(jù)的形狀以及它與其他模型、表和庫(kù)之間的關(guān)系。在這種情況下,數(shù)據(jù)庫(kù)條目是 schema 的一個(gè)實(shí)例,包含 schema 中描述的所有屬性。
數(shù)據(jù)庫(kù) schema 通常分為兩類(lèi):定義數(shù)據(jù)文件實(shí)際存儲(chǔ)方式的物理數(shù)據(jù)庫(kù) schema 和邏輯數(shù)據(jù)庫(kù) schema,它描述了應(yīng)用于存儲(chǔ)數(shù)據(jù)的所有邏輯約束,包括完整性、表和視圖。常見(jiàn)包括
- 星型模式(star schema)
- 雪花模式(snowflake schema)
- 事實(shí)星座模型(fact constellation schema 或 galaxy schema)
星型模式是類(lèi)似于一個(gè)簡(jiǎn)單的數(shù)據(jù)倉(cāng)庫(kù)圖,包括一對(duì)多的事實(shí)表和維度表。它使用非規(guī)范化數(shù)據(jù)。
雪花模式是更為復(fù)雜的一種流行的數(shù)據(jù)庫(kù)模式,在該模式下,維度表是規(guī)范化的,可以節(jié)省存儲(chǔ)空間并最大限度地減少數(shù)據(jù)冗余。
事實(shí)星座模式遠(yuǎn)比星型模式和雪花模式復(fù)雜得多。它擁有多個(gè)共享多個(gè)維度表的事實(shí)表。
Kubernetes 中的 schema
通過(guò)上面的闡述,大概上可以明白 schema 究竟是什么東西了,在 Kubernetes 中也有 schema 的概念,通過(guò)對(duì) kubernetes 中資源(GVK)的規(guī)范定義、相互關(guān)系間的映射等,schema 即 k8s 資源對(duì)象元數(shù)據(jù)。
而 kubernetes 中資源對(duì)象即 ??Group?
?? ??Version?
?? ??Kind?
?? 這些被定義在 ??staging/src/k8s.io/api/type.go?
? 中,即平時(shí)所操作的 yaml 文件,例如
apiVersion apps/v1
kind Deployment
metadata
name ngx
namespace default
spec
selector
matchLabels
app ngx
template
metadata
labels
app nginx
spec
containers
name ngx-schema
image nginx
ports
containerPort80
而對(duì)應(yīng)的的即為 ??TypeMeta?
?? 、??ObjectMeta?
?? 和 ??DeploymentSpec?
??,??TypeMeta?
?? 為 ??kind?
?? 與 ??apiserver?
??,??ObjectMeta?
?? 為 ??Name?
?? 、??Namespace?
?? ??CreationTimestamp?
? 等段。
??DeploymentSpec?
? 則對(duì)應(yīng)了 yaml 中的 spec。
而整個(gè) yaml 組成了 一個(gè) k8s 的資源對(duì)象。
type Deployment struct {
metav1.TypeMeta `json:",inline"`
// Standard object metadata.
// +optional
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Specification of the desired behavior of the Deployment.
// +optional
Spec DeploymentSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
// Most recently observed status of the Deployment.
// +optional
Status DeploymentStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}
??register.go?
? 則是將對(duì)應(yīng)的資源類(lèi)型注冊(cè)到 schema 中的類(lèi)
var (
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
// Adds the list of known types to the given scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Deployment{},
&DeploymentList{},
&StatefulSet{},
&StatefulSetList{},
&DaemonSet{},
&DaemonSetList{},
&ReplicaSet{},
&ReplicaSetList{},
&ControllerRevision{},
&ControllerRevisionList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}
而 ??apimachinery?
? 包則是 schema 的實(shí)現(xiàn),通過(guò)看其內(nèi)容可以發(fā)現(xiàn),kubernetes 中 schema 就是 GVK 的屬性約束 與 GVR 之間的映射。
通過(guò)示例了解 schema
例如在 ??apps/v1/deployment?
?? 這個(gè)資源,在代碼中表示 ??k8s.io/api/apps/v1/types.go?
?? ,如果需要對(duì)其資源進(jìn)行擴(kuò)展那么需要怎么做?如,建立一個(gè) ??StateDeplyment?
? 資源
type Deployment struct {
metav1.TypeMeta `json:",inline"`
// Standard object metadata.
// +optional
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
如上述代碼所示,Deployment 中的 ??metav1.TypeMeta?
?? 和 ??metav1.ObjectMeta?
?
那么我們復(fù)制一個(gè) Deployment 為 StateDeployment,注意,因?yàn)?Deployment 的兩個(gè)屬性, ??metav1.TypeMeta?
?? 和 ??metav1.ObjectMeta?
? 分別實(shí)現(xiàn)了不同的方法,如圖所示
所以在實(shí)現(xiàn)方法時(shí),需要實(shí)現(xiàn) ??DeepCopyinfo?
?? , ??DeepCopy?
?? 和繼承接口 ??Object?
?? 的 ??DeepCopyObject?
? 方法
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *StateDeployment) DeepCopyInto(out *StateDeployment) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StateDeployment.
func (in *StateDeployment) DeepCopy() *StateDeployment {
if in == nil {
return nil
}
out := new(StateDeployment)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *StateDeployment) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
那么擴(kuò)展一個(gè)資源的整個(gè)流為:
- 資源類(lèi)型在:?
?k8s.io/api/{Group}/types.go?
? - 資料類(lèi)型的實(shí)現(xiàn)接口?
?k8s.io/apimachinery/pkg/runtime/interfaces.go.Object?
? - 其中是基于?
?Deployment?
?? 的類(lèi)型,??metav1.TypeMeta?
?? 和??metav1.ObjectMeta?
? - ?
?metav1.TypeMeta?
?? 實(shí)現(xiàn)了??GetObjectKind()?
?? ;??metav1.ObjectMeta?
?? 實(shí)現(xiàn)了??DeepCopyinfo=()?
??,??DeepCopy()?
?? ,還需要實(shí)現(xiàn)??DeepCopyObject()?
? - 最后注冊(cè)資源到 schema 中?
?k8s.io/api/apps/v1/register.go?
?