想打印k8s资源YAML结果搞懂了Client-Side & Server-Side Apply
前言
由于查看k8s资源YAML时常看到沉长的YAML与手写的格式,相差甚远不利于阅读,经过探索官方文档,才理解什么是Client-Side & Server-Side Apply。
先看一下我用client-go在生成Deployment的YAML格式,核心代码如下:
k8sDeployment, _ := clientSet.AppsV1().Deployments(namespace).Get(context.TODO(), deploymentName, metav1.GetOptions{})
k8sDeployment.Kind = "Deployment"
k8sDeployment.APIVersion = "apps/v1"
k8sDeployment.SetManagedFields(nil) // 不显示管理字段,至于什么是管理字段? 请继续阅读后面的内容.
runtimeWorkload = k8sDeployment
yamlPrinter := printers.YAMLPrinter{}
buffers := bytes.NewBufferString("")
yamlErr := yamlPrinter.PrintObj(runtimeWorkload, buffers)
YAML := buffers.String()
效果:

之前一直有这样一个困扰,例如这样的一个Pod资源,可以看到像kubectl.kubernetes.io/last-applied-configuration annotation和 managedFields 这两个字段,并不是我们手写YAML中存在的,他们是什么呢?
用一个例子展现:
kubectl get pods demo -o yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"creationTimestamp":null,"labels":{"run":"demo"},"name":"demo","namespace":"default"},"spec":{"containers":[{"image":"nginx","name":"demo","resources":{}}],"dnsPolicy":"ClusterFirst","restartPolicy":"Always"},"status":{}}
creationTimestamp: "2022-05-28T07:28:51Z"
labels:
run: demo
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
.: {}
f:kubectl.kubernetes.io/last-applied-configuration: {}
f:labels:
.: {}
f:run: {}
....
由这两个字段,引出本文的两位主角,Client-Side Apply(以下简称CSA)和Server-Side Apply(以下简称SSA)
- kubectl.kubernetes.io/last-applied-configuration是使用kubectl apply进行Client-Side Apply时,由kubectl自行填充的。
- managedFields 则是由kubectl apply的增强功能 Server-Side Apply 的引入而添加。
Client-Side Apply
kubectl apply是一种声明示的K8S对象管理方式,是我们最常用的应用部署,升级方式之一。
需要特别指出的是,kubectl apply声明的仅仅是它关心的字段的状态,而不是整个对象的真实状态。apply表达的意思是:此次提交管理的字段应该和apply的配置文件一致,其它字段并不关心。
比如首次部署时,K8S会将replicas值设置为默认1,随后由HPA控制器扩容到合适的副本数。
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: nginx
name: nginx
spec:
# replicas: 1 不要设置replicas
selector:
matchLabels:
app: nginx
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: nginx
spec:
containers:
- image: nginx:latest
name: nginx
resources: {}
当升级应用时(修改镜像版本),修改配置文件中的image字段,再次执行kubectl apply。此时kubectl apply只会影响镜像版本 ,而不会影响HPA控制器设置的副本数。在这个例子中,replicas字段不是kubectl apply管理的字段,因此更新镜像时不会被删除,避免了每次应用升级时,副本数都会被重置。
在上述例子中,为了能识别出replicas不是kubectl管理的字段,kubectl需要一个标识,用来追踪对象中哪些字段是由kubectl apply管理的,而这个标识就是last-applied-configuration。
该annotation是在kubectl apply时,由kubectl客户端自行填充——每次执行kubectl apply时(未启用SSA),kubectl会将本次apply的配置文件全量的记录在last-applied-configurationannotation中,用于追踪哪些字段由kubectl apply管理。
CSA工作工作机制:
Apply一个资源对象时,如果该对象不存在,则创建它(同时写入last-applied-configuration)。如果对象已经存在,则kubectl需要根据以下三个状态:
- 当前配置文件所表示的对象在集群中的真实状态。(修改对象前先Get一次)当前apply的配置。以及上次apply的配置。 (在last-applied-configuration里)。
- 当前apply的配置。
- 以及上次apply的配置。 (在last-applied-configuration里)
计算patch
通过patch方式进行更新(而不是将配置文件全量的发送到服务端)。patch报文的计算方法如下:
- 计算需要被删除的字段。如果字段存在在last-applied-configuration中,但配置文件中没有,将删除它们。
- 计算需要修改或添加的字段。如果配置文件中的字段与真实状态不一致,则添加或修改它们。
- 对于那些last-applied-configuration中不存在的字段,不要修改它们(例如上述示例中的replicas字段)。
CSA的合并策略
详细的patch计算示例可参考K8S文档中给出的详细示例。
由此可见,last-applied-configuration体现的是一种ownership的关系,表示哪些字段是由kubectl管理,它是kubectl apply时,计算patch报文的依据。
Server-Side Apply
Server-Side Apply 是另一种声明式的对象管理方式,和CSA的作用是基本一致的。SSA始于从1.14开始发布alpha版本,到1.16beta,到1.18beta2,终于在1.22升级为GA。
它协助用户、控制器通过声明式配置的方式管理他们的资源。 客户端可以发送完整描述的目标(A fully specified intent), 声明式地创建和修改对象。
顾名思义,SSA将对象合并的逻辑转移到了服务端(APIServer),客户端只需提交完整的配置文件,剩下的工作交给服务端处理。 在kubectl中使用SSA,只需在kubectl apply时加上--server-side参数即可,例如这样:
kubectl apply --server-side=true -f - <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: test-server-side-apply
data:
a: "a"
b: "b"
EOF
部署成功后,查看对象会发现该对象中不再存在之前CSA中的last-applied-configuration,取而代之的是metadata.managedFields。查看上面apply创建的资源:
apiVersion: v1
data:
a: a
b: b
kind: ConfigMap
metadata:
creationTimestamp: "2022-12-04T07:59:24Z"
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:data:
f:a: {}
f:b: {}
manager: kubectl
operation: Apply
time: "2022-12-04T07:59:24Z"
name: test-server-side-apply
namespace: default
resourceVersion: "1304750"
uid: d265df3d-b9e9-4d0f-91c2-e654f850d25a
字段管理(field management)机制追踪对象字段的变化。 当一个字段值改变时,其所有权从当前管理器(manager)转移到施加变更的管理器。 当尝试将新配置应用到一个对象时,如果字段有不同的值,且由其他管理器管理, 将会引发冲突。 冲突引发警告信号:此操作可能抹掉其他协作者的修改。 冲突可以被刻意忽略,这种情况下,值将会被改写,所有权也会发生转移。
SSA的合并策略
在介绍SSA的合并策略前,我们先了解一下CSA的合并策略。CSA的合并规则是基于Kubernetes的strategic merge patch方式,不同的字段类型分别有各自不同的合并策略,规则比较复杂。这也导致了CSA容易产生更多的Bug。SSA针对这个问题做了优化,相较于CSA,SSA定义了更加规范和准确的合并规则。 这里抄录文档中的一段表格加以说明:

SSA的优点
简化客户端逻辑,CSA是一个很重的客户端逻辑,里面有复杂的对象合并操作,这意味着apply这项操作和kubectl是深度绑定的,使用其他客户端或者在控制器(Controller)中难以使用apply方式来配置对象。而SSA将这些合并的逻辑转移到了服务端,提供单一的API,客户端实现方式得以简化。这让apply的能力得以整合到client-go中,让应用可以通过client-go来使用apply的能力。
更细粒度的字段所有权管理,减少错误覆盖配置的可能性
相比于last-applied-configuration,SSA使用managedFields来管理每个字段的ownership,这是一种更细粒度的字段管理方式。这使得多个管理者之间能更好的协作,且其自带冲突检测,能很大程度避免错误覆盖配置的发生。
当使用SSA时,dry-run的逻辑也放在服务端执行。相比CSA,服务端dry-run可以真实的经过validating/mutating admission webhooks的校验,从而获取最准确的返回结果。这是CSA无法实现的。
总之CSA和SSA是两种不同实现的声明示管理Kubernetes对象的方式。SSA的出现是为了解决了CSA中存在的一些挑战与问题,如apply逻辑和kubectl深度绑定、strategic merge patch复杂多bug等等。SSA发展至今已是Kubernetes中的一个关键特性,相信其最终的目标将会是完全取代CSA,成为Kubernetes中唯一的apply方式。
想打印k8s资源YAML结果搞懂了Client-Side & Server-Side Apply的更多相关文章
- 不想再被鄙视?那就看进来! 一文搞懂Python2字符编码
程序员都自视清高,觉得自己是创造者,经常鄙视不太懂技术的产品或者QA.可悲的是,程序员之间也相互鄙视,程序员的鄙视链流传甚广,作为一个Python程序员,自然最关心的是下面这幅图啦 我们项目组一值使用 ...
- java线程间通信:一个小Demo完全搞懂
版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.从一个小Demo说起 上篇我们聊到了Java多线程的同步 ...
- 一文搞懂容器运行时 Containerd
文章转载自:https://www.qikqiak.com/post/containerd-usage/ 在学习 Containerd 之前我们有必要对 Docker 的发展历史做一个简单的回顾,因为 ...
- 真正“搞”懂HTTP协议05之What's HTTP?
前面几篇文章,我从纵向的空间到横向的时间,再到一个具体的小栗子,可以说是全方位,无死角的覆盖了HTTP的大部分基本框架,但是我聊的都太宽泛了,很多内容都是一笔带过,再加上一句后面再说就草草结束了.并且 ...
- 真正“搞”懂http协议01—背景故事
去年读了<图解HTTP>.<图解TCP/IP>以及<图解网络硬件>但是读了之后并没有什么深刻的印象,只是有了一层模糊的脉络,刚好最近又接触了一些有关http的相关内 ...
- 搞懂分布式技术10:LVS实现负载均衡的原理与实践
搞懂分布式技术10:LVS实现负载均衡的原理与实践 浅析负载均衡及LVS实现 原创: fireflyc 写程序的康德 2017-09-19 负载均衡 负载均衡(Load Balance,缩写LB)是一 ...
- 搞懂分布式技术2:分布式一致性协议与Paxos,Raft算法
搞懂分布式技术2:分布式一致性协议与Paxos,Raft算法 2PC 由于BASE理论需要在一致性和可用性方面做出权衡,因此涌现了很多关于一致性的算法和协议.其中比较著名的有二阶提交协议(2 Phas ...
- Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!
本文原作者: Wizey,作者博客:http://wenshixin.gitee.io,即时通讯网收录时有改动,感谢原作者的无私分享. 1.引言 典型的Web端即时通讯技术应用场景,主要有以下两种形式 ...
- 后端技术杂谈9:先搞懂Docker核心概念吧
本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...
- 彻底搞懂 JS 中 this 机制
彻底搞懂 JS 中 this 机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.com/jasonGeng88/blog 目录 this 是什么 this 的四种绑定规 ...
随机推荐
- vs2019远程调试win7系统的程序
vs2019远程调试 一.安装vs2019远程调试工具 首先让调试的电脑(也就是不安装vs2019的电脑),安装vs2019远程调试工具:VS_RemoteTools.exe. 网址:进行下载.h ...
- 修改百分浏览器(centbrowser)、谷歌和火狐浏览器默认字体的方法
1,百分浏览器(centbrowser) 在浏览器的安装位置D:\Program Files\Cent Browser\User Data编辑文件custome.css,如果没有此文件可新建一个,内容 ...
- 用猿大师的VLC播放插件在高版本Chrome播放RTSP视频流,并抓图、录像、回放、倍速等
因为项目上需要把海康威视摄像头集成到WEB网页中播放,于是开始了对WEB播放摄像头方案的各种折腾. 2015年之前还可以用VLC原生播放器在Chrome.Firefox等浏览器中直接播放,延迟比较低, ...
- 《MySQL是怎样运行的》第二章小结
- VMware虚拟机迁移至Xen
1.VMware虚拟机导出OVF文件. 2.从Citrix Xencenter导入OVf文件 3.导入时,检查Local storage disk 下disk是否正确,如果曾导入失败,重复导入会产生多 ...
- 还不知道如何在java中终止一个线程?快来,一文给你揭秘
目录 简介 Thread.stop被禁用之谜 怎么才能安全? 捕获异常之后的处理 总结 简介 工作中我们经常会用到线程,一般情况下我们让线程执行就完事了,那么你们有没有想过如何去终止一个正在运行的线程 ...
- Available parameters are [arg0, collection, list]错误的解决
关于这个错误 每次只要是俩list集合一嵌套起来,就会报出这个错误,检查过,并不是关键字的误用: 这个才是根本原因: 当mybatis传入参数为list集合的时候:mybatis会自动把其封装为一个m ...
- 63.C++类型转换
类型转换(cast)是将一种数据类型转换成另一种数据类型.例如,如果将一个整型值赋给一个浮点类型的变量,编译器会暗地里将其转换成浮点类型. 转换是非常有用的,但是它也会带来一些问题,比如在转换 ...
- Revit BIM模型在ArcGIS Pro中的数据组织及转换成SLPK后的图层结构解析
ArcGIS Pro对Revit 数据有自己的一套分层方式. 在ArcGIS Pro中打开bim文件会发现都是按照相同的方式组织数据: 将rvt格式数据转换成SLPK格式后的数据结构(将slpk数据直 ...
- Vim基本使用方法来啦
一.Vim是什么 Vim是一个高度可配置的文本编辑器,用于创建和更改任何类型的文本非常高效.与大多数UNIX系统和Apple OS X一起,它被包含为"vi".Vim是稳定的,并且 ...