使用 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,它將從空狀態開始。

指定結構化模式

CustomResources 將結構化資料儲存在自定義欄位中(除了 API 伺服器隱式驗證的內建欄位 apiVersionkindmetadata)。透過 OpenAPI v3.0 驗證,可以指定一個模式,該模式在建立和更新期間進行驗證,有關此模式的詳細資訊和限制,請參見下文。

對於 apiextensions.k8s.io/v1,CustomResourceDefinitions 必須定義結構化模式。在 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。與諸如 ConfigMap 等原生 Kubernetes 資源一樣,如果你指定了 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 已被修剪。

此示例透過新增 --validate=false 命令列選項來關閉客戶端驗證,以演示 API 伺服器的行為。由於 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 欄位被修剪,但外部的一切都沒有被修剪。

整型或字串

模式中帶有 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 被展開為上面所示的兩種模式之一。

原始擴充套件

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 多個版本以及將物件從一個版本遷移到另一個版本的更多資訊,請參閱 Custom resource definition versioning

高階主題

終結器

終結器(Finalizers) 允許控制器實現非同步預刪除鉤子。自定義物件支援與內建物件類似的終結器。

你可以像這樣向自定義物件新增終結器

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

自定義終結器的識別符號由域名、正斜槓和終結器名稱組成。任何控制器都可以將終結器新增到任何物件的終結器列表中。

對具有終結器物件進行的第一次刪除請求會為 metadata.deletionTimestamp 欄位設定一個值,但不會刪除它。一旦設定了此值,finalizers 列表中的條目只能被移除。在任何終結器仍然存在的情況下,也無法強制刪除物件。

當設定了 metadata.deletionTimestamp 欄位後,監視物件的控制器會執行它們處理的所有終結器,並在完成後將終結器從列表中移除。每個控制器都有責任從列表中移除其終結器。

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

一旦終結器列表為空,即所有終結器都已執行完畢,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 擴充套件可用於使用 通用表示式語言 (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.33 [stable] (預設啟用:true)

如果你使用的是低於 v1.30 的 Kubernetes 版本,則需要顯式啟用 CRDValidationRatcheting 功能門 才能使用此行為,然後此行為將應用於叢集中的所有 CustomResourceDefinition。

如果你啟用了功能門,Kubernetes 會為 CustomResourceDefinitions 實現 驗證棘輪機制。API 伺服器願意接受對更新後無效的資源的更新,前提是資源中未能透過驗證的每個部分在更新操作中都沒有更改。換句話說,資源中任何仍然無效的無效部分都必須已經是錯誤的。你不能使用此機制來更新有效資源使其變為無效。

此功能允許 CRD 作者在某些條件下自信地向 OpenAPIV3 模式新增新的驗證。使用者可以安全地更新到新模式,而無需增加物件的版本或破壞工作流。

儘管 CRD 的 OpenAPIV3 模式中放置的大多數驗證都支援棘輪機制,但也有一些例外。以下 OpenAPIV3 模式驗證在 Kubernetes 1.34 的實現中不支援棘輪機制,如果違反,將像往常一樣繼續丟擲錯誤:

  • 量詞

    • 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-list-map-keys 因更改列表模式的對映鍵而產生的錯誤將不會被棘輪化。

  • required 因更改必填欄位列表而產生的錯誤將不會被棘輪化。

  • properties 新增/刪除/修改屬性名稱不會被棘輪化,但如果屬性名稱保持不變,則對每個屬性的模式和子模式中的驗證進行更改可能會被棘輪化。

  • additionalProperties 移除以前指定的 additionalProperties 驗證將不會被棘輪化。

  • metadata 來自 Kubernetes 對物件 metadata 的內建驗證的錯誤不會被棘輪化(例如物件名稱或標籤值中的字元)。如果你為自定義資源的元資料指定了自己額外的規則,則該額外驗證將被棘輪化。

驗證規則

特性狀態: Kubernetes v1.29 [stable]

驗證規則使用 通用表示式語言 (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))驗證兩個 listSet 是否不相交
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 中是否存在且僅存在一次

交叉引用: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
    
  • 如果規則的作用域是一個具有額外屬性(即對映)的物件,則可以透過 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)
stringself.startsWith('kube')

apiVersionkindmetadata.namemetadata.generateName 始終可從物件的根和任何帶有 x-kubernetes-embedded-resource 註釋的物件訪問。其他元資料屬性不可訪問。

透過 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 RESERVED 關鍵字

注意:CEL RESERVED 關鍵字需要與要轉義的精確屬性名稱匹配(例如,單詞 sprint 中的 int 不會被轉義)。

轉義示例

