Kubernetes是一个完全以资源为中心的系统,资源是Kubernetes中最重要的概念,Kubernetes的生态系统都围绕着资源进行运作。
Kubernetes将资源再次分组和版本化,形成Group、Version、Resource。
Group被称为资源组,在Kubernetes API Server中也称其为APIGroup。
Version被称为资源版本,在Kubernetes API Server中也可以被称为APIVersions。
Resource被称为资源,在Kubernetes API Server中也可称其为APIResource。
Kind被称为资源种类,描述Resource的种类,与Resource为同一个级别。
Kubernetes系统支持多个Group,每个Group支持多个Version,每个Version支持多个Resource,其中部分资源同时会拥有自己的子资源(SubResource),例如Deployment资源拥有Status子资源。
资源组、资源版本、资源、子资源的完整表现形式为<group>/<version>/<resource>/<subresource>。常用的Deployment资源的完整表现形式就是apps/v1/deployments/status。
每一个资源都拥有一定数量的资源操作方法,用于Etcd集群存储中对资源对象的增删改查操作。Kubernetes系统支持8种资源操作方法,分别是create、delete、deletecollection、get、list、patch、update、watch。每一个资源都至少有两个版本,分别为外部版本和内部版本。开发者也可以通过CRD实现自定义资源,允许用户将自己定义的资源添加到Kubernetes系统当中。
Group Group(资源组)在Kubernetes API Server中可以称其为APIGroup。Kubernetes系统中定义了许多资源组,并按照不同的功能进行划分。资源组的数据结构代码如下
1 2 3 4 5 6 7 8 9 10 type APIGroup struct { TypeMeta `json:",inline"` Name string `json:"name" protobuf:"bytes,1,opt,name=name"` Versions []GroupVersionForDiscovery `json:"versions" protobuf:"bytes,2,rep,name=versions"` PreferredVersion GroupVersionForDiscovery `json:"preferredVersion,omitempty" protobuf:"bytes,3,opt,name=preferredVersion"` ServerAddressByClientCIDRs []ServerAddressByClientCIDR `json:"serverAddressByClientCIDRs,omitempty" protobuf:"bytes,4,rep,name=serverAddressByClientCIDRs"` }
在Kubernetes系统中,支持两类资源组,分别是拥有组名的资源组和没有组名的资源组。拥有组名的资源组其表现形式为<group>/<version>/<resource>,例如apps/v1/deployments。没有组名的资源组又被称为核心资源组,其表现形式为/<version>/<resource>。
Version 每当资源的新版本发布时,都需要设置版本号,目的是为了在兼容旧版本的同时不断升级新版本。Kubernetes的资源版本控制可分为3种,分别是Alpha、Beta和Stable。
Alpha版本为内部测试版本,用于Kubernetes开发者内部测试,该版本是不稳定的,可能存在很多缺陷和漏洞。Beta版本为相对稳定的版本,经过社区和官方的多次讨论。Stable版本为正式发布的版本,Stable版本基本形成了产品,不会被删除。
资源版本数据结构代码如下:
1 2 3 4 5 6 type APIVersions struct { TypeMeta `json:",inline"` Versions []string `json:"versions" protobuf:"bytes,1,rep,name=versions"` ServerAddressByClientCIDRs []ServerAddressByClientCIDR `json:"serverAddressByClientCIDRs" protobuf:"bytes,2,rep,name=serverAddressByClientCIDRs"` }
Resource 在Kubernetes体系架构中,资源是Kubernetes最重要的概念,Kubernetes本质上是一个资源控制系统。
一个资源被实例化以后会表达为一个资源对象(Resource Object)。在Kubernetes系统中定义并运行着各式各样的资源对象,所有的资源对象都是Entity(实体),Kubernetes用这些Entity来表示当前状态。Kubernetes目前支持持久化实体和短暂性实体两种实体。
持久性实体在资源创建后会持久确保该对象存在,例如Deployment,短暂性实体在资源对象创建后,如果出现故障或者调度失败,不会重新创建该对象,例如Pod。资源数据结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 type APIResource struct { Name string `json:"name" protobuf:"bytes,1,opt,name=name"` SingularName string `json:"singularName" protobuf:"bytes,6,opt,name=singularName"` Namespaced bool `json:"namespaced" protobuf:"varint,2,opt,name=namespaced"` Group string `json:"group,omitempty" protobuf:"bytes,8,opt,name=group"` Version string `json:"version,omitempty" protobuf:"bytes,9,opt,name=version"` Kind string `json:"kind" protobuf:"bytes,3,opt,name=kind"` Verbs Verbs `json:"verbs" protobuf:"bytes,4,opt,name=verbs"` ShortNames []string `json:"shortNames,omitempty" protobuf:"bytes,5,rep,name=shortNames"` Categories []string `json:"categories,omitempty" protobuf:"bytes,7,rep,name=categories"` StorageVersionHash string `json:"storageVersionHash,omitempty" protobuf:"bytes,10,opt,name=storageVersionHash"` }
在Kubernetes中,同一资源对应两个版本号,分别为内部和外部版本号。External Object(外部版本资源对象)用于对外暴露给用户请求的接口所使用的资源对象,Internal Object(内部版本使用对象)不对外暴露,仅在Kubernetes API Server内部使用,用于多资源版本的转换。
资源的内部版本和外部版本是需要相互进行转换的,用于转换的函数需要事先初始化到资源注册表中,多个外部版本之间的资源进行相互转换需要通过内部版本进行中转,这也是Kubernetes实现多资源版本转换的关键。
资源的内部版本定义了所支持的资源类型(types.go)、资源验证方法(validation.go)、资源注册至资源注册表的方法(install.go)等。资源的外部版本定义了资源的转换方法(conversion.go),资源的默认值(defaults.go)等。
以Deployment资源为例,内部版本定义在pkg/apis/apps目录下,其中register.go代码文件定义了所属的资源组和资源版本,内部版本通过runtime.APIVersionInternal标识。
1 2 3 4 const GroupName = "apps" var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal}
每一个Kubernetes资源目录,都通过type.go代码文件定义当前资源组/资源版本下所支持的资源类型。
在每一个Kubernetes资源组目录中,都有一个install.go代码文件,负责将资源信息注册到资源注册表中。
一个资源组下拥有多个资源版本,例如apps资源组用于v1,v1beta1,v1beta2等资源版本。当使用apps资源组下的Deployment资源时,在一些场景下,如果不指定资源版本,则使用该资源的首选版本。以apps资源组为例,注册资源时会注册多个资源版本,
在Kubernetes系统中,针对每一个资源都有一定的操作方法,不同的资源对象拥有不同的操作方法,例如对于Pod资源,可以执行create、delete、get等操作。资源操作方法可以通过Verbs数据结构进行描述,代码如下
1 2 3 4 5 type Verbs []string func (vs Verbs) String () string { return fmt.Sprintf("%v" , []string (vs)) }
Kubernetes系统拥有强大的高扩展功能,其中自定义资源是一种常见的扩展方式,可以将自己定义的资源添加到Kubernetes当中。
无论内置资源还是自定义资源,都通过资源对象描述文件进行定义。一个资源对象需要用5个字段来进行描述,分别是Group/Version、Kind、MetaData、Spec、Status。这些字段定义在YAML或JSON文件中。Kubernetes系统中的所有资源对象都可以通过YAML或者JSON来进行定义。
runtime.Object Runtime(运行时)一般指程序或者语言核心库的实现。runtime.Object是Kubernetes类型系统的基石,Kubernetes上所有的资源对象实际上就是一种Go语言的Struct类型,都有一个共同的结构叫做runtime.Object。其结构如下
1 2 3 4 type Object interface { GetObjectKind() schema.ObjectKind DeepCopyObject() Object }
其提供了两个方法,分别是GetObjectKind用于设置并返回GroupVersionKind和DeepCopyObject用于深复制当前资源对象。
1 2 3 4 5 6 7 8 type ObjectKind interface { SetGroupVersionKind(kind GroupVersionKind) GroupVersionKind() GroupVersionKind }
Kubernetes中任意资源对象都可以通过runtime.Object来存储它的类型并且进行深拷贝操作。实例代码将Pod资源对象转换为了runtime.Object之后再次转换为资源对象,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/kubernetes/pkg/apis/core" "reflect" ) func main () { pod := &core.Pod{ TypeMeta: v1.TypeMeta{Kind: "Pod" }, ObjectMeta: v1.ObjectMeta{Labels: map [string ]string {"name" : "foo" }}, } pod.DeepCopyObject() pod.GroupVersionKind() obj := runtime.Object(pod) pod2, ok := obj.(*core.Pod) if !ok { panic ("unexpected" ) } if !reflect.DeepEqual(pod, pod2) { panic ("unexpected" ) } }
Scheme资源注册表 Kubernetes系统拥有众多的资源,每一个资源就是一个资源类型,这些资源需要一个统一的注册、存储、查询、管理机制。Kubernetes系统中所有的资源类型都需要注册到Scheme资源注册表中,其是一个内存型的资源注册表,拥有以下特点:
支持注册多种资源类型,包括内部和外部版本
支持多版本的转换机制
支持不同资源的序列化反序列化机制
Scheme资源注册表数据结构主要由4个map结构组成,分别是gvkToType、typeToGVK、unversionedTypes、unversionedKinds,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 type Scheme struct { 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 {}) converter *conversion.Converter versionPriority map [string ][]string observedVersions []schema.GroupVersion schemeName string }
在Scheme资源注册表中,不同的资源类型使用的注册方法不同
scheme.AddUnversionedTypes:注册UnversionedType资源类型。
scheme.AddKnownTypes:注册KnownTypes资源类型
scheme.AddKnownTypeWithName:注册KnownType资源类型,须指定资源的Kind资源种类名称
AddKnownTypes方法在注册资源类型时,无需指定Kind名称,而是通过reflect机制来获取资源类型的名称作为种类名称。
1 2 3 4 5 6 7 8 9 10 11 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) } }
Codec编解码器 Codec编解码器接口定义如下
1 2 3 4 5 6 7 8 9 10 11 12 type Encoder interface { Encode(obj Object, w io.Writer) error Identifier() Identifier } type Decoder interface { Decode(data []byte , defaults *schema.GroupVersionKind, into Object) (Object, *schema.GroupVersionKind, error) } type Serializer interface { Encoder Decoder } type Codec Serializer
kubernetes目前支持3种主要的序列化器,分别是jsonSerializer、yamlSerializer、protobufSerializer。
编解码器通过NewCodecFactory函数实例化,在实例化过程中会将上述三种序列化器全部实例化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 func NewCodecFactory (scheme *runtime.Scheme, mutators ...CodecFactoryOptionsMutator) CodecFactory { options := CodecFactoryOptions{Pretty: true } for _, fn := range mutators { fn(&options) } serializers := newSerializersForScheme(scheme, json.DefaultMetaFactory, options) return newCodecFactory(scheme, serializers) } func newSerializersForScheme (scheme *runtime.Scheme, mf json.MetaFactory, options CodecFactoryOptions) []serializerType { jsonSerializer := json.NewSerializerWithOptions( mf, scheme, scheme, json.SerializerOptions{Yaml: false , Pretty: false , Strict: options.Strict}, ) jsonSerializerType := serializerType{ AcceptContentTypes: []string {runtime.ContentTypeJSON}, ContentType: runtime.ContentTypeJSON, FileExtensions: []string {"json" }, EncodesAsText: true , Serializer: jsonSerializer, Framer: json.Framer, StreamSerializer: jsonSerializer, } if options.Pretty { jsonSerializerType.PrettySerializer = json.NewSerializerWithOptions( mf, scheme, scheme, json.SerializerOptions{Yaml: false , Pretty: true , Strict: options.Strict}, ) } yamlSerializer := json.NewSerializerWithOptions( mf, scheme, scheme, json.SerializerOptions{Yaml: true , Pretty: false , Strict: options.Strict}, ) protoSerializer := protobuf.NewSerializer(scheme, scheme) protoRawSerializer := protobuf.NewRawSerializer(scheme, scheme) serializers := []serializerType{ jsonSerializerType, { AcceptContentTypes: []string {runtime.ContentTypeYAML}, ContentType: runtime.ContentTypeYAML, FileExtensions: []string {"yaml" }, EncodesAsText: true , Serializer: yamlSerializer, }, { AcceptContentTypes: []string {runtime.ContentTypeProtobuf}, ContentType: runtime.ContentTypeProtobuf, FileExtensions: []string {"pb" }, Serializer: protoSerializer, Framer: protobuf.LengthDelimitedFramer, StreamSerializer: protoRawSerializer, }, } for _, fn := range serializerExtensions { if serializer, ok := fn(scheme); ok { serializers = append (serializers, serializer) } } return serializers }
Converter资源版本转换器 在Kubernetes中,同一资源拥有多个资源版本,Kubernetes系统允许同一资源的不同资源版本进行转换。Converter资源版本转换器主要用于解决多资源版本的转换问题,Kubernetes系统中的一个资源支持多个资源版本,Kubernetes通过内部版本机制实现资源的版本转换。
Converter转换器数据结构主要存放转换函数,转换器数据结构代码如下:
1 2 3 4 5 6 7 8 9 10 11 type Converter struct { conversionFuncs ConversionFuncs generatedConversionFuncs ConversionFuncs ignoredConversions map [typePair]struct {} ignoredUntypedConversions map [typePair]struct {} nameFunc func (t reflect.Type) string }
Converter转换函数需要通过注册才能在Kubernetes中进行使用,需要通过以下的注册转换函数进行注册
scheme.AddIgnoredConversionType:注册忽略的资源类型
scheme.AddConversionFuncs:注册多个Conversion Func转换函数
scheme.AddConversionFunc:注册单个Conversion Func转换函数
scheme.AddGeneratedConversionFunc:注册自动生成的转换函数
scheme.AddFieldLabelConversionFunc:注册字段标签的转换函数
Converter转换器在Kubernetes中使用十分广泛,例如Deployment资源对象,起初使用v1beta1资源版本,后来推出稳定的v1版本,因此会将v1beta1版本转换为v1版本,Converter转换器通过Converter函数进行资源版本的转换。