小言_互联网的博客

云原生 | Kubernetes - apply 操作是如何计算配置差异并合并变更的?

318人阅读  评论(0)

目录

合并补丁计算

不同类型字段的合并方式

合并对基本类型字段的更新

合并对 map 字段的变更

合并 list 类型字段的变更 

如果 list 中元素都是基本类型则替换整个 list

如果 list 中元素为复合类型则逐个执行合并

合并基本类型元素 list 


注意: patch 是一种更新操作,其作用域为对象的一些特定字段而不是整个对象。 这使得你可以更新对象的特定字段集合而不必先要读回对象。

kubectl apply 更新对象的现时配置,它是通过向 API 服务器发送一个 patch 请求 来执行更新动作的。 所提交的补丁中定义了对现时对象配置中特定字段的更新。 kubectl apply 命令会使用当前的配置文件、现时配置以及现时配置中保存的 last-applied-configuration 注解内容来计算补丁更新内容。

合并补丁计算

kubectl apply 命令将配置文件的内容写入到 kubectl.kubernetes.io/last-applied-configuration 注解中。 这些内容用来识别配置文件中已经移除的、因而也需要从现时配置中删除的字段。 用来计算要删除或设置哪些字段的步骤如下:

  1. 计算要删除的字段,即在 last-applied-configuration 中存在但在 配置文件中不再存在的字段。
  2. 计算要添加或设置的字段,即在配置文件中存在但其取值与现时配置不同的字段。

下面是一个例子。假定此文件是某 Deployment 对象的配置文件:


  
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: nginx-deployment
  5. spec:
  6. selector:
  7. matchLabels:
  8. app: nginx
  9. template:
  10. metadata:
  11. labels:
  12. app: nginx
  13. spec:
  14. containers:
  15. - name: nginx
  16. image: nginx:1.16.1 # 更新该镜像
  17. ports:
  18. - containerPort: 80

同时假定同一 Deployment 对象的现时配置如下:


  
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. annotations:
  5. # ...
  6. kubectl.kubernetes.io/last-applied-configuration: |
  7. { "apiVersion": "apps/v1", "kind": "Deployment",
  8. "metadata":{ "annotations":{}, "name": "nginx-deployment", "namespace": "default"},
  9. "spec":{ "minReadySeconds":5, "selector":{ "matchLabels":{ "app":nginx}}, "template":{ "metadata":{ "labels":{ "app": "nginx"}},
  10. "spec":{ "containers":[{ "image": "nginx:1.14.2", "name": "nginx",
  11. "ports":[{ "containerPort":80}]}]}}}}
  12. # ...
  13. spec:
  14. replicas: 2
  15. # ...
  16. minReadySeconds: 5
  17. selector:
  18. matchLabels:
  19. # ...
  20. app: nginx
  21. template:
  22. metadata:
  23. # ...
  24. labels:
  25. app: nginx
  26. spec:
  27. containers:
  28. - image: nginx:1.14.2
  29. # ...
  30. name: nginx
  31. ports:
  32. - containerPort: 80
  33. # ...

下面是 kubectl apply 将执行的合并计算:

  1. 通过读取 last-applied-configuration 并将其与配置文件中的值相比较, 计算要删除的字段。 对于本地对象配置文件中显式设置为空的字段,清除其在现时配置中的设置, 无论这些字段是否出现在 last-applied-configuration 中。 在此例中,minReadySeconds 出现在 last-applied-configuration 注解中,但 并不存在于配置文件中。 动作: 从现时配置中删除 minReadySeconds 字段。
  2. 通过读取配置文件中的值并将其与现时配置相比较,计算要设置的字段。 在这个例子中,配置文件中的 image 值与现时配置中的 image 不匹配。 动作:设置现时配置中的 image 值。
  3. 设置 last-applied-configuration 注解的内容,使之与配置文件匹配。
  4. 将第 1、2、3 步骤得出的结果合并,构成向 API 服务器发送的补丁请求内容。

下面是此合并操作之后形成的现时配置:


  
  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. annotations:
  5. # ...
  6. # 注解中包含更新后的 image,nginx 1.11.9,
  7. # 但不包含更新后的 replicas
  8. kubectl.kubernetes.io/last-applied-configuration: |
  9. { "apiVersion": "apps/v1", "kind": "Deployment",
  10. "metadata":{ "annotations":{}, "name": "nginx-deployment", "namespace": "default"},
  11. "spec":{ "selector":{ "matchLabels":{ "app":nginx}}, "template":{ "metadata":{ "labels":{ "app": "nginx"}},
  12. "spec":{ "containers":[{ "image": "nginx:1.16.1", "name": "nginx",
  13. "ports":[{ "containerPort":80}]}]}}}}
  14. # ...
  15. spec:
  16. selector:
  17. matchLabels:
  18. # ...
  19. app: nginx
  20. replicas: 2
  21. # minReadySeconds 此字段被清除
  22. # ...
  23. template:
  24. metadata:
  25. # ...
  26. labels:
  27. app: nginx
  28. spec:
  29. containers:
  30. - image: nginx:1.16.1
  31. # ...
  32. name: nginx
  33. ports:
  34. - containerPort: 80
  35. # ...
  36. # ...
  37. # ...
  38. # ...

不同类型字段的合并方式

配置文件中的特定字段与现时配置合并时,合并方式取决于字段类型。 字段类型有几种:

  • 基本类型:字段类型为 stringinteger 或 boolean 之一。 例如:image 和 replicas 字段都是基本类型字段。

    动作: 替换。

  • map:也称作 object。类型为 map 或包含子域的复杂结构。例如,labels、 annotationsspec 和 metadata 都是 map。

    动作: 合并元素或子字段。

  • list:包含元素列表的字段,其中每个元素可以是基本类型或 map。 例如,containersports 和 args 都是 list。

    动作: 不一定。

