透過 CustomResourceDefinitions 擴充 Kubernetes API

本頁說明如何透過建立 CustomResourceDefinition,將自訂資源安裝到 Kubernetes API 中。

開始之前

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

您的 Kubernetes 伺服器必須是 1.16 或更新版本。若要檢查版本,請輸入 kubectl version。如果您使用的是仍受支援的舊版 Kubernetes,請切換到該版本的文件,以查看與您的叢集相關的建議。

建立 CustomResourceDefinition

當您建立新的 CustomResourceDefinition (CRD) 時,Kubernetes API 伺服器會為您指定的每個版本建立新的 RESTful 資源路徑。從 CRD 物件建立的自訂資源可以是命名空間範圍或叢集範圍,如 CRD 的 spec.scope 欄位中所指定。與現有的內建物件一樣,刪除命名空間會刪除該命名空間中的所有自訂物件。CustomResourceDefinition 本身是非命名空間範圍的,並且適用於所有命名空間。

例如,如果您將下列 CustomResourceDefinition 儲存到 resourcedefinition.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.stable.example.com
spec:
  # group name to use for REST API: /apis/<group>/<version>
  group: stable.example.com
  # list of versions supported by this CustomResourceDefinition
  versions:
    - name: v1
      # 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
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                cronSpec:
                  type: string
                image:
                  type: string
                replicas:
                  type: integer
  # 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

並建立它

kubectl apply -f resourcedefinition.yaml

然後會在以下位置建立新的命名空間 RESTful API 端點

/apis/stable.example.com/v1/namespaces/*/crontabs/...

然後可以使用此端點 URL 來建立和管理自訂物件。這些物件的 kind 將會是您在上面建立的 CustomResourceDefinition 物件規格中的 CronTab

建立端點可能需要幾秒鐘。您可以監看 CustomResourceDefinition 的 Established 條件是否為 true,或監看 API 伺服器的探索資訊,以查看您的資源是否顯示。

建立自訂物件

建立 CustomResourceDefinition 物件後,您可以建立自訂物件。自訂物件可以包含自訂欄位。這些欄位可以包含任意 JSON。在以下範例中,cronSpecimage 自訂欄位在 CronTab 類型的自訂物件中設定。CronTab 類型來自您在上面建立的 CustomResourceDefinition 物件的規格。

如果您將下列 YAML 儲存到 my-crontab.yaml

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * * */5"
  image: my-awesome-cron-image

並建立它

kubectl apply -f my-crontab.yaml

然後您可以使用 kubectl 管理您的 CronTab 物件。例如

kubectl get crontab

應該列印出像這樣的清單

NAME                 AGE
my-new-cron-object   6s

使用 kubectl 時,資源名稱不區分大小寫,您可以使用 CRD 中定義的單數或複數形式,以及任何簡短名稱。

您也可以檢視原始 YAML 資料

kubectl get ct -o yaml

您應該會看到它包含您用來建立它的 YAML 中的自訂 cronSpecimage 欄位

apiVersion: v1
items:
- apiVersion: stable.example.com/v1
  kind: CronTab
  metadata:
    annotations:
      kubectl.kubernetes.io/last-applied-configuration: |
        {"apiVersion":"stable.example.com/v1","kind":"CronTab","metadata":{"annotations":{},"name":"my-new-cron-object","namespace":"default"},"spec":{"cronSpec":"* * * * */5","image":"my-awesome-cron-image"}}        
    creationTimestamp: "2021-06-20T07:35:27Z"
    generation: 1
    name: my-new-cron-object
    namespace: default
    resourceVersion: "1326"
    uid: 9aab1d66-628e-41bb-a422-57b8b3b1f5a9
  spec:
    cronSpec: '* * * * */5'
    image: my-awesome-cron-image
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

刪除 CustomResourceDefinition

當您刪除 CustomResourceDefinition 時,伺服器將解除安裝 RESTful API 端點,並刪除其中儲存的所有自訂物件。

kubectl delete -f resourcedefinition.yaml
kubectl get crontabs
Error from server (NotFound): Unable to list {"stable.example.com" "v1" "crontabs"}: the server could not
find the requested resource (get crontabs.stable.example.com)

如果您稍後重新建立相同的 CustomResourceDefinition,它將從空白開始。

指定結構化綱要

CustomResource 會在自訂欄位中儲存結構化資料 (以及 API 伺服器隱含驗證的內建欄位 apiVersionkindmetadata)。透過 OpenAPI v3.0 驗證,可以指定綱要,該綱要在建立和更新期間進行驗證,請比較下方以取得此類綱要的詳細資訊和限制。

使用 apiextensions.k8s.io/v1,結構化綱要的定義對於 CustomResourceDefinition 是強制性的。在 CustomResourceDefinition 的 Beta 版本中,結構化綱要是選用的。

結構化綱要是 OpenAPI v3.0 驗證綱要,其

  1. 為根目錄、物件節點的每個指定欄位 (透過 OpenAPI 中的 propertiesadditionalProperties) 以及陣列節點中的每個項目 (透過 OpenAPI 中的 items) 指定非空類型 (透過 OpenAPI 中的 type),但下列情況除外:
    • 具有 x-kubernetes-int-or-string: true 的節點
    • 具有 x-kubernetes-preserve-unknown-fields: true 的節點
  2. 針對物件中的每個欄位以及陣列中的每個項目,這些項目指定於 allOfanyOfoneOfnot 中的任何一個,綱要也會指定這些邏輯連接詞之外的欄位/項目(比較範例 1 和 2)。
  3. 不會在 allOfanyOfoneOfnot 內設定 descriptiontypedefaultadditionalPropertiesnullable,但 x-kubernetes-int-or-string: true 的兩種模式除外(見下文)。
  4. 如果指定了 metadata,則僅允許對 metadata.namemetadata.generateName 進行限制。

非結構化範例 1

allOf:
- properties:
    foo:
      ...

與規則 2 衝突。以下是正確的寫法

properties:
  foo:
    ...
allOf:
- properties:
    foo:
      ...

非結構化範例 2

allOf:
- items:
    properties:
      foo:
        ...

與規則 2 衝突。以下是正確的寫法

items:
  properties:
    foo:
      ...
allOf:
- items:
    properties:
      foo:
        ...

非結構化範例 3

properties:
  foo:
    pattern: "abc"
  metadata:
    type: object
    properties:
      name:
        type: string
        pattern: "^a"
      finalizers:
        type: array
        items:
          type: string
          pattern: "my-finalizer"
anyOf:
- properties:
    bar:
      type: integer
      minimum: 42
  required: ["bar"]
  description: "foo bar object"

由於以下違規行為,因此不是結構化綱要

  • 根目錄的類型遺失(規則 1)。
  • foo 的類型遺失(規則 1)。
  • anyOf 內部的 bar 未在外部指定(規則 2)。
  • bartype 位於 anyOf 內部(規則 3)。
  • 描述設定在 anyOf 內部(規則 3)。
  • metadata.finalizers 可能未受限制(規則 4)。

