【k8s源码篇】序列化存储1之resource model序列化

参考

序列化

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 包中

65615fb4b2be3e5c086347c6333a6ced.png

1.1 | json 序列化

  • 以常用的 json 协议格式为例,该协议由 serializer.json.Serializer 结构体负责实现, 在 staging/src/k8s.io/apimachinery/pkg/runtime/serializer/json/json.go 中定义,图解其中包含的组件如下:

38112368db8bbc99a2f417267a649f83.png

  • 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 的流程如下:

04e9915360b89aea994103514c06829e.png

从源码的角度看 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
}

其中的逻辑分析流程如下:

b6d9d4cfa1109a693e12210e4bc9189e.png

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)
}

其中的逻辑分析流程如下:

d646717aac2628b6a068850f707ccf5d.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值