云原生学习路线导航页(持续更新中)
- 本文是 Kubernetes operator学习 系列第五篇,主要对 k8s.io/api 和 k8s.io/apimachinery 两个项目 进行学习
- 基于 kubernetes v1.24.0 代码分析
- Kubernetes operator学习系列 快捷链接
- Kubernetes operator(一)client-go篇
- Kubernetes operator(二)CRD篇
- Kubernetes operator(三)code-generator 篇
- Kubernetes operator(四)controller-tools 篇
- Kubernetes operator(五)api 和 apimachinery 篇
k8s.io/api
k8s.io/api
项目,维护着 Kubernetes 所有内建资源 的 struct定义。doc.go、register.go、types.go
。
apps/v1/types.go
为例,查看其内容,发现包含 GroupVersion=apps/v1
下的所有Resource结构定义。
k8s.io/api
这个项目提供的。k8s.io/apimachinery
项目是一个关于Kubernetes API资源的工具集,为 k8s.io/api
项目所有的资源,提供下列能力。
k8s.io/apimachinery
,就可以很方便的操作 kubernetes API。type Pod struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
Spec PodSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
Status PodStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}
apimachinery/pkg/runtime/types.go
type TypeMeta struct {
// +optional
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty" protobuf:"bytes,1,opt,name=apiVersion"`
// +optional
Kind string `json:"kind,omitempty" yaml:"kind,omitempty" protobuf:"bytes,2,opt,name=kind"`
}
apimachinery/pkg/apis/meta/v1/types.go
type ObjectMeta struct {
Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"`
GenerateName string `json:"generateName,omitempty" protobuf:"bytes,2,opt,name=generateName"`
Namespace string `json:"namespace,omitempty" protobuf:"bytes,3,opt,name=namespace"`
SelfLink string `json:"selfLink,omitempty" protobuf:"bytes,4,opt,name=selfLink"`
UID types.UID `json:"uid,omitempty" protobuf:"bytes,5,opt,name=uid,casttype=k8s.io/kubernetes/pkg/types.UID"`
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"`
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"`
ZZZ_DeprecatedClusterName 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/runtime/schema/group_version.go
文件中apps/v1/Deployment
和 apps/v1beta1/Deployment
的相互转换,均是先转成internal的Deployment,再转成 对外的版本internal版本
的资源编写逻辑,就可以处理所有version的资源kubernetes/pkg/apis
中,每个目录都是一个group,每个group都有一个 internal 的 资源 types.go 文件staging/src/k8s.io/api/apps/v1/register.go
文件,package v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name use in this package
const GroupName = "apps"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
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
}
staging/src/k8s.io/apimachinery/pkg/runtime/scheme.go
文件中,有 Scheme 结构type Scheme struct {
// map,记录 gvk-->type。其中type是通过反射的方式记录的
gvkToType map[schema.GroupVersionKind]reflect.Type
// map,记录 type-->gvk
typeToGVK map[reflect.Type][]schema.GroupVersionKind
// map,记录 type-->gvk。像pod这种,只有一个version的,就记录在这里。
unversionedTypes map[reflect.Type]schema.GroupVersionKind
// map,记录 gvk-->type。像pod这种,只有一个version的,就记录在这里。
unversionedKinds map[string]reflect.Type
// Map from version and resource to the corresponding func to convert
// resource field labels in that version to internal version.
fieldLabelConversionFuncs map[schema.GroupVersionKind]FieldLabelConversionFunc
// map,记录默认方法。为某一个具体的type,设置默认值
defaulterFuncs map[reflect.Type]func(interface{})
// 转换器
converter *conversion.Converter
// 记录version的优先级。当没有选择version的时候,优先使用谁
versionPriority map[string][]string
// observedVersions keeps track of the order we've seen versions during type registration
observedVersions []schema.GroupVersion
// schemeName is the name of this scheme. If you don't specify a name, the stack of the NewScheme caller will be used.
// This is useful for error reporting to indicate the origin of the scheme.
schemeName string
}
staging/src/k8s.io/apimachinery/pkg/runtime/scheme.go
文件中还提供了一个方法 NewScheme(),用于初始化一个空的Scheme对象func NewScheme() *Scheme {
s := &Scheme{
gvkToType: map[schema.GroupVersionKind]reflect.Type{},
typeToGVK: map[reflect.Type][]schema.GroupVersionKind{},
unversionedTypes: map[reflect.Type]schema.GroupVersionKind{},
unversionedKinds: map[string]reflect.Type{},
fieldLabelConversionFuncs: map[schema.GroupVersionKind]FieldLabelConversionFunc{},
defaulterFuncs: map[reflect.Type]func(interface{}){},
versionPriority: map[string][]string{},
schemeName: naming.GetNameFromCallsite(internalPackages...),
}
s.converter = conversion.NewConverter(nil)
// Enable couple default conversions by default.
utilruntime.Must(RegisterEmbeddedConversions(s))
utilruntime.Must(RegisterStringConversions(s))
return s
}
staging/src/k8s.io/apimachinery/pkg/runtime/scheme.go
文件还提供了很多方法,用于将GVK注册到Scheme对象中。用的比较多的是AddKnownTypes()方法func (s *Scheme) AddKnownTypes(gv schema.GroupVersion, types ...Object) {
s.addObservedVersion(gv)
for _, obj := range types {
t := reflect.TypeOf(obj)
if t.Kind() != reflect.Ptr {
panic("All types must be pointers to structs.")
}
t = t.Elem()
s.AddKnownTypeWithName(gv.WithKind(t.Name()), obj)
}
}
func (s *Scheme) AddKnownTypes(gv schema.GroupVersion, types ...Object)
staging/src/k8s.io/api/apps/v1/register.go
文件中,使用 AddKnownTypes 方法,将apps/v1下的所有Kind,都注册到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
}
func (s *Scheme) KnownTypes(gv schema.GroupVersion) map[string]reflect.Type
types := Scheme.KnownTypes(schema.GroupVersion{
Group: "apps",
Version: "v1",
})
func (s *Scheme) VersionsForGroupKind(gk schema.GroupKind) []schema.GroupVersion
groupVersions := Scheme.VersionsForGroupKind(
schema.GroupKind{
Group: "apps",
Kind: "Deployment",
})
// 输出
["apps/v1" "apps/v1beta1" "apps/v1beta2"]
func (s *Scheme) ObjectKinds(obj Object) ([]schema.GroupVersionKind, bool, error)
gvks, notVersioned, err := Scheme.ObjectKinds(&appsv1.Deployment{})
// 输出
["apps/v1 Deployment"]
func (s *Scheme) New(kind schema.GroupVersionKind) (Object, error)
deployment, err := Scheme.New(schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
})
func (s *Scheme) AddConversionFunc(a, b interface{}, fn conversion.ConversionFunc) error {
return s.converter.RegisterUntypedConversionFunc(a, b, fn)
}
GET /apis/apps/v1/deployments
type RESTMapping struct {
// Resource is the GroupVersionResource (location) for this endpoint
Resource schema.GroupVersionResource
// GroupVersionKind is the GroupVersionKind (data format) to submit to this endpoint
GroupVersionKind schema.GroupVersionKind
// Scope contains the information needed to deal with REST Resources that are in a resource hierarchy
Scope RESTScope
}
KindFor
和 KindsFor
就是将 GVR 转成 GVK 的方法type RESTMapper interface {
// KindFor takes a partial resource and returns the single match. Returns an error if there are multiple matches
KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error)
// KindsFor takes a partial resource and returns the list of potential kinds in priority order
KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error)
// ResourceFor takes a partial resource and returns the single match. Returns an error if there are multiple matches
ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error)
// ResourcesFor takes a partial resource and returns the list of potential resource in priority order
ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error)
// RESTMapping identifies a preferred resource mapping for the provided group kind.
RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error)
// RESTMappings returns all resource mappings for the provided group kind if no
// version search is provided. Otherwise identifies a preferred resource mapping for
// the provided version(s).
RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error)
ResourceSingularizer(resource string) (singular string, err error)
}
staging/src/k8s.io/apimachinery/pkg/api/meta/restmapper.go
type DefaultRESTMapper struct {
defaultGroupVersions []schema.GroupVersion
resourceToKind map[schema.GroupVersionResource]schema.GroupVersionKind
kindToPluralResource map[schema.GroupVersionKind]schema.GroupVersionResource
kindToScope map[schema.GroupVersionKind]RESTScope
singularToPlural map[schema.GroupVersionResource]schema.GroupVersionResource
pluralToSingular map[schema.GroupVersionResource]schema.GroupVersionResource
}
staging/src/k8s.io/apimachinery/pkg/api/meta/restmapper.go
中还提供了一个 NewDefaultRESTMapper
方法,用于新建一个DefaultRESTMapperstaging/src/k8s.io/apimachinery/pkg/runtime/serializer
包下staging/src/k8s.io/apimachinery/pkg/runtime/interfaces.go
文件中,提供了序列化的通用接口 Serializer
。Serializer接口提供了编解码能力。type Serializer interface {
Encoder
Decoder
}
staging/src/k8s.io/apimachinery/pkg/runtime/interfaces.go
文件中type Encoder interface {
Encode(obj Object, w io.Writer) error
Identifier() Identifier
}
staging/src/k8s.io/apimachinery/pkg/runtime/interfaces.go
文件中type Decoder interface {
Decode(data []byte, defaults *schema.GroupVersionKind, into Object) (Object, *schema.GroupVersionKind, error)
}
staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go
文件中,提供了json序列化器type Serializer struct {
meta MetaFactory
options SerializerOptions
creater runtime.ObjectCreater
typer runtime.ObjectTyper
identifier runtime.Identifier
}
runtime.interface.go
中的Serializer接口,实现了 Encode、Decode方法NewSerializer
、NewSerializerWithOptions
staging/src/k8s.io/apimachinery/pkg/runtime/serializer/yaml/yaml.go
文件中,提供了yaml序列化器type yamlSerializer struct {
// the nested serializer
runtime.Serializer
}
runtime.interface.go
中的Serializer接口staging/src/k8s.io/apimachinery/pkg/runtime/serializer/protobuf/protobuf.go
文件中,提供了protobuf序列化器type Serializer struct {
prefix []byte
creater runtime.ObjectCreater
typer runtime.ObjectTyper
}
runtime.interface.go
中的Serializer接口scheme.AddConversionFunc(
(*appsv1.Deployment)(nil),
(*appsv1beta1.Deployment)(nil),
func(a, b interface{}, scope conversion.Scope) error{
v1deploy := a.(*appsv1.Deployment)
v1beta1deploy := b.(*appsv1beta1.Deployment)
// make conversion here
return nil
})