相反地,以下對應的綱要是結構化的

type: object
description: "foo bar object"
properties:
  foo:
    type: string
    pattern: "abc"
  bar:
    type: integer
  metadata:
    type: object
    properties:
      name:
        type: string
        pattern: "^a"
anyOf:
- properties:
    bar:
      minimum: 42
  required: ["bar"]

結構化綱要規則的違規情況會在 CustomResourceDefinition 的 NonStructural 條件中報告。

欄位修剪

CustomResourceDefinitions 將驗證過的資源資料儲存在叢集的持久儲存區 etcd 中。與原生 Kubernetes 資源(例如 ConfigMap)一樣,如果您指定的欄位 API 伺服器無法辨識,則未知的欄位會在持久儲存之前被修剪(移除)。

apiextensions.k8s.io/v1beta1 轉換為 apiextensions.k8s.io/v1 的 CRD 可能缺少結構化綱要,且 spec.preserveUnknownFields 可能為 true

對於以 apiextensions.k8s.io/v1beta1 建立且 spec.preserveUnknownFields 設定為 true 的舊版 CustomResourceDefinition 物件,以下情況也適用

  • 未啟用修剪。
  • 您可以儲存任意資料。

為了與 apiextensions.k8s.io/v1 相容,請更新您的自訂資源定義以

  1. 使用結構化 OpenAPI 綱要。
  2. spec.preserveUnknownFields 設定為 false

如果您將下列 YAML 儲存到 my-crontab.yaml

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * * */5"
  image: my-awesome-cron-image
  someRandomField: 42

並建立它

kubectl create --validate=false -f my-crontab.yaml -o yaml

您的輸出會類似於

apiVersion: stable.example.com/v1
kind: CronTab
metadata:
  creationTimestamp: 2017-05-31T12:56:35Z
  generation: 1
  name: my-new-cron-object
  namespace: default
  resourceVersion: "285"
  uid: 9423255b-4600-11e7-af6a-28d2447dc82b
spec:
  cronSpec: '* * * * */5'
  image: my-awesome-cron-image

請注意,欄位 someRandomField 已被修剪。

此範例關閉了用戶端驗證,以示範 API 伺服器的行為,方法是加入 --validate=false 命令列選項。由於 OpenAPI 驗證綱要也會發布給用戶端,因此 kubectl 也會檢查未知的欄位,並在這些物件傳送至 API 伺服器之前就拒絕它們。

控制修剪

預設情況下,自訂資源的所有未指定欄位(跨所有版本)都會被修剪。但是,可以透過在 結構化 OpenAPI v3 驗證綱要中加入 x-kubernetes-preserve-unknown-fields: true,選擇不針對特定欄位子樹進行修剪。

例如

type: object
properties:
  json:
    x-kubernetes-preserve-unknown-fields: true

欄位 json 可以儲存任何 JSON 值,而不會修剪任何內容。

您也可以部分指定允許的 JSON;例如

type: object
properties:
  json:
    x-kubernetes-preserve-unknown-fields: true
    type: object
    description: this is arbitrary JSON

透過這樣做,僅允許 object 類型的值。

針對每個指定的屬性(或 additionalProperties),再次啟用修剪

type: object
properties:
  json:
    x-kubernetes-preserve-unknown-fields: true
    type: object
    properties:
      spec:
        type: object
        properties:
          foo:
            type: string
          bar:
            type: string

透過這樣做,值

json:
  spec:
    foo: abc
    bar: def
    something: x
  status:
    something: x

會修剪為

json:
  spec:
    foo: abc
    bar: def
  status:
    something: x

這表示指定 spec 物件中的 something 欄位會被修剪,但外部的所有內容則不會。

IntOrString

具有 x-kubernetes-int-or-string: true 的綱要中的節點會從規則 1 中排除,因此以下是結構化的

type: object
properties:
  foo:
    x-kubernetes-int-or-string: true

這些節點也部分從規則 3 中排除,因為允許以下兩種模式(完全相同,附加欄位的順序沒有變化)

x-kubernetes-int-or-string: true
anyOf:
  - type: integer
  - type: string
...

以及

x-kubernetes-int-or-string: true
allOf:
  - anyOf:
      - type: integer
      - type: string
  - ... # zero or more
...

透過其中一種規格,整數和字串都可以驗證。

發布驗證綱要中,x-kubernetes-int-or-string: true 會展開為上面顯示的兩種模式之一。

RawExtension

RawExtensions(如 runtime.RawExtension 中)包含完整的 Kubernetes 物件,即具有 apiVersionkind 欄位。

可以透過設定 x-kubernetes-embedded-resource: true 來指定這些嵌入式物件(完全沒有限制或部分指定)。例如

type: object
properties:
  foo:
    x-kubernetes-embedded-resource: true
    x-kubernetes-preserve-unknown-fields: true

在這裡,欄位 foo 保留完整的物件,例如

foo:
  apiVersion: v1
  kind: Pod
  spec:
    ...

由於 x-kubernetes-preserve-unknown-fields: true 是與此一起指定的,因此不會修剪任何內容。但是,x-kubernetes-preserve-unknown-fields: true 的使用是選用的。

透過 x-kubernetes-embedded-resource: trueapiVersionkindmetadata 會隱含地指定和驗證。

提供 CRD 的多個版本

請參閱 自訂資源定義版本控制,以取得關於提供 CustomResourceDefinition 的多個版本以及將您的物件從一個版本移轉到另一個版本的更多資訊。

進階主題

定案器

Finalizers 允許控制器實作非同步的預先刪除掛鉤。自訂物件支援類似於內建物件的 finalizers。

您可以像這樣將 finalizer 新增至自訂物件

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  finalizers:
  - stable.example.com/finalizer

自訂 finalizers 的識別碼包含網域名稱、正斜線和 finalizer 的名稱。任何控制器都可以將 finalizer 新增至任何物件的 finalizers 清單。

對具有 finalizers 的物件的第一個刪除請求會設定 metadata.deletionTimestamp 欄位的值,但不會刪除它。一旦設定此值,finalizers 清單中的項目就只能移除。在任何 finalizers 存在的情況下,也不可能強制刪除物件。

當設定 metadata.deletionTimestamp 欄位時,監看物件的控制器會執行它們處理的任何 finalizers,並在完成後從清單中移除 finalizer。每個控制器都有責任從清單中移除其 finalizer。

metadata.deletionGracePeriodSeconds 的值控制輪詢更新之間的時間間隔。

一旦 finalizers 清單為空,表示所有 finalizers 都已執行,資源就會被 Kubernetes 刪除。

驗證

自訂資源會透過 OpenAPI v3.0 綱要、啟用 驗證規則功能時的 x-kubernetes-validations 來驗證,而且您可以使用 准入 Webhook 新增額外的驗證。

