在Kubernetes源码分析— API Server之API Install篇中,我们了解到K8S可以支持多版本的API,但是Rest API的不同版本中接口的输入输出参数的格式是有差别的,Kubernetes是怎么处理这个问题的呢?另外Kubernetes支持yaml、json两个格式的配置,同时又能够支持json、yaml和pb等格式的编解码进行协议传输,那么Kubernetes又是如何实现各种数据对象的序列化、反序列化的呢?
// Encoders write objects to a serialized form type Encoder interface { // Encode writes an object to a stream. Implementations may return errors if the versions are // incompatible, or if no conversion is defined. Encode(obj Object, w io.Writer) error }
// Decoders attempt to load an object from data. type Decoder interface { // Decode attempts to deserialize the provided data using either the innate typing of the scheme or the // default kind, group, and version provided. It returns a decoded object as well as the kind, group, and // version from the serialized data, or an error. If into is non-nil, it will be used as the target type // and implementations may choose to use it rather than reallocating an object. However, the object is not // guaranteed to be populated. The returned object is not guaranteed to match into. If defaults are // provided, they are applied to the data by default. If no defaults or partial defaults are provided, the // type of the into may be used to guide conversion decisions. Decode(data []byte, defaults *schema.GroupVersionKind, into Object) (Object, *schema.GroupVersionKind, error) }
// Serializer is the core interface for transforming objects into a serialized format and back. // Implementations may choose to perform conversion of the object, but no assumptions should be made. type Serializer interface { Encoder Decoder }
type StorageSerializer interface { // SupportedMediaTypes are the media types supported for reading and writing objects. SupportedMediaTypes() []SerializerInfo
// UniversalDeserializer returns a Serializer that can read objects in multiple supported formats // by introspecting the data at rest. UniversalDeserializer() Decoder
// 返回一个encoder,该encoder能够保证写入底层序列化器的对象是指定的GV // EncoderForVersion returns an encoder that ensures objects being written to the provided // serializer are in the provided group version. EncoderForVersion(serializer Encoder, gv GroupVersioner) Encoder
// 返回一个decoder,该decoder能够保证被底层序列化器的反序列化的对象是指定的GV // DecoderForVersion returns a decoder that ensures objects being read by the provided // serializer are in the provided group version by default. DecoderToVersion(serializer Decoder, gv GroupVersioner) Decoder }
Codec is a Serializer that deals with the details of versioning objects. It offers the same // interface as Serializer, so this is a marker to consumers that care about the version of the objects // they receive. type Codec Serializer
// CodecForVersions creates a codec with the provided serializer. If an object is decoded and its group is not in the list, // it will default to runtime.APIVersionInternal. If encode is not specified for an object's group, the object is not // converted. If encode or decode are nil, no conversion is performed. func(f CodecFactory)CodecForVersions(encoder runtime.Encoder, decoder runtime.Decoder, encode runtime.GroupVersioner, decode runtime.GroupVersioner)runtime.Codec { // TODO: these are for backcompat, remove them in the future if encode == nil { encode = runtime.DisabledGroupVersioner } if decode == nil { decode = runtime.InternalGroupVersioner } return versioning.NewDefaultingCodecForScheme(f.scheme, encoder, decoder, encode, decode) }
// DecoderToVersion returns a decoder that targets the provided group version. func(f CodecFactory)DecoderToVersion(decoder runtime.Decoder, gv runtime.GroupVersioner)runtime.Decoder { return f.CodecForVersions(nil, decoder, nil, gv) }
// EncoderForVersion returns an encoder that targets the provided group version. func(f CodecFactory)EncoderForVersion(encoder runtime.Encoder, gv runtime.GroupVersioner)runtime.Encoder { return f.CodecForVersions(encoder, nil, gv, nil) }
type ObjectConvertor interface { // Convert attempts to convert one object into another, or returns an error. This method does // not guarantee the in object is not mutated. The context argument will be passed to // all nested conversions. Convert(in, out, context interface{}) error // ConvertToVersion takes the provided object and converts it the provided version. This // method does not guarantee that the in object is not mutated. This method is similar to // Convert() but handles specific details of choosing the correct output version. ConvertToVersion(in Object, gv GroupVersioner) (out Object, err error) ConvertFieldLabel(version, kind, label, valuestring) (string, string, error) }
// ConvertToVersion converts in to the provided outVersion without copying the input first, which // is only safe if the output object is not mutated or reused. func(c unsafeObjectConvertor)ConvertToVersion(in Object, outVersion GroupVersioner)(Object, error) { return c.Scheme.UnsafeConvertToVersion(in, outVersion) }
// UnsafeConvertToVersion will convert in to the provided target if such a conversion is possible, // but does not guarantee the output object does not share fields with the input object. It attempts to be as // efficient as possible when doing conversion. func(s *Scheme)UnsafeConvertToVersion(in Object, target GroupVersioner)(Object, error) { return s.convertToVersion(false, in, target) }
// convertToVersion handles conversion with an optional copy. func(s *Scheme)convertToVersion(copybool, in Object, target GroupVersioner)(Object, error) { var t reflect.Type
if u, ok := in.(Unstructured); ok { typed, err := s.unstructuredToTyped(u) if err != nil { returnnil, err }
in = typed // unstructuredToTyped returns an Object, which must be a pointer to a struct. t = reflect.TypeOf(in).Elem() // 从指针转换为一个结构对象
} else { // determine the incoming kinds with as few allocations as possible. t = reflect.TypeOf(in) // 只有指针对象才能被转换 if t.Kind() != reflect.Ptr { returnnil, fmt.Errorf("only pointer types may be converted: %v", t) } t = t.Elem() // 得到指针的结构对象 if t.Kind() != reflect.Struct { returnnil, fmt.Errorf("only pointers to struct types may be converted: %v", t) } }
kinds, ok := s.typeToGVK[t] // 得到存储在scheme中的GVK数据,可能有多个 if !ok || len(kinds) == 0 { returnnil, NewNotRegisteredErrForType(t) }
gvk, ok := target.KindForGroupVersionKinds(kinds) // 基于GroupVersioner从源GVKs得到统一的最终目标GVK, // 譬如存储到ETCD来说,同时希望按照统一的版本来存储。 if !ok { // try to see if this type is listed as unversioned (for legacy support) // TODO: when we move to server API versions, we should completely remove the unversioned concept if unversionedKind, ok := s.unversionedTypes[t]; ok { if gvk, ok := target.KindForGroupVersionKinds([]schema.GroupVersionKind{unversionedKind}); ok { return copyAndSetTargetKind(copy, in, gvk) } return copyAndSetTargetKind(copy, in, unversionedKind) } returnnil, NewNotRegisteredErrForTarget(t, target) }
// target wants to use the existing type, set kind and return (no conversion necessary) for _, kind := range kinds { // 如果gvk 是kinds中的一种,那说明版本一致,资源对象结构一致,我们只需要把对象内容拷贝出来,并设置好目标GVK即可。 if gvk == kind { return copyAndSetTargetKind(copy, in, gvk) } }
// 如果类型是unversioned,那么没有转化你的必要 // type is unversioned, no conversion necessary if unversionedKind, ok := s.unversionedTypes[t]; ok { if gvk, ok := target.KindForGroupVersionKinds([]schema.GroupVersionKind{unversionedKind}); ok { return copyAndSetTargetKind(copy, in, gvk) } return copyAndSetTargetKind(copy, in, unversionedKind) }
// Encode ensures the provided object is output in the appropriate group and version, invoking // conversion if necessary. Unversioned objects (according to the ObjectTyper) are output as is. func(c *codec)Encode(obj runtime.Object, w io.Writer) error { switch obj.(type) { case *runtime.Unknown, runtime.Unstructured: returnc.encoder.Encode(obj, w) }
ifc.encodeVersion == nil || isUnversioned { if e, ok := obj.(runtime.NestedObjectEncoder); ok { if err := e.EncodeNestedObjects(DirectEncoder{Encoder: c.encoder, ObjectTyper: c.typer}); err != nil { return err } } objectKind := obj.GetObjectKind() old := objectKind.GroupVersionKind() objectKind.SetGroupVersionKind(gvks[0]) err = c.encoder.Encode(obj, w) objectKind.SetGroupVersionKind(old) return err }
// Perform a conversion if necessary objectKind := obj.GetObjectKind() old := objectKind.GroupVersionKind() out, err := c.convertor.ConvertToVersion(obj, c.encodeVersion) if err != nil { return err }
if e, ok := out.(runtime.NestedObjectEncoder); ok { if err := e.EncodeNestedObjects(DirectEncoder{Version: c.encodeVersion, Encoder: c.encoder, ObjectTyper: c.typer}); err != nil { return err } }
// Conversion is responsible for setting the proper group, version, and kind onto the outgoing object err = c.encoder.Encode(out, w) // restore the old GVK, in case conversion returned the same object objectKind.SetGroupVersionKind(old) return err }