CustomResourceDefinitions 中的版本
此页面解释了如何向 CustomResourceDefinitions 添加版本信息,以指示 CustomResourceDefinitions 的稳定性级别,或将 API 提升到新版本并进行 API 表示之间的转换。它还描述了如何将对象从一个版本升级到另一个版本。
开始之前
你需要一个 Kubernetes 集群,并且必须配置 kubectl 命令行工具才能与你的集群通信。建议在至少有两个不充当控制平面主机的节点的集群上运行本教程。如果你还没有集群,可以使用 minikube 创建一个,或者可以使用这些 Kubernetes 游乐场之一
你应该对自定义资源有初步了解。
你的 Kubernetes 服务器必须是 v1.16 或更高版本。要检查版本,请输入kubectl version
。概述
CustomResourceDefinition API 提供了一种引入和升级到新的 CustomResourceDefinition 版本的工作流程。
创建 CustomResourceDefinition 时,第一个版本在 CustomResourceDefinition spec.versions
列表中设置为适当的稳定性级别和版本号。例如,v1beta1
表示第一个版本尚未稳定。所有自定义资源对象最初都将以此版本存储。
创建 CustomResourceDefinition 后,客户端可以开始使用 v1beta1
API。
稍后可能需要添加新版本,例如 v1
。
添加新版本
- 选择转换策略。由于自定义资源对象需要能够在两个版本上提供,这意味着有时它们将以与存储版本不同的版本提供。为了使之成为可能,自定义资源对象有时必须在存储的版本和提供的版本之间进行转换。如果转换涉及模式更改并需要自定义逻辑,则应使用转换 Webhook。如果没有模式更改,则可以使用默认的
None
转换策略,并且在提供不同版本时,只会修改apiVersion
字段。 - 如果使用转换 Webhook,请创建和部署转换 Webhook。有关更多详细信息,请参阅Webhook 转换。
- 更新 CustomResourceDefinition 以在
spec.versions
列表中包含新版本,并将served:true
设置为 true。此外,将spec.conversion
字段设置为所选的转换策略。如果使用转换 Webhook,请配置spec.conversion.webhookClientConfig
字段以调用该 Webhook。
添加新版本后,客户端可以逐步迁移到新版本。一些客户端使用旧版本,而另一些客户端使用新版本是完全安全的。
将存储的对象迁移到新版本
- 请参阅将现有对象升级到新的存储版本部分。
在将对象升级到新的存储版本之前、期间和之后,客户端使用旧版本和新版本都是安全的。
删除旧版本
- 确保所有客户端都完全迁移到新版本。可以查看 kube-apiserver 日志,以帮助识别仍在通过旧版本访问的任何客户端。
- 在
spec.versions
列表中,将旧版本的served
设置为false
。如果任何客户端仍在意外地使用旧版本,它们可能会开始报告错误,尝试访问旧版本的自定义资源对象。如果发生这种情况,请切换回旧版本上的served:true
,将剩余的客户端迁移到新版本,然后重复此步骤。 - 确保已完成将现有对象升级到新存储版本的步骤。
- 验证 CustomResourceDefinition 中
spec.versions
列表中新版本的storage
是否设置为true
。 - 验证 CustomResourceDefinition
status.storedVersions
中是否不再列出旧版本。
- 验证 CustomResourceDefinition 中
- 从 CustomResourceDefinition
spec.versions
列表中删除旧版本。 - 在转换 Webhook 中删除对旧版本的转换支持。
指定多个版本
CustomResourceDefinition API versions
字段可用于支持你开发的自定义资源的多个版本。版本可以具有不同的模式,并且转换 Webhook 可以在版本之间转换自定义资源。Webhook 转换应尽可能遵循Kubernetes API 约定。具体来说,请参阅 API 更改文档,以获取一组有用的注意事项和建议。
注意
在apiextensions.k8s.io/v1beta1
中,存在 version
字段,而不是 versions
。version
字段已弃用,并且是可选的,但如果它不是空的,则必须与 versions
字段中的第一个项目匹配。此示例显示了具有两个版本的 CustomResourceDefinition。对于第一个示例,假设所有版本共享相同的模式,它们之间没有转换。YAML 中的注释提供了更多上下文。
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
# name must match the spec fields below, and be in the form: <plural>.<group>
name: crontabs.example.com
spec:
# group name to use for REST API: /apis/<group>/<version>
group: example.com
# list of versions supported by this CustomResourceDefinition
versions:
- name: v1beta1
# Each version can be enabled/disabled by Served flag.
served: true
# One and only one version must be marked as the storage version.
storage: true
# A schema is required
schema:
openAPIV3Schema:
type: object
properties:
host:
type: string
port:
type: string
- name: v1
served: true
storage: false
schema:
openAPIV3Schema:
type: object
properties:
host:
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:
# None conversion assumes the same schema for all versions and only sets the apiVersion
# field of custom resources to the proper value
strategy: None
# either Namespaced or Cluster
scope: Namespaced
names:
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
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: CronTab
# shortNames allow shorter string to match your resource on the CLI
shortNames:
- ct
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
# name must match the spec fields below, and be in the form: <plural>.<group>
name: crontabs.example.com
spec:
# group name to use for REST API: /apis/<group>/<version>
group: example.com
# list of versions supported by this CustomResourceDefinition
versions:
- name: v1beta1
# Each version can be enabled/disabled by Served flag.
served: true
# One and only one version must be marked as the storage version.
storage: true
- name: v1
served: true
storage: false
validation:
openAPIV3Schema:
type: object
properties:
host:
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:
# None conversion assumes the same schema for all versions and only sets the apiVersion
# field of custom resources to the proper value
strategy: None
# either Namespaced or Cluster
scope: Namespaced
names:
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
plural: crontabs
# singular name to be used as an alias on the CLI and for display
singular: crontab
# kind is normally the PascalCased singular type. Your resource manifests use this.
kind: CronTab
# shortNames allow shorter string to match your resource on the CLI
shortNames:
- ct
你可以将 CustomResourceDefinition 保存在 YAML 文件中,然后使用 kubectl apply
创建它。
kubectl apply -f my-versioned-crontab.yaml
创建后,API 服务器开始在 HTTP REST 端点上提供每个启用的版本。在上面的示例中,API 版本在 /apis/example.com/v1beta1
和 /apis/example.com/v1
上可用。
版本优先级
无论在 CustomResourceDefinition 中定义版本的顺序如何,kubectl 都使用具有最高优先级的版本作为访问对象的默认版本。优先级是通过解析 name 字段来确定版本号、稳定性(GA、Beta 或 Alpha)以及该稳定性级别内的顺序来确定的。
用于对版本进行排序的算法旨在以 Kubernetes 项目对 Kubernetes 版本进行排序的相同方式对版本进行排序。版本以 v
开头,后跟数字、可选的 beta
或 alpha
标记以及可选的附加数字版本信息。从广义上讲,版本字符串可能类似于 v2
或 v2beta1
。版本使用以下算法排序
- 遵循 Kubernetes 版本模式的条目将先于不遵循 Kubernetes 版本模式的条目排序。
- 对于遵循 Kubernetes 版本模式的条目,版本字符串的数字部分从最大到最小排序。
- 如果字符串
beta
或alpha
在第一个数字部分之后,它们将按照该顺序在没有beta
或alpha
后缀的等效字符串之后排序(假定为 GA 版本)。 - 如果
beta
或alpha
之后还有另一个数字,则这些数字也从最大到最小排序。 - 不符合上述格式的字符串将按字母顺序排序,并且数字部分不进行特殊处理。请注意,在下面的示例中,
foo1
排在foo10
之上。这与遵循 Kubernetes 版本模式的条目的数字部分的排序方式不同。
如果你查看以下已排序的版本列表,这可能会更有意义
- v10
- v2
- v1
- v11beta2
- v10beta3
- v3beta1
- v12alpha1
- v11alpha2
- foo1
- foo10
对于指定多个版本中的示例,版本排序顺序为 v1
,后跟 v1beta1
。这会导致 kubectl 命令使用 v1
作为默认版本,除非提供的对象指定了版本。
版本弃用
Kubernetes v1.19 [稳定]
从 v1.19 开始,CustomResourceDefinition 可以指示其定义的资源的特定版本已弃用。当向该资源的已弃用版本发出 API 请求时,会在 API 响应中以标头的形式返回警告消息。如果需要,可以自定义资源的每个已弃用版本的警告消息。
自定义的警告消息应指示已弃用的 API 组、版本和种类,并且应指示应使用哪个 API 组、版本和种类(如果适用)。
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
storage: false
# This indicates the v1alpha1 version of the custom resource is deprecated.
# API requests to this version receive a warning header in the server response.
deprecated: true
# This overrides the default warning returned to API clients making v1alpha1 API requests.
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
# This indicates the v1beta1 version of the custom resource is deprecated.
# API requests to this version receive a warning header in the server response.
# A default warning message is returned for this version.
deprecated: true
schema: ...
- name: v1
served: true
storage: true
schema: ...
# Deprecated in v1.16 in favor of 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
storage: false
# This indicates the v1alpha1 version of the custom resource is deprecated.
# API requests to this version receive a warning header in the server response.
deprecated: true
# This overrides the default warning returned to API clients making v1alpha1 API requests.
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
# This indicates the v1beta1 version of the custom resource is deprecated.
# API requests to this version receive a warning header in the server response.
# A default warning message is returned for this version.
deprecated: true
- name: v1
served: true
storage: true
版本删除
在为所有提供旧版本自定义资源的集群将现有存储的数据迁移到较新的 API 版本,并且从 CustomResourceDefinition 的 status.storedVersions
中删除旧版本之前,无法从 CustomResourceDefinition 清单中删除旧的 API 版本。
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: v1beta1
# This indicates the v1beta1 version of the custom resource is no longer served.
# API requests to this version receive a not found error in the server response.
served: false
schema: ...
- name: v1
served: true
# The new served version should be set as the storage version
storage: true
schema: ...
Webhook 转换
Kubernetes v1.16 [稳定]
注意
Webhook 转换自 1.15 起可用作 Beta 版,自 Kubernetes 1.13 起可用作 Alpha 版。必须启用CustomResourceWebhookConversion
功能,对于 Beta 功能,许多集群会自动启用此功能。请参阅功能门控文档以获取更多信息。上面的示例在版本之间进行了 None 转换,该转换仅在转换时设置 apiVersion
字段,而不更改对象的其余部分。API 服务器还支持在需要转换时调用外部服务的 Webhook 转换。例如,当
- 自定义资源请求的版本与存储版本不同。
- 在某个版本中创建了 Watch,但更改的对象存储在另一个版本中。
- 自定义资源的 PUT 请求的版本与存储版本不同。
为了涵盖所有这些情况并优化 API 服务器的转换,转换请求可能包含多个对象,以尽量减少外部调用。Webhook 应该独立执行这些转换。
编写一个转换 Webhook 服务器
请参考 自定义资源转换 Webhook 服务器 的实现,该服务器在 Kubernetes e2e 测试中进行了验证。该 Webhook 处理 API 服务器发送的 ConversionReview
请求,并发送回封装在 ConversionResponse
中的转换结果。请注意,请求包含需要独立转换的自定义资源列表,而无需更改对象的顺序。示例服务器的组织方式可以重用于其他转换。大多数通用代码位于 framework 文件 中,只留下 一个函数 用于实现不同的转换。
注意
示例转换 Webhook 服务器将ClientAuth
字段 保留为空,默认为 NoClientCert
。这意味着 Webhook 服务器不会验证客户端(据推测是 API 服务器)的身份。如果您需要相互 TLS 或其他方式来验证客户端,请参阅如何验证 API 服务器。允许的变更
转换 Webhook 不得更改转换对象 metadata
内部的任何内容,labels
和 annotations
除外。尝试更改 name
、UID
和 namespace
将被拒绝,并导致导致转换的请求失败。所有其他更改都将被忽略。
部署转换 Webhook 服务
部署转换 Webhook 的文档与准入 Webhook 示例服务的文档相同。下一节的假设是,转换 Webhook 服务器部署到 default
命名空间中名为 example-conversion-webhook-server
的服务,并在路径 /crdconvert
上提供流量服务。
注意
当 Webhook 服务器作为服务部署到 Kubernetes 集群中时,必须通过端口 443 上的服务公开(服务器本身可以有任意端口,但服务对象应将其映射到端口 443)。如果服务使用了不同的端口,则 API 服务器和 Webhook 服务之间的通信可能会失败。配置 CustomResourceDefinition 以使用转换 Webhook
可以通过修改 spec
的 conversion
部分来扩展 None
转换示例以使用转换 Webhook。
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
# name must match the spec fields below, and be in the form: <plural>.<group>
name: crontabs.example.com
spec:
# group name to use for REST API: /apis/<group>/<version>
group: example.com
# list of versions supported by this CustomResourceDefinition
versions:
- name: v1beta1
# Each version can be enabled/disabled by Served flag.
served: true
# One and only one version must be marked as the storage version.
storage: true
# Each version can define its own schema when there is no top-level
# schema is defined.
schema:
openAPIV3Schema:
type: object
properties:
hostPort:
type: string
- name: v1
served: true
storage: false
schema:
openAPIV3Schema:
type: object
properties:
host:
type: string
port:
type: string
conversion:
# the Webhook strategy instructs the API server to call an external webhook for any conversion between custom resources.
strategy: Webhook
# webhook is required when strategy is `Webhook` and it configures the webhook endpoint to be called by API server.
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: ["v1","v1beta1"]
clientConfig:
service:
namespace: default
name: example-conversion-webhook-server
path: /crdconvert
caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
# either Namespaced or Cluster
scope: Namespaced
names:
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
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: CronTab
# shortNames allow shorter string to match your resource on the CLI
shortNames:
- ct
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
# name must match the spec fields below, and be in the form: <plural>.<group>
name: crontabs.example.com
spec:
# group name to use for REST API: /apis/<group>/<version>
group: example.com
# prunes object fields that are not specified in OpenAPI schemas below.
preserveUnknownFields: false
# list of versions supported by this CustomResourceDefinition
versions:
- name: v1beta1
# Each version can be enabled/disabled by Served flag.
served: true
# One and only one version must be marked as the storage version.
storage: true
# Each version can define its own schema when there is no top-level
# schema is defined.
schema:
openAPIV3Schema:
type: object
properties:
hostPort:
type: string
- name: v1
served: true
storage: false
schema:
openAPIV3Schema:
type: object
properties:
host:
type: string
port:
type: string
conversion:
# the Webhook strategy instructs the API server to call an external webhook for any conversion between custom resources.
strategy: Webhook
# webhookClientConfig is required when strategy is `Webhook` and it configures the webhook endpoint to be called by API server.
webhookClientConfig:
service:
namespace: default
name: example-conversion-webhook-server
path: /crdconvert
caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
# either Namespaced or Cluster
scope: Namespaced
names:
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
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: CronTab
# shortNames allow shorter string to match your resource on the CLI
shortNames:
- ct
可以将 CustomResourceDefinition 保存在 YAML 文件中,然后使用 kubectl apply
应用它。
kubectl apply -f my-versioned-crontab-with-conversion.yaml
在应用新更改之前,请确保转换服务已启动并运行。
联系 Webhook
一旦 API 服务器确定应将请求发送到转换 Webhook,它需要知道如何联系 Webhook。这在 Webhook 配置的 webhookClientConfig
节中指定。
转换 Webhook 可以通过 URL 或服务引用调用,并且可以选择包含自定义 CA 包以用于验证 TLS 连接。
URL
url
以标准 URL 形式(scheme://host:port/path
)提供 Webhook 的位置。
host
不应引用集群中运行的服务;而是通过指定 service
字段来使用服务引用。在某些 API 服务器中,主机可能会通过外部 DNS 解析(即,kube-apiserver
无法解析集群内 DNS,因为这将是分层违规)。host
也可以是 IP 地址。
请注意,除非您格外小心地在所有运行可能需要调用此 Webhook 的 API 服务器的主机上运行此 Webhook,否则使用 localhost
或 127.0.0.1
作为 host
是有风险的。此类安装可能不具备可移植性,或者不容易在新集群中运行。
方案必须是 "https";URL 必须以 "https://" 开头。
不允许尝试使用用户或基本身份验证(例如 "user:password@")。也不允许使用片段 ("#...") 和查询参数 ("?...")。
以下是一个配置为调用 URL 的转换 Webhook 示例(并期望使用系统信任根来验证 TLS 证书,因此不指定 caBundle)
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
...
spec:
...
conversion:
strategy: Webhook
webhook:
clientConfig:
url: "https://my-webhook.example.com:9443/my-webhook-path"
...
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
...
spec:
...
conversion:
strategy: Webhook
webhookClientConfig:
url: "https://my-webhook.example.com:9443/my-webhook-path"
...
服务引用
webhookClientConfig
中的 service
节是对转换 Webhook 服务的引用。如果 Webhook 在集群内运行,则应使用 service
而不是 url
。服务命名空间和名称是必需的。端口是可选的,默认为 443。路径是可选的,默认为 "/"。
以下是一个 Webhook 示例,该 Webhook 配置为在子路径 "/my-path" 上调用端口 "1234" 上的服务,并使用自定义 CA 包针对 ServerName my-service-name.my-service-namespace.svc
验证 TLS 连接。
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
...
spec:
...
conversion:
strategy: Webhook
webhook:
clientConfig:
service:
namespace: my-service-namespace
name: my-service-name
path: /my-path
port: 1234
caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
...
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
...
spec:
...
conversion:
strategy: Webhook
webhookClientConfig:
service:
namespace: my-service-namespace
name: my-service-name
path: /my-path
port: 1234
caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
...
Webhook 请求和响应
请求
Webhook 会收到 POST 请求,其中 Content-Type: application/json
,正文是以 JSON 形式序列化的 apiextensions.k8s.io
API 组中的 ConversionReview
API 对象。
Webhook 可以使用其 CustomResourceDefinition 中的 conversionReviewVersions
字段指定它们接受的 ConversionReview
对象的版本。
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
...
spec:
...
conversion:
strategy: Webhook
webhook:
conversionReviewVersions: ["v1", "v1beta1"]
...
创建 apiextensions.k8s.io/v1
自定义资源定义时,conversionReviewVersions
是必填字段。Webhook 必须支持当前和以前的 API 服务器理解的至少一个 ConversionReview
版本。
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
...
spec:
...
conversion:
strategy: Webhook
conversionReviewVersions: ["v1", "v1beta1"]
...
如果未指定 conversionReviewVersions
,则创建 apiextensions.k8s.io/v1beta1
自定义资源定义时的默认值为 v1beta1
。
API 服务器发送它们支持的 conversionReviewVersions
列表中的第一个 ConversionReview
版本。如果 API 服务器不支持列表中的任何版本,则不允许创建自定义资源定义。如果 API 服务器遇到以前创建的转换 Webhook 配置,并且不支持 API 服务器知道如何发送的任何 ConversionReview
版本,则尝试调用 Webhook 将失败。
此示例显示了请求将 CronTab
对象转换为 example.com/v1
的 ConversionReview
对象中包含的数据
{
"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"
}
]
}
}
{
# 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"
}
]
}
}
响应
Webhook 使用 200 HTTP 状态代码、Content-Type: application/json
以及包含 ConversionReview
对象(与发送的版本相同)的正文进行响应,其中填充了 response
节,并序列化为 JSON。
如果转换成功,Webhook 应返回包含以下字段的 response
节
uid
,从发送到 Webhook 的request.uid
中复制result
,设置为{"status":"Success"}
convertedObjects
,包含来自request.objects
的所有对象,并转换为request.desiredAPIVersion
以下是来自 Webhook 的最小成功响应示例
{
"apiVersion": "apiextensions.k8s.io/v1",
"kind": "ConversionReview",
"response": {
# must match <request.uid>
"uid": "705ab4f5-6393-11e8-b7cc-42010a800002",
"result": {
"status": "Success"
},
# Objects must match the order of request.objects, and have apiVersion set to <request.desiredAPIVersion>.
# 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"
}
]
}
}
{
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
"apiVersion": "apiextensions.k8s.io/v1beta1",
"kind": "ConversionReview",
"response": {
# must match <request.uid>
"uid": "705ab4f5-6393-11e8-b7cc-42010a800002",
"result": {
"status": "Failed"
},
# Objects must match the order of request.objects, and have apiVersion set to <request.desiredAPIVersion>.
# 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"
}
]
}
}
如果转换失败,Webhook 应返回包含以下字段的 response
节
uid
,从发送到 Webhook 的request.uid
中复制result
,设置为{"status":"Failed"}
警告
转换失败可能会中断对自定义资源的读取和写入访问,包括更新或删除资源的能力。应尽可能避免转换失败,并且不应将其用于强制执行验证约束(请改用验证模式或 Webhook 准入)。以下是来自 Webhook 的响应示例,指示转换请求失败,并带有可选消息
{
"apiVersion": "apiextensions.k8s.io/v1",
"kind": "ConversionReview",
"response": {
"uid": "<value from request.uid>",
"result": {
"status": "Failed",
"message": "hostPort could not be parsed into a separate host and port"
}
}
}
{
# Deprecated in v1.16 in favor of apiextensions.k8s.io/v1
"apiVersion": "apiextensions.k8s.io/v1beta1",
"kind": "ConversionReview",
"response": {
"uid": "<value from request.uid>",
"result": {
"status": "Failed",
"message": "hostPort could not be parsed into a separate host and port"
}
}
}
写入、读取和更新版本化的 CustomResourceDefinition 对象
写入对象时,该对象将以写入时指定为存储版本的版本存储。如果存储版本发生更改,则现有对象永远不会自动转换。但是,新创建或更新的对象将以新的存储版本写入。对象可能以不再提供的版本写入。
读取对象时,您需要在路径中指定版本。您可以请求当前提供的任何版本的对象。如果您指定的版本与对象的存储版本不同,则 Kubernetes 会以您请求的版本向您返回对象,但存储的对象不会在磁盘上更改。
在提供读取请求时返回的对象会发生什么,取决于 CRD 的 spec.conversion
中指定的内容
- 如果指定了默认的
strategy
值None
,则对对象的唯一修改是更改apiVersion
字符串,并且可能修剪未知字段(取决于配置)。请注意,如果存储版本和请求版本之间的架构不同,则不太可能导致好的结果。特别是,如果相同的数据在不同版本之间以不同的字段表示,则不应使用此策略。 - 如果指定了Webhook 转换,则此机制会控制转换。
如果您更新现有对象,则该对象将以当前为存储版本的版本重写。这是对象从一个版本更改为另一个版本的唯一方法。
为了说明这一点,请考虑以下假设的事件序列
- 存储版本为
v1beta1
。您创建一个对象。该对象以v1beta1
版本存储 - 您将版本
v1
添加到您的 CustomResourceDefinition,并将其指定为存储版本。此处v1
和v1beta1
的架构是相同的,这通常是在 Kubernetes 生态系统中将 API 提升为稳定版时的典型情况。 - 您以
v1beta1
版本读取对象,然后以v1
版本再次读取该对象。除了 apiVersion 字段外,两个返回的对象都是相同的。 - 您创建一个新对象。该对象以
v1
版本存储。您现在有两个对象,一个对象为v1beta1
,另一个对象为v1
。 - 您更新第一个对象。由于
v1
是当前的存储版本,因此现在该对象以v1
版本存储。
以前的存储版本
API 服务器会在状态字段 storedVersions
中记录曾经标记为存储版本的每个版本。对象可能以曾经被指定为存储版本的任何版本存储。在从未作为存储版本的版本中,不能存在任何对象。
将现有对象升级到新的存储版本
在弃用版本并放弃支持时,请选择存储升级过程。
选项 1:使用存储版本迁移器
- 运行存储版本迁移器
- 从 CustomResourceDefinition
status.storedVersions
字段中删除旧版本。
选项 2:手动将现有对象升级到新的存储版本
以下是将 v1beta1
升级到 v1
的示例过程。
- 在 CustomResourceDefinition 文件中将
v1
设置为存储版本,并使用 kubectl 应用它。storedVersions
现在为v1beta1, v1
。 - 编写一个升级过程,以列出所有现有对象并以相同的内容写入它们。这会强制后端以当前存储版本(即
v1
)写入对象。 - 从 CustomResourceDefinition
status.storedVersions
字段中删除v1beta1
。
注意
--subresource
标志与 kubectl 的 get、patch、edit 和 replace 命令一起使用,用于获取和更新所有支持它们的 API 资源的子资源,例如 status
和 scale
。此标志从 kubectl v1.24 版本开始可用。之前,通过 kubectl 读取子资源(如 status
)需要使用 kubectl --raw
,而使用 kubectl 更新子资源是完全不可能的。从 v1.24 开始,可以使用 kubectl
工具编辑或修补 CRD 对象上的 status
子资源。请参阅 如何使用子资源标志修补 Deployment。
此页面是 Kubernetes v1.32 文档的一部分。如果您正在运行不同版本的 Kubernetes,请查阅该版本的文档。
以下是使用 kubectl
修补 CRD 对象的 status
子资源的示例
kubectl patch customresourcedefinitions <CRD_Name> --subresource='status' --type='merge' -p '{"status":{"storedVersions":["v1"]}}'