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。如果 SCHEMA 沒有變化,則可以使用預設的 `None` 轉換策略,並且在提供不同版本時只修改 `apiVersion` 欄位。
- 如果使用轉換 Webhook,請建立並部署轉換 Webhook。有關詳細資訊,請參閱Webhook 轉換。
- 更新 CustomResourceDefinition,在 `spec.versions` 列表中包含新版本,並設定 `served: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 的 `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 版本模式的條目,版本字串的數字部分從大到小排序。
- 如果第一個數字部分後面跟著字串 `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 [stable]
從 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 [stable]
注意
Webhook 轉換自 1.15 起以 beta 版提供,自 Kubernetes 1.13 起以 alpha 版提供。必須啟用 `CustomResourceWebhookConversion` 功能,對於許多叢集的 beta 功能來說,這會自動啟用。有關更多資訊,請參閱功能門文件。上面的例子在版本之間有一個 None 轉換,它在轉換時只設置 `apiVersion` 欄位,不改變物件的其餘部分。當需要轉換時,API 伺服器還支援呼叫外部服務的 Webhook 轉換。例如,當:
- 自定義資源以與儲存版本不同的版本請求時。
- 在某個版本中建立 Watch,但更改後的物件儲存在另一個版本中。
- 自定義資源 PUT 請求的版本與儲存版本不同。
為了涵蓋所有這些情況並最佳化 API 伺服器的轉換,轉換請求可能包含多個物件,以儘量減少外部呼叫。Webhook 應該獨立執行這些轉換。
編寫轉換 Webhook 伺服器
請參閱在 Kubernetes e2e 測試中驗證的自定義資源轉換 Webhook 伺服器的實現。Webhook 處理 API 伺服器傳送的 `ConversionReview` 請求,併發送回包裝在 `ConversionResponse` 中的轉換結果。請注意,請求包含需要獨立轉換且不改變物件順序的自定義資源列表。示例伺服器的組織方式是可重用於其他轉換。大多數通用程式碼位於框架檔案中,只留下一個函式需要為不同的轉換實現。
注意
示例轉換 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 或服務引用呼叫,並且可以選擇包含用於驗證 TLS 連線的自定義 CA 捆綁包。
URL
`url` 以標準 URL 格式(`scheme://host:port/path`)給出 Webhook 的位置。
`host` 不應引用叢集中執行的服務;請改用 `service` 欄位指定服務引用。在某些 apiserver(例如,`kube-apiserver` 無法解析叢集內 DNS,因為這將違反分層)中,`host` 可能會透過外部 DNS 解析。`host` 也可以是 IP 地址。
請注意,將 `localhost` 或 `127.0.0.1` 用作 `host` 存在風險,除非你非常小心地在所有執行 apiserver(可能需要呼叫此 webhook)的主機上執行此 webhook。此類安裝可能不可移植或不易在新叢集中執行。
方案必須是“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 示例,它配置為在子路徑 "/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`,並且請求體中包含一個 `apiextensions.k8s.io` API 組中的 `ConversionReview` API 物件,序列化為 JSON。
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 將失敗。
此示例顯示了 `ConversionReview` 物件中包含的資料,用於將 `CronTab` 物件轉換為 `example.com/v1` 的請求。
{
"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` 字串,並且可能裁剪未知欄位(取決於配置)。請注意,如果儲存版本和請求版本之間的 schema 不同,這不太可能產生好的結果。特別是,如果同一資料在不同版本之間以不同欄位表示,則不應使用此策略。
- 如果指定了Webhook 轉換,則此機制控制轉換。
如果你更新現有物件,它會以當前儲存版本重寫。這是物件從一個版本更改到另一個版本的唯一方式。
為了說明這一點,考慮以下一系列假設事件:
- 儲存版本是 `v1beta1`。你建立了一個物件。它以 `v1beta1` 版本儲存。
- 你將版本 `v1` 新增到你的 CustomResourceDefinition 並將其指定為儲存版本。在這裡,`v1` 和 `v1beta1` 的 schema 是相同的,這通常是在 Kubernetes 生態系統中將 API 提升到穩定版時的情況。
- 你以 `v1beta1` 版本讀取你的物件,然後再次以 `v1` 版本讀取該物件。除了 apiVersion 欄位外,兩個返回的物件都是相同的。
- 你建立了一個新物件。它以 `v1` 版本儲存。你現在有兩個物件,其中一個在 `v1beta1`,另一個在 `v1`。
- 你更新了第一個物件。它現在以 `v1` 版本儲存,因為這是當前的儲存版本。
以前的儲存版本
API 伺服器在 `storedVersions` 狀態欄位中記錄每個曾被標記為儲存版本的版本。物件可能已儲存在任何曾被指定為儲存版本的版本。儲存中不能存在從未作為儲存版本的版本的物件。
將現有物件升級到新的儲存版本
棄用版本和刪除支援時,請選擇儲存升級過程。
選項 1: 使用儲存版本遷移器
- 執行 儲存版本遷移器。
- 從 CustomResourceDefinition 的 `status.storedVersions` 欄位中移除舊版本。
選項 2: 手動將現有物件升級到新的儲存版本
以下是將 `v1beta1` 升級到 `v1` 的示例過程。
- 在 CustomResourceDefinition 檔案中將 `v1` 設定為儲存版本,並使用 kubectl 應用。`storedVersions` 現在是 `v1beta1, v1`。
- 編寫升級程式以列出所有現有物件並以相同內容寫入它們。這會強制後端以當前儲存版本(即 `v1`)寫入物件。
- 從 CustomResourceDefinition 的 `status.storedVersions` 欄位中移除 `v1beta1`。
注意
以下是如何使用 `kubectl` 為 CRD 物件修補 `status` 子資源的示例。
kubectl patch customresourcedefinitions <CRD_Name> --subresource='status' --type='merge' -p '{"status":{"storedVersions":["v1"]}}'