屬性名稱帶轉義屬性名稱的規則
名稱空間self.__namespace__ > 0
x-propself.x__dash__prop > 0
redact__dself.redact__underscores__d > 0
stringself.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' with Properties物件 / "訊息型別"
'object' with AdditionalProperties對映
'object' with x-kubernetes-embedded-type物件 / "訊息型別",'apiVersion'、'kind'、'metadata.name' 和 'metadata.generateName' 隱式包含在模式中
'object' with x-kubernetes-preserve-unknown-fields物件 / "訊息型別",未知欄位在 CEL 表示式中不可訪問
x-kubernetes-int-or-string動態物件,可以是整數或字串,type(value) 可用於檢查型別
'arraylist
'array' with x-kubernetes-list-type=map具有基於對映的相等性和唯一鍵保證的列表
'array' with x-kubernetes-list-type=set具有基於集合的相等性和唯一條目保證的列表
'boolean'布林值
'number' (所有格式)雙精度浮點數
'integer' (所有格式)整數 (64)
'null'null 型別
'string'string
'string' with format=byte (base64 編碼)位元組
'string' with format=date時間戳 (google.protobuf.Timestamp)
'string' with format=datetime時間戳 (google.protobuf.Timestamp)
'string' with format=duration持續時間 (google.protobuf.Duration)

交叉引用: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,返回的錯誤將正確引用欄位 x 的位置。

fieldPath 值必須是相對 JSON 路徑,其作用域為模式中 x-kubernetes-validations 擴充套件的位置。此外,它應該引用模式中已存在的欄位。例如,當驗證檢查對映 testMap 下的特定屬性 foo 時,你可以將 fieldPath 設定為 ".testMap.foo".testMap['foo']'。如果驗證需要檢查兩個列表中唯一的屬性,則 fieldPath 可以設定為任一列表。例如,它可以設定為 .testList1.testList2。目前它支援子操作以引用現有欄位。有關更多資訊,請參閱 Kubernetes 中的 JSONPath 支援fieldPath 欄位不支援按數字索引陣列。

設定 fieldPath 是可選的。

optionalOldSelf 欄位

特性狀態: Kubernetes v1.33 [stable] (預設啟用:true)

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

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

如果 optionalOldSelf 設定為 true,則過渡規則將始終被評估,並且 oldSelf 的型別將更改為 CEL Optional 型別。

optionalOldSelf 在模式作者希望透過比 預設的基於等價的行為 提供更多控制工具來對新值引入新的(通常更嚴格的)約束,同時仍然允許使用舊的驗證來“祖父”或棘輪化舊值的情況下非常有用。

使用示例

CEL描述
self.foo == "foo" || (oldSelf.hasValue() && oldSelf.value().foo != "foo")棘輪規則。一旦值設定為“foo”,它必須保持為 foo。但如果它在引入“foo”約束之前存在,則可以使用任何值
[oldSelf.orValue(""), self].all(x, ["OldCase1", "OldCase2"].exists(case, x == case)) || ["NewCase1", "NewCase2"].exists(case, self == case) || ["NewCase"].has(self)“如果 oldSelf 使用了被刪除的列舉案例,則對這些案例進行棘輪驗證”
oldSelf.optMap(o, o.size()).orValue(0) < 4 || self.size() >= 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) 不一定可以在現有物件和對同一物件的後續更新之間進行關聯。

如果模式節點包含無法應用的過渡規則(例如,“舊 Self 不能在模式中不可關聯的部分中使用 path”),則會在 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 欄位的預設值除外),並且必須根據提供的模式進行驗證。例如,在上面的示例中,spec 欄位的預設值 {"replicas": "foo", "badger": 1} 將無效,因為 badger 是一個未知欄位,並且 replicas 不是字串。

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

預設值和可空性

對於未指定 nullable 標誌或將其設定為 false 的欄位,null 值將在預設值發生之前被修剪。如果存在預設值,它將被應用。當 nullable 為 true 時,null 值將被保留並且不會被預設設定。

例如,給定下面的 OpenAPI 模式

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

建立 foobarbaz 具有 null 值的物件

spec:
  foo: null
  bar: null
  baz: null

導致

spec:
  foo: "default"
  bar: null

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

在 OpenAPI 中釋出驗證模式

CustomResourceDefinition OpenAPI v3 驗證模式,如果它們是 結構化的啟用修剪,則會作為 OpenAPI v3 和 OpenAPI v2 從 Kubernetes API 伺服器釋出。建議使用 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 JSONPath 表示。

  • /status 子資源的 PUT 請求接受一個自定義資源物件,並忽略除了狀態節之外的所有更改。

  • /status 子資源的 PUT 請求僅驗證自定義資源的狀態節。

  • 對自定義資源的 PUT/POST/PATCH 請求忽略狀態節的更改。

  • 除了對 .metadata.status 的更改外,.metadata.generation 值將針對所有更改遞增。

  • 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 列出屬於該類別的資源。

以下示例在 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

下一步

上次修改時間:2025 年 5 月 12 日下午 2:52 (PST):將 yaml 示例標記為可獲取語法高亮顯示 (365e6495ea)