
编解码器
编解码器,包含编码器与解码器,指的是可以表示数据的任何格式,或者将数据转换为特定格式的过程。在 kubernetes 中应用则是将 Etcd 集群中的数据进行编解码操作。
1、接口定义
Codec 包含 Encode
Decoder
两个方法,前者用于将对象编码,后者将对象解码,内部的具体编解码器都需要实现这两个方法。
1.1 Encoder
type Encoder interface {
Encode(obj Object, w io.Writer) error
Identifier() Identifier
}
1.2 Decoder
type Decoder interface {
Decode(data []byte, defaults *schema.GroupVersionKind, into Object) (Object, *schema.GroupVersionKind, error)
}
2、序列化器
编解码器包含 3 种序列化器,在进行编解码操作时,每一种序列化器都对资源对象的 metav1.TypeMeta(即APIVersion和Kind字段)进行验证,如果资源对象未提供这些字段,就会返回错误。
2.1 JsonSerializer
JSON 格式序列化、反序列化器,使用 application/json 的 ContentType 作为标识。实际使用则通过 Go 语言标准库 encoding/json 来实现序列化和反序列化操作。
type Serializer struct {
meta MetaFactory
options SerializerOptions
creater runtime.ObjectCreater
typer runtime.ObjectTyper
identifier runtime.Identifier
}
初始化流程:
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,
}
在序列化过程中直接将对象编码为 JSON 格式,这里有一个小优化,如果开启 pretty 参数,则会使用 caseSensitiveJsonIterator.MarshalIndent
函数(封装了 github.com/json-iterator/go 第三方库,区分大小写、性能更优、兼容性好)优化格式。
反序列化操作通过 s.meta.Interpret 函数从 JSON 格式数据中提取出资源对象的 APIVersion 和 Kind 字段,最后通过 caseSensitiveJsonIterator.Unmarshal
函数将 JSON 数据反序列化并返回。
2.2 YamlSerializer
YAML 格式序列化、序列化器,使用 application/yaml 的 ContentType 作为标识。 实际使用则通过第三方库 gopkg.in/yaml.v2 来实现序列化和反序列化操作。
type yamlSerializer struct {
runtime.Serializer
}
初始化流程:
yamlSerializer := json.NewSerializerWithOptions(
mf, scheme, scheme,
json.SerializerOptions{Yaml: true, Pretty: false, Strict: options.Strict},
)
serializers := []serializerType{
{
AcceptContentTypes: []string{runtime.ContentTypeYAML},
ContentType: runtime.ContentTypeYAML,
FileExtensions: []string{"yaml"},
EncodesAsText: true,
Serializer: yamlSerializer,
StrictSerializer: strictYAMLSerializer,
},
}
序列化过程中先将对象转换为 JSON 格式,在通过 yaml.JSONToYAML 将 JSON 格式转换为 YAML 格式并返回数据。反序列化过程先将格式转换为 JSON,之后流程同 JSON 解码过程一致。
2.3 protobufSerializer
Protobuf 格式序列化、反序列化器,使用 application/vnd.kubernetes.protobuf 的 ContentType 作为标识。
type Serializer struct {
prefix []byte
creater runtime.ObjectCreater
typer runtime.ObjectTyper
}
初始化流程:
protoSerializer := protobuf.NewSerializer(scheme, scheme)
protoRawSerializer := protobuf.NewRawSerializer(scheme, scheme)
serializers := []serializerType{
{
AcceptContentTypes: []string{runtime.ContentTypeProtobuf},
ContentType: runtime.ContentTypeProtobuf,
FileExtensions: []string{"pb"},
Serializer: protoSerializer,
StrictSerializer: protoSerializer,
Framer: protobuf.LengthDelimitedFramer,
StreamSerializer: protoRawSerializer,
},
}
3、版本转换器
资源版本转换器主要用于解决多资源版本转换问题,其原理通过内部版本作为桥梁,转换时先将指定版本转换为内部版本,再将内部版本转换为目标版本,如此一来只要资源支持内部版本,则可以在多个版本之间进行转换。
3.1 转换器
type Converter struct {
conversionFuncs ConversionFuncs // 默认转换函数,定义在资源目录下的 conversion.go 代码文件中
generatedConversionFuncs ConversionFuncs // 自动生成的转换函数,定义在资源目录下的 zz_generated.conversion.go 代码文件中
ignoredUntypedConversions map[typePair]struct{} // 若资源对象注册到此字段,则忽略此资源对象的转换操作
}
不管是默认的转换函数,还是自动生成的转换函数,都是同一类型,其中 key 是一个结构体,里面包含了需要转换原版本和目标版本关系,如下所示:
type typePair struct {
source reflect.Type // 需要转换的源版本
dest reflect.Type // 需要转换的目标版本
}
3.2 注册转换函数
Converter 转换函数需要通过注册才能在 Kubernetes 内部使用:
scheme.AddIgnoredConversionType:注册忽略的资源类型,不会执行转换操作,忽略资源对象的转换操作;
scheme.AddConversionFunc:注册单个 Conversion Func 转换函数;
scheme.AddGeneratedConversionFunc:注册自动生成的转换函数;
3.3 转换流程
- 感谢你赐予我前进的力量