【k8s源码篇】序列化存储1之resource model序列化
参考K8s源码分析(5)-Resource Meta 序列化K8s源码分析(6)-Resource Content 序列化序列化1 | Resource Meta 序列化(相当于 GVK 部分)所有 resource 的基本定义 model(scheme部分已介绍),总结起来就是所有的 resource 都会通过继承的方式来继承 type meta 和 object meta 类型,通过组合成员变
参考
序列化
1 | Resource Meta 序列化(相当于 GVK 部分)
- 所有 resource 的基本定义 model(scheme部分已介绍),总结起来就是所有的 resource 都会通过继承的方式来继承 type meta 和 object meta 类型,通过组合成员变量的方式来组合了属于 resource 自己特定的 spec 和 status
- 众所周知,我们和 kubernetes 的交互的接口就是 resource 定义的 yaml 文件
- 一个 resource object 主要是由 type meta, object meta, 还有 spec 组成
- 其中 type meta 就是 group, version, kind
- 如果要把这些信息存储在后端的 etcd cluster 里,就避免不了序列化和反序列化的过程
- 在 kubernetes 的世界里支持的序列化和反序列化的格式有很多,比方说有 json 格式, yaml 格式, protobuf 格式等。不同协议的支持定义在
staging/src/k8s.io/apimachinery/pkg/runtime/serializer
包中
1.1 | json 序列化
- 以常用的 json 协议格式为例,该协议由
serializer.json.Serializer
结构体负责实现, 在staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go
中定义,图解其中包含的组件如下:
-
MetaFactory 来负责序列化 resource 的 group, version, kind。
-
SerializerOption 负责定义是否为 yaml 格式,是否需要 pretty 美化处理,是否为 strict 严格处理。
-
ObjectTyper 和 ObjectCreater 负责序列化之后识别类型以及创建对象。
serializer.json.Serializer
的源码定义如下:
// staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go
// 若是 yaml 文件,是否需要 pretty 美化处理,是否需要 strict 严格处理
type SerializerOptions struct {
Yaml bool
Pretty bool
Strict bool
}
type Serializer struct {
meta MetaFactory // 负责序列化 resource 的 group、version、kind
options SerializerOptions // yaml 美化选项
creater runtime.ObjectCreater // 创建对象
typer runtime.ObjectTyper // 识别类型
identifier runtime.Identifier
}
func NewSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper, pretty bool) *Serializer {
return NewSerializerWithOptions(meta, creater, typer, SerializerOptions{false, pretty, false})
}
func NewYAMLSerializer(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper) *Serializer {
return NewSerializerWithOptions(meta, creater, typer, SerializerOptions{true, false, false})
}
func NewSerializerWithOptions(meta MetaFactory, creater runtime.ObjectCreater, typer runtime.ObjectTyper, options SerializerOptions) *Serializer {
return &Serializer{
meta: meta,
creater: creater,
typer: typer,
options: options,
identifier: identifier(options),
}
}
1.2 | json 反序列化
- 接下来我们看 resource 的 type meta 对象是如何通过反序列化从而得到的,由上述分析 serializer.json.Serializer 的 MetaFactory 组件负责反序列化 resource 的 group, version, kind,其 overall 的流程如下:
从源码的角度看 MetaFactory 定义如下:
// staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/meta.go
type MetaFactory interface {
Interpret(data []byte) (*schema.GroupVersionKind, error)
}
var DefaultMetaFactory = SimpleMetaFactory{}
// MetaFactory 为接口类型,它的默认实现为 SimpleMetaFactory
type SimpleMetaFactory struct {
}
// SimpleMetaFactory 通过实现 Interpret() 方法来完成反序列化
func (SimpleMetaFactory) Interpret(data []byte) (*schema.GroupVersionKind, error) {
findKind := struct {
APIVersion string `json:"apiVersion,omitempty"`
Kind string `json:"kind,omitempty"`
}{}
// Interpret() 方法利用 encoding/json 开源工具的 json.Unmarshal() 方法来完成对资源的 group, version, kind 的提取
if err := json.Unmarshal(data, &findKind); err != nil {
return nil, fmt.Errorf("couldn't get version/kind; json parse error: %v", err)
}
gv, err := schema.ParseGroupVersion(findKind.APIVersion)
if err != nil {
return nil, err
}
return &schema.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: findKind.Kind}, nil
}
-
MetaFactory 为接口类型,它的默认实现为 SimpleMetaFactory。
-
SimpleMetaFactory 通过实现 Interpret() 方法来完成反序列化。
-
Interpret() 方法利用 encoding/json 开源工具的 json.Unmarshal() 方法来完成对资源的 group, version, kind 的提取。
2 | Resource Content 序列化(相当于资源属性部分)
在这里我们同样还是以 json 协议格式的数据做为例子,来继续介绍 serializer.json.Serializer 组件是如何序列化得到 resource 的 content,其中包括利用 decode 操作从请求中提取相关的 resource 对象, 以及利用 encode 操作来把相关 resource 写入到响应中去。
2.1 | 反序列化 Resource Decode
serializer.json.Serializer.Decode()
方法中定义了 decode 操作:
func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
data := originalData
// 若是 yaml 文件,则将其转换为 json
if s.options.Yaml {
altered, err := yaml.YAMLToJSON(data)
if err != nil {
return nil, nil, err
}
data = altered
}
// 提取原始数据中的 resource meta,也就是 GVK
actual, err := s.meta.Interpret(data)
if err != nil {
return nil, nil, err
}
// 若传参的 gvk 不为空, 则根据新获得 gvk 和 传参的 gvk 做一些操作,确定一个 gvk (暂时不清楚这是什么操作)
if gvk != nil {
*actual = gvkWithDefaults(*actual, *gvk)
}
// 此部分 我理解为检验 是否有错 不太清楚 into 是什么
// 若 into 是不认识的类型
if unk, ok := into.(*runtime.Unknown); ok && unk != nil {
unk.Raw = originalData
unk.ContentType = runtime.ContentTypeJSON
unk.GetObjectKind().SetGroupVersionKind(*actual)
return unk, actual, nil
}
// 若 into 是认识的类型,但是非空
if into != nil {
_, isUnstructured := into.(runtime.Unstructured)
types, _, err := s.typer.ObjectKinds(into)
switch {
case runtime.IsNotRegisteredError(err), isUnstructured:
if err := caseSensitiveJSONIterator.Unmarshal(data, into); err != nil {
return nil, actual, err
}
return into, actual, nil
case err != nil:
return nil, actual, err
default:
*actual = gvkWithDefaults(*actual, types[0])
}
}
// 判断获取到 kind 是否为空,为空 报错
if len(actual.Kind) == 0 {
return nil, actual, runtime.NewMissingKindErr(string(originalData))
}
// 判断获取到的 verion 是否为空,为空 报错
if len(actual.Version) == 0 {
return nil, actual, runtime.NewMissingVersionErr(string(originalData))
}
// use the target if necessary
// 创建 类型对象
obj, err := runtime.UseOrCreateObject(s.typer, s.creater, *actual, into)
if err != nil {
return nil, actual, err
}
// 将 二进制数据 进行反序列化
if err := caseSensitiveJSONIterator.Unmarshal(data, obj); err != nil {
return nil, actual, err
}
// If the deserializer is non-strict, return successfully here.
// 若没有严格要求格式,那么直接返回
if !s.options.Strict {
return obj, actual, nil
}
// 若严格要求了格式,那么需要再次处理,对原始数据进行处理,转换成相应的格式
altered, err := yaml.YAMLToJSONStrict(originalData)
if err != nil {
return nil, actual, runtime.NewStrictDecodingError(err.Error(), string(originalData))
}
// 深拷贝一份 类型对象
strictObj := obj.DeepCopyObject()
// 若格式转换成功,那么就返回
if err := strictCaseSensitiveJSONIterator.Unmarshal(altered, strictObj); err != nil {
return nil, actual, runtime.NewStrictDecodingError(err.Error(), string(originalData))
}
// 若转换不成功,那么返回未转换格式 的 类型对象
return obj, actual, nil
}
其中的逻辑分析流程如下:
2.2 | 序列化 Resource Encode
serializer.json.Serializer.Encode()
方法定义了 encode 操作:
func (s *Serializer) Encode(obj runtime.Object, w io.Writer) error {
if co, ok := obj.(runtime.CacheableObject); ok {
return co.CacheEncode(s.Identifier(), s.doEncode, w)
}
return s.doEncode(obj, w)
}
func (s *Serializer) doEncode(obj runtime.Object, w io.Writer) error {
// 若 要求 yaml 格式
if s.options.Yaml {
// 先将 类型对象 转换为 json 二进制数据
json, err := caseSensitiveJSONIterator.Marshal(obj)
if err != nil {
return err
}
// 再将 json 二进制数据 转换为 yaml(格式?)
data, err := yaml.JSONToYAML(json)
if err != nil {
return err
}
_, err = w.Write(data)
return err
}
// 是否json pretty 美化
if s.options.Pretty {
// 装换为 json pretty
data, err := caseSensitiveJSONIterator.MarshalIndent(obj, "", " ")
if err != nil {
return err
}
_, err = w.Write(data)
return err
}
// 以上都没有的话 那就正常转换为 json 形式
encoder := json.NewEncoder(w)
return encoder.Encode(obj)
}
其中的逻辑分析流程如下:
更多推荐
所有评论(0)