此外,以下限制適用於綱要

  • 這些欄位無法設定

    • definitions,
    • dependencies,
    • deprecated,
    • discriminator,
    • id,
    • patternProperties,
    • readOnly,
    • writeOnly,
    • xml,
    • $ref.
  • 欄位 uniqueItems 無法設定為 true

  • 欄位 additionalProperties 無法設定為 false

  • 欄位 additionalPropertiesproperties 互斥。

當啟用 驗證規則功能且 CustomResourceDefinition 綱要是 結構化綱要時,x-kubernetes-validations 擴充功能可用於使用 Common Expression Language (CEL) 表達式來驗證自訂資源。

請參閱 結構化綱要章節,以了解其他限制和 CustomResourceDefinition 功能。

綱要定義於 CustomResourceDefinition 中。在以下範例中,CustomResourceDefinition 將以下驗證套用至自訂物件

  • spec.cronSpec 必須是字串,且必須採用規則運算式所描述的形式。
  • spec.replicas 必須是整數,且最小值必須為 1,最大值必須為 10。

將 CustomResourceDefinition 儲存至 resourcedefinition.yaml

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com
spec:
  group: stable.example.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        # openAPIV3Schema is the schema for validating custom objects.
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                cronSpec:
                  type: string
                  pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
                image:
                  type: string
                replicas:
                  type: integer
                  minimum: 1
                  maximum: 10
  scope: Namespaced
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
    shortNames:
    - ct

並建立它

kubectl apply -f resourcedefinition.yaml

如果種類為 CronTab 的自訂物件的欄位中存在無效值,則會拒絕建立自訂物件的請求。在以下範例中,自訂物件包含具有無效值的欄位

  • spec.cronSpec 與規則運算式不符。
  • spec.replicas 大於 10。

如果您將下列 YAML 儲存到 my-crontab.yaml

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * *"
  image: my-awesome-cron-image
  replicas: 15

並嘗試建立它

kubectl apply -f my-crontab.yaml

然後您會收到錯誤

The CronTab "my-new-cron-object" is invalid: []: Invalid value: map[string]interface {}{"apiVersion":"stable.example.com/v1", "kind":"CronTab", "metadata":map[string]interface {}{"name":"my-new-cron-object", "namespace":"default", "deletionTimestamp":interface {}(nil), "deletionGracePeriodSeconds":(*int64)(nil), "creationTimestamp":"2017-09-05T05:20:07Z", "uid":"e14d79e7-91f9-11e7-a598-f0761cb232d1", "clusterName":""}, "spec":map[string]interface {}{"cronSpec":"* * * *", "image":"my-awesome-cron-image", "replicas":15}}:
validation failure list:
spec.cronSpec in body should match '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
spec.replicas in body should be less than or equal to 10

如果欄位包含有效值,則會接受物件建立請求。

將以下 YAML 儲存至 my-crontab.yaml

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * * */5"
  image: my-awesome-cron-image
  replicas: 5

並建立它

kubectl apply -f my-crontab.yaml
crontab "my-new-cron-object" created

驗證棘輪效應

功能狀態: Kubernetes v1.30 [beta] (預設啟用:true)

如果您使用的 Kubernetes 版本早於 v1.30,您需要明確啟用 CRDValidationRatcheting 功能閘道,才能使用此行為,然後此行為會套用至您叢集中的所有 CustomResourceDefinitions。

如果您啟用了功能閘道,Kubernetes 會為 CustomResourceDefinitions 實作驗證棘輪效應。API 伺服器願意接受對更新後無效的資源進行更新,前提是資源中未通過驗證的每個部分都未被更新操作變更。換句話說,資源的任何無效部分保持無效,則必須已經是錯誤的。您無法使用此機制來更新有效的資源,使其變為無效。

此功能允許 CRD 的作者在特定條件下放心地將新的驗證新增至 OpenAPIV3 綱要。使用者可以安全地更新到新的綱要,而無需提高物件的版本或中斷工作流程。

雖然 CRD 的 OpenAPIV3 綱要中放置的大多數驗證都支援棘輪效應,但也有一些例外情況。在 Kubernetes 1.32 的實作中,以下 OpenAPIV3 綱要驗證不受棘輪效應支援,如果違反,將繼續像平常一樣拋出錯誤

  • 量詞

    • allOf
    • oneOf
    • anyOf
    • not
    • 這些欄位之一的後代中的任何驗證
  • x-kubernetes-validations 對於 Kubernetes 1.28,CRD 驗證規則會被棘輪效應忽略。從 Kubernetes 1.29 的 Alpha 2 開始,只有當 x-kubernetes-validations 不參照 oldSelf 時,才會進行棘輪效應。

    轉換規則永遠不會進行棘輪效應:只有不使用 oldSelf 的規則引發的錯誤,在其值未變更的情況下才會自動進行棘輪效應。

    若要為 CEL 表達式撰寫自訂棘輪效應邏輯,請查看 optionalOldSelf

  • x-kubernetes-list-type 由於變更子綱要的清單類型而產生的錯誤將不會進行棘輪效應。例如,將 set 新增至具有重複項目的清單將始終導致錯誤。

  • x-kubernetes-map-keys 由於變更清單綱要的對應金鑰而產生的錯誤將不會進行棘輪效應。

  • required 由於變更必要欄位清單而產生的錯誤將不會進行棘輪效應。

  • properties 新增/移除/修改屬性的名稱不會進行棘輪效應,但如果屬性的名稱保持不變,則變更每個屬性綱要和子綱要中的驗證可能會進行棘輪效應。

  • additionalProperties 移除先前指定的 additionalProperties 驗證將不會進行棘輪效應。

  • metadata 來自 Kubernetes 內建物件 metadata 驗證的錯誤不會進行棘輪效應(例如物件名稱或標籤值中的字元)。如果您為自訂資源的 metadata 指定自己的額外規則,則該額外驗證將會進行棘輪效應。

驗證規則

功能狀態: Kubernetes v1.29 [stable]

驗證規則使用 Common Expression Language (CEL) 來驗證自訂資源值。驗證規則使用 x-kubernetes-validations 擴充功能包含在 CustomResourceDefinition 綱要中。

規則的作用域設定為綱要中 x-kubernetes-validations 擴充功能的位置。而 CEL 表達式中的 self 變數會繫結至作用域值。

所有驗證規則的作用域都設定為目前的物件:不支援跨物件或具狀態的驗證規則。

例如

  ...
  openAPIV3Schema:
    type: object
    properties:
      spec:
        type: object
        x-kubernetes-validations:
          - rule: "self.minReplicas <= self.replicas"
            message: "replicas should be greater than or equal to minReplicas."
          - rule: "self.replicas <= self.maxReplicas"
            message: "replicas should be smaller than or equal to maxReplicas."
        properties:
          ...
          minReplicas:
            type: integer
          replicas:
            type: integer
          maxReplicas:
            type: integer
        required:
          - minReplicas
          - replicas
          - maxReplicas

將拒絕建立此自訂資源的請求

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  minReplicas: 0
  replicas: 20
  maxReplicas: 10

並傳回以下回應