当 kubectl apply 更新某个 map 或 list 字段时,它通常不会替换整个字段,而是会 更新其中的各个子元素。例如,当合并 Deployment 的 spec 时,kubectl 并不会 将其整个替换掉。相反,实际操作会是对 replicas 这类 spec 的子字段来执行比较和更新。


合并对基本类型字段的更新

基本类型字段会被替换或清除。

说明: - 表示的是“不适用”,因为指定数值未被使用。

字段在对象配置文件中 字段在现时对象配置中 字段在 last-applied-configuration 中 动作
- 将配置文件中值设置到现时配置上。
- 将配置文件中值设置到现时配置上。
- 从现时配置中移除。
- 什么也不做。保持现时值。

合并对 map 字段的变更

用来表示映射的字段在合并时会逐个子字段或元素地比较:

说明: - 表示的是“不适用”,因为指定数值未被使用。

键存在于对象配置文件中 键存在于现时对象配置中 键存在于 last-applied-configuration 中 动作
- 比较子域取值。
- 将现时配置设置为本地配置值。
- 从现时配置中删除键。
- 什么也不做,保留现时值。

合并 list 类型字段的变更 

对 list 类型字段的变更合并会使用以下三种策略之一:

  • 如果 list 所有元素都是基本类型则替换整个 list。
  • 如果 list 中元素是复合结构则逐个元素执行合并操作。
  • 合并基本类型元素构成的 list。

策略的选择是基于各个字段做出的。

如果 list 中元素都是基本类型则替换整个 list

将整个 list 视为一个基本类型字段。或者整个替换或者整个删除。 此操作会保持 list 中元素顺序不变

示例: 使用 kubectl apply 来更新 Pod 中 Container 的 args 字段。此操作会 将现时配置中的 args 值设为配置文件中的值。 所有之前添加到现时配置中的 args 元素都会丢失。 配置文件中的 args 元素的顺序在被添加到现时配置中时保持不变。


  
  1. # last-applied-configuration 值
  2. args: [ "a", "b"]
  3. # 配置文件值
  4. args: [ "a", "c"]
  5. # 现时配置
  6. args: [ "a", "b", "d"]
  7. # 合并结果
  8. args: [ "a", "c"]

合并操作将配置文件中的值当做新的 list 值。

如果 list 中元素为复合类型则逐个执行合并

此操作将 list 视为 map,并将每个元素中的特定字段当做其主键。 逐个元素地执行添加、删除或更新操作。结果顺序无法得到保证。

此合并策略会使用每个字段上的一个名为 patchMergeKey 的特殊标签。 Kubernetes 源代码中为每个字段定义了 patchMergeKey: types.go 当合并由 map 组成的 list 时,给定元素中被设置为 patchMergeKey 的字段会被 当做该元素的 map 键值来使用。

例如: 使用 kubectl apply 来更新 Pod 规约中的 containers 字段。 此操作会将 containers 列表视作一个映射来执行合并,每个元素的主键为 name


  
  1. # last-applied-configuration 值
  2. containers:
  3. - name: nginx
  4. image: nginx: 1.16
  5. - name: nginx-helper-a # 键 nginx-helper-a 会被删除
  6. image: helper: 1.3
  7. - name: nginx-helper-b # 键 nginx-helper-b 会被保留
  8. image: helper: 1.3
  9. # 配置文件值
  10. containers:
  11. - name: nginx
  12. image: nginx: 1.16
  13. - name: nginx-helper-b
  14. image: helper: 1.3
  15. - name: nginx-helper-c # 键 nginx-helper-c 会被添加
  16. image: helper: 1.3
  17. # 现时配置
  18. containers:
  19. - name: nginx
  20. image: nginx: 1.16
  21. - name: nginx-helper-a
  22. image: helper: 1.3
  23. - name: nginx-helper-b
  24. image: helper: 1.3
  25. args: [ "run"] # 字段会被保留
  26. - name: nginx-helper-d # 键 nginx-helper-d 会被保留
  27. image: helper: 1.3
  28. # 合并结果
  29. containers:
  30. - name: nginx
  31. image: nginx: 1.16
  32. # 元素 nginx-helper-a 被删除
  33. - name: nginx-helper-b
  34. image: helper: 1.3
  35. args: [ "run"] # 字段被保留
  36. - name: nginx-helper-c # 新增元素
  37. image: helper: 1.3
  38. - name: nginx-helper-d # 此元素被忽略(保留)
  39. image: helper: 1.3

解释:

  • 名为 "nginx-helper-a" 的容器被删除,因为配置文件中不存在同名的容器。
  • 名为 "nginx-helper-b" 的容器的现时配置中的 args 被保留。 kubectl apply 能够辩识出现时配置中的容器 "nginx-helper-b" 与配置文件 中的容器 "nginx-helper-b" 相同,即使它们的字段值有些不同(配置文件中未给定 args 值)。这是因为 patchMergeKey 字段(name)的值在两个版本中都一样。
  • 名为 "nginx-helper-c" 的容器是新增的,因为在配置文件中的这个容器尚不存在 于现时配置中。
  • 名为 "nginx-helper-d" 的容器被保留下来,因为在 last-applied-configuration 中没有与之同名的元素。

合并基本类型元素 list 

在 Kubernetes 1.5 中,尚不支持对由基本类型元素构成的 list 进行合并。

说明: 选择上述哪种策略是由源码中给定字段的 patchStrategy 标记来控制的: types.go 如果 list 类型字段未设置 patchStrategy,则整个 list 会被替换掉。



转载:https://blog.csdn.net/Trollz/article/details/128312857
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场