CustomResourceDefinition 中的版本

本頁說明如何將版本資訊新增至 CustomResourceDefinitions,以指出 CustomResourceDefinitions 的穩定性層級,或使用 API 表示之間的轉換將您的 API 進階到新版本。它也說明如何將物件從一個版本升級到另一個版本。

開始之前

您需要有一個 Kubernetes 叢集,並且必須設定 kubectl 命令列工具以與您的叢集通訊。建議在至少有兩個節點且未充當控制平面主機的叢集上執行本教學課程。如果您還沒有叢集,可以使用 minikube 建立一個,或者您可以使用這些 Kubernetes playground 之一

您應該初步了解自訂資源

您的 Kubernetes 伺服器必須是 v1.16 或更新版本。若要檢查版本,請輸入 kubectl version

概觀

CustomResourceDefinition API 提供了一個工作流程,用於引入和升級到 CustomResourceDefinition 的新版本。

建立 CustomResourceDefinition 時,第一個版本會在 CustomResourceDefinition spec.versions 清單中設定為適當的穩定性層級和版本號碼。例如,v1beta1 表示第一個版本尚未穩定。所有自訂資源物件最初都會儲存在此版本。

建立 CustomResourceDefinition 後,用戶端可以開始使用 v1beta1 API。

稍後可能需要新增新版本,例如 v1

新增新版本

  1. 選擇轉換策略。由於自訂資源物件需要能夠在兩個版本中提供服務,這表示它們有時會以與儲存版本不同的版本提供服務。為了實現這一點,自訂資源物件有時必須在它們儲存的版本和它們服務的版本之間進行轉換。如果轉換涉及結構描述變更並需要自訂邏輯,則應使用轉換 Webhook。如果沒有結構描述變更,則可以使用預設的 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 中,新版本的 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,後接數字、可選的 betaalpha 指定,以及可選的其他數字版本資訊。廣義而言,版本字串可能看起來像 v2v2beta1。版本使用以下演算法排序:

  • 符合 Kubernetes 版本模式的條目會優先於不符合的條目進行排序。
  • 對於符合 Kubernetes 版本模式的條目,版本字串的數字部分會從大到小排序。
  • 如果字串 betaalpha 出現在第一個數字部分之後,它們會依該順序排序,在沒有 betaalpha 後綴的對等字串之後(預計為 GA 版本)。
  • 如果另一個數字跟在 betaalpha 之後,這些數字也會從大到小排序。
  • 不符合上述格式的字串會依字母順序排序,且數字部分不會被特殊處理。請注意,在以下範例中,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 中移除之前,較舊的 API 版本無法從 CustomResourceDefinition 資訊清單中移除。

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 伺服器

請參閱 自訂資源轉換 Webhook 伺服器的實作,該伺服器在 Kubernetes e2e 測試中經過驗證。Webhook 處理 API 伺服器傳送的 ConversionReview 請求,並將轉換結果包裝在 ConversionResponse 中傳回。請注意,請求包含需要獨立轉換的自訂資源列表,且不變更物件的順序。範例伺服器的組織方式使其可以重複用於其他轉換。大多數常見程式碼都位於 framework 檔案中,僅留下 一個函數需要針對不同的轉換進行實作。

允許的變更

轉換 Webhook 不得變更轉換後物件的 metadata 內部的任何內容,labelsannotations 除外。嘗試變更 nameUIDnamespace 將會遭到拒絕,並導致導致轉換的請求失敗。所有其他變更都會被忽略。

部署轉換 Webhook 服務

部署轉換 Webhook 的文件與 准入 Webhook 範例服務的文件相同。以下各節的假設是,轉換 Webhook 伺服器已部署到 default 命名空間中名為 example-conversion-webhook-server 的服務,並在路徑 /crdconvert 上服務流量。

設定 CustomResourceDefinition 以使用轉換 Webhook

可以擴充 None 轉換範例,透過修改 specconversion 區段來使用轉換 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,否則使用 localhost127.0.0.1 作為 host 是有風險的。此類安裝可能不具可攜性,或不容易在新叢集中執行。

scheme 必須為 "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 設定為呼叫連接埠 "1234" 上子路徑 "/my-path" 的服務,並使用自訂 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,其中 ConversionReview API 物件位於 apiextensions.k8s.io 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 列表中的第一個版本。如果列表中沒有任何版本受到 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 中指定了什麼

  • 如果指定了預設的 strategyNone,則對物件的唯一修改是變更 apiVersion 字串,以及可能的修剪未知的欄位(取決於設定)。請注意,如果儲存版本和請求版本之間的架構不同,這不太可能產生良好的結果。特別是,如果相同資料在不同版本之間以不同的欄位表示,則不應使用此策略。
  • 如果指定了Webhook 轉換,則此機制會控制轉換。

如果您更新現有的物件,它會以目前為儲存版本的版本重新寫入。這是物件可以從一個版本變更為另一個版本的唯一方式。

為了說明這一點,請考慮以下假設的事件序列

  1. 儲存版本為 v1beta1。您建立一個物件。它以版本 v1beta1 儲存
  2. 您將版本 v1 新增至 CustomResourceDefinition,並將其指定為儲存版本。此處 v1v1beta1 的架構相同,這通常是在 Kubernetes 生態系統中將 API 升級到穩定版時的情況。
  3. 您以版本 v1beta1 讀取您的物件,然後您再次以版本 v1 讀取該物件。除了 apiVersion 欄位之外,兩個傳回的物件都相同。
  4. 您建立一個新物件。它以版本 v1 儲存。您現在有兩個物件,其中一個物件位於 v1beta1,另一個物件位於 v1
  5. 您更新第一個物件。由於 v1 是目前的儲存版本,因此現在以版本 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
上次修改時間:2024 年 6 月 19 日下午 4:41 PST:修正 CRD 文件中錯誤命名的欄位 (#46863) (1dca66b534)