The CronTab "my-new-cron-object" is invalid:
* spec: Invalid value: map[string]interface {}{"maxReplicas":10, "minReplicas":0, "replicas":20}: replicas should be smaller than or equal to maxReplicas.

x-kubernetes-validations 可以有多個規則。x-kubernetes-validations 下的 rule 代表將由 CEL 評估的表達式。message 代表驗證失敗時顯示的訊息。如果未設定訊息,則以上回應將為

The CronTab "my-new-cron-object" is invalid:
* spec: Invalid value: map[string]interface {}{"maxReplicas":10, "minReplicas":0, "replicas":20}: failed rule: self.replicas <= self.maxReplicas

驗證規則會在建立/更新 CRD 時編譯。如果驗證規則編譯失敗,則 CRD 建立/更新的請求將會失敗。編譯過程也包含類型檢查。

編譯失敗

  • no_matching_overload:此函數沒有適用於引數類型的多載。

    例如,針對整數類型欄位的規則(例如 self == true)將會產生錯誤

    Invalid value: apiextensions.ValidationRule{Rule:"self == true", Message:""}: compilation failed: ERROR: \<input>:1:6: found no matching overload for '_==_' applied to '(int, bool)'
    
  • no_such_field:不包含所需的欄位。

    例如,針對不存在欄位的規則(例如 self.nonExistingField > 0)將傳回以下錯誤

    Invalid value: apiextensions.ValidationRule{Rule:"self.nonExistingField > 0", Message:""}: compilation failed: ERROR: \<input>:1:5: undefined field 'nonExistingField'
    
  • invalid argument:巨集引數無效。

    例如,規則(例如 has(self))將傳回錯誤

    Invalid value: apiextensions.ValidationRule{Rule:"has(self)", Message:""}: compilation failed: ERROR: <input>:1:4: invalid argument to has() macro
    

驗證規則範例

