前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >kubectl apply 之后客户端做了什么?

kubectl apply 之后客户端做了什么?

原创
作者头像
Duncan_
发布2023-01-03 22:43:26
1.8K0
发布2023-01-03 22:43:26
举报

kubectl apply 之后客户端做了什么?

前言

在学习 kubernetes 源码过程中,看到 kubectl apply 源码里面有个很有意思的现象。起初我以为当我们执行 kubectl apply -f deployment.yaml 之后,客户端会把 deployment.yaml 完整地发送给 api-server,然后让 api-server 重新渲染这个 deployment 资源并更替旧的资源。

实际上却并非这样,当我们执行 kubectl apply 的时候,默认是采用的是 client-side apply 模式。客户端会先会生成一个增量的 patch 对象,然后在发送给 api-server 进行 patch 操作。而生成这个增量信息生成的算法,是通过三路数据合并得到的。

本文源码选取

kubectl 的源码本身应该在 git@github.com:kubernetes/kubectl.git 仓库。但是在 kubernetes 大仓里面也有一个用于发布到公共类库的镜像源码。所以我直接下载 kubernetes 大仓 git@github.com:kubernetes/kubernetes.git ,查看源码更加方便一些。我的 kubectl 客户端版本是 v1.21.3,所以就切换到对应标签 v1.21.3

kubectl apply 执行流程

下面用伪代码大概描述下 kubectl apply 的执行流程

WechatIMG222.jpeg
WechatIMG222.jpeg

在这个流程中,首先是准备了三路合并的资源对象, modifiedcurrentoriginal。其中 modified 是从用户传入的文件中获取的资源对象。current 则是从 api-server 获取的实际运行的资源对象信息。original 则是从 current 资源对象的 lac(last-applied-configuration) 注解中获取的上一次 apply 的原始拷贝。

这个三路资源对象数据的关系可以这样理解,current 是上一次三路合并里面 modified 资源对象基础上,增加一些必填项、默认值、状态信息以及服务端修改之后的资源对象。由于 current 已经被修改了,所以需要使用一个注解把原本没有修改的资源对象信息给记录下来,所以其实本次三路合并的 original 实际就是上一次三路合并的 modified 的拷贝信息。

接着 kubectl apply 对三路资源对象比较分析,得出一个增量数据 patch。这个 patch 是遵循 kubernetes 自己定义的 strategic merge patch 格式的增量信息,内容包含了本次需要更改、增加以及删除的字段操作信息,也包含了更新 lac 注解内容。最后通过 api-serverpatch 接口,完成了对目标资源对象的更新操作。

三路资源对象合并,生成增量 patch

下面我们仔细阅读一下 strategicpatch.CreateThreeWayMergePatch 源码,看看 patch 内容是怎么产生的。

源码解析在代码的注解中

代码语言:go
复制
func CreateThreeWayMergePatch(original, modified, current []byte, schema LookupPatchMeta, 
    overwrite bool, fns ...mergepatch.PreconditionFunc) ([]byte, error) {

	...
	deltaMapDiffOptions := DiffOptions{
		IgnoreDeletions: true,
		SetElementOrder: true,
	}
	// 对比 current 与 modified,忽略删除字段的操作,只返回新增和修改字段的操作
	deltaMap, err := diffMaps(currentMap, modifiedMap, schema, deltaMapDiffOptions)
	if err != nil {
		return nil, err
	}
	deletionsMapDiffOptions := DiffOptions{
		SetElementOrder:           true,
		IgnoreChangesAndAdditions: true,
	}
	// 对比 original 与 modified, 忽略新增和修改内容,只返回删除的字段的操作
	deletionsMap, err := diffMaps(originalMap, modifiedMap, schema, deletionsMapDiffOptions)
	if err != nil {
		return nil, err
	}

	mergeOptions := MergeOptions{}
	// 合并新增、修改以及删除操作
	patchMap, err := mergeMap(deletionsMap, deltaMap, schema, mergeOptions)
	if err != nil {
		return nil, err
	}

	...

	// 这里 original 和 current 的 diff 可以理解为默认值、状态字段以及服务端的更改。
	// 当 overwrite == true ,客户端的更改将会覆盖服务端的更改。
	// 当 overwrite == false ,客户端更改如果与服务端更改有冲突,则会报错。
	if !overwrite {
		changeMapDiffOptions := DiffOptions{}
		changedMap, err := diffMaps(originalMap, currentMap, schema, changeMapDiffOptions)
		if err != nil {
			return nil, err
		}

		hasConflicts, err := MergingMapsHaveConflicts(patchMap, changedMap, schema)
		if err != nil {
			return nil, err
		}

		if hasConflicts {
			return nil, mergepatch.NewErrConflict(mergepatch.ToYAMLOrError(patchMap), mergepatch.ToYAMLOrError(changedMap))
		}
	}

	// 最后返回这次客户端更改的增量操作集合
	return json.Marshal(patchMap)
}

简单来说,CreateThreeWayMergePatch 分为三步来生成增量 patch 的。

第一步是对 currentmodifieddiff 操作,忽略删除字段的操作,值保留新增与修改字段的操作,生成 deltaMap

  • 忽略删除字段的操作,是因为 current 里面包含了一些默认值、状态信息以及服务端对于资源对象的一些更改操作,这些并不包含在用户传入的资源对象里面。如果不忽略删除字段操作,这些默认值、状态值以及一些服务端的修改就会被认为是需要做删除的操作字段。
  • 真正需要删除操作的字段,应该是通过 original 和 modified 对比得到的。
  • 除了正常的字段更新,这里还会包含注解的更新,因为注解 "lac" 在前面过程中被 modified 资源对象重新赋值了

第二步对 originalmodifieddiff 操作,忽略新增与修改的字段的操作,保留删除字段的操作,生成 deleteMap

  • 真正需要删除的字段操作,是通过 originalmodified 对比才能够得到的
  • 这里忽略了新增和修改字段的操作,第一是因为这个在第一步已经计算出来了,第二是因为对于一些默认字段的修改操作,currentmodified 对比的结果是修改,而 originalmodified 对比的结果是新增。显然修改操作比新增操作是更加符合对 current 资源对象的操作。

第三步就是合并 deltaMapdeleteMappatchMap

总结

最后我们了解到,我们经常执行的 kubectl apply ,实际并不是把我们传入的资源文件原封不动的传给 api-server,而是在客户端提前做好处理,得到增量的patch 再向 api-server 发起对目标对象的 patch 操作。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • kubectl apply 之后客户端做了什么?
    • 前言
      • 本文源码选取
        • kubectl apply 执行流程
          • 三路资源对象合并,生成增量 patch
            • 总结
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
            http://www.vxiaotou.com