使用 CustomResourceDefinitions 擴充套件 Kubernetes API
本頁面展示瞭如何透過建立 CustomResourceDefinition 將自定義資源安裝到 Kubernetes API 中。
準備工作
你需要一個 Kubernetes 叢集,並且 kubectl 命令列工具必須配置為與你的叢集通訊。建議在至少有兩個不是控制平面主機的節點上執行本教程。如果你還沒有叢集,你可以使用 minikube 建立一個,或者使用這些 Kubernetes 遊樂場之一。
你的 Kubernetes 伺服器版本必須是 1.16 或更高。要檢查版本,請輸入 kubectl version。
建立 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。在以下示例中,cronSpec 和 image 自定義欄位在 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 中的自定義 cronSpec 和 image 欄位
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 伺服器隱式驗證的內建欄位 apiVersion、kind 和 metadata)。透過 OpenAPI v3.0 驗證,可以指定一個模式,該模式在建立和更新期間進行驗證,有關此模式的詳細資訊和限制,請參見下文。
對於 apiextensions.k8s.io/v1,CustomResourceDefinitions 必須定義結構化模式。在 CustomResourceDefinition 的 Beta 版本中,結構化模式是可選的。
結構化模式是 OpenAPI v3.0 驗證模式,它
- 為根、物件節點的每個指定欄位(透過 OpenAPI 中的
properties或additionalProperties)和陣列節點的每個項(透過 OpenAPI 中的items)指定一個非空型別(透過 OpenAPI 中的type),但以下情況除外:- 一個帶有
x-kubernetes-int-or-string: true的節點 - 一個帶有
x-kubernetes-preserve-unknown-fields: true的節點
- 一個帶有
- 對於物件中的每個欄位和陣列中的每個項,如果在任何
allOf、anyOf、oneOf或not中指定,則模式還在這些邏輯連線詞之外指定欄位/項(比較示例 1 和 2)。 - 不在
allOf、anyOf、oneOf或not中設定description、type、default、additionalProperties、nullable,但x-kubernetes-int-or-string: true的兩種模式除外(見下文)。 - 如果指定了
metadata,則只允許對metadata.name和metadata.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)。bar的type位於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 相容,請更新你的自定義資源定義以
- 使用結構化 OpenAPI 模式。
- 將
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 物件,即帶有 apiVersion 和 kind 欄位。
透過設定 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: true,apiVersion、kind 和 metadata 被隱式指定和驗證。
提供多個 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。欄位
additionalProperties與properties互斥。
當 驗證規則 功能啟用且 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 的實現中不支援棘輪機制,如果違反,將像往常一樣繼續丟擲錯誤:
量詞
allOfoneOfanyOfnot- 這些欄位的任何後代中的任何驗證
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
注意
你可以在 CEL Playground 中快速測試 CEL 表示式。驗證規則在 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 模式中宣告的任何欄位以及
apiVersion、kind、metadata.name和metadata.generateName進行欄位選擇。這包括在同一個表示式中選擇spec和status中的欄位# ... 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) |
| string | self.startsWith('kube') |
apiVersion、kind、metadata.name 和 metadata.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-prop | self.x__dash__prop > 0 |
| redact__d | self.redact__underscores__d > 0 |
| string | self.startsWith('kube') |
具有 x-kubernetes-list-type 為 set 或 map 的陣列上的相等性會忽略元素順序,即 [1, 2] == [2, 1]。具有 x-kubernetes-list-type 的陣列上的連線使用列表型別的語義
set:X + Y執行並集操作,其中X中所有元素的陣列位置保持不變,並且Y中不相交的元素被追加,保留其部分順序。map:X + Y執行合併操作,其中X中所有鍵的陣列位置保持不變,但當X和Y的鍵集相交時,值會被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) 可用於檢查型別 |
| 'array | list |
| '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 時進行檢查。請注意,可以在同一規則上設定 message 和 messageExpression,如果兩者都存在,則將使用 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,則模式的一部分是可關聯的;任何 set 或 atomic 陣列父模式都使得無法明確地將 self 與 oldSelf 關聯。
以下是一些過渡規則的示例
| 用例 | 規則 |
|---|---|
| 不變性 | self.foo == oldSelf.foo |
| 一旦賦值,阻止修改/刪除 | oldSelf != 'bar' || self == 'bar' 或 !has(oldSelf.field) || has(self.field) |
| 僅追加集合 | self.all(element, element in oldSelf) |
| 如果舊值是 X,新值只能是 A 或 B,不能是 Y 或 Z | oldSelf != '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 長度的限制,則成本系統始終假定最壞情況,並且對於任何可迭代的內容(列表、對映等)都會發生這種情況。
因此,最佳實踐是透過 maxItems、maxProperties 和 maxLength 對將在驗證規則中處理的任何內容設定限制,以防止在成本估算過程中出現驗證錯誤。例如,給定以下具有一個規則的模式
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。如果使用驗證規則,請儘可能避免巢狀列表和對映。
預設值
注意
要使用預設值,你的 CustomResourceDefinition 必須使用 API 版本apiextensions.k8s.io/v1。預設值允許在 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
這樣 cronSpec 和 replicas 都將被預設設定
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
建立 foo、bar 和 baz 具有 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 create 和 kubectl apply) 和模式解釋 (kubectl explain)。已釋出的模式還可以用於其他目的,例如客戶端生成或文件。
與 OpenAPI V2 的相容性
為了與 OpenAPI V2 相容,OpenAPI v3 驗證模式會對 OpenAPI v2 模式進行有損轉換。該模式顯示在 OpenAPI v2 規範 的 definitions 和 paths 欄位中。
在轉換為保持與早期 1.13 版本中 kubectl 向後相容期間,會應用以下修改。這些修改可防止 kubectl 過於嚴格並拒絕它不理解的有效 OpenAPI 模式。轉換不會修改 CRD 中定義的驗證模式,因此不會影響 API 伺服器中的 驗證。
以下欄位因 OpenAPI v2 不支援而被移除。
- 欄位
allOf、anyOf、oneOf和not被移除
- 欄位
如果設定了
nullable: true,我們將刪除type、nullable、items和properties,因為 OpenAPI v2 無法表達可空性。為了避免 kubectl 拒絕好的物件,這是必要的。
額外的列印列
kubectl 工具依賴於伺服器端輸出格式。叢集的 API 伺服器決定 kubectl get 命令顯示哪些列。你可以為 CustomResourceDefinition 自定義這些列。以下示例添加了 Spec、Replicas 和 Age 列。
將 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
注意輸出中的 NAME、SPEC、REPLICAS 和 AGE 列
NAME SPEC REPLICAS AGE
my-new-cron-object * * * * * 1 7s
注意
NAME 列是隱式的,不需要在 CustomResourceDefinition 中定義。優先順序
每列都包含一個 priority 欄位。目前,優先順序區分標準檢視或寬檢視(使用 -o wide 標誌)中顯示的列。
- 優先順序為
0的列顯示在標準檢視中。 - 優先順序大於
0的列僅在寬檢視中顯示。
型別
列的 type 欄位可以是以下任何一種(比較 OpenAPI v3 資料型別)
integer– 非浮點數number– 浮點數string– 字串boolean–true或falsedate– 作為自此時間戳以來的時間差呈現。
如果 CustomResource 中的值與為列指定的型別不匹配,則該值將被省略。使用 CustomResource 驗證以確保值型別正確。
格式
列的 format 欄位可以是以下任何一種
int32int64float雙精度浮點數bytedatedate-timepassword
列的 format 控制 kubectl 列印值時使用的樣式。
欄位選擇器
欄位選擇器 允許客戶端根據一個或多個資源欄位的值選擇自定義資源。
所有自定義資源都支援 metadata.name 和 metadata.namespace 欄位選擇器。
在 CustomResourceDefinition 中宣告的欄位,當包含在 CustomResourceDefinition 的 spec.versions[*].selectableFields 欄位中時,也可以與欄位選擇器一起使用。
自定義資源的可選擇欄位
Kubernetes v1.32 [stable] (預設啟用:true)CustomResourceDefinition 的 spec.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
獲取藍色襯衫(檢索 color 為 blue 的襯衫)
kubectl get shirts.stable.example.com --field-selector spec.color=blue
應輸出
NAME COLOR SIZE
example1 blue S
example2 blue M
僅獲取 color 為 green 且 size 為 M 的資源
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和.specJSONPath 表示。對
/status子資源的PUT請求接受一個自定義資源物件,並忽略除了狀態節之外的所有更改。對
/status子資源的PUT請求僅驗證自定義資源的狀態節。對自定義資源的
PUT/POST/PATCH請求忽略狀態節的更改。除了對
.metadata或.status的更改外,.metadata.generation值將針對所有更改遞增。CRD OpenAPI 驗證模式的根目錄中只允許以下結構
descriptionexampleexclusiveMaximumexclusiveMinimumexternalDocsformatitemsmaximummaxItemsmaxLengthminimumminItemsminLengthmultipleOfpatternpropertiesrequiredtitletypeuniqueItems
擴縮子資源
當擴縮子資源啟用時,將暴露自定義資源的 /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
下一步
閱讀有關 自定義資源 的內容。