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`。

新增新版本

  1. 選擇一種轉換策略。由於自定義資源物件需要能夠以兩個版本提供服務,這意味著它們有時會以不同於儲存版本的版本提供服務。為了實現這一點,自定義資源物件有時必須在它們儲存的版本和它們提供服務的版本之間進行轉換。如果轉換涉及模式更改並需要自定義邏輯,則應使用轉換 Webhook。如果 SCHEMA 沒有變化,則可以使用預設的 `None` 轉換策略,並且在提供不同版本時只修改 `apiVersion` 欄位。
  2. 如果使用轉換 Webhook,請建立並部署轉換 Webhook。有關詳細資訊,請參閱Webhook 轉換
  3. 更新 CustomResourceDefinition,在 `spec.versions` 列表中包含新版本,並設定 `served:true`。此外,將 `spec.conversion` 欄位設定為所選的轉換策略。如果使用轉換 Webhook,請配置 `spec.conversion.webhookClientConfig` 欄位以呼叫 Webhook。

一旦添加了新版本,客戶端就可以逐步遷移到新版本。有些客戶端使用舊版本,而另一些客戶端使用新版本是完全安全的。

將儲存物件遷移到新版本

  1. 請參閱將現有物件升級到新的儲存版本一節。

在將物件升級到新的儲存版本之前、期間和之後,客戶端使用舊版本和新版本都是安全的。

移除舊版本

  1. 確保所有客戶端都已完全遷移到新版本。可以檢視 kube-apiserver 日誌,以幫助識別仍然透過舊版本訪問的客戶端。
  2. 在 `spec.versions` 列表中,將舊版本的 `served` 設定為 `false`。如果任何客戶端仍然意外地使用舊版本,它們可能會開始報告嘗試以舊版本訪問自定義資源物件時出現錯誤。如果發生這種情況,請將舊版本的 `served` 切換回 `true`,將剩餘的客戶端遷移到新版本,然後重複此步驟。
  3. 確保已完成將現有物件升級到新的儲存版本步驟。
    1. 驗證 CustomResourceDefinition 的 `spec.versions` 列表中新版本的 `storage` 是否設定為 `true`。
    2. 驗證 CustomResourceDefinition 的 `status.storedVersions` 中是否不再列出舊版本。
  4. 從 CustomResourceDefinition 的 `spec.versions` 列表中移除舊版本。
  5. 在轉換 Webhook 中放棄對舊版本的轉換支援。

指定多個版本

CustomResourceDefinition API 的 `versions` 欄位可用於支援你開發的自定義資源的多個版本。版本可以有不同的架構,並且轉換 Webhook 可以在版本之間轉換自定義資源。Webhook 轉換應在適用的情況下遵循 Kubernetes API 約定。具體來說,請參閱 API 更改文件,瞭解一組有用的注意事項和建議。

此示例顯示了一個具有兩個版本的 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]

上面的例子在版本之間有一個 None 轉換,它在轉換時只設置 `apiVersion` 欄位,不改變物件的其餘部分。當需要轉換時,API 伺服器還支援呼叫外部服務的 Webhook 轉換。例如,當:

  • 自定義資源以與儲存版本不同的版本請求時。
  • 在某個版本中建立 Watch,但更改後的物件儲存在另一個版本中。
  • 自定義資源 PUT 請求的版本與儲存版本不同。

為了涵蓋所有這些情況並最佳化 API 伺服器的轉換,轉換請求可能包含多個物件,以儘量減少外部呼叫。Webhook 應該獨立執行這些轉換。

編寫轉換 Webhook 伺服器

請參閱在 Kubernetes e2e 測試中驗證的自定義資源轉換 Webhook 伺服器的實現。Webhook 處理 API 伺服器傳送的 `ConversionReview` 請求,併發送回包裝在 `ConversionResponse` 中的轉換結果。請注意,請求包含需要獨立轉換且不改變物件順序的自定義資源列表。示例伺服器的組織方式是可重用於其他轉換。大多數通用程式碼位於框架檔案中,只留下一個函式需要為不同的轉換實現。

允許的突變

轉換 Webhook 不得修改轉換物件 `metadata` 中的任何內容,`labels` 和 `annotations` 除外。嘗試更改 `name`、`UID` 和 `namespace` 將被拒絕,並導致觸發轉換的請求失敗。所有其他更改都將被忽略。

部署轉換 Webhook 服務

部署轉換 Webhook 的文件與准入 Webhook 示例服務相同。以下部分假設轉換 Webhook 伺服器部署到 `default` 名稱空間中名為 `example-conversion-webhook-server` 的服務,並在路徑 `/crdconvert` 上提供流量。

配置 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 響應示例,指示轉換請求失敗,幷包含可選訊息

{
  "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 轉換,則此機制控制轉換。

如果你更新現有物件,它會以當前儲存版本重寫。這是物件從一個版本更改到另一個版本的唯一方式。

為了說明這一點,考慮以下一系列假設事件:

  1. 儲存版本是 `v1beta1`。你建立了一個物件。它以 `v1beta1` 版本儲存。
  2. 你將版本 `v1` 新增到你的 CustomResourceDefinition 並將其指定為儲存版本。在這裡,`v1` 和 `v1beta1` 的 schema 是相同的,這通常是在 Kubernetes 生態系統中將 API 提升到穩定版時的情況。
  3. 你以 `v1beta1` 版本讀取你的物件,然後再次以 `v1` 版本讀取該物件。除了 apiVersion 欄位外,兩個返回的物件都是相同的。
  4. 你建立了一個新物件。它以 `v1` 版本儲存。你現在有兩個物件,其中一個在 `v1beta1`,另一個在 `v1`。
  5. 你更新了第一個物件。它現在以 `v1` 版本儲存,因為這是當前的儲存版本。

以前的儲存版本

API 伺服器在 `storedVersions` 狀態欄位中記錄每個曾被標記為儲存版本的版本。物件可能已儲存在任何曾被指定為儲存版本的版本。儲存中不能存在從未作為儲存版本的版本的物件。

將現有物件升級到新的儲存版本

棄用版本和刪除支援時,請選擇儲存升級過程。

選項 1: 使用儲存版本遷移器

  1. 執行 儲存版本遷移器
  2. 從 CustomResourceDefinition 的 `status.storedVersions` 欄位中移除舊版本。

選項 2: 手動將現有物件升級到新的儲存版本

以下是將 `v1beta1` 升級到 `v1` 的示例過程。

  1. 在 CustomResourceDefinition 檔案中將 `v1` 設定為儲存版本,並使用 kubectl 應用。`storedVersions` 現在是 `v1beta1, v1`。
  2. 編寫升級程式以列出所有現有物件並以相同內容寫入它們。這會強制後端以當前儲存版本(即 `v1`)寫入物件。
  3. 從 CustomResourceDefinition 的 `status.storedVersions` 欄位中移除 `v1beta1`。
最後修改於 2025 年 2 月 19 日太平洋標準時間上午 11:19:更新 kubetl 子資源文件 (ab6b9ae2ed)