想打印k8s资源YAML结果搞懂了Client-Side & Server-Side Apply

科技资讯 投稿 7100 0 评论

想打印k8s资源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(

效果:

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自行填充的。
  1. managedFields 则是由kubectl apply的增强功能 Server-Side Apply 的引入而添加。

Client-Side Apply

需要特别指出的是,kubectl apply声明的仅仅是它关心的字段的状态,而不是整个对象的真实状态。apply表达的意思是:此次提交管理的字段应该和apply的配置文件一致,其它字段并不关心。

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管理的字段,因此更新镜像时不会被删除,避免了每次应用升级时,副本数都会被重置。

该annotation是在kubectl apply时,由kubectl客户端自行填充——每次执行kubectl apply时(未启用SSA),kubectl会将本次apply的配置文件全量的记录在last-applied-configurationannotation中,用于追踪哪些字段由kubectl apply管理。

CSA工作工作机制:

    当前配置文件所表示的对象在集群中的真实状态。(修改对象前先Get一次)当前apply的配置。以及上次apply的配置。 (在last-applied-configuration里)。
  • 当前apply的配置。
  • 以及上次apply的配置。 (在last-applied-configuration里)

计算patch

通过patch方式进行更新(而不是将配置文件全量的发送到服务端)。patch报文的计算方法如下:

    计算需要被删除的字段。如果字段存在在last-applied-configuration中,但配置文件中没有,将删除它们。
  1. 计算需要修改或添加的字段。如果配置文件中的字段与真实状态不一致,则添加或修改它们。
  2. 对于那些last-applied-configuration中不存在的字段,不要修改它们(例如上述示例中的replicas字段)。

CSA的合并策略

由此可见,last-applied-configuration体现的是一种ownership的关系,表示哪些字段是由kubectl管理,它是kubectl apply时,计算patch报文的依据。

Server-Side Apply

它协助用户、控制器通过声明式配置的方式管理他们的资源。 客户端可以发送完整描述的目标(A fully specified intent), 声明式地创建和修改对象。

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的优点

更细粒度的字段所有权管理,减少错误覆盖配置的可能性

当使用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

赞同 (34) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