規則目的
self.minReplicas <= self.replicas && self.replicas <= self.maxReplicas驗證定義副本的三個欄位的順序是否正確
'Available' in self.stateCounts驗證具有 'Available' 金鑰的項目是否存在於對應中
(size(self.list1) == 0) != (size(self.list2) == 0)驗證兩個清單中只有一個是非空的,但不是兩個都是
!('MY_KEY' in self.map1) || self['MY_KEY'].matches('^[a-zA-Z]*$')驗證對應中特定金鑰的值(如果它在對應中)
self.envars.filter(e, e.name == 'MY_ENV').all(e, e.value.matches('^[a-zA-Z]*$')驗證金鑰欄位 'name' 為 'MY_ENV' 的 listMap 項目的 'value' 欄位
has(self.expired) && self.created + self.ttl < self.expired驗證 'expired' 日期是否在 'create' 日期加上 'ttl' 期間之後
self.health.startsWith('ok')驗證 'health' 字串欄位是否具有前綴 'ok'
self.widgets.exists(w, w.key == 'x' && w.foo < 10)驗證具有金鑰 'x' 的 listMap 項目的 'foo' 屬性是否小於 10
type(self) == string ? self == '100%' : self == 1000驗證 int-or-string 欄位的整數和字串案例
self.metadata.name.startsWith(self.prefix)驗證物件的名稱是否具有另一個欄位值的前綴
self.set1.all(e, !(e in self.set2))驗證兩個 listSets 是否不相交
size(self.names) == size(self.details) && self.names.all(n, n in self.details)驗證 'details' 對應是否以 'names' listSet 中的項目作為金鑰
size(self.clusters.filter(c, c.name == self.primary)) == 1驗證 'primary' 屬性在 'clusters' listMap 中是否只有一個出現次數

Xref: CEL 上支援的評估

  • 如果規則的作用域設定為資源的根目錄,則它可能會選取在 CRD 的 OpenAPIv3 綱要中宣告的任何欄位,以及 apiVersionkindmetadata.namemetadata.generateName。這包括在同一個表達式中選取 specstatus 中的欄位

      ...
      openAPIV3Schema:
        type: object
        x-kubernetes-validations:
          - rule: "self.status.availableReplicas >= self.spec.minReplicas"
        properties:
            spec:
              type: object
              properties:
                minReplicas:
                  type: integer
                ...
            status:
              type: object
              properties:
                availableReplicas:
                  type: integer
    
  • 如果規則的作用域設定為具有屬性的物件,則物件的可存取屬性可以透過 self.field 進行欄位選取,並且可以透過 has(self.field) 檢查欄位的存在。在 CEL 表達式中,Null 值欄位會被視為不存在的欄位。

      ...
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            x-kubernetes-validations:
              - rule: "has(self.foo)"
            properties:
              ...
              foo:
                type: integer
    
  • 如果規則的作用域設定為具有 additionalProperties 的物件(即對應),則對應的值可以透過 self[mapKey] 存取,可以透過 mapKey in self 檢查對應的包含關係,並且可以透過 CEL 巨集和函數(例如 self.all(...))存取對應的所有項目。

      ...
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            x-kubernetes-validations:
              - rule: "self['xyz'].foo > 0"
            additionalProperties:
              ...
              type: object
              properties:
                foo:
                  type: integer
    
  • 如果規則的作用域設定為陣列,則陣列的元素可以透過 self[i] 以及巨集和函數存取。

      ...
      openAPIV3Schema:
        type: object
        properties:
          ...
          foo:
            type: array
            x-kubernetes-validations:
              - rule: "size(self) == 1"
            items:
              type: string
    
  • 如果規則的作用域設定為純量,則 self 會繫結至純量值。

      ...
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              ...
              foo:
                type: integer
                x-kubernetes-validations:
                - rule: "self > 0"
    

範例

欄位規則的作用域類型規則範例
根物件self.status.actual <= self.spec.maxDesired
物件的對應self.components['Widget'].priority < 10
整數清單self.values.all(value, value >= 0 && value < 100)
字串self.startsWith('kube')

apiVersionkindmetadata.namemetadata.generateName 始終可以從物件的根目錄以及任何 x-kubernetes-embedded-resource 註解的物件存取。無法存取其他 metadata 屬性。

透過 x-kubernetes-preserve-unknown-fields 保留在自訂資源中的未知資料在 CEL 表達式中無法存取。這包括

  • 透過具有 x-kubernetes-preserve-unknown-fields 的物件綱要保留的未知欄位值。

  • 屬性綱要是「未知類型」的物件屬性。「未知類型」以遞迴方式定義為

    • 沒有類型且 x-kubernetes-preserve-unknown-fields 設定為 true 的綱要
    • 項目綱要是「未知類型」的陣列
    • additionalProperties 綱要是「未知類型」的物件

只有 [a-zA-Z_.-/][a-zA-Z0-9_.-/]* 形式的屬性名稱可以存取。當在表達式中存取時,可存取的屬性名稱會根據以下規則逸出

逸出序列等效的屬性名稱
__underscores____
__dot__.
__dash__-
__slash__/
__{keyword}__CEL 保留關鍵字

注意:CEL 保留關鍵字需要與確切的屬性名稱相符才能逸出(例如,單字 sprint 中的 int 不會逸出)。

逸出範例

屬性名稱具有逸出屬性名稱的規則
namespaceself.__namespace__ > 0
x-propself.x__dash__prop > 0
redact__dself.redact__underscores__d > 0
字串self.startsWith('kube')

對於 x-kubernetes-list-typesetmap 的陣列,等式會忽略元素順序,即 [1, 2] == [2, 1]。對於具有 x-kubernetes-list-type 的陣列,串連會使用清單類型的語意

  • setX + Y 執行聯集,其中保留 X 中所有元素的陣列位置,並附加 Y 中不相交的元素,同時保留其部分順序。

  • mapX + Y 執行合併,其中保留 X 中所有金鑰的陣列位置,但當 XY 的金鑰集相交時,這些值會被 Y 中的值覆寫。具有不相交金鑰的 Y 中的元素會被附加,同時保留其部分順序。

以下是 OpenAPIv3 和 CEL 類型之間的宣告類型對應

OpenAPIv3 類型CEL 類型
具有屬性的 'object'物件 /「訊息類型」
具有 AdditionalProperties 的 'object'對應
具有 x-kubernetes-embedded-type 的 'object'物件 /「訊息類型」,'apiVersion'、'kind'、'metadata.name' 和 'metadata.generateName' 隱含地包含在綱要中
具有 x-kubernetes-preserve-unknown-fields 的 'object'物件 /「訊息類型」,未知欄位在 CEL 表達式中不可存取
x-kubernetes-int-or-string動態物件,可以是整數或字串,type(value) 可以用於檢查類型
'array'清單
具有 x-kubernetes-list-type=map 的 'array'具有基於對應的等式和唯一金鑰保證的清單
具有 x-kubernetes-list-type=set 的 'array'具有基於集合的等式和唯一項目保證的清單
'boolean'布林值
'number'(所有格式)雙精度浮點數
'integer'(所有格式)整數 (64)
'null'null_type
'string'字串
'string',格式為 byte (base64 編碼)位元組
'string',格式為 date時間戳記 (google.protobuf.Timestamp)
'string',格式為 datetime時間戳記 (google.protobuf.Timestamp)
'string',格式為 duration持續時間 (google.protobuf.Duration)

xref: CEL 類型OpenAPI 類型Kubernetes 結構化綱要

messageExpression 欄位

message 欄位類似,後者定義了驗證規則失敗時報告的字串,messageExpression 允許您使用 CEL 表達式來建構訊息字串。這允許您在驗證失敗訊息中插入更具描述性的資訊。messageExpression 必須評估字串,並且可以使用與 rule 欄位相同的變數。例如

x-kubernetes-validations:
- rule: "self.x <= self.maxLimit"
  messageExpression: '"x exceeded max limit of " + string(self.maxLimit)'

請記住,CEL 字串串連(+ 運算子)不會自動轉換為字串。如果您有非字串純量,請使用 string(<value>) 函數將純量轉換為字串,如以上範例所示。

messageExpression 必須評估為字串,這會在寫入 CRD 時進行檢查。請注意,可以在同一個規則上設定 messagemessageExpression,如果兩者都存在,則會使用 messageExpression。但是,如果 messageExpression 評估為錯誤,則會改為使用 message 中定義的字串,並且會記錄 messageExpression 錯誤。如果 messageExpression 中定義的 CEL 表達式產生空字串或包含換行符號的字串,也會發生此回退。

如果滿足上述條件之一,且未設定 message,則會改為使用預設的驗證失敗訊息。

messageExpression 是 CEL 表達式,因此 驗證函數的資源使用中列出的限制適用。如果在 messageExpression 執行期間由於資源限制而停止評估,則不會執行進一步的驗證規則。

設定 messageExpression 是選用的。

message 欄位

如果您想要設定靜態訊息,您可以提供 message 而不是 messageExpression。如果驗證失敗,message 的值會用作不透明的錯誤字串。

設定 message 是選用的。

reason 欄位

您可以在 validation 中新增機器可讀的驗證失敗原因,以便在請求未通過此驗證規則時傳回。

例如

x-kubernetes-validations:
- rule: "self.x <= self.maxLimit"
  reason: "FieldValueInvalid"

傳回給呼叫者的 HTTP 狀態碼將與第一個失敗的驗證規則的原因相符。目前支援的原因為:「FieldValueInvalid」、「FieldValueForbidden」、「FieldValueRequired」、「FieldValueDuplicate」。如果未設定或原因不明,則預設使用「FieldValueInvalid」。

設定 reason 是選用的。

fieldPath 欄位

您可以指定驗證失敗時傳回的欄位路徑。

例如

x-kubernetes-validations:
- rule: "self.foo.test.x <= self.maxLimit"
  fieldPath: ".foo.test.x"

在以上範例中,驗證檢查欄位 x 的值應小於 maxLimit 的值。如果未指定 fieldPath,則當驗證失敗時,fieldPath 將預設為 self 的作用域位置。如果指定了 fieldPath,則傳回的錯誤將使 fieldPath 正確參照欄位 x 的位置。

fieldPath 值必須是相對於此綱要中 x-kubernetes-validations 擴充功能位置的 JSON 路徑。此外,它應參照綱要內的現有欄位。例如,當驗證檢查對應 testMap 下的特定屬性 foo 時,您可以將 fieldPath 設定為 ".testMap.foo".testMap['foo']'。如果驗證需要檢查兩個清單中的唯一屬性,則 fieldPath 可以設定為其中一個清單。例如,它可以設定為 .testList1.testList2。它支援子操作以參照目前的現有欄位。請參閱 Kubernetes 中的 JSONPath 支援以取得更多資訊。fieldPath 欄位不支援以數字方式索引陣列。

設定 fieldPath 是選用的。

optionalOldSelf 欄位

功能狀態: Kubernetes v1.30 [beta] (預設啟用:true)

如果您的叢集未啟用 CRD 驗證棘輪效應,則 CustomResourceDefinition API 不包含此欄位,嘗試設定它可能會導致錯誤。

optionalOldSelf 欄位是一個布林值欄位,它會改變以下描述的 轉換規則的行為。通常,如果無法確定 oldSelf,則轉換規則將不會評估:在物件建立期間或在更新中引入新值時。

如果 optionalOldSelf 設定為 true,則轉換規則將始終被評估,並且 oldSelf 的類型將變更為 CEL Optional 類型。

在綱要作者希望使用比 預設的基於等式的行為提供的更具控制力的工具來對新值引入更新、通常更嚴格的限制,同時仍然允許使用較舊的驗證來「祖父化」或棘輪化舊值的情況下,optionalOldSelf 非常有用。

使用範例

CEL描述
`self.foo == "foo"
[oldSelf.orValue(""), self].all(x, ["OldCase1", "OldCase2"].exists(case, x == case))
oldSelf.optMap(o, o.size()).orValue(0) < 4

驗證函數

可用的函數包括

轉換規則

包含參照識別碼 oldSelf 的表達式的規則會隱含地被視為轉換規則。轉換規則允許綱要作者防止兩個原本有效的狀態之間的特定轉換。例如

type: string
enum: ["low", "medium", "high"]
x-kubernetes-validations:
- rule: "!(self == 'high' && oldSelf == 'low') && !(self == 'low' && oldSelf == 'high')"
  message: cannot transition directly between 'low' and 'high'

與其他規則不同,轉換規則僅適用於符合以下條件的操作

  • 該操作更新現有的物件。轉換規則永遠不適用於建立操作。

  • 舊值和新值都存在。仍然可以透過在父節點上放置轉換規則來檢查值是否已新增或移除。轉換規則永遠不適用於自訂資源建立。當放置在選用欄位上時,轉換規則將不適用於設定或取消設定欄位的更新操作。

  • 轉換規則驗證的綱要節點的路徑必須解析為可在舊物件和新物件之間比較的節點。例如,清單項目及其後代 (spec.foo[10].bar) 不一定可以在現有物件和稍後對同一物件的更新之間建立關聯。

如果綱要節點包含永遠無法套用的轉換規則(例如「oldSelf 無法在路徑內綱要的不可關聯部分上使用」),則會在 CRD 寫入時產生錯誤。

轉換規則僅允許在綱要的可關聯部分上使用。如果所有 array 父綱要的類型都是 x-kubernetes-list-type=map,則綱要的一部分是可關聯的;任何 setatomic 陣列父綱要都會使 selfoldSelf 之間的明確關聯變得不可能。

以下是一些轉換規則的範例

轉換規則範例
使用案例規則
不可變性self.foo == oldSelf.foo
防止指派後修改/移除oldSelf != 'bar' || self == 'bar'!has(oldSelf.field) || has(self.field)
僅附加集合self.all(element, element in oldSelf)
如果先前的值是 X,則新值只能是 A 或 B,不能是 Y 或 ZoldSelf != 'X' || self in ['A', 'B']
單調(非遞減)計數器self >= oldSelf

驗證函數的資源使用

當您建立或更新使用驗證規則的 CustomResourceDefinition 時,API 伺服器會檢查執行這些驗證規則可能產生的影響。如果評估某個規則的執行成本過高,則 API 伺服器會拒絕建立或更新操作,並傳回錯誤訊息。在執行階段也使用類似的系統來觀察解譯器採取的動作。如果解譯器執行的指令過多,則會停止規則的執行,並產生錯誤。每個 CustomResourceDefinition 也被允許一定量的資源來完成執行其所有驗證規則。如果在建立時評估其規則的總和超過該限制,則也會發生驗證錯誤。

如果您僅指定始終花費相同時間量的規則,而與其輸入的大小無關,則您不太可能遇到驗證資源預算的問題。例如,斷言 self.foo == 1 的規則本身沒有任何在驗證資源預算群組上被拒絕的風險。但是,如果 foo 是字串,並且您定義了驗證規則 self.foo.contains("someString"),則該規則的執行時間會根據 foo 的長度而變長。另一個範例是,如果 foo 是陣列,並且您指定了驗證規則 self.foo.all(x, x > 5)。成本系統始終假設最壞情況,如果未給出 foo 長度的限制,並且這將發生在任何可以迭代的內容(清單、對應等)上。

因此,最佳做法是針對驗證規則中將處理的任何內容,透過 maxItemsmaxPropertiesmaxLength 設定限制,以防止成本評估期間發生驗證錯誤。例如,給定具有一個規則的此綱要

openAPIV3Schema:
  type: object
  properties:
    foo:
      type: array
      items:
        type: string
      x-kubernetes-validations:
        - rule: "self.all(x, x.contains('a string'))"

然後 API 伺服器會基於驗證預算理由拒絕此規則,並產生錯誤

spec.validation.openAPIV3Schema.properties[spec].properties[foo].x-kubernetes-validations[0].rule: Forbidden:
CEL rule exceeded budget by more than 100x (try simplifying the rule, or adding maxItems, maxProperties, and
maxLength where arrays, maps, and strings are used)

拒絕發生是因為 self.all 意味著在 foo 中的每個字串上呼叫 contains(),這反過來會檢查給定的字串,以查看它是否包含 'a string'。在沒有限制的情況下,這是一個非常昂貴的規則。

如果您未指定任何驗證限制,則此規則的估計成本將超過每個規則的成本限制。但是,如果您在適當的位置新增限制,則規則將被允許

openAPIV3Schema:
  type: object
  properties:
    foo:
      type: array
      maxItems: 25
      items:
        type: string
        maxLength: 10
      x-kubernetes-validations:
        - rule: "self.all(x, x.contains('a string'))"

成本評估系統除了規則本身的估計成本外,還會考慮規則將被執行的次數。例如,以下規則將具有與先前範例相同的估計成本(儘管規則現在定義在個別陣列項目上)

openAPIV3Schema:
  type: object
  properties:
    foo:
      type: array
      maxItems: 25
      items:
        type: string
        x-kubernetes-validations:
          - rule: "self.contains('a string'))"
        maxLength: 10

如果清單內的清單具有使用 self.all 的驗證規則,則這比具有相同規則的非巢狀清單要昂貴得多。在非巢狀清單上可能允許的規則可能需要在兩個巢狀清單上設定較低的限制才能被允許。例如,即使沒有設定限制,以下規則也是允許的

openAPIV3Schema:
  type: object
  properties:
    foo:
      type: array
      items:
        type: integer
    x-kubernetes-validations:
      - rule: "self.all(x, x == 5)"

但是,以下綱要(新增了巢狀陣列)上的相同規則會產生驗證錯誤

openAPIV3Schema:
  type: object
  properties:
    foo:
      type: array
      items:
        type: array
        items:
          type: integer
        x-kubernetes-validations:
          - rule: "self.all(x, x == 5)"

這是因為 foo 的每個項目本身都是一個陣列,並且每個子陣列反過來都會呼叫 self.all。如果使用驗證規則,請盡可能避免巢狀清單和對應。

預設值

預設值允許在 OpenAPI v3 驗證綱要中指定預設值

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com
spec:
  group: stable.example.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        # openAPIV3Schema is the schema for validating custom objects.
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                cronSpec:
                  type: string
                  pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
                  default: "5 0 * * *"
                image:
                  type: string
                replicas:
                  type: integer
                  minimum: 1
                  maximum: 10
                  default: 1
  scope: Namespaced
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
    shortNames:
    - ct

透過這樣做,cronSpecreplicas 都會預設為

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  image: my-awesome-cron-image

導致

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "5 0 * * *"
  image: my-awesome-cron-image
  replicas: 1

預設值會發生在物件上

  • 在使用請求版本預設值向 API 伺服器發出的請求中,
  • 在從 etcd 讀取時,使用儲存版本預設值,
  • 在使用具有非空修補程式的變更准入外掛程式之後,使用准入 Webhook 物件版本預設值。

從 etcd 讀取資料時套用的預設值不會自動寫回 etcd。需要透過 API 發出更新請求,才能將這些預設值持久儲存回 etcd。

預設值必須經過修剪(metadata 欄位的預設值除外),並且必須根據提供的結構描述進行驗證。

針對 x-kubernetes-embedded-resources: true 節點的 metadata 欄位(或涵蓋 metadata 的預設值部分)的預設值,在 CustomResourceDefinition 建立期間不會進行修剪,而是在處理請求期間透過修剪步驟進行修剪。

預設值設定與可空值 (Nullable)

對於未指定可空值標記或給定 false 值的欄位,其空值將在預設值設定之前被修剪。如果存在預設值,則將會套用。當可空值為 true 時,空值將會被保留,且不會設定預設值。

例如,給定以下 OpenAPI 結構描述

type: object
properties:
  spec:
    type: object
    properties:
      foo:
        type: string
        nullable: false
        default: "default"
      bar:
        type: string
        nullable: true
      baz:
        type: string

建立一個物件,其中 foobarbaz 的值為空值

spec:
  foo: null
  bar: null
  baz: null

導致

spec:
  foo: "default"
  bar: null

foo 因為欄位不可空值而被修剪並設定預設值,bar 因為 nullable: true 而保留空值,而 baz 因為欄位不可空值且沒有預設值而被修剪。

在 OpenAPI 中發布驗證結構描述

CustomResourceDefinition OpenAPI v3 驗證結構描述,這些結構描述是 結構化 的,並且 啟用修剪,會從 Kubernetes API 伺服器發布為 OpenAPI v3 和 OpenAPI v2。建議使用 OpenAPI v3 文件,因為它是 CustomResourceDefinition OpenAPI v3 驗證結構描述的無損表示,而 OpenAPI v2 則表示有損轉換。

kubectl 命令列工具會使用已發布的結構描述來執行用戶端驗證 (kubectl createkubectl apply)、結構描述說明 (kubectl explain) 在自訂資源上。已發布的結構描述也可以用於其他目的,例如用戶端產生或文件編寫。

與 OpenAPI V2 的相容性

為了與 OpenAPI V2 相容,OpenAPI v3 驗證結構描述會對 OpenAPI v2 結構描述執行有損轉換。該結構描述會顯示在 OpenAPI v2 規格 中的 definitionspaths 欄位中。

在轉換期間會套用以下修改,以保持與先前 1.13 版本中 kubectl 的回溯相容性。這些修改可防止 kubectl 過於嚴格,並拒絕其無法理解的有效 OpenAPI 結構描述。轉換不會修改 CRD 中定義的驗證結構描述,因此不會影響 API 伺服器中的 驗證

  1. 以下欄位由於 OpenAPI v2 不支援而被移除。

    • 欄位 allOfanyOfoneOfnot 已移除
  2. 如果設定了 nullable: true,我們會捨棄 typenullableitemsproperties,因為 OpenAPI v2 無法表達可空值。為了避免 kubectl 拒絕良好的物件,這是必要的。

額外的印表機欄位

kubectl 工具依賴伺服器端輸出格式設定。您叢集的 API 伺服器決定 kubectl get 命令顯示哪些欄位。您可以為 CustomResourceDefinition 自訂這些欄位。以下範例新增了 SpecReplicasAge 欄位。

將 CustomResourceDefinition 儲存至 resourcedefinition.yaml

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com
spec:
  group: stable.example.com
  scope: Namespaced
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
    shortNames:
    - ct
  versions:
  - name: v1
    served: true
    storage: true
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              cronSpec:
                type: string
              image:
                type: string
              replicas:
                type: integer
    additionalPrinterColumns:
    - name: Spec
      type: string
      description: The cron spec defining the interval a CronJob is run
      jsonPath: .spec.cronSpec
    - name: Replicas
      type: integer
      description: The number of jobs launched by the CronJob
      jsonPath: .spec.replicas
    - name: Age
      type: date
      jsonPath: .metadata.creationTimestamp

建立 CustomResourceDefinition

kubectl apply -f resourcedefinition.yaml

使用前一節的 my-crontab.yaml 建立一個執行個體。

調用伺服器端列印

kubectl get crontab my-new-cron-object

請注意輸出中的 NAMESPECREPLICASAGE 欄位

NAME                 SPEC        REPLICAS   AGE
my-new-cron-object   * * * * *   1          7s

優先順序

每個欄位都包含 priority 欄位。目前,優先順序區分在標準視圖或寬視圖(使用 -o wide 旗標)中顯示的欄位。

  • 優先順序為 0 的欄位會在標準視圖中顯示。
  • 優先順序大於 0 的欄位僅在寬視圖中顯示。

類型

欄位的 type 欄位可以是以下任何一種(比較 OpenAPI v3 資料類型

  • integer – 非浮點數
  • number – 浮點數
  • string – 字串
  • booleantruefalse
  • date – 以自此時間戳記以來的時間差方式呈現。

如果 CustomResource 內的值與為欄位指定的類型不符,則會省略該值。使用 CustomResource 驗證來確保值類型正確。

格式

欄位的 format 欄位可以是以下任何一種

  • int32
  • int64
  • float
  • 雙精度浮點數
  • byte
  • date
  • date-time
  • password

欄位的 format 控制 kubectl 列印值時使用的樣式。

欄位選擇器

欄位選擇器 讓用戶端可以根據一個或多個資源欄位的值來選擇自訂資源。

所有自訂資源都支援 metadata.namemetadata.namespace 欄位選擇器。

CustomResourceDefinition 中宣告的欄位,如果包含在 CustomResourceDefinitionspec.versions[*].selectableFields 欄位中,也可以與欄位選擇器一起使用。

自訂資源的可選欄位

功能狀態: Kubernetes v1.32 [stable] (預設啟用:true)

CustomResourceDefinitionspec.versions[*].selectableFields 欄位可用於宣告自訂資源中的哪些其他欄位可以與 CustomResourceFieldSelectors 功能閘道 的功能一起用於欄位選擇器(此功能閘道自 Kubernetes v1.31 起預設啟用)。以下範例將 .spec.color.spec.size 欄位新增為可選欄位。

將 CustomResourceDefinition 儲存到 shirt-resource-definition.yaml

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: shirts.stable.example.com
spec:
  group: stable.example.com
  scope: Namespaced
  names:
    plural: shirts
    singular: shirt
    kind: Shirt
  versions:
  - name: v1
    served: true
    storage: true
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              color:
                type: string
              size:
                type: string
    selectableFields:
    - jsonPath: .spec.color
    - jsonPath: .spec.size
    additionalPrinterColumns:
    - jsonPath: .spec.color
      name: Color
      type: string
    - jsonPath: .spec.size
      name: Size
      type: string

建立 CustomResourceDefinition

kubectl apply -f https://k8s.io/examples/customresourcedefinition/shirt-resource-definition.yaml

透過編輯 shirt-resources.yaml 定義一些襯衫;例如

---
apiVersion: stable.example.com/v1
kind: Shirt
metadata:
  name: example1
spec:
  color: blue
  size: S
---
apiVersion: stable.example.com/v1
kind: Shirt
metadata:
  name: example2
spec:
  color: blue
  size: M
---
apiVersion: stable.example.com/v1
kind: Shirt
metadata:
  name: example3
spec:
  color: green
  size: M

建立自訂資源

kubectl apply -f https://k8s.io/examples/customresourcedefinition/shirt-resources.yaml

取得所有資源

kubectl get shirts.stable.example.com

輸出為

NAME       COLOR  SIZE
example1   blue   S
example2   blue   M
example3   green  M

提取藍色襯衫(檢索 colorblue 的襯衫)

kubectl get shirts.stable.example.com --field-selector spec.color=blue

應輸出

NAME       COLOR  SIZE
example1   blue   S
example2   blue   M

僅取得 colorgreensizeM 的資源

kubectl get shirts.stable.example.com --field-selector spec.color=green,spec.size=M

應輸出

NAME       COLOR  SIZE
example2   blue   M

子資源

自訂資源支援 /status/scale 子資源。

狀態和規模子資源可以選擇性地透過在 CustomResourceDefinition 中定義它們來啟用。

狀態子資源

當啟用狀態子資源時,會公開自訂資源的 /status 子資源。

  • 狀態和規格段落分別由自訂資源內的 .status.spec JSONPaths 表示。

  • /status 子資源的 PUT 請求會取得自訂資源物件,並忽略對狀態段落以外任何內容的變更。

  • /status 子資源的 PUT 請求僅驗證自訂資源的狀態段落。

  • 對自訂資源的 PUT/POST/PATCH 請求會忽略對狀態段落的變更。

  • .metadata.generation 值會針對所有變更遞增,但對 .metadata.status 的變更除外。

  • 僅允許以下建構在 CRD OpenAPI 驗證結構描述的根目錄中

    • description
    • example
    • exclusiveMaximum
    • exclusiveMinimum
    • externalDocs
    • format
    • items
    • maximum
    • maxItems
    • maxLength
    • minimum
    • minItems
    • minLength
    • multipleOf
    • pattern
    • properties
    • required
    • title
    • type
    • uniqueItems

規模子資源

當啟用規模子資源時,會公開自訂資源的 /scale 子資源。autoscaling/v1.Scale 物件會作為 /scale 的酬載傳送。

若要啟用規模子資源,請在 CustomResourceDefinition 中定義以下欄位。

  • specReplicasPath 定義自訂資源內對應於 scale.spec.replicas 的 JSONPath。

    • 這是必要的值。
    • 僅允許 .spec 下且使用點符號的 JSONPath。
    • 如果自訂資源中的 specReplicasPath 下沒有值,則 /scale 子資源將在 GET 時傳回錯誤。
  • statusReplicasPath 定義自訂資源內對應於 scale.status.replicas 的 JSONPath。

    • 這是必要的值。
    • 僅允許 .status 下且使用點符號的 JSONPath。
    • 如果自訂資源中的 statusReplicasPath 下沒有值,則 /scale 子資源中的狀態副本值將預設為 0。
  • labelSelectorPath 定義自訂資源內對應於 Scale.Status.Selector 的 JSONPath。

    • 這是選用值。
    • 必須設定此值才能與 HPA 和 VPA 搭配使用。
    • 僅允許 .status.spec 下且使用點符號的 JSONPath。
    • 如果自訂資源中的 labelSelectorPath 下沒有值,則 /scale 子資源中的狀態選擇器值將預設為空字串。
    • 此 JSON 路徑指向的欄位必須是字串欄位(而非複雜的選擇器結構),其中包含字串形式的序列化標籤選擇器。

在以下範例中,狀態和規模子資源都已啟用。

將 CustomResourceDefinition 儲存至 resourcedefinition.yaml

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com
spec:
  group: stable.example.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                cronSpec:
                  type: string
                image:
                  type: string
                replicas:
                  type: integer
            status:
              type: object
              properties:
                replicas:
                  type: integer
                labelSelector:
                  type: string
      # subresources describes the subresources for custom resources.
      subresources:
        # status enables the status subresource.
        status: {}
        # scale enables the scale subresource.
        scale:
          # specReplicasPath defines the JSONPath inside of a custom resource that corresponds to Scale.Spec.Replicas.
          specReplicasPath: .spec.replicas
          # statusReplicasPath defines the JSONPath inside of a custom resource that corresponds to Scale.Status.Replicas.
          statusReplicasPath: .status.replicas
          # labelSelectorPath defines the JSONPath inside of a custom resource that corresponds to Scale.Status.Selector.
          labelSelectorPath: .status.labelSelector
  scope: Namespaced
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
    shortNames:
    - ct

並建立它

kubectl apply -f resourcedefinition.yaml

在建立 CustomResourceDefinition 物件之後,您可以建立自訂物件。

如果您將下列 YAML 儲存到 my-crontab.yaml

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * * */5"
  image: my-awesome-cron-image
  replicas: 3

並建立它

kubectl apply -f my-crontab.yaml

然後會在以下位置建立新的命名空間 RESTful API 端點

/apis/stable.example.com/v1/namespaces/*/crontabs/status

以及

/apis/stable.example.com/v1/namespaces/*/crontabs/scale

可以使用 kubectl scale 命令來擴展自訂資源的規模。例如,以下命令將上面建立的自訂資源的 .spec.replicas 設定為 5

kubectl scale --replicas=5 crontabs/my-new-cron-object
crontabs "my-new-cron-object" scaled

kubectl get crontabs my-new-cron-object -o jsonpath='{.spec.replicas}'
5

您可以使用 PodDisruptionBudget 來保護已啟用規模子資源的自訂資源。

類別

類別是自訂資源所屬的群組資源清單(例如 all)。您可以使用 kubectl get <category-name> 列出屬於該類別的資源。

以下範例在 CustomResourceDefinition 的類別清單中新增了 all,並說明如何使用 kubectl get all 輸出自訂資源。

將以下 CustomResourceDefinition 儲存到 resourcedefinition.yaml

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com
spec:
  group: stable.example.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                cronSpec:
                  type: string
                image:
                  type: string
                replicas:
                  type: integer
  scope: Namespaced
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
    shortNames:
    - ct
    # categories is a list of grouped resources the custom resource belongs to.
    categories:
    - all

並建立它

kubectl apply -f resourcedefinition.yaml

在建立 CustomResourceDefinition 物件之後,您可以建立自訂物件。

將以下 YAML 儲存至 my-crontab.yaml

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * * */5"
  image: my-awesome-cron-image

並建立它

kubectl apply -f my-crontab.yaml

您可以在使用 kubectl get 時指定類別

kubectl get all

它將包含種類為 CronTab 的自訂資源

NAME                          AGE
crontabs/my-new-cron-object   3s

下一步