自定義資源
自定義資源 是 Kubernetes API 的擴充套件。本頁面討論何時向 Kubernetes 叢集新增自定義資源以及何時使用獨立的(Standalone)服務。它描述了新增自定義資源的兩種方法以及如何選擇它們。
自定義資源
資源是 Kubernetes API 中的一個端點,它儲存特定種類的 API 物件的集合;例如,內建的 pods 資源包含 Pod 物件的集合。
自定義資源是 Kubernetes API 的擴充套件,它不一定在預設的 Kubernetes 安裝中可用。它代表了特定 Kubernetes 安裝的定製。然而,許多核心 Kubernetes 功能現在都使用自定義資源構建,使 Kubernetes 更加模組化。
自定義資源可以透過動態註冊在執行中的叢集中出現和消失,並且叢集管理員可以獨立於叢集本身更新自定義資源。一旦安裝了自定義資源,使用者就可以使用 kubectl 建立和訪問其物件,就像他們對 Pods 等內建資源一樣。
自定義控制器
自定義資源本身允許你儲存和檢索結構化資料。當你將自定義資源與一個 自定義控制器 結合使用時,自定義資源就提供了一個真正的 宣告式 API。
Kubernetes 宣告式 API 強制職責分離。你宣告資源的期望狀態。Kubernetes 控制器使 Kubernetes 物件的當前狀態與你宣告的期望狀態保持同步。這與命令式 API 相反,命令式 API 中你 指示 伺服器做什麼。
你可以在執行中的叢集上部署和更新自定義控制器,而獨立於叢集的生命週期。自定義控制器可以與任何型別的資源一起工作,但當它們與自定義資源結合使用時尤其有效。Operator 模式結合了自定義資源和自定義控制器。你可以使用自定義控制器將特定應用程式的領域知識編碼到 Kubernetes API 的擴充套件中。
我應該向我的 Kubernetes 叢集新增自定義資源嗎?
在建立新 API 時,考慮是 將你的 API 與 Kubernetes 叢集 API 聚合 還是讓你的 API 獨立執行。
如果出現以下情況,請考慮 API 聚合 | 如果出現以下情況,請首選獨立 API |
---|---|
你的 API 是宣告式的。 | 你的 API 不符合宣告式模型。 |
你希望你的新型別可以使用 kubectl 進行讀寫。 | 不需要 kubectl 支援。 |
你希望在 Kubernetes UI(例如儀表盤)中檢視你的新型別,就像內建型別一樣。 | 不需要 Kubernetes UI 支援。 |
你正在開發一個新的 API。 | 你已經有一個程式可以提供你的 API 並且執行良好。 |
你願意接受 Kubernetes 對 REST 資源路徑的格式限制,例如 API 組和名稱空間。(請參閱 API 概述。) | 你需要特定的 REST 路徑以與已定義的 REST API 相容。 |
你的資源自然地作用於叢集或叢集的名稱空間。 | 叢集或名稱空間作用域的資源不適合;你需要控制資源路徑的細節。 |
你想要重用 Kubernetes API 支援功能。 | 你不需要這些功能。 |
宣告式 API
在宣告式 API 中,通常
- 你的 API 由相對較少的、相對較小的物件(資源)組成。
- 這些物件定義了應用程式或基礎設施的配置。
- 這些物件更新頻率相對較低。
- 人類通常需要讀寫這些物件。
- 對物件的主要操作是 CRUD(建立、讀取、更新和刪除)。
- 不需要跨物件事務:API 表示期望狀態,而不是精確狀態。
命令式 API 不是宣告式的。你的 API 可能不是宣告式的跡象包括
- 客戶端說“執行此操作”,然後操作完成後立即收到同步響應。
- 客戶端說“執行此操作”,然後收到一個操作 ID,並且必須檢查一個單獨的操作物件以確定請求是否完成。
- 你談論遠端過程呼叫 (RPC)。
- 直接儲存大量資料;例如,每個物件 > 幾 KB,或 > 數千個物件。
- 需要高頻寬訪問(每秒 10 次請求持續不斷)。
- 儲存應用程式處理的最終使用者資料(如影像、PII 等)或其他大規模資料。
- 對物件的自然操作不是 CRUD 式的。
- API 不容易建模為物件。
- 你選擇用操作 ID 或操作物件來表示待處理的操作。
我應該使用 ConfigMap 還是自定義資源?
如果符合以下任何條件,請使用 ConfigMap
- 存在一個已有的、文件完善的配置檔案格式,例如
mysql.cnf
或pom.xml
。 - 你希望將整個配置放入 ConfigMap 的一個鍵中。
- 配置檔案主要用於在叢集的 Pod 中執行的程式,以消費該檔案來配置自身。
- 檔案的消費者更喜歡透過 Pod 中的檔案或 Pod 中的環境變數進行消費,而不是透過 Kubernetes API。
- 你希望在檔案更新時透過 Deployment 等執行滾動更新。
注意
對於敏感資料,請使用 Secret,它類似於 ConfigMap 但更安全。如果以下大多數情況適用,請使用自定義資源(CRD 或聚合 API)
- 你希望使用 Kubernetes 客戶端庫和 CLI 來建立和更新新資源。
- 你希望
kubectl
提供頂級支援;例如,kubectl get my-object object-name
。 - 你希望構建新的自動化,用於監視新物件的更新,然後對其他物件執行 CRUD 操作,反之亦然。
- 你希望編寫處理物件更新的自動化。
- 你希望使用 Kubernetes API 約定,例如
.spec
、.status
和.metadata
。 - 你希望該物件是受控資源集合的抽象,或對其他資源的彙總。
新增自定義資源
Kubernetes 提供了兩種向叢集新增自定義資源的方式
- CRD 簡單且無需任何程式設計即可建立。
- API 聚合 需要程式設計,但允許對 API 行為(例如資料儲存方式和 API 版本之間的轉換)進行更多控制。
Kubernetes 提供這兩種選項以滿足不同使用者的需求,以便在易用性和靈活性方面都不受影響。
聚合 API 是主 API 伺服器後面的從屬 API 伺服器,主 API 伺服器充當代理。這種安排稱為 API 聚合 (AA)。對使用者而言,Kubernetes API 似乎得到了擴充套件。
CRD 允許使用者建立新的資源型別,而無需新增另一個 API 伺服器。你不需要了解 API 聚合即可使用 CRD。
無論如何安裝,新資源都被稱為自定義資源,以區別於內建的 Kubernetes 資源(如 Pod)。
注意
避免將自定義資源用作應用程式、終端使用者或監控資料的資料儲存:將應用程式資料儲存在 Kubernetes API 中的架構設計通常表示設計過於緊密耦合。
從架構上講,雲原生應用程式架構傾向於元件之間的松耦合。如果你的工作負載的一部分需要支援服務來執行其例行操作,則將該支援服務作為元件執行或將其作為外部服務使用。這樣,你的工作負載就不依賴於 Kubernetes API 來執行其正常操作。
CustomResourceDefinition
CustomResourceDefinition API 資源允許你定義自定義資源。定義 CRD 物件會建立具有你指定名稱和模式的新自定義資源。Kubernetes API 提供並處理自定義資源的儲存。CRD 物件本身的名稱必須是派生自定義的資源名稱及其 API 組的有效 DNS 子域名;有關更多詳細資訊,請參閱 如何建立 CRD。此外,由 CRD 定義其種類/資源的物件的名稱也必須是有效的 DNS 子域名。
這使你無需編寫自己的 API 伺服器來處理自定義資源,但實現的通用性意味著你的靈活性不如使用 API 伺服器聚合。
請參閱自定義控制器示例,瞭解如何註冊新的自定義資源、使用新資源型別的例項以及使用控制器處理事件的示例。
API 伺服器聚合
通常,Kubernetes API 中的每個資源都需要處理 REST 請求和管理物件持久儲存的程式碼。主 Kubernetes API 伺服器處理 pods 和 services 等內建資源,還可以透過 CRD 泛型處理自定義資源。
聚合層 允許你透過編寫和部署自己的 API 伺服器,為自定義資源提供專門的實現。主 API 伺服器將請求委託給你的 API 伺服器,以處理你負責的自定義資源,使其對所有客戶端可用。
選擇新增自定義資源的方法
CRD 更易於使用。聚合 API 更靈活。選擇最符合你需求的方法。
通常,如果出現以下情況,CRD 是一個不錯的選擇
- 你只有少數幾個欄位
- 你正在公司內部使用該資源,或者作為小型開源專案的一部分使用(而不是商業產品)
易用性比較
CRD 比聚合 API 更容易建立。
CRD | 聚合 API |
---|---|
不需要程式設計。使用者可以選擇任何語言來編寫 CRD 控制器。 | 需要程式設計和構建二進位制檔案和映象。 |
無需額外服務執行;CRD 由 API 伺服器處理。 | 需要建立可能失敗的額外服務。 |
CRD 建立後無需持續支援。任何 Bug 修復都作為正常的 Kubernetes 主版本升級的一部分進行。 | 可能需要定期從上游獲取 Bug 修復,並重建和更新聚合 API 伺服器。 |
無需處理 API 的多個版本;例如,當您控制此資源的客戶端時,可以與 API 同步升級它。 | 你需要處理 API 的多個版本;例如,當你開發一個要與世界共享的擴充套件時。 |
高階功能和靈活性
聚合 API 提供更高階的 API 功能和對其他功能(例如儲存層)的自定義。
特性 | 描述 | CRD | 聚合 API |
---|---|---|---|
驗證 | 幫助使用者防止錯誤,並允許你獨立於客戶端演進你的 API。這些功能在許多客戶端無法同時更新時最有用。 | 是。大多數驗證可以在 CRD 中使用 OpenAPI v3.0 驗證 來指定。CRDValidationRatcheting 功能門允許在資源失敗部分未更改的情況下,也可以忽略使用 OpenAPI 指定的失敗驗證。透過新增 Validating Webhook 支援任何其他驗證。 | 是,任意驗證檢查 |
預設值 | 見上文 | 是的,可以透過 OpenAPI v3.0 驗證 default 關鍵字(1.17 GA),或者透過 Mutating Webhook(儘管當從 etcd 讀取舊物件時不會執行此操作)。 | 是 |
多版本控制 | 允許透過兩個 API 版本提供相同的物件。可以幫助簡化 API 更改,例如欄位重新命名。如果您控制客戶端版本,則不那麼重要。 | 是 | 是 |
自定義儲存 | 如果您需要不同效能模式的儲存(例如,時間序列資料庫而不是鍵值儲存)或為了安全進行隔離(例如,敏感資訊加密等) | 否 | 是 |
自定義業務邏輯 | 在建立、讀取、更新或刪除物件時執行任意檢查或操作 | 是的,使用 Webhooks。 | 是 |
擴縮子資源 | 允許 HorizontalPodAutoscaler 和 PodDisruptionBudget 等系統與你的新資源互動 | 是 | 是 |
狀態子資源 | 允許細粒度訪問控制,使用者可以編寫 spec 部分,控制器可以編寫 status 部分。允許在自定義資源資料變動時遞增物件 Generation(要求資源中包含獨立的 spec 和 status 部分) | 是 | 是 |
其他子資源 | 新增除了 CRUD 之外的操作,例如“logs”或“exec”。 | 否 | 是 |
戰略合併補丁 | 新端點支援帶有 Content-Type: application/strategic-merge-patch+json 的 PATCH。對於更新可能在本地和伺服器上都已修改的物件很有用。更多資訊,請參閱 “使用 kubectl patch 就地更新 API 物件” | 否 | 是 |
Protocol Buffers | 新資源支援想要使用 Protocol Buffers 的客戶端 | 否 | 是 |
OpenAPI Schema | 是否存在一個 OpenAPI (swagger) 模式,可以從伺服器動態獲取型別?是否透過確保只設置允許的欄位來保護使用者免於拼寫錯誤的欄位名?是否強制執行型別(換句話說,不要將 int 放入 string 欄位)? | 是,基於 OpenAPI v3.0 驗證 模式 (1.16 GA)。 | 是 |
例項名稱 | 此擴充套件機制是否對以這種方式定義的種類/資源的物件名稱施加任何限制? | 是的,這類物件的名稱必須是有效的 DNS 子域名。 | 否 |
常見功能
與在 Kubernetes 平臺之外實現 API 相比,透過 CRD 或 AA 建立自定義資源,你的 API 可以獲得許多功能
特性 | 作用 |
---|---|
CRUD | 新端點支援透過 HTTP 和 kubectl 進行 CRUD 基本操作。 |
Watch | 新端點透過 HTTP 支援 Kubernetes Watch 操作。 |
發現 | kubectl 和儀表盤等客戶端會自動對你的資源提供列表、顯示和欄位編輯操作。 |
json-patch | 新端點支援帶有 Content-Type: application/json-patch+json 的 PATCH。 |
合併補丁 | 新端點支援帶有 Content-Type: application/merge-patch+json 的 PATCH。 |
HTTPS | 新端點使用 HTTPS |
內建認證 | 訪問擴充套件使用核心 API 伺服器(聚合層)進行認證 |
內建授權 | 訪問擴充套件可以重用核心 API 伺服器使用的授權;例如 RBAC。 |
終結器 | 阻止刪除擴充套件資源,直到外部清理完成。 |
Admission Webhook | 在任何建立/更新/刪除操作期間設定預設值並驗證擴充套件資源。 |
UI/CLI 顯示 | Kubectl、儀表盤可以顯示擴充套件資源。 |
未設定與空值 | 客戶端可以將未設定的欄位與零值欄位區分開來。 |
客戶端庫生成 | Kubernetes 提供通用客戶端庫,以及生成特定型別客戶端庫的工具。 |
標籤和註解 | 工具知道如何為核心和自定義資源編輯的常見物件元資料。 |
準備安裝自定義資源
在向叢集新增自定義資源之前,有幾點需要注意。
第三方程式碼和新的故障點
雖然建立 CRD 不會自動新增任何新的故障點(例如,透過導致第三方程式碼在你的 API 伺服器上執行),但包(例如,Charts)或其他安裝包通常包括 CRD 以及實現新自定義資源業務邏輯的第三方程式碼的 Deployment。
安裝聚合 API 伺服器總是涉及執行新的 Deployment。
儲存
自定義資源會像 ConfigMap 一樣佔用儲存空間。建立過多的自定義資源可能會使 API 伺服器的儲存空間過載。
聚合 API 伺服器可能會使用與主 API 伺服器相同的儲存,在這種情況下,同樣的警告也適用。
身份認證、授權和審計
CRD 總是使用與 API 伺服器內建資源相同的身份認證、授權和審計日誌。
如果你使用 RBAC 進行授權,大多數 RBAC 角色將不會授予對新資源的訪問許可權(除了 cluster-admin 角色或任何使用萬用字元規則建立的角色)。你需要明確授予對新資源的訪問許可權。CRD 和聚合 API 通常捆綁了它們新增的型別的新角色定義。
聚合 API 伺服器可能會或可能不會使用與主 API 伺服器相同的身份認證、授權和審計。
訪問自定義資源
Kubernetes 客戶端庫 可用於訪問自定義資源。並非所有客戶端庫都支援自定義資源。Go 和 Python 客戶端庫支援。
新增自定義資源後,你可以使用以下方式訪問它
kubectl
- Kubernetes 動態客戶端。
- 你編寫的 REST 客戶端。
- 使用 Kubernetes 客戶端生成工具 生成的客戶端(生成客戶端是一項高階任務,但某些專案可能會隨 CRD 或 AA 提供客戶端)。
自定義資源欄位選擇器
欄位選擇器 允許客戶端根據一個或多個資源欄位的值選擇自定義資源。
所有自定義資源都支援 metadata.name
和 metadata.namespace
欄位選擇器。
在 CustomResourceDefinition 中宣告的欄位也可以與欄位選擇器一起使用,當它們包含在 CustomResourceDefinition 的 spec.versions[*].selectableFields
欄位中時。
自定義資源的可選欄位
Kubernetes v1.32 [stable]
(預設啟用:true)CustomResourceDefinition 的 spec.versions[*].selectableFields
欄位可用於宣告自定義資源中的哪些其他欄位可以在欄位選擇器中使用。
以下示例將 .spec.color
和 .spec.size
欄位新增為可選欄位。
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
然後可以使用欄位選擇器僅獲取 color
為 blue
的資源
kubectl get shirts.stable.example.com --field-selector spec.color=blue
輸出應該是
NAME COLOR SIZE
example1 blue S
example2 blue M