From e10996a1d7faf183993077388ec7b67adc0daafb Mon Sep 17 00:00:00 2001 From: Qiming Teng Date: Wed, 9 Jun 2021 19:06:44 +0800 Subject: [PATCH] [zh] Resync server-side-apply page --- .../reference/using-api/server-side-apply.md | 167 ++++++++++++++---- 1 file changed, 132 insertions(+), 35 deletions(-) diff --git a/content/zh/docs/reference/using-api/server-side-apply.md b/content/zh/docs/reference/using-api/server-side-apply.md index 207f8b0796..aa0b3fef20 100644 --- a/content/zh/docs/reference/using-api/server-side-apply.md +++ b/content/zh/docs/reference/using-api/server-side-apply.md @@ -5,7 +5,6 @@ weight: 25 min-kubernetes-server-version: 1.16 --- @@ -25,15 +23,15 @@ min-kubernetes-server-version: 1.16 ## 简介 {#introduction} 服务器端应用协助用户、控制器通过声明式配置的方式管理他们的资源。 -它发送完整描述的目标(A fully specified intent), +客户端可以发送完整描述的目标(A fully specified intent), 声明式地创建和/或修改 [对象](/zh/docs/concepts/overview/working-with-objects/kubernetes-objects/)。 @@ -84,7 +82,7 @@ Server side apply is meant both as a replacement for the original `kubectl apply` and as a simpler mechanism for controllers to enact their changes. If you have Server Side Apply enabled, the control plane tracks managed fields -for all newlly created objects. +for all newly created objects. --> 服务器端应用既是原有 `kubectl apply` 的替代品, 也是控制器发布自身变化的一个简化机制。 @@ -133,7 +131,7 @@ the appliers, results in a conflict. Shared field owners may give up ownership of a field by removing it from their configuration. Field management is stored in a`managedFields` field that is part of an object's -[`metadata`](/docs/reference/generated/kubernetes-api/{{< latest-version >}}/#objectmeta-v1-meta). +[`metadata`](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#objectmeta-v1-meta). A simple example of an object created by Server Side Apply could look like this: --> @@ -142,7 +140,8 @@ A simple example of an object created by Server Side Apply could look like this: 共享字段的所有者可以放弃字段的所有权,这只需从配置文件中删除该字段即可。 字段管理的信息存储在 `managedFields` 字段中,该字段是对象的 -[`metadata`](/docs/reference/generated/kubernetes-api/{{< latest-version >}}/#objectmeta-v1-meta)中的一部分。 +[`metadata`](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#objectmeta-v1-meta) +中的一部分。 服务器端应用创建对象的简单示例如下: @@ -356,15 +355,14 @@ would have failed due to conflicting ownership. The merging strategy, implemented with Server Side Apply, provides a generally more stable object lifecycle. Server Side Apply tries to merge fields based on -the fact who manages them instead of overruling just based on values. This way -it is intended to make it easier and more stable for multiple actors updating -the same object by causing less unexpected interference. +the actor who manages them instead of overruling based on values. This way +multiple actors can update the same object without causing unexpected interference. --> ## 合并策略 {#merge-strategy} 由服务器端应用实现的合并策略,提供了一个总体更稳定的对象生命周期。 -服务器端应用试图依据谁管理它们来合并字段,而不只是根据值来否决。 -这么做是为了多个参与者可以更简单、更稳定的更新同一个对象,且避免引起意外干扰。 +服务器端应用试图依据负责管理它们的主体来合并字段,而不是根据值来否决。 +这么做是为了多个主体可以更新同一个对象,且不会引起意外的相互干扰。 Kubernetes 1.16 和 1.17 中添加了一些标记, @@ -399,18 +397,116 @@ Kubernetes 1.16 和 1.17 中添加了一些标记, | Golang 标记 | OpenAPI extension | 可接受的值 | 描述 | 引入版本 | |---|---|---|---|---| -| `//+listType` | `x-kubernetes-list-type` | `atomic`/`set`/`map` | 适用于 list。 `atomic` 和 `set` 适用于只包含标量元素的 list。 `map` 适用于只包含嵌套类型的 list。 如果配置为 `atomic`, 合并时整个列表会被替换掉; 任何时候,唯一的管理器都把列表作为一个整体来管理。如果是 `set` 或 `map` ,不同的管理器也可以分开管理条目。 | 1.16 | -| `//+listMapKey` | `x-kubernetes-list-map-keys` | 用来唯一标识条目的 map keys 切片,例如 `["port", "protocol"]` | 仅当 `+listType=map` 时适用。组合值的字符串切片必须唯一标识列表中的条目。尽管有多个 key,`listMapKey` 是单数的,这是因为 key 需要在 Go 类型中单独的指定。 | 1.16 | +| `//+listType` | `x-kubernetes-list-type` | `atomic`/`set`/`map` | 适用于 list。`set` 适用于仅包含标量元素的列表。这些元素必须是不重复的。`map` 仅适用于包含嵌套类型的列表。列表中的键(参见 `listMapKey`)不可以重复。`atomic` 适用于任何类型的列表。如果配置为 `atomic`,则合并时整个列表会被替换掉。任何时候,只有一个管理器负责管理指定列表。如果配置为 `set` 或 `map`,不同的管理器也可以分开管理条目。 | 1.16 | +| `//+listMapKey` | `x-kubernetes-list-map-keys` | 字段名称的列表,例如,`["port", "protocol"]` | 仅当 `+listType=map` 时适用。取值为字段名称的列表,这些字段值的组合能够唯一标识列表中的条目。尽管可以存在多个键,`listMapKey` 是单数的,这是因为键名需要在 Go 类型中各自独立指定。键字段必须是标量。 | 1.16 | | `//+mapType` | `x-kubernetes-map-type` | `atomic`/`granular` | 适用于 map。 `atomic` 指 map 只能被单个的管理器整个的替换。 `granular` 指 map 支持多个管理器各自更新自己的字段。 | 1.17 | | `//+structType` | `x-kubernetes-map-type` | `atomic`/`granular` | 适用于 structs;否则就像 `//+mapType` 有相同的用法和 openapi 注释.| 1.17 | + +若未指定 `listType`,API 服务器将 `patchMergeStrategy=merge` 标记解释为 +`listType=map` 并且视对应的 `patchMergeKey` 标记为 `listMapKey` 取值。 + +`atomic` 列表类型是递归的。 + +这些标记都是用源代码注释的方式给出的,不必作为字段标签(tag)再重复。 + + +### 拓扑变化时的兼容性 {#compatibility-across-toplogy-changes} + + +在极少的情况下,CRD 或者内置类型的作者可能希望更改其资源中的某个字段的 +拓扑配置,同时又不提升版本号。 +通过升级集群或者更新 CRD 来更改类型的拓扑信息与更新现有对象的结果不同。 +变更的类型有两种:一种是将字段从 `map`/`set`/`granular` 更改为 `atomic`, +另一种是做逆向改变。 + + +当 `listType`、`mapType` 或 `structType` 从 `map`/`set`/`granular` 改为 +`atomic` 时,现有对象的整个列表、映射或结构的属主都会变为这些类型的 +元素之一的属主。这意味着,对这些对象的进一步变更会引发冲突。 + + +当一个列表、映射或结构从 `atomic` 改为 `map`/`set`/`granular` 之一 +时,API 服务器无法推导这些字段的新的属主。因此,当对象的这些字段 +再次被更新时不会引发冲突。出于这一原因,不建议将某类型从 `atomic` 改为 +`map`/`set`/`granular`。 + +以下面的自定义资源为例: + +```yaml +apiVersion: example.com/v1 +kind: Foo +metadata: + name: foo-sample + managedFields: + - manager: manager-one + operation: Apply + apiVersion: example.com/v1 + fields: + f:spec: + f:data: {} +spec: + data: + key1: val1 + key2: val2 +``` + + +在 `spec.data` 从 `atomic` 改为 `granular` 之前,`manager-one` 是 +`spec.data` 字段及其所包含字段(`key1` 和 `key2`)的属主。 +当对应的 CRD 被更改,使得 `spec.data` 变为 `granular` 拓扑时, +`manager-one` 继续拥有顶层字段 `spec.data`(这意味着其他管理者想 +删除名为 `data` 的映射而不引起冲突是不可能的),但不再拥有 +`key1` 和 `key2`。因此,其他管理者可以在不引起冲突的情况下更改 +或删除这些字段。 + -### 在控制器中使用服务器端应用 {#using-server-side-apply-in-controller} +## 在控制器中使用服务器端应用 {#using-server-side-apply-in-controller} 控制器的开发人员可以把服务器端应用作为简化控制器的更新逻辑的方式。 读-改-写 和/或 patch 的主要区别如下所示: @@ -463,7 +559,7 @@ might not be able to resolve or act on these conflicts. 强烈推荐:设置控制器在冲突时强制执行,这是因为冲突发生时,它们没有其他解决方案或措施。 -### 转移所有权 {#transferring-ownership} +## 转移所有权 {#transferring-ownership} 除了通过[冲突解决方案](#conflicts)提供的并发控制, 服务器端应用提供了一些协作方式来将字段所有权从用户转移到控制器。 @@ -526,7 +622,7 @@ is not what the user wants to happen, even temporarily. 这里有两个解决方案: -- (容易) 把 `replicas` 留在配置文件中;当 HPA 最终写入那个字段, +- (基本操作)把 `replicas` 留在配置文件中;当 HPA 最终写入那个字段, 系统基于此事件告诉用户:冲突发生了。在这个时间点,可以安全的删除配置文件。 -- (高级)然而,如果用户不想等待,比如他们想为合作伙伴保持集群清晰, +- (高级操作)然而,如果用户不想等待,比如他们想为合作伙伴保持集群清晰, 那他们就可以执行以下步骤,安全的从配置文件中删除 `replicas`。 首先,用户新定义一个只包含 `replicas` 字段的配置文件: @@ -561,13 +657,13 @@ kubectl apply -f https://k8s.io/examples/application/ssa/nginx-deployment-replic 如果应用操作和 HPA 控制器产生冲突,那什么都不做。 -冲突只是表明控制器在更早的流程中已经对字段声明过所有权。 +冲突表明控制器在更早的流程中已经对字段声明过所有权。 在此时间点,用户可以从配置文件中删除 `replicas` 。 @@ -583,7 +679,7 @@ automatically deleted. No clean up is required. 这里不需要执行清理工作。 -## 在用户之间转移所有权 {#transferring-ownership-between-users} +### 在用户之间转移所有权 {#transferring-ownership-between-users} 通过在配置文件中把一个字段设置为相同的值,用户可以在他们之间转移字段的所有权, 从而共享了字段的所有权。 @@ -763,7 +859,7 @@ Data: [{"op": "replace", "path": "/metadata/managedFields", "value": [{}]}] -这一操作将用只包含一个空条目的 list 覆写 managedFields, +这一操作将用只包含一个空条目的列表覆写 managedFields, 来实现从对象中整个的去除 managedFields。 -注意,只把 managedFields 设置为空 list 并不会重置字段。 +注意,只把 managedFields 设置为空列表并不会重置字段。 这么做是有目的的,所以 managedFields 将永远不会被与该字段无关的客户删除。 在重置操作结合 managedFields 以外其他字段更改的场景中, @@ -804,7 +900,8 @@ should have the same flag setting. --> ## 禁用此功能 {#disabling-the-feature} -服务器端应用是一个 beta 版特性,默认启用。 +服务器端应用是一个 Beta 版特性,默认启用。 要关闭此[特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates), 你需要在启动 `kube-apiserver` 时包含参数 `--feature-gates ServerSideApply=false`。 -如果你有多个 `kube-apiserver` 副本,他们都应该有相同的标记设置。 \ No newline at end of file +如果你有多个 `kube-apiserver` 副本,它们的标志设置应该都相同。 +