前言

由于查看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 annotationmanagedFields 这两个字段,并不是我们手写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)

  1. kubectl.kubernetes.io/last-applied-configuration是使用kubectl apply进行Client-Side Apply时,由kubectl自行填充的。
  2. 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报文的计算方法如下:

  1. 计算需要被删除的字段。如果字段存在在last-applied-configuration中,但配置文件中没有,将删除它们。
  2. 计算需要修改或添加的字段。如果配置文件中的字段与真实状态不一致,则添加或修改它们。
  3. 对于那些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的更多相关文章

  1. 不想再被鄙视?那就看进来! 一文搞懂Python2字符编码

    程序员都自视清高,觉得自己是创造者,经常鄙视不太懂技术的产品或者QA.可悲的是,程序员之间也相互鄙视,程序员的鄙视链流传甚广,作为一个Python程序员,自然最关心的是下面这幅图啦 我们项目组一值使用 ...

  2. java线程间通信:一个小Demo完全搞懂

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.从一个小Demo说起 上篇我们聊到了Java多线程的同步 ...

  3. 一文搞懂容器运行时 Containerd

    文章转载自:https://www.qikqiak.com/post/containerd-usage/ 在学习 Containerd 之前我们有必要对 Docker 的发展历史做一个简单的回顾,因为 ...

  4. 真正“搞”懂HTTP协议05之What's HTTP?

    前面几篇文章,我从纵向的空间到横向的时间,再到一个具体的小栗子,可以说是全方位,无死角的覆盖了HTTP的大部分基本框架,但是我聊的都太宽泛了,很多内容都是一笔带过,再加上一句后面再说就草草结束了.并且 ...

  5. 真正“搞”懂http协议01—背景故事

    去年读了<图解HTTP>.<图解TCP/IP>以及<图解网络硬件>但是读了之后并没有什么深刻的印象,只是有了一层模糊的脉络,刚好最近又接触了一些有关http的相关内 ...

  6. 搞懂分布式技术10:LVS实现负载均衡的原理与实践

    搞懂分布式技术10:LVS实现负载均衡的原理与实践 浅析负载均衡及LVS实现 原创: fireflyc 写程序的康德 2017-09-19 负载均衡 负载均衡(Load Balance,缩写LB)是一 ...

  7. 搞懂分布式技术2:分布式一致性协议与Paxos,Raft算法

    搞懂分布式技术2:分布式一致性协议与Paxos,Raft算法 2PC 由于BASE理论需要在一致性和可用性方面做出权衡,因此涌现了很多关于一致性的算法和协议.其中比较著名的有二阶提交协议(2 Phas ...

  8. Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!

    本文原作者: Wizey,作者博客:http://wenshixin.gitee.io,即时通讯网收录时有改动,感谢原作者的无私分享. 1.引言 典型的Web端即时通讯技术应用场景,主要有以下两种形式 ...

  9. 后端技术杂谈9:先搞懂Docker核心概念吧

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  10. 彻底搞懂 JS 中 this 机制

    彻底搞懂 JS 中 this 机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.com/jasonGeng88/blog 目录 this 是什么 this 的四种绑定规 ...

随机推荐

  1. vuforia 打包IOS 第一次启动正常, 删掉过程重新启动初始化失败。

    我使用的是2019.4.17版本,降级到2019.2.17问题解决

  2. NX二次开发获取NX主程序路径

    //头文件 #include <Windows.h> #include <iostream> #include <NXOpen/ListingWindow.hxx> ...

  3. swiper常见问题、动态加载数据问题

    swiper加载静态文件是没有问题的 swiper加载动态文件需要在请求后再加载这个函数 参考链接:  https://blog.csdn.net/webzrh/article/details/781 ...

  4. springboot-项目获取resources下文件

    背景: 项目的resources 目录下放置了一份txt文件,需求是想获取到这份文件转成File对象,调用文件上传的接口进行文件上传操作. 实现: 1.使用 ResourceUtils:本地ok,测试 ...

  5. 一文读懂字符编码ASCII、Unicode与UTF-8

    先说一下,为什么写这篇文章? 最近在写一个Http协议栈当涉及CRLF控制字符写入时,发现自己对CRLF与\r\n的关系不太了解,因此决定详细学习一下:查阅资料的同时,又遇到UTF-8与ASCII编码 ...

  6. Python练习--简单练习(一看就能写出来的代码)

    两数之和 数字的阶乘 求圆的面积 (输入半径,求解圆的面积) 求区间内所有素数的和 求前N个数字的平方和

  7. 在CentOS中搭建NFS

    概述 NFS是一款经典的网络文件系统,在Linux上我们可以通过创建一个NFS服务在不同的服务器之间共享磁盘文件,而不用在多个服务器之间进行不断的拷贝复制,麻烦且浪费存储空间.在k8s中我们也可以使用 ...

  8. jmeter关于常用取样器的设置

      常用创建操作   1.线程组:测试计划(右键)-->线程(用户)-->线程组   2.http请求:线程组(右键)-->取样器-->http请求   3.察看结果树:线程组 ...

  9. Windows下解决python pip命令下载慢的方法(超简单)

    首先,常用的国内镜像: 1 https://pypi.tuna.tsinghua.edu.cn/simple/ 清华大学(推荐) 2 http://pypi.douban.com/simple/ 豆瓣 ...

  10. 遗传算法(启发式算法)—R实现

    遗传算法 遗传算法(Genetic Algorithm,GA)最早是由美国的 John holland于20世纪70年代提出,该算法是根据大自然中生物体进化规律而设计提出的.是模拟达尔文生物进化论的自 ...