diff --git a/content/zh/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning.md b/content/zh/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning.md index c479dce83f..9a03e0f89e 100644 --- a/content/zh/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning.md +++ b/content/zh/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning.md @@ -1,5 +1,5 @@ --- -title: 用户自定义资源的版本 +title: CustomResourceDefinition 的版本 content_type: task weight: 30 min-kubernetes-server-version: v1.16 @@ -21,8 +21,9 @@ This page explains how to add versioning information to level of your CustomResourceDefinitions or advance your API to a new version with conversion between API representations. It also describes how to upgrade an object from one version to another. --> 本页介绍如何添加版本信息到 -[CustomResourceDefinitions](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#customresourcedefinition-v1beta1-apiextensions), -如何表示 CustomResourceDefinitions 的稳定水平或者用 API 之间的表征的转换提高您的 API 到一个新的版本。 +[CustomResourceDefinitions](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#customresourcedefinition-v1beta1-apiextensions)。 +目的是标明 CustomResourceDefinitions 的稳定级别或者服务于 API 升级。 +API 升级时需要在不同 API 表示形式之间进行转换。 本页还描述如何将对象从一个版本升级到另一个版本。 ## {{% heading "prerequisites" %}} @@ -32,7 +33,7 @@ level of your CustomResourceDefinitions or advance your API to a new version wit -你应该对[自定义资源](/zh/docs/concepts/extend-kubernetes/api-extension/custom-resources/) +你应该对[定制资源](/zh/docs/concepts/extend-kubernetes/api-extension/custom-resources/) 有一些初步了解。 {{< version-check >}} @@ -41,10 +42,7 @@ You should have a initial understanding of [custom resources](/docs/concepts/ext -## 概览 - -CustomResourceDefinition API 提供了用于引入和升级的工作流程到 CustomResourceDefinition 的新版本。 +## 概览 -创建 CustomResourceDefinition 时,会在 CustomResourceDefinition `spec.versions` 列表设置适当的稳定级和版本号。例如`v1beta1`表示第一个版本尚未稳定。所有自定义资源对象将首先存储在这个版本 +CustomResourceDefinition API 提供了用于引入和升级的工作流程到 CustomResourceDefinition +的新版本。 -创建 CustomResourceDefinition 后,客户端可以开始使用 v1beta1 API。 +创建 CustomResourceDefinition 时,会在 CustomResourceDefinition `spec.versions` +列表设置适当的稳定级别和版本号。例如,`v1beta1` 表示第一个版本尚未稳定。 +所有定制资源对象将首先用这个版本保存。 -稍后可能需要添加新版本,例如 v1。 +创建 CustomResourceDefinition 后,客户端可以开始使用 `v1beta1` API。 + +稍后可能需要添加新版本,例如 `v1`。 -增加一个新版本: +添加新版本: -1. 选择一种转化策略。由于自定义资源对象需要能够两种版本都可用,这意味着它们有时会以与存储版本不同的版本。为了能够做到这一点, - 有时必须在它们存储的版本和提供的版本。如果转换涉及结构变更,并且需要自定义逻辑,转换应该使用 webhook。如果没有结构变更, - 则使用 None 默认转换策略,不同版本时只有`apiVersion`字段有变更。 -2. 如果使用转换 Webhook,请创建并部署转换 Webhook。希望看到更多详细信息,请参见 [Webhook conversion](#webhook转换)。 -3. 更新 CustomResourceDefinition,来将新版本包含在具有`served:true`的 spec.versions 列表。另外,设置`spec.conversion`字段 - 到所选的转换策略。如果使用转换 Webhook,请配置`spec.conversion.webhookClientConfig`来调用 webhook。 +1. 选择一种转化策略。由于定制资源对象需要能够两种版本都可用, + 这意味着它们有时会以与存储版本不同的版本来提供服务。为了能够做到这一点, + 有时必须在它们存储的版本和提供的版本之间进行转换。如果转换涉及模式变更, + 并且需要自定义逻辑,则应该使用 Webhook 来完成。如果没有模式变更, + 则可使用默认的 `None` 转换策略,为不同版本提供服务时只有 `apiVersion` 字段 + 会被改变。 +2. 如果使用转换 Webhook,请创建并部署转换 Webhook。更多详细信息请参见 + [Webhook conversion](#webhook-conversion)。 +3. 更新 CustomResourceDefinition,将新版本设置为 `served:true`,加入到 + `spec.versions` 列表。另外,还要设置 `spec.conversion` 字段 + 为所选的转换策略。如果使用转换 Webhook,请配置 + `spec.conversion.webhookClientConfig` 来调用 Webhook。 +添加新版本后,客户端可以逐步迁移到新版本。让某些客户使用旧版本的同时 +支持其他人使用新版本是相当安全的。 +将存储的对象迁移到新版本: + + -添加新版本后,客户端可以逐步迁移到新版本。对于某些客户而言,在使用旧版本的同时支持其他人使用新版本。 -将存储的对象迁移到新版本: +1. 请参阅[将现有对象升级到新的存储版本](#upgrade-existing-objects-to-a-new-stored-version)节。 -1. 请参阅 [将现有对象升级到新的存储版本](#将现有对象升级到新的存储版本) 章节。 - -对于客户来说,在将对象升级到新的存储版本之前,期间和之后使用旧版本和新版本都是安全的。 +对于客户来说,在将对象升级到新的存储版本之前、期间和之后使用旧版本和新版本都是安全的。 删除旧版本: -1. 确保所有客户端都已完全迁移到新版本。kube-apiserver 可以查看日志以帮助识别仍通过进行访问的所有客户端旧版本。 -2. 在`spec.versions`列表中将旧版本的 served 设置为 false。如果任何客户端仍然意外地使用他们可能开始报告的旧版本尝试访问旧版本的自定义资源对象时出错。 - 如果发生这种情况,请切换回在旧版本上使用`served:true`,然后迁移其他客户使用新版本,然后重复此步骤。 -3. 确保已完成 [将现有对象升级到新存储版本](#将现有对象升级到新的存储版本) 的步骤。 - 1. 在 CustomResourceDefinition 的`spec.versions`列表中,确认新版本的`stored`已设置为`true`。 - 2. 确认旧版本不再列在 CustomResourceDefinition `status.storedVersions`。 -4. 从 CustomResourceDefinition`spec.versions` 列表中删除旧版本。 -5. 在转换 webhooks 中放弃对旧版本的转换支持。 +1. 确保所有客户端都已完全迁移到新版本。 + 可以查看 kube-apiserver 的日志以识别仍通过旧版本进行访问的所有客户端。 +1. 在 `spec.versions` 列表中将旧版本的 `served` 设置为 `false`。 + 如果仍有客户端意外地使用旧版本,他们可能开始会报告采用旧版本尝试访 + 定制资源的错误消息。 + 如果发生这种情况,请将旧版本的`served:true` 恢复,然后迁移余下的客户端 + 使用新版本,然后重复此步骤。 +1. 确保已完成[将现有对象升级到新存储版本](#upgrade-existing-objects-to-a-new-stored-version) + 的步骤。 + 1. 在 CustomResourceDefinition 的 `spec.versions` 列表中,确认新版本的 + `stored` 已被设置为 `true`。 + 2. 确认旧版本不在 CustomResourceDefinition `status.storedVersions` 中。 +1. 从 CustomResourceDefinition `spec.versions` 列表中删除旧版本。 +1. 在转换 Webhooks 中放弃对旧版本的转换支持。 ## 指定多个版本 {#specify-multiple-versions} -CustomResourceDefinition API 的`versions`字段可用于支持您自定义资源的多个版本已经开发的。版本可以具有不同的架构,并且转换 Webhooks 可以在版本之间转换自定义资源。 -在适用的情况下,Webhook 转换应遵循 [Kubernetes API](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md)。 +CustomResourceDefinition API 的 `versions` 字段可用于支持你所开发的 +定制资源的多个版本。版本可以具有不同的模式,并且转换 Webhooks +可以在多个版本之间转换定制资源。 +在适当的情况下,Webhook 转换应遵循 +[Kubernetes API 约定](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md)。 +尤其是,请查阅 +[API 变更文档](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api_changes.md) +以了解一些有用的常见错误和建议。 {{< note >}} -在 `apiextensions.k8s.io/v1beta1` 版本中,有一个 `version` 字段,名字不叫做 `versions`。 -`version` 字段已经被废弃,成为可选项。不过如果该字段不是空,则必须与 -`versions` 字段中的第一个条目匹配。 +在 `apiextensions.k8s.io/v1beta1` 版本中曾经有一个 `version` 字段, +名字不叫做 `versions`。该 `version` 字段已经被废弃,成为可选项。 +不过如果该字段不是空,则必须与 `versions` 字段中的第一个条目匹配。 {{< /note >}} -此示例显示了两个版本的 CustomResourceDefinition。第一个例子,假设所有的版本共享相同的模式而它们之间没有转换。YAML 中的评论提供了更多背景信息。 +下面的示例显示了两个版本的 CustomResourceDefinition。 +第一个例子中假设所有的版本使用相同的模式而它们之间没有转换。 +YAML 中的注释提供了更多背景信息。 {{< tabs name="CustomResourceDefinition_versioning_example_1" >}} {{% tab name="apiextensions.k8s.io/v1" %}} @@ -181,19 +207,19 @@ between them. The comments in the YAML provide more context. apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: - # name must match the spec fields below, and be in the form: . + # name 必须匹配后面 spec 中的字段,且使用格式 . name: crontabs.example.com spec: - # group name to use for REST API: /apis// + # 组名,用于 REST API: /apis// group: example.com - # list of versions supported by this CustomResourceDefinition + # 此 CustomResourceDefinition 所支持的版本列表 versions: - name: v1beta1 - # Each version can be enabled/disabled by Served flag. + # 每个 version 可以通过 served 标志启用或禁止 served: true - # One and only one version must be marked as the storage version. + # 有且只能有一个 version 必须被标记为存储版本 storage: true - # A schema is required + # schema 是必需字段 schema: openAPIV3Schema: type: object @@ -213,43 +239,44 @@ spec: type: string port: type: string - # The conversion section is introduced in Kubernetes 1.13+ with a default value of - # None conversion (strategy sub-field set to None). + # conversion 节是 Kubernetes 1.13+ 版本引入的,其默认值为无转换,即 + # strategy 子字段设置为 None。 conversion: - # None conversion assumes the same schema for all versions and only sets the apiVersion - # field of custom resources to the proper value + # None 转换假定所有版本采用相同的模式定义,仅仅将定制资源的 apiVersion + # 设置为合适的值. strategy: None - # either Namespaced or Cluster + # 可以是 Namespaced 或 Cluster scope: Namespaced names: - # plural name to be used in the URL: /apis/// + # 名称的复数形式,用于 URL: /apis/// plural: crontabs - # singular name to be used as an alias on the CLI and for display + # 名称的单数形式,用于在命令行接口和显示时作为其别名 singular: crontab - # kind is normally the CamelCased singular type. Your resource manifests use this. + # kind 通常是驼峰编码(CamelCased)的单数形式,用于资源清单中 kind: CronTab - # shortNames allow shorter string to match your resource on the CLI + # shortNames 允许你在命令行接口中使用更短的字符串来匹配你的资源 shortNames: - ct ``` {{% /tab %}} {{% tab name="apiextensions.k8s.io/v1beta1" %}} + ```yaml -# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1 +# 在 v1.16 中被弃用以推荐使用 apiextensions.k8s.io/v1 apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: - # name must match the spec fields below, and be in the form: . + # name 必须匹配后面 spec 中的字段,且使用格式 . name: crontabs.example.com spec: - # group name to use for REST API: /apis// + # 组名,用于 REST API: /apis// group: example.com - # list of versions supported by this CustomResourceDefinition + # 此 CustomResourceDefinition 所支持的版本列表 versions: - name: v1beta1 - # Each version can be enabled/disabled by Served flag. + # 每个 version 可以通过 served 标志启用或禁止 served: true - # One and only one version must be marked as the storage version. + # 有且只能有一个 version 必须被标记为存储版本 storage: true - name: v1 served: true @@ -262,22 +289,22 @@ spec: type: string port: type: string - # The conversion section is introduced in Kubernetes 1.13+ with a default value of - # None conversion (strategy sub-field set to None). + # conversion 节是 Kubernetes 1.13+ 版本引入的,其默认值为无转换,即 + # strategy 子字段设置为 None。 conversion: - # None conversion assumes the same schema for all versions and only sets the apiVersion - # field of custom resources to the proper value + # None 转换假定所有版本采用相同的模式定义,仅仅将定制资源的 apiVersion + # 设置为合适的值. strategy: None - # either Namespaced or Cluster + # 可以是 Namespaced 或 Cluster scope: Namespaced names: - # plural name to be used in the URL: /apis/// + # 名称的复数形式,用于 URL: /apis/// plural: crontabs - # singular name to be used as an alias on the CLI and for display + # 名称的单数形式,用于在命令行接口和显示时作为其别名 singular: crontab - # kind is normally the CamelCased singular type. Your resource manifests use this. + # kind 通常是驼峰编码(CamelCased)的单数形式,用于资源清单中 kind: CronTab - # shortNames allow shorter string to match your resource on the CLI + # shortNames 允许你在命令行接口中使用更短的字符串来匹配你的资源 shortNames: - ct ``` @@ -288,7 +315,8 @@ spec: You can save the CustomResourceDefinition in a YAML file, then use `kubectl apply` to create it. --> -你可以将 CustomResourceDefinition 存储在 YAML 文件中,然后使用`kubectl apply`来创建它。 +你可以将 CustomResourceDefinition 存储在 YAML 文件中,然后使用 +`kubectl apply` 来创建它。 ```shell kubectl apply -f my-versioned-crontab.yaml @@ -299,8 +327,9 @@ After creation, the API server starts to serve each enabled version at an HTTP REST endpoint. In the above example, the API versions are available at `/apis/example.com/v1beta1` and `/apis/example.com/v1`. --> -在创建之后,apiserver 开始在 HTTP REST 端点上为每个启用的版本提供服务。 -在上面的示例中,API 版本可以在`/apis/example.com/v1beta1` 和 `/apis/example.com/v1`中获得。 +在创建之后,API 服务器开始在 HTTP REST 端点上为每个已启用的版本提供服务。 +在上面的示例中,API 版本可以在 `/apis/example.com/v1beta1` 和 +`/apis/example.com/v1` 处获得。 ### 版本优先级 -不考虑 CustomResourceDefinition 中版本被定义的顺序,kubectl 使用具有最高优先级的版本作为访问对象的默认版本。 -通过解析 _name_ 字段确定优先级来决定版本号,稳定性(GA,Beta,或者 Alpha),以及该稳定性水平内的序列。 +不考虑 CustomResourceDefinition 中版本被定义的顺序,kubectl 使用 +具有最高优先级的版本作为访问对象的默认版本。 +通过解析 _name_ 字段确定优先级来决定版本号,稳定性(GA、Beta 或 Alpha) +级别及该稳定性级别内的序列。 -用于对版本进行排序的算法被设计成与 Kubernetes 项目对 Kubernetes 版本进行排序的方式相同。 -版本以`v`开头跟一个数字,一个可选的`beta` 或者 `alpha`命名,和一个可选的附加的数字型的版本信息。 -从广义上讲,版本字符串可能看起来像`v2`或者`v2beta1`。 +用于对版本进行排序的算法在设计上与 Kubernetes 项目对 Kubernetes 版本进行排序的方式相同。 +版本以 `v` 开头跟一个数字,一个可选的 `beta` 或者 `alpha` 和一个可选的附加数字 +作为版本信息。 +从广义上讲,版本字符串可能看起来像 `v2` 或者 `v2beta1`。 使用以下算法对版本进行排序: - 遵循 Kubernetes 版本模式的条目在不符合条件的条目之前进行排序。 - 对于遵循 Kubernetes 版本模式的条目,版本字符串的数字部分从最大到最小排序。 -- 如果字符串 `beta` 或 `alpha` 跟随第一数字部分,它们按顺序排序,在没有 `beta` 或 `alpha` - 后缀(假定为 GA 版本)的等效字符串后面。 -- 如果另一个数字跟在`beta`或`alpha`之后,那么这些数字也是从最大到最小排序。 +- 如果第一个数字后面有字符串 `beta` 或 `alpha`,它们首先按去掉 `beta` 或 + `alpha` 之后的版本号排序(相当于 GA 版本),之后按 `beta` 先、`alpha` 后的顺序排序, +- 如果 `beta` 或 `alpha` 之后还有另一个数字,那么也会针对这些数字 + 从大到小排序。 - 不符合上述格式的字符串按字母顺序排序,数字部分不经过特殊处理。 - 请注意,在下面的示例中,`foo1`在 `foo10`上方排序。这与遵循 Kubernetes 版本模式的条目的数字部分排序不同。 + 请注意,在下面的示例中,`foo1` 排在 `foo10` 之前。 + 这与遵循 Kubernetes 版本模式的条目的数字部分排序不同。 -如果查看以下排序版本列表可以明白: +如果查看以下版本排序列表,这些规则就容易懂了: ```none - v10 @@ -375,8 +409,106 @@ version sort order is `v1`, followed by `v1beta1`. This causes the kubectl command to use `v1` as the default version unless the provided object specifies the version. --> -对于 [指定多个版本](#specify-multiple-versions) 中的示例,版本排序顺序为 `v1`,后跟着 `v1beta1`。 -这导致了 kubectl 命令使用 `v1` 作为默认版本,除非提供对象指定版本。 +对于[指定多个版本](#specify-multiple-versions)中的示例,版本排序顺序为 +`v1`,后跟着 `v1beta1`。 +这导致了 kubectl 命令使用 `v1` 作为默认版本,除非所提供的对象指定了版本。 + + +### 版本废弃 + +{{< feature-state state="stable" for_k8s_version="v1.19" >}} + + +从 v1.19 开始,CustomResourceDefinition 可用来标明所定义的资源的特定版本 +被废弃。当发起对已废弃的版本的 API 请求时,会在 API 响应中以 HTTP 头部 +的形式返回警告消息。 +如果需要,可以对资源的每个废弃版本定制该警告消息。 + + +定制的警告消息应该标明废弃的 API 组、版本和类别(kind),并且应该标明 +应该使用(如果有的话)哪个 API 组、版本和类别作为替代。 + +{{< tabs name="CustomResourceDefinition_versioning_deprecated" >}} +{{% tab name="apiextensions.k8s.io/v1" %}} + +```yaml +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition + name: crontabs.example.com +spec: + group: example.com + names: + plural: crontabs + singular: crontab + kind: CronTab + scope: Namespaced + versions: + - name: v1alpha1 + served: true + # 此属性标明此定制资源的 v1alpha1 版本已被弃用。 + # 发给此版本的 API 请求会在服务器响应中收到警告消息头。 + deprecated: true + # 此属性设置用来覆盖返回给发送 v1alpha1 API 请求的客户端的默认警告信息。 + deprecationWarning: "example.com/v1alpha1 CronTab is deprecated; see http://example.com/v1alpha1-v1 for instructions to migrate to example.com/v1 CronTab" + schema: ... + - name: v1beta1 + served: true + # 此属性标明该定制资源的 v1beta1 版本已被弃用。 + # 发给此版本的 API 请求会在服务器响应中收到警告消息头。 + # 针对此版本的请求所返回的是默认的警告消息。 + deprecated: true + schema: ... + - name: v1 + served: true + storage: true + schema: ... +``` +{{% /tab %}} +{{% tab name="apiextensions.k8s.io/v1beta1" %}} +```yaml +# 在 v1.16 中弃用以推荐使用 apiextensions.k8s.io/v1 +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: crontabs.example.com +spec: + group: example.com + names: + plural: crontabs + singular: crontab + kind: CronTab + scope: Namespaced + validation: ... + versions: + - name: v1alpha1 + served: true + # 此属性标明此定制资源的 v1alpha1 版本已被弃用。 + # 发给此版本的 API 请求会在服务器响应中收到警告消息头。 + deprecated: true + # 此属性设置用来覆盖返回给发送 v1alpha1 API 请求的客户端的默认警告信息。 + deprecationWarning: "example.com/v1alpha1 CronTab is deprecated; see http://example.com/v1alpha1-v1 for instructions to migrate to example.com/v1 CronTab" + - name: v1beta1 + served: true + # 此属性标明该定制资源的 v1beta1 版本已被弃用。 + # 发给此版本的 API 请求会在服务器响应中收到警告消息头。 + # 针对此版本的请求所返回的是默认的警告消息。 + deprecated: true + - name: v1 + served: true + storage: true +``` +{{% /tab %}} +{{< /tabs >}} + -## Webhook转换 +## Webhook 转换 {#webhook-conversion} {{< feature-state state="stable" for_k8s_version="v1.16" >}} {{< note >}} -Webhook 转换在 Kubernetes 1.15 中作为 beta 功能。 -要使用它,应启用`CustomResourceWebhookConversion`功能。 -在大多数集群上,这类 beta 特性应该时自动启用的。 -请参阅[特行门控](/zh/docs/reference/command-line-tools-reference/feature-gates/) 文档以获得更多信息。 +Webhook 转换在 Kubernetes 1.13 版本引入,在 Kubernetes 1.15 中成为 Beta 功能。 +要使用此功能,应启用 `CustomResourceWebhookConversion` 特性。 +在大多数集群上,这类 Beta 特性应该是自动启用的。 +请参阅[特性门控](/zh/docs/reference/command-line-tools-reference/feature-gates/) +文档以获得更多信息。 {{< /note >}} -上面的例子在版本之间有一个 None 转换,它只在转换时设置`apiVersion`字段而不改变对象的其余部分。apiserver 还支持在需要转换时调用外部服务的 webhook 转换。例如: +上面的例子在版本之间有一个 None 转换,它只在转换时设置 `apiVersion` 字段 +而不改变对象的其余部分。API 服务器还支持在需要转换时调用外部服务的 webhook 转换。 +例如: -* 自定义资源被要求在一个不同的版本里而不是一个存储的版本里。 -* Watch 在一个版本中创建,但更改对象存储在另一个版本中。 -* 自定义资源 PUT 请求在一个不同的版本里而不是一个存储的版本。 +* 定制资源的请求版本与其存储版本不同。 +* 使用某版本创建了 Watch 请求,但所更改对象以另一版本存储。 +* 定制资源的 PUT 请求所针对版本与存储版本不同。 -为了涵盖所有这些情况并通过 API 服务优化转换,转换对象可能包含多个对象,以便最大限度地减少外部调用。webhook 应该独立执行这些转换。 +为了涵盖所有这些情况并优化 API 服务器所作的转换,转换请求可以包含多个对象, +以便减少外部调用。Webhook 应该独立执行各个转换。 ### 编写一个转换 Webhook 服务器 -请参考[自定义资源转换 webhook 服务](https://github.com/kubernetes/kubernetes/tree/v1.15.0/test/images/crd-conversion-webhook/main.go) 的实施,这在 Kubernetes e2e 测试中得到验证。webhook 处理由 apiserver 发送的`ConversionReview`请求,并发送回包含在`ConversionResponse`中的转换结果。请注意,请求包含需要独立转换不改变对象顺序的自定义资源列表。示例服务器的组织方式使其可以重用于其他转换。大多数常见代码都位于 [框架文件](https://github.com/kubernetes/kubernetes/tree/v1.14.0/test/images/crd-conversion-webhook/converter/framework.go) 中,只留下 [示例](https://github.com/kubernetes/kubernetes/blob/v1.13.0/test/images/crd-conversion-webhook/converter/example_converter.go#L29-L80) 用于实施不同的转换。 +请参考[定制资源转换 Webhook 服务器](https://github.com/kubernetes/kubernetes/tree/v1.15.0/test/images/crd-conversion-webhook/main.go) +的实现;该实现在 Kubernetes e2e 测试中得到验证。 +Webhook 处理由 API 服务器发送的 `ConversionReview` 请求,并在 +`ConversionResponse` 中封装发回转换结果。 +请注意,请求包含需要独立转换的定制资源列表,这些对象在被转换之后不能改变其 +在列表中的顺序。该示例服务器的组织方式使其可以复用于其他转换。 +大多数常见代码都位于 +[framework 文件](https://github.com/kubernetes/kubernetes/tree/v1.15.0/test/images/crd-conversion-webhook/converter/framework.go) +中,只留下 +[一个函数](https://github.com/kubernetes/kubernetes/blob/v1.13.0/test/images/crd-conversion-webhook/converter/example_converter.go#L29-L80) +用于实现不同的转换。 {{< note >}} -示例转换 webhook 服务器留下`ClientAuth`字段为 +转换 Webhook 服务器示例中将 `ClientAuth` 字段设置为 [空](https://github.com/kubernetes/kubernetes/tree/v1.13.0/test/images/crd-conversion-webhook/config.go#L47-L48), -默认为`NoClientCert`。 - -这意味着 webhook 服务器没有验证客户端的身份,据称是 apiserver。 - -如果您需要相互 TLS 或者其他方式来验证客户端,请参阅如何 +默认为 `NoClientCert`。 +这意味着 webhook 服务器没有验证客户端(也就是 API 服务器)的身份。 +如果你需要双向 TLS 或者其他方式来验证客户端,请参阅如何 [验证 API 服务](/zh/docs/reference/access-authn-authz/extensible-admission-controllers/#authenticate-apiservers)。 {{< /note >}} + +#### 被允许的变更 + +转换 Webhook 不可以更改被转换对象的 `metadata` 中除 `labels` 和 `annotations` +之外的任何属性。 +尝试更改 `name`、`UID` 和 `namespace` 时都会导致引起转换的请求失败。 +所有其他变更只是被忽略而已。 + {{< note >}} -当 webhook 服务器作为一个部署到 Kubernetes 集群中的服务器时,它必须通过端口443上的服务器公开(服务器本身可以有一个任意端口,但是服务器对象应该将它映射到端口443)。 -如果为服务器使用不同的端口,则 apiserver 和 webhook 服务器之间的通信可能会失败。 +当 Webhook 服务器作为一个服务被部署到 Kubernetes 集群中时,它必须 +通过端口 443 公开其服务(服务器本身可以使用任意端口,但是服务对象 +应该将它映射到端口 443)。 +如果为服务器使用不同的端口,则 API 服务器和 Webhook 服务器之间的通信 +可能会失败。 {{< /note >}} ### 配置 CustomResourceDefinition 以使用转换 Webhook -通过修改 `spec` 中的 `conversion` 部分,可以扩展 `None` 转换示例来使用转换 webhook。 +通过修改 `spec` 中的 `conversion` 部分,可以扩展 `None` 转换示例来 +使用转换 Webhook。 {{< tabs name="CustomResourceDefinition_versioning_example_2" >}} {{% tab name="apiextensions.k8s.io/v1" %}} @@ -491,20 +663,19 @@ section of the `spec`: apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: - # name must match the spec fields below, and be in the form: . + # name 必须匹配后面 spec 中的字段,且使用格式 . name: crontabs.example.com spec: - # group name to use for REST API: /apis// + # 组名,用于 REST API: /apis// group: example.com - # list of versions supported by this CustomResourceDefinition + # 此 CustomResourceDefinition 所支持的版本列表 versions: - name: v1beta1 - # Each version can be enabled/disabled by Served flag. + # 每个 version 可以通过 served 标志启用或禁止 served: true - # One and only one version must be marked as the storage version. + # 有且只能有一个 version 必须被标记为存储版本 storage: true - # Each version can define it's own schema when there is no top-level - # schema is defined. + # 当不存在顶级模式定义时,每个版本(version)可以定义其自身的模式 schema: openAPIV3Schema: type: object @@ -523,13 +694,16 @@ spec: port: type: string conversion: - # a Webhook strategy instruct API server to call an external webhook for any conversion between custom resources. + # Webhook strategy 告诉 API 服务器调用外部 Webhook 来完成定制资源 + # 之间的转换 strategy: Webhook - # webhook is required when strategy is `Webhook` and it configures the webhook endpoint to be called by API server. + # 当 strategy 为 "Webhook" 时,webhook 属性是必需的 + # 该属性配置将被 API 服务器调用的 Webhook 端点 webhook: - # conversionReviewVersions indicates what ConversionReview versions are understood/preferred by the webhook. - # The first version in the list understood by the API server is sent to the webhook. - # The webhook must respond with a ConversionReview object in the same version it received. + # conversionReviewVersions 标明 Webhook 所能理解或偏好使用的 + # ConversionReview 对象版本。 + # API 服务器所能理解的列表中的第一个版本会被发送到 Webhook + # Webhook 必须按所接收到的版本响应一个 ConversionReview 对象 conversionReviewVersions: ["v1","v1beta1"] clientConfig: service: @@ -537,42 +711,41 @@ spec: name: example-conversion-webhook-server path: /crdconvert caBundle: "Ci0tLS0tQk......tLS0K" - # either Namespaced or Cluster + # 可以是 Namespaced 或 Cluster scope: Namespaced names: - # plural name to be used in the URL: /apis/// + # 名称的复数形式,用于 URL: /apis/// plural: crontabs - # singular name to be used as an alias on the CLI and for display + # 名称的单数形式,用于在命令行接口和显示时作为其别名 singular: crontab - # kind is normally the CamelCased singular type. Your resource manifests use this. + # kind 通常是驼峰编码(CamelCased)的单数形式,用于资源清单中 kind: CronTab - # shortNames allow shorter string to match your resource on the CLI + # shortNames 允许你在命令行接口中使用更短的字符串来匹配你的资源 shortNames: - ct ``` {{% /tab %}} {{% tab name="apiextensions.k8s.io/v1beta1" %}} ```yaml -# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1 +# 在 v1.16 中被弃用以推荐使用 apiextensions.k8s.io/v1 apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: - # name must match the spec fields below, and be in the form: . + # name 必须匹配后面 spec 中的字段,且使用格式 . name: crontabs.example.com spec: - # group name to use for REST API: /apis// + # 组名,用于 REST API: /apis// group: example.com - # prunes object fields that are not specified in OpenAPI schemas below. + # 裁剪掉下面的 OpenAPI 模式中未曾定义的对象字段 preserveUnknownFields: false - # list of versions supported by this CustomResourceDefinition + # 此 CustomResourceDefinition 所支持的版本列表 versions: - name: v1beta1 - # Each version can be enabled/disabled by Served flag. + # 每个 version 可以通过 served 标志启用或禁止 served: true - # One and only one version must be marked as the storage version. + # 有且只能有一个 version 必须被标记为存储版本 storage: true - # Each version can define it's own schema when there is no top-level - # schema is defined. + # 当不存在顶级模式定义时,每个版本(version)可以定义其自身的模式 schema: openAPIV3Schema: type: object @@ -591,25 +764,26 @@ spec: port: type: string conversion: - # a Webhook strategy instruct API server to call an external webhook for any conversion between custom resources. + # Webhook strategy 告诉 API 服务器调用外部 Webhook 来完成定制资源 strategy: Webhook - # webhookClientConfig is required when strategy is `Webhook` and it configures the webhook endpoint to be called by API server. + # 当 strategy 为 "Webhook" 时,webhookClientConfig 属性是必需的 + # 该属性配置将被 API 服务器调用的 Webhook 端点 webhookClientConfig: service: namespace: default name: example-conversion-webhook-server path: /crdconvert caBundle: "Ci0tLS0tQk......tLS0K" - # either Namespaced or Cluster + # 可以是 Namespaced 或 Cluster scope: Namespaced names: - # plural name to be used in the URL: /apis/// + # 名称的复数形式,用于 URL: /apis/// plural: crontabs - # singular name to be used as an alias on the CLI and for display + # 名称的单数形式,用于在命令行接口和显示时作为其别名 singular: crontab - # kind is normally the CamelCased singular type. Your resource manifests use this. + # kind 通常是驼峰编码(CamelCased)的单数形式,用于资源清单中 kind: CronTab - # shortNames allow shorter string to match your resource on the CLI + # shortNames 允许你在命令行接口中使用更短的字符串来匹配你的资源 shortNames: - ct ``` @@ -620,7 +794,8 @@ spec: You can save the CustomResourceDefinition in a YAML file, then use `kubectl apply` to apply it. --> -您可以将 CustomResourceDefinition 保存在 YAML 文件中,然后使用`kubectl apply`来应用它。 +你可以将 CustomResourceDefinition 保存在 YAML 文件中,然后使用 +`kubectl apply` 来应用它。 ```shell kubectl apply -f my-versioned-crontab-with-conversion.yaml @@ -643,9 +818,11 @@ and can optionally include a custom CA bundle to use to verify the TLS connectio --> ### 调用 Webhook -apiserver 一旦确定请求应发送到转换 webhook,它需要知道如何调用 webhook。这是在`webhookClientConfig`中指定的 webhook 配置。 +API 服务器一旦确定请求应发送到转换 Webhook,它需要知道如何调用 Webhook。 +这是在 `webhookClientConfig` 中指定的 Webhook 配置。 -转换 webhook 可以通过调用 URL 或服务,并且可以选择包含自定义 CA 包,以用于验证 TLS 连接。 +转换 Webhook 可以通过 URL 或服务引用来调用,并且可以选择包含自定义 CA 包, +以用于验证 TLS 连接。 ### URL @@ -665,13 +842,16 @@ which run an apiserver which might need to make calls to this webhook. Such installs are likely to be non-portable, i.e., not easy to turn up in a new cluster. --> +url 以标准 URL 形式给出 Webhook 的位置(`scheme://host:port/path`)。 +`host` 不应引用集群中运行的服务,而应通过指定 `service` 字段来提供 +服务引用。 +在某些 API 服务器中,`host` 可以通过外部 DNS 进行解析(即 +`kube-apiserver` 无法解析集群内 DNS,那样会违反分层规则)。 +`host` 也可以是 IP 地址。 -url 以标准 URL 形式给出 webhook 的位置(`scheme://host:port/path`)。 -`host`不应引用集群中运行的服务;采用通过指定`service`字段来提供服务引用。 -`host`可以通过某些 apiserver 中的外部 DNS 进行解析(即`kube-apiserver`无法解析集群内 DNS 违反分层规则)。主机也可以是 IP 地址。 - -请注意,除非您非常小心在所有主机上运行此 Webhook,否则 localhost 或 127.0.0.1 用作主机是风险很大的,运行一个 apiserver 可能需要对此进行调用 - webhook。这样的安装很可能是不可移植的,即不容易出现在新集群中。 +请注意,除非你非常小心地在所有运行着可能调用 Webhook 的 API 服务器的 +主机上运行此 Webhook,否则将 `localhost` 或 `127.0.0.1` 用作 `host` +是风险很大的。这样的安装很可能是不可移植的,即很难在新集群中启用。 +HTTP 协议必须为 `https`;URL 必须以 `https://` 开头。 -方案必须为`https`:URL 必须以`https://`开头。 +尝试使用用户或基本身份验证(例如,使用`user:password@`)是不允许的。 +URL 片段(`#...`)和查询参数(`?...`)也是不允许的。 -尝试使用用户或基本身份验证,例如不允许使用`user:password@`。片段(`#...`)和查询参数(`?...`)也不允许。 - -这是配置为调用 URL 的转换 Webhook 的示例(并且期望使用系统信任根来验证 TLS 证书,因此不指定 caBundle): +下面是为调用 URL 来执行转换 Webhook 的示例,其中期望使用系统信任根 +来验证 TLS 证书,因此未指定 caBundle: {{< tabs name="CustomResourceDefinition_versioning_example_3" >}} {{% tab name="apiextensions.k8s.io/v1" %}} @@ -707,7 +888,7 @@ spec: {{% /tab %}} {{% tab name="apiextensions.k8s.io/v1beta1" %}} ```yaml -# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1 +# 在 v1.16 中已弃用以推荐使用 apiextensions.k8s.io/v1 apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition ... @@ -736,16 +917,19 @@ at the subpath "/my-path", and to verify the TLS connection against the ServerNa --> ### 服务引用 -`webhookClientConfig`内部的`service`段是对转换 webhook 服务的引用。如果 Webhook 在集群中运行,则应使用`service`而不是`url`。 -服务名称空间和名称是必需的。端口是可选的,默认为 443。该路径是可选的,默认为`/`。 +`webhookClientConfig` 内部的 `service` 段是对转换 Webhook 服务的引用。 +如果 Webhook 在集群中运行,则应使用 `service` 而不是 `url`。 +服务的名字空间和名称是必需的。端口是可选的,默认为 443。 +路径是可选的,默认为`/`。 -这是一个配置为在端口`1234`上调用服务的 Webhook 的示例在子路径`/my-path`下,并针对 ServerName 验证 TLS 连接 -使用自定义 CA 捆绑包的`my-service-name.my-service-namespace.svc`。 +下面配置中,服务配置为在端口 `1234`、子路径 `/my-path` 上被调用。 +例子中针对 ServerName `my-service-name.my-service-namespace.svc`, +使用自定义 CA 包验证 TLS 连接。 {{< tabs name="CustomResourceDefinition_versioning_example_4" >}} {{% tab name="apiextensions.k8s.io/v1" %}} ```yaml -apiVersion: apiextensions.k8s.io/v1b +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition ... spec: @@ -765,7 +949,7 @@ spec: {{% /tab %}} {{% tab name="apiextensions.k8s.io/v1beta1" %}} ```yaml -# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1 +# v1.16 中被弃用以推荐使用 apiextensions.k8s.io/v1 apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition ... @@ -801,9 +985,12 @@ with the `conversionReviewVersions` field in their CustomResourceDefinition: ### 请求 -向 Webhooks 发送 POST 请求,请求的内容类型为:application/json,与 APIapitensions.k8s.io API 组中的 ConversionReview API 对象一起使用序列化为 JSON 作为主体。 +向 Webhooks 发起请求的动词是 POST,请求的 `Content-Type` 为 `application/json`。 +请求的主题为 JSON 序列化形式的 +apiextensions.k8s.io API 组的 ConversionReview API 对象。 -Webhooks 可以指定他们接受的`ConversionReview`对象的版本在其 CustomResourceDefinition 中使用`conversionReviewVersions`字段: +Webhooks 可以在其 CustomResourceDefinition 中使用`conversionReviewVersions` 字段 +设置它们接受的 `ConversionReview` 对象的版本: {{< tabs name="conversionReviewVersions" >}} {{% tab name="apiextensions.k8s.io/v1" %}} @@ -826,14 +1013,15 @@ spec: Webhooks are required to support at least one `ConversionReview` version understood by the current and previous API server. --> - -创建时,`conversionReviewVersions`是必填字段`apiextensions.k8s.io/v1`自定义资源定义。 -需要 Webhooks 支持至少一个`ConversionReview`当前和以前的 apiserver 可以理解的版本。 +创建 `apiextensions.k8s.io/v1` 版本的自定义资源定义时, +`conversionReviewVersions`是必填字段。 +Webhooks 要求支持至少一个 `ConversionReview` 当前和以前的 API 服务器 +可以理解的版本。 {{% /tab %}} {{% tab name="apiextensions.k8s.io/v1beta1" %}} ```yaml -# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1 +# v1.16 已弃用以推荐使用 apiextensions.k8s.io/v1 apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition ... @@ -848,112 +1036,102 @@ spec: If no `conversionReviewVersions` are specified, the default when creating `apiextensions.k8s.io/v1beta1` custom resource definitions is `v1beta1`. --> +创建 apiextensions.k8s.io/v1beta1 定制资源定义时若未指定 +`conversionReviewVersions`,则默认值为 v1beta1。 -如果未指定`conversionReviewVersions`,则创建时的默认值 apiextensions.k8s.io/v1beta1 自定义资源定义为 v1beta1。 {{% /tab %}} {{< /tabs >}} + +API 服务器将 `conversionReviewVersions` 列表中他们所支持的第一个 +`ConversionReview` 资源版本发送给 Webhook。 +如果列表中的版本都不被 API 服务器支持,则无法创建自定义资源定义。 +如果某 API 服务器遇到之前创建的转换 Webhook 配置,并且该配置不支持 +API 服务器知道如何发送的任何 `ConversionReview` 版本,调用 Webhook +的尝试会失败。 - -此示例显示了包含在`ConversionReview`对象中的数据请求将`CronTab`对象转换为`example.com/v1`: +下面的示例显示了包含在 `ConversionReview` 对象中的数据, +该请求意在将 `CronTab` 对象转换为 `example.com/v1`: {{< tabs name="ConversionReview_request" >}} {{% tab name="apiextensions.k8s.io/v1" %}} ```yaml -{ - "apiVersion": "apiextensions.k8s.io/v1", - "kind": "ConversionReview", - "request": { - # Random uid uniquely identifying this conversion call - "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", - - # The API group and version the objects should be converted to - "desiredAPIVersion": "example.com/v1", - - # The list of objects to convert. - # May contain one or more objects, in one or more versions. - "objects": [ - { - "kind": "CronTab", - "apiVersion": "example.com/v1beta1", - "metadata": { - "creationTimestamp": "2019-09-04T14:03:02Z", - "name": "local-crontab", - "namespace": "default", - "resourceVersion": "143", - "uid": "3415a7fc-162b-4300-b5da-fd6083580d66" - }, - "hostPort": "localhost:1234" - }, - { - "kind": "CronTab", - "apiVersion": "example.com/v1beta1", - "metadata": { - "creationTimestamp": "2019-09-03T13:02:01Z", - "name": "remote-crontab", - "resourceVersion": "12893", - "uid": "359a83ec-b575-460d-b553-d859cedde8a0" - }, - "hostPort": "example.com:2345" - } - ] - } -} +apiVersion: apiextensions.k8s.io/v1 +kind: ConversionReview +request: + # 用来唯一标识此转换调用的随机 UID + uid: 705ab4f5-6393-11e8-b7cc-42010a800002 + + # 对象要转换到的目标 API 组和版本 + desiredAPIVersion: example.com/v1 + + # 要转换的对象列表 + # 其中可能包含一个或多个对象,版本可能相同也可能不同 + objects: + - kind: CronTab + apiVersion: example.com/v1beta1 + metadata: + creationTimestamp: "2019-09-04T14:03:02Z" + name: local-crontab + namespace: default + resourceVersion: "143" + uid: "3415a7fc-162b-4300-b5da-fd6083580d66" + hostPort: "localhost:1234" + - kind: CronTab + apiVersion: example.com/v1beta1 + metadata: + creationTimestamp: "2019-09-03T13:02:01Z" + name: remote-crontab + resourceVersion: "12893", + uid: "359a83ec-b575-460d-b553-d859cedde8a0" + hostPort: example.com:2345 ``` {{% /tab %}} {{% tab name="apiextensions.k8s.io/v1beta1" %}} ```yaml -{ - # Deprecated in v1.16 in favor of apiextensions.k8s.io/v1 - "apiVersion": "apiextensions.k8s.io/v1beta1", - "kind": "ConversionReview", - "request": { - # Random uid uniquely identifying this conversion call - "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", - - # The API group and version the objects should be converted to - "desiredAPIVersion": "example.com/v1", - - # The list of objects to convert. - # May contain one or more objects, in one or more versions. - "objects": [ - { - "kind": "CronTab", - "apiVersion": "example.com/v1beta1", - "metadata": { - "creationTimestamp": "2019-09-04T14:03:02Z", - "name": "local-crontab", - "namespace": "default", - "resourceVersion": "143", - "uid": "3415a7fc-162b-4300-b5da-fd6083580d66" - }, - "hostPort": "localhost:1234" - }, - { - "kind": "CronTab", - "apiVersion": "example.com/v1beta1", - "metadata": { - "creationTimestamp": "2019-09-03T13:02:01Z", - "name": "remote-crontab", - "resourceVersion": "12893", - "uid": "359a83ec-b575-460d-b553-d859cedde8a0" - }, - "hostPort": "example.com:2345" - } - ] - } -} +# v1.16 中已废弃以推荐使用 apiextensions.k8s.io/v1 +apiVersion: apiextensions.k8s.io/v1beta1 +kind: ConversionReview +request: + # 用来唯一标识此转换调用的随机 UID + uid: 705ab4f5-6393-11e8-b7cc-42010a800002 + + # 对象要转换到的目标 API 组和版本 + desiredAPIVersion: example.com/v1 + + # 要转换的对象列表 + # 其中可能包含一个或多个对象,版本可能相同也可能不同 + objects: + - kind: CronTab + apiVersion: example.com/v1beta1 + metadata: + creationTimestamp: "2019-09-04T14:03:02Z" + name: local-crontab + namespace: default + resourceVersion: "143" + uid: "3415a7fc-162b-4300-b5da-fd6083580d66" + hostPort: "localhost:1234" + - kind: CronTab + apiVersion: example.com/v1beta1 + metadata: + creationTimestamp: "2019-09-03T13:02:01Z" + name: remote-crontab + resourceVersion: "12893", + uid: "359a83ec-b575-460d-b553-d859cedde8a0" + hostPort: example.com:2345 ``` {{% /tab %}} {{< /tabs >}} + ### 响应 -Webhooks 响应是以 200 HTTP 状态代码,`Content-Type:application/json`,和包含 ConversionReview 对象的主体(与发送的版本相同), -带有`response`节的序列,并序列化为 JSON。 +Webhooks 响应包含 200 HTTP 状态代码、`Content-Type: application/json`, +在主体中包含 JSON 序列化形式的数据,在 `response` 节中给出 + ConversionReview 对象(与发送的版本相同)。 -如果转换成功,则 Webhook 应该返回包含以下字段的`response`节: -* `uid`,从发送到 webhook 的`request.uid`复制而来 -* `result`,设置为`{"status":"Success"}}` -* `convertedObjects`,包含来自`request.objects`的所有对象,转换为`request.desiredVersion` +如果转换成功,则 Webhook 应该返回包含以下字段的 `response` 节: + +* `uid`,从发送到 webhook 的 `request.uid` 复制而来 +* `result`,设置为 `{"status":"Success"}}` +* `convertedObjects`,包含来自 `request.objects` 的所有对象,均已转换为 + `request.desiredVersion` Webhook 的最简单成功响应示例: {{< tabs name="ConversionReview_response_success" >}} {{% tab name="apiextensions.k8s.io/v1" %}} ```yaml -{ - "apiVersion": "apiextensions.k8s.io/v1", - "kind": "ConversionReview", - "response": { - # must match - "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", - "result": { - "status": "Success" - }, - # Objects must match the order of request.objects, and have apiVersion set to . - # kind, metadata.uid, metadata.name, and metadata.namespace fields must not be changed by the webhook. - # metadata.labels and metadata.annotations fields may be changed by the webhook. - # All other changes to metadata fields by the webhook are ignored. - "convertedObjects": [ - { - "kind": "CronTab", - "apiVersion": "example.com/v1", - "metadata": { - "creationTimestamp": "2019-09-04T14:03:02Z", - "name": "local-crontab", - "namespace": "default", - "resourceVersion": "143", - "uid": "3415a7fc-162b-4300-b5da-fd6083580d66" - }, - "host": "localhost", - "port": "1234" - }, - { - "kind": "CronTab", - "apiVersion": "example.com/v1", - "metadata": { - "creationTimestamp": "2019-09-03T13:02:01Z", - "name": "remote-crontab", - "resourceVersion": "12893", - "uid": "359a83ec-b575-460d-b553-d859cedde8a0" - }, - "host": "example.com", - "port": "2345" - } - ] - } -} +apiVersion: apiextensions.k8s.io/v1 +kind: ConversionReview +response: + # 必须与 匹配 + uid: "705ab4f5-6393-11e8-b7cc-42010a800002" + result: + status: Success + # 这里的对象必须与 request.objects 中的对象顺序相同并且其 apiVersion + # 被设置为 。 + # kind、metadata.uid、metadata.name 和 metadata.namespace 等字段都不可 + # 被 Webhook 修改。 + # Webhook 可以更改 metadata.labels 和 metadata.annotations 字段值 + # Webhook 对 metadata 中其他字段的更改都会被忽略 + convertedObjects: + - kind: CronTab + apiVersion: example.com/v1 + metadata: + creationTimestamp: "2019-09-04T14:03:02Z" + name: local-crontab + namespace: default + resourceVersion: "143", + uid: "3415a7fc-162b-4300-b5da-fd6083580d66" + host: localhost + port: "1234" + - kind: CronTab + apiVersion: example.com/v1 + metadata: + creationTimestamp: "2019-09-03T13:02:01Z", + name: remote-crontab + resourceVersion: "12893", + uid: "359a83ec-b575-460d-b553-d859cedde8a0" + host: example.com + port: "2345" ``` {{% /tab %}} {{% tab name="apiextensions.k8s.io/v1beta1" %}} ```yaml -{ - # Deprecated in v1.16 in favor of apiextensions.k8s.io/v1 - "apiVersion": "apiextensions.k8s.io/v1beta1", - "kind": "ConversionReview", - "response": { - # must match - "uid": "705ab4f5-6393-11e8-b7cc-42010a800002", - "result": { - "status": "Failed" - }, - # Objects must match the order of request.objects, and have apiVersion set to . - # kind, metadata.uid, metadata.name, and metadata.namespace fields must not be changed by the webhook. - # metadata.labels and metadata.annotations fields may be changed by the webhook. - # All other changes to metadata fields by the webhook are ignored. - "convertedObjects": [ - { - "kind": "CronTab", - "apiVersion": "example.com/v1", - "metadata": { - "creationTimestamp": "2019-09-04T14:03:02Z", - "name": "local-crontab", - "namespace": "default", - "resourceVersion": "143", - "uid": "3415a7fc-162b-4300-b5da-fd6083580d66" - }, - "host": "localhost", - "port": "1234" - }, - { - "kind": "CronTab", - "apiVersion": "example.com/v1", - "metadata": { - "creationTimestamp": "2019-09-03T13:02:01Z", - "name": "remote-crontab", - "resourceVersion": "12893", - "uid": "359a83ec-b575-460d-b553-d859cedde8a0" - }, - "host": "example.com", - "port": "2345" - } - ] - } -} +# v1.16 中已弃用以推荐使用 apiextensions.k8s.io/v1 +apiVersion: apiextensions.k8s.io/v1beta1 +kind: ConversionReview +response: + # 必须与 匹配 + uid: "705ab4f5-6393-11e8-b7cc-42010a800002" + result: + status: Failed + # 这里的对象必须与 request.objects 中的对象顺序相同并且其 apiVersion + # 被设置为 。 + # kind、metadata.uid、metadata.name 和 metadata.namespace 等字段都不可 + # 被 Webhook 修改。 + # Webhook 可以更改 metadata.labels 和 metadata.annotations 字段值 + # Webhook 对 metadata 中其他字段的更改都会被忽略 + convertedObjects: + - kind: CronTab + apiVersion: example.com/v1 + metadata: + creationTimestamp: "2019-09-04T14:03:02Z" + name: local-crontab + namespace: default + resourceVersion: "143", + uid: "3415a7fc-162b-4300-b5da-fd6083580d66" + host: localhost + port: "1234" + - kind: CronTab + apiVersion: example.com/v1 + metadata: + creationTimestamp: "2019-09-03T13:02:01Z", + name: remote-crontab + resourceVersion: "12893", + uid: "359a83ec-b575-460d-b553-d859cedde8a0" + host: example.com + port: "2345" ``` {{% /tab %}} {{< /tabs >}} + +如果转换失败,则 Webhook 应该返回包含以下字段的 `response` 节: -如果转换失败,则 Webhook 应该返回包含以下字段的`response`节: -*`uid`,从发送到 webhook 的`request.uid`复制而来 -*`result`,设置为`{"status":"Failed"}` +*`uid`,从发送到 Webhook 的 `request.uid` 复制而来 +*`result`,设置为 `{"status": "Failed"}` {{< warning >}} - -转换失败会破坏对自定义资源的读写访问,包括更新或删除资源的能力。转换失败应尽可能避免使用,并且不应用于强制验证 - 约束(改用验证模式 或 Webhook admission)。 +转换失败会破坏对定制资源的读写访问,包括更新或删除资源的能力。 +转换失败应尽可能避免,并且不可用于实施合法性检查约束 +(应改用验证模式或 Webhook 准入插件)。 {{< /warning >}} - -写入对象时,它将保留在写入时指定为存储版本的版本中。如果存储版本发生变化,现有对象永远不会自动转换。然而,新创建或更新的对象将在新的存储版本中编写。对象可能已在不再被服务的版本中编写。 +写入对象时,将使用写入时指定的存储版本来存储。如果存储版本发生变化, +现有对象永远不会被自动转换。然而,新创建或被更新的对象将以新的存储版本写入。 +对象写入的版本不再被支持是有可能的。 - -当读取对象时,将版本指定为路径的一部分。 -如果指定的版本与对象的持久版本不同,Kubernetes 会在您请求的版本里将对象返还给您,但是在提供请求时,持久化对象既不会在磁盘上更改,也不会以任何方式进行转换(除了更改`apiVersion`字符串)。您可以在当前提供的任何版本中请求对象。 +当读取对象时,作为路径的一部分,你需要指定版本。 +如果所指定的版本与对象的持久版本不同,Kubernetes 会按所请求的版本将对象返回, +但是在满足服务请求时,被持久化的对象既不会在磁盘上更改,也不会以任何方式进行 +转换(除了 `apiVersion` 字符串被更改之外)。你可以以当前提供的任何版本 +来请求对象。 -如果您更新了一个现有对象,它将在现在的存储版本中被重写。 -这是对象可以从一个版本改到另一个版本的唯一办法。 +如果你更新一个现有对象,它将以当前的存储版本被重写。 +这是可以将对象从一个版本改到另一个版本的唯一办法。 -1. 存储版本是`v1beta1`。 - 它保存在版本`v1beta1`的存储中。 -2. 您将版本`v1`添加到 CustomResourceDefinition 中,并将其指定为存储版本。 -3. 您在版本`v1beta1`中读取您的对象,然后您再次在版本`v1`中读取对象。 - 除了 apiVersion 字段之外,两个返回的对象都是相同的。 -4. 您创建一个新对象。 - 它存储在版本`v1`的存储中。 - 您现在有两个对象,其中一个位于`v1beta1`,另一个位于`v1`。 -5. 您更新第一个对象。 - 它现在保存在版本`v1`中,因为那是当前的存储版本。 +1. 存储版本是 `v1beta1`。你创建一个对象。该对象以版本 `v1beta1` 存储。 +2. 你将为 CustomResourceDefinition 添加版本 `v1`,并将其指定为存储版本。 +3. 你使用版本 `v1beta1` 来读取你的对象,然后你再次用版本 `v1` 读取对象。 + 除了 apiVersion 字段之外,返回的两个对象是完全相同的。 +4. 你创建一个新对象。对象以版本 `v1` 保存在存储中。 + 你现在有两个对象,其中一个是 `v1beta1`,另一个是 `v1`。 +5. 你更新第一个对象。该对象现在以版本 `v1` 保存,因为 `v1` 是当前的存储版本。 -API 服务在状态字段`storedVersions`中记录曾被标记为存储版本的每个版本。 -对象可能已被保留在任何曾被指定为存储版本的版本中。 -从未成为存储版本的版本的存储中不能存在任何对象。 +API 服务器在状态字段 `storedVersions` 中记录曾被标记为存储版本的每个版本。 +对象可能以任何曾被指定为存储版本的版本保存。 +存储中不会出现从未成为存储版本的版本的对象。 -## 将现有对象升级到新的存储版本 +## 将现有对象升级到新的存储版本 {#upgrade-existing-objects-to-a-new-stored-version} -弃用版本并删除支持时,请设计存储升级过程。 -以下是从`v1beta1`升级到`v1`的示例过程。 +弃用版本并删除其支持时,请设计存储升级过程。 + + + +*选项 1:* 使用存储版本迁移程序(Storage Version Migrator) + +1. 运行[存储版本迁移程序](https://github.com/kubernetes-sigs/kube-storage-version-migrator) +2. 从 CustomResourceDefinition 的 `status.storedVersions` 字段中去掉 + 老的版本。 + + +*选项 2:* 手动将现有对象升级到新的存储版本 + +以下是从 `v1beta1` 升级到 `v1` 的示例过程。 -1. 将`v1`设置为 CustomResourceDefinition 文件中的存储,并使用 kubectl 应用它。 - `storedVersions`现在是`v1beta1、 v1`。 -2. 编写升级过程以列出所有现有对象并使用相同内容编写它们。 - 这会强制后端在当前存储版本中写入对象,即`v1`。 -3. 通过从`storedVersions`字段中删除`v1beta1`来更新 CustomResourceDefinition`Status`。 - +1. 在 CustomResourceDefinition 文件中将 `v1` 设置为存储版本,并使用 kubectl 应用它。 + `storedVersions`现在是`v1beta1, v1`。 +2. 编写升级过程以列出所有现有对象并使用相同内容将其写回存储。 + 这会强制后端使用当前存储版本(即 `v1`)写入对象。 +3. 通过从 `storedVersions` 字段中删除 `v1beta1` 来更新 CustomResourceDefinition + 的`Status`。