返回文章列表

Kubernetes 有狀態應用程式與准入控制最佳實踐

本文探討在 Kubernetes 中管理有狀態應用程式的最佳實踐,涵蓋 StatefulSets 和 Operators 的使用,以及如何利用准入控制機制確保叢集安全和資源管理。文章深入剖析 Operators 的發展歷程及其在管理複雜有狀態應用程式中的優勢,同時提供 StatefulSets

Kubernetes 系統設計

Kubernetes StatefulSets 有助於佈署有狀態應用程式,但 Kubernetes 本身並不完全理解這些應用程式的運作方式。備份、容錯移轉、升級等操作在 StatefulSets 中需要特別考量。Operator 的出現解決了這個問題,它封裝了特定應用程式的領域知識,擴充套件了 Kubernetes 的功能。Operator Framework 的推出更進一步推動了 Operator 的發展,使其不僅適用於有狀態應用程式,更適合複雜的資料服務。選擇使用 StatefulSets 時需謹慎,並注意無頭服務的建立、PersistentVolume 的分配以及 Pod 的刪除策略。對於複雜的資料系統,使用 preStop 鉤子確保優雅關閉。Operator 能簡化複雜操作,建議評估是否使用現有 Operator 或將應用程式封裝成 Operator。Kubernetes 准入控制確保叢集安全並實施策略,分為驗證和變更兩種,可應用於策略治理、安全性以及資源管理。准入控制器型別包括標準和動態(Webhook),Webhook 可在執行時組態,並在核心 Kubernetes 程式碼之外開發。本文提供准入 Webhook 的 YAML 組態範例,並解說其功能和重要性,以及最佳實踐,例如理解准入控制器的順序、區分修改和驗證准入控制器,以及避免迴圈依賴。

管理狀態與有狀態應用程式的最佳實踐

Kubernetes 的 StatefulSets 為引入複雜的有狀態資料系統作為可行的負載做出了重大貢獻。然而,Kubernetes 對於在 StatefulSet 中執行的負載其實並不完全理解。其他複雜的操作,如備份、容錯移轉、長官者註冊、新副本註冊和升級等,都是需要定期進行的操作,並且在以 StatefulSets 執行時需要仔細考慮。

Operators 的出現

在 Kubernetes 發展初期,CoreOS 的 SRE(Site Reliability Engineers)工程師創造了一類別新的雲原生軟體,稱為 Operators。最初的目的是將執行特定應用程式的領域特定知識封裝到一個擴充套件 Kubernetes 的特定控制器中。可以想像,在 StatefulSet 控制器的基礎上,能夠佈署、擴充套件、升級、備份和執行 Cassandra 或 Kafka 的一般維護操作。一些最早的 Operators 是為 etcd 和 Prometheus 建立的,Prometheus 使用時間序列資料函式庫來保持指標隨時間的變化。正確的建立、備份和還原 Prometheus 或 etcd 例項的組態可以由 Operator 處理,並且是新的 Kubernetes 管理的物件,就像 Pod 或 Deployment 一樣。

Operators 的發展與應用

直到最近,Operators 仍然是由 SRE 或軟體供應商為其特定應用程式建立的一次性工具。2018 年中,Red Hat 建立了 Operator Framework,一套包括 SDK 生產週期管理器和未來模組的工具,這些工具將啟用諸如計量、市場和登入檔型別功能。Operators 不僅適用於有狀態的應用程式,而且由於其自定義控制器邏輯,它們絕對更適合複雜的資料服務和有狀態系統。

StatefulSet 和 Operator 最佳實踐

需要狀態和可能複雜的管理和組態操作的大型分散式應用程式可以從 Kubernetes StatefulSets 和 Operators 中受益。Operators 仍在不斷演進,但它們得到了整個社群的支援,因此這些最佳實踐是根據目前的能力:

  • 應該謹慎決定是否使用 StatefulSets,因為有狀態的應用程式通常需要更深入的管理,而協調器尚不能很好地管理這些(閱讀第220頁的“Operators”以瞭解 Kubernetes 中這種缺陷的未來解決方案)。
  • 不會自動建立 StatefulSet 的無頭服務(headless Service),必須在佈署時建立它,以便正確地將 Pod 作為個別節點進行定址。
  • 當應用程式需要順序命名和可靠的擴充套件時,這並不總是意味著它需要分配 PersistentVolumes。
  • 如果叢集中的某個節點變得無回應,則任何作為 StatefulSet 一部分的 Pod 都不會被自動刪除;相反,它們將在寬限期後進入終止或未知狀態。清除此 Pod 的唯一方法是從叢集中刪除節點物件,或者 kubelet 重新開始工作並直接刪除 Pod,或者 Operator 強制刪除 Pod。強制刪除應該是最後的選擇,並且應該非常小心,以確保曾經擁有已刪除 Pod 的節點不會重新上線,因為叢集中現在將有兩個具有相同名稱的 Pod。您可以使用 kubectl delete pod nginx-0 --grace-period=0 --force 強制刪除 Pod。

詳細刪除步驟

# 強制刪除Pod
kubectl delete pod nginx-0 --grace-period=0 --force

#### 內容解密:
此指令用於強制刪除名為 `nginx-0` 的 Pod。其中 `--grace-period=0` 表示不等待 Pod 的正常關閉過程,直接強制刪除;`--force` 表示強制執行刪除操作。這種做法需要謹慎使用,因為它可能會導致資料不一致或其他問題。

# 對API伺服器進行補丁以刪除條目
kubectl patch pod nginx-0 -p '{"metadata":{"finalizers":null}}'

#### 內容解密:
當 Pod 處於未知狀態且無法正常刪除時,可以使用 `kubectl patch` 命令對 Pod 物件進行補丁,移除其 finalizers,從而允許刪除操作繼續。此操作需謹慎,因為它可能導致資源未被正確清理。
  • 如果您正在執行具有某種長官者選舉或資料複製確認過程的複雜資料系統,請使用 preStop 鉤子在 Pod 被刪除之前正確關閉任何連線、強制長官者選舉或驗證資料同步,使用優雅關閉過程。
  • 當需要有狀態資料的應用程式是複雜的資料管理系統時,請嘗試確定是否存在 Operator 以幫助管理應用程式更複雜的生命週期元件。如果應用程式是在內部構建的,則可能值得研究是否將應用程式封裝為 Operator 以增加應用的可管理性。

StatefulSet 與 Operator 的關係

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 內容解密:

rectangle "管理" as node1
rectangle "擴充套件" as node2
rectangle "執行" as node3
rectangle "簡化" as node4
rectangle "需要" as node5
rectangle "包括" as node6

node1 --> node2
node2 --> node3
node3 --> node4
node4 --> node5
node5 --> node6

@enduml

此圖示展示了 Kubernetes 如何透過 StatefulSet 和 Operator 管理有狀態應用程式,以及 Operator 如何簡化複雜的操作,如備份、升級和容錯移轉。

圖表說明

此圖表清晰地展示了 Kubernetes、StatefulSet 和 Operator 之間的關係,以及它們如何協同工作來管理和簡化有狀態應用程式的操作。其中,Operator 的作用是簡化複雜的操作,如備份、升級和容錯移轉,這些對於有狀態應用程式來說是非常重要的。

第 17 章:准入控制與授權

控制對 Kubernetes API 的存取是確保叢集安全性的關鍵,同時也能作為對所有使用者、工作負載和叢集元件實施政策和治理的手段。在本章中,我們將分享如何使用准入控制器和授權模組來啟用特定功能,以及如何自訂它們以滿足特定的需求。

在探討准入控制和授權之前,讓我們先回顧一下 API 請求透過 API 伺服器的流程。圖 17-1 提供了對准入控制和授權在該流程中如何以及在哪裡發生的深入瞭解。它描述了透過 Kubernetes API 伺服器的端對端請求流程,直到物件被接受並儲存到儲存中。請從左到右跟隨 API 請求透過 API 伺服器,特別注意准入控制和授權的順序。我們將在本章中介紹這些的最佳實踐。

圖 17-1. Kubernetes API 請求流程

准入控制

你是否曾經想過,當你在一個不存在的名稱空間中定義資源時,為什麼名稱空間會自動建立?或者預設儲存類別是如何被選中的?這些變更是由一個名為准入控制器的功能驅動的。在本文中,我們將探討如何使用准入控制器在伺服器端代表使用者實施 Kubernetes 最佳實踐,以及如何利用准入控制來管理 Kubernetes 叢集的使用方式。

什麼是准入控制器?

准入控制器位於 Kubernetes API 伺服器請求流程的路徑中,並在身份驗證和授權階段之後接收請求。它們用於在將請求物件儲存到儲存之前對其進行驗證或變更(或兩者兼而有之)。驗證准入控制器和變更准入控制器之間的區別在於,變更准入控制器可以修改它們允許的請求物件,而驗證准入控制器則不能。

為什麼它們很重要?

由於准入控制器位於所有 API 伺服器請求的路徑中,因此您可以使用它們來實作多種不同的功能。通常,准入控制器的使用可以分為以下三類別:

  • 政策和治理:准入控制器允許執行政策以滿足業務需求;例如:
    • 在 dev 名稱空間中只能使用內部雲端負載平衡器。
    • Pod 中的所有容器都必須具有資源限制。
    • 為所有資源新增預定義的標準標籤或註解,使其可被現有工具發現。
    • 所有 Ingress 資源僅使用 HTTPS。
  • 安全性:您可以使用准入控制器在叢集中實施一致的安全性態勢。一個典型的例子是 Pod Security Admission 控制器,它根據 Pod 規格中定義的安全敏感欄位組態來決定是否允許 Pod。例如,它可以拒絕特權容器或主機檔案系統中特定路徑的使用。
  • 資源管理:准入控制器允許您驗證以提供叢集使用者的最佳實踐;例如:
    • 確保所有 Ingress 的完全合格網域名稱(FQDN)都屬於特定的字尾。
    • 確保 Ingress FQDN 不重疊。
    • Pod 中的所有容器都必須具有資源限制。

准入控制器型別

有兩類別准入控制器:標準和動態。標準准入控制器被編譯到 API 伺服器中,並作為每個 Kubernetes 版本的外掛提供;它們需要在 API 伺服器啟動時進行組態。另一方面,動態控制器可以在執行時進行組態,並在核心 Kubernetes 程式碼之外開發。唯一型別的動態准入控制是准入 Webhook,它透過 HTTP 回撥接收准入請求。

預設情況下,建議的准入控制器是啟用的。您可以使用 Kubernetes API 伺服器上的以下標誌啟用額外的准入控制器:--enable-admission-plugins

在目前的 Kubernetes 版本中,預設啟用以下准入控制器: CertificateApproval、CertificateSigning、CertificateSubjectRestriction、 DefaultIngressClass、DefaultStorageClass、DefaultTolerationSeconds、 LimitRanger、MutatingAdmissionWebhook、NamespaceLifecycle、 PersistentVolumeClaimResize、PodSecurity、Priority、ResourceQuota、 RuntimeClass、ServiceAccount、StorageObjectInUseProtection、 TaintNodesByCondition、ValidatingAdmissionWebhook。

您可以在 Kubernetes 檔案中找到 Kubernetes 准入控制器的列表及其功能。

您可能已經注意到,要啟用的建議准入控制器列表中有 MutatingAdmissionWebhookValidatingAdmissionWebhook。這些標準准入控制器本身並不實作任何准入邏輯;相反,它們用於組態在叢集中執行的 Webhook 端點,以轉發准入請求物件。

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: "validate-ingress.k8s.io"
webhooks:
- name: "validate-ingress.k8s.io"
  clientConfig:
    service:
      name: ingress-validator
      namespace: default
    caBundle: <BASE64 encoded CA Bundle>
  rules:
  - apiGroups:
    - networking.k8s.io
    apiVersions:
    - v1
    operations:
    - CREATE
    - UPDATE
    resources:
    - ingresses
    scope: Namespaced
  timeoutSeconds: 5
  admissionReviewVersions:
  - v1

此 YAML 組態解說:

此組態定義了一個 ValidatingWebhookConfiguration 物件,用於設定一個驗證 Webhook,用於檢查對 Ingress 資源的 CREATE 和 UPDATE 操作。主要欄位說明如下:

  • apiVersionkind:指定了物件的 API 版本和型別。
  • metadata.name:指定了組態的名稱。
  • webhooks:定義了一個 Webhook 的列表,每個 Webhook 都包含以下主要欄位:
    • name:Webhook 的名稱。
    • clientConfig:Webhook 的客戶端組態,指定了用於連線到 Webhook 後端的服務和 CA 組。
      • service:指定了提供 Webhook 後端的服務名稱和名稱空間。
      • caBundle:用於驗證 Webhook 後端伺服器憑證的 CA 組(BASE64 編碼)。
    • rules:定義了觸發 Webhook 的規則,包括:
      • apiGroupsapiVersionsoperationsresourcesscope:指定了哪些 API 群組、版本、操作、資源和範圍會觸發 Webhook。在此範例中,針對 networking.k8s.io/v1 Ingress 資源的 CREATE 和 UPDATE 操作會觸發 Webhook,並且範圍限定在名稱空間內。
      • timeoutSeconds:指定了 Webhook 的超時時間(秒)。
      • admissionReviewVersions:指定了支援的 AdmissionReview 版本。

為什麼這個組態很重要?

這個組態允許 Kubernetes 在對 Ingress 資源進行特定操作時,將請求傳送給指定的 Webhook 後端進行驗證。這樣,您就可以實施自訂的驗證邏輯,例如檢查 Ingress 資源是否符合特定的安全或合規要求。

准入 Webhook 的組態與最佳實踐

在 Kubernetes 中,准入 Webhook 是一種強大的工具,用於在資源建立、更新或刪除時執行自定義驗證和修改。瞭解如何有效地組態准入 Webhook 至關重要,因為這涉及到一致性和故障模式之間的權衡。

ValidatingWebhookConfiguration 資源組態

以下是一個 ValidatingWebhookConfiguration 資源的示例,詳細描述了每個欄位的功能:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: ## 資源名稱
webhooks:
- name: ## 准入 Webhook 的名稱,當審查請求被拒絕時將顯示給使用者
  clientConfig:
    service:
      namespace: ## 包含准入 Webhook Pod 的名稱空間
      name: ## 用於連線准入 Webhook 的服務名稱
      path: ## Webhook URL
    caBundle: ## 用於驗證 Webhook 伺服器憑證的 PEM 編碼 CA 套件
  rules:
  - operations:
    - ## 觸發 API 伺服器向該 Webhook 傳送請求的特定操作(例如,建立、更新、刪除、連線)
    apiGroups:
    - ""
    apiVersions:
    - "*"
    resources:
    - ## 按名稱指定的特定資源(例如,佈署、服務、入口)
  failurePolicy: ## 定義如何處理存取問題或無法識別的錯誤,必須是 Ignore 或 Fail
  admissionReviewVersions: ["v1"] ## 指定接受的 AdmissionReview 物件版本
  sideEffects: ## 表示 Webhook 是否可能產生需要處理的副作用
  timeoutSeconds: 5 ## API 伺服器在將請求視為失敗之前等待回應的時間

內容解密:

  • apiVersionkind 指定了資源的型別和版本。
  • metadata.name 是資源的名稱。
  • webhooks 列出了所有的 Webhook 組態。
  • clientConfig 定義瞭如何連線到 Webhook 服務。
  • rules 描述了哪些操作和資源會觸發 Webhook。
  • failurePolicy 定義了當發生錯誤時的處理策略。
  • admissionReviewVersions 指定了支援的 AdmissionReview 版本。
  • sideEffects 表示 Webhook 是否有副作用。
  • timeoutSeconds 設定了超時時間。

MutatingWebhookConfiguration 資源組態

ValidatingWebhookConfiguration 類別似,MutatingWebhookConfiguration 用於定義修改准入 Webhook。主要的區別在於 kind 和新增的 reinvocationPolicy 欄位。

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: ## 資源名稱
webhooks:
- name: ## 准入 Webhook 的名稱,當審查請求被拒絕時將顯示給使用者
  clientConfig:
    service:
      namespace: ## 包含准入 Webhook Pod 的名稱空間
      name: ## 用於連線准入 Webhook 的服務名稱
      path: ## Webhook URL
    caBundle: ## 用於驗證 Webhook 伺服器憑證的 PEM 編碼 CA 套件
  rules:
  - operations:
    - ## 觸發 API 伺服器向該 Webhook 傳送請求的特定操作(例如,建立、更新、刪除、連線)
    apiGroups:
    - ""
    apiVersions:
    - "*"
    resources:
    - ## 按名稱指定的特定資源(例如,佈署、服務、入口)
  failurePolicy: ## 定義如何處理存取問題或無法識別的錯誤,必須是 Ignore 或 Fail
  admissionReviewVersions: ["v1"] ## 指定接受的 AdmissionReview 物件版本
  sideEffects: ## 表示 Webhook 是否可能產生需要處理的副作用
  reinvocationPolicy: ## 控制如果對物件進行了其他修改,是否重新呼叫修改 Webhook
  timeoutSeconds: 5 ## API 伺服器在將請求視為失敗之前等待回應的時間

內容解密:

  • ValidatingWebhookConfiguration 相似,但多了 reinvocationPolicy
  • reinvocationPolicy 控制是否在物件被其他 Webhook 修改後重新呼叫該 Webhook。

准入控制的最佳實踐

  1. 瞭解准入控制器的順序:在目前支援的 Kubernetes 版本中,准入外掛的順序不再重要,但瞭解請求流程仍然至關重要。
  2. 區分修改和驗證准入控制器:修改准入控制器總是在驗證准入控制器之前執行,因為通常不會希望驗證將要被修改的物件。
  3. 避免迴圈依賴:不要讓 Webhook 之間產生迴圈依賴,這可能會導致請求被無限期地延遲或失敗。