在 Kubernetes 環境中,管理有狀態應用程式的更新至關重要。StatefulSet 提供了滾動更新機制,允許逐步更新 Pod,將服務中斷風險降至最低。本文將詳細介紹如何使用 RollingUpdate 策略和 Partition 引數實作更精細的控制,例如 Canary 發布,並探討如何觀察更新狀態和進行回復操作。同時,我們也會提供一些 StatefulSet 的最佳實踐,幫助您更好地管理有狀態應用程式。
在更新 StatefulSet 時,kubectl rollout status 命令可以幫助我們監控更新進度,確保每個 Pod 都按預期更新。updateStrategy.type: RollingUpdate 允許我們使用 rollingUpdate.partition 引數控制更新的 Pod 範圍。設定 Partition 後,只有序號大於或等於 Partition 值的 Pod 會被更新,方便進行 Canary 發布,驗證新版本的功能和穩定性後再更新剩餘 Pod。如果更新過程中出現問題,我們可以透過修改 YAML 檔案並重新套用,或是使用 kubectl rollout undo 命令回復到之前的版本,確保應用程式的穩定執行。
使用 StatefulSet 佈署有狀態應用程式
滾動更新與 Canary 發布
在 Kubernetes 中,StatefulSet 是一種用於管理有狀態應用程式的 API 物件。它確保了 Pod 的身份和永續性,使其非常適合用於需要穩定網路身份和持久儲存的應用程式,如資料函式庫。
滾動更新
滾動更新是一種 StatefulSet 更新策略,它允許您逐步更新 Pod,以最小化對應用程式的影響。以下是一個使用 MySQL 作為範例的滾動更新流程:
準備 StatefulSet 組態檔案:首先,您需要準備一個 StatefulSet 的 YAML 組態檔案,例如
mysql-statefulset-rolling-update.yaml。該檔案定義了 MySQL StatefulSet 的規格,包括容器映像、服務名稱等。更新容器映像:在組態檔案中,將 MySQL 的映像版本從
8.3.0更新至8.4.0。這是透過修改spec.containers.image欄位來實作的。spec: containers: - name: mysql image: mysql:8.4.0套用組態變更:使用
kubectl apply命令將更新後的組態檔案套用到叢集。$ kubectl apply -f mysql-statefulset-rolling-update.yaml觀察滾動更新過程:使用
kubectl rollout status命令觀察 StatefulSet 的滾動更新過程。$ kubectl rollout status statefulset -n mysql
使用 Partition 進行 Canary 發布
在進行滾動更新時,您可以使用 partition 欄位來控制哪些 Pod 應該被更新。這使得您可以進行 canary 發布,即先更新一部分 Pod,以測試新版本是否穩定。
設定 Partition:在 StatefulSet 的
updateStrategy部分,設定partition為所需的序號。這樣,只有序號大於或等於該值的 Pod 才會被更新。updateStrategy: type: RollingUpdate rollingUpdate: partition: 2套用變更並觀察:套用變更後,觀察 StatefulSet 的更新過程。只有指定的 Pod 會被更新。
驗證 Canary:登入到新的 Pod 中,驗證新版本是否運作正常。
$ kubectl exec -it -n mysql k8sutils -- /bin/bash root@k8sutils:/# mysql -u root -p -h mysql-stateful-2.mysql-headless完成滾動更新:如果 canary 發布成功,您可以將
partition設定為 0,以完成整個 StatefulSet 的滾動更新。
程式碼解說
以下是一個範例 YAML 組態檔案,用於定義 MySQL StatefulSet 的滾動更新策略:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql-stateful
spec:
serviceName: mysql-headless
podManagementPolicy: OrderedReady
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 0
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.4.0
ports:
- containerPort: 3306
內容解密:
apiVersion和kind:定義了 Kubernetes 物件的 API 版本和型別。metadata:提供了關於物件的中繼資料,如名稱。spec.serviceName:指定了與 StatefulSet 相關聯的無頭服務名稱。updateStrategy.type:定義了更新策略的型別,這裡使用的是RollingUpdate。rollingUpdate.partition:控制哪些 Pod 應該被更新,設為 0 表示全部更新。replicas:指定了 StatefulSet 中 Pod 的副本數量。template.spec.containers.image:定義了容器所使用的映像版本。
管理StatefulSet的滾動更新與回復
在前一章中,我們討論瞭如何使用Kubernetes Deployment來管理無狀態應用程式。本章節將著重於StatefulSet的滾動更新與回復操作。
觀察StatefulSet的滾動更新狀態
使用kubectl rollout status命令可以觀察StatefulSet的滾動更新狀態:
$ kubectl rollout status statefulset -n mysql
Waiting for partitioned roll out to finish: 1 out of 3 new pods have been updated...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
Waiting for partitioned roll out to finish: 2 out of 3 new pods have been updated...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
partitioned roll out complete: 3 new pods have been updated...
如上所示,滾動更新到mysql:8.4.0映像版本已成功完成。
回復StatefulSet
對於StatefulSet,回復操作與Deployment類別似,可以使用kubectl rollout undo命令。但是,對於StatefulSet,建議使用宣告式模型來引入變更。
使用宣告式模型進行回復
宣告式模型的優點是,可以將變更提交到原始碼儲存函式庫,並透過CI/CD管道自動套用變更。要回復StatefulSet,只需還原提交並重新套用組態即可。
# 修改YAML manifest檔案或還原提交
# 套用變更
$ kubectl apply -f mysql-statefulset.yaml
使用指令式模型進行分階段滾動更新
雖然可以使用kubectl patch命令進行分階段滾動更新,但這種方法可讀性較差,且容易出錯。
$ kubectl patch sts mysql-stateful -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}' -n mysql
StatefulSet最佳實踐
本文總結了使用StatefulSet時的已知最佳實踐。
使用宣告式物件管理
宣告式模型是DevOps世界中的良好實踐,可以使用kubectl apply命令進行宣告式更新。
避免將TerminationGracePeriodSeconds設定為0
將TerminationGracePeriodSeconds設定為0將導致Pod立即終止,這對於StatefulSet來說是強烈不建議的。StatefulSet通常需要優雅的清理或preStop生命週期鉤子來執行。
使用指令式命令刪除物件
使用指令式命令刪除物件更可預測,且不容易出錯。宣告式刪除資源主要用於CI/CD場景中。
重點整理
- 使用宣告式模型管理StatefulSet。
- 避免將
TerminationGracePeriodSeconds設定為0。 - 使用指令式命令刪除物件。
DaemonSet – 在節點上維護 Pod 單例
前幾章已經解釋並演示瞭如何使用最常見的 Kubernetes 控制器來管理 Pods,例如 ReplicaSet、Deployment 和 StatefulSet。一般來說,當執行包含實際業務邏輯的雲應用程式元件時,您需要使用 Deployments 或 StatefulSets 來控制您的 Pods。在某些情況下,當您需要將批處理工作負載作為應用程式的一部分執行時,您將使用 Jobs 和 CronJobs。
然而,在某些情況下,您需要執行具有支援功能的元件,例如執行維護任務或彙總日誌和指標。更具體地說,如果您有任何需要在叢集中的每個節點上執行的任務,則可以使用 DaemonSet 來執行它們。DaemonSet 的目的是確保每個節點(除非另有指定)執行一個 Pod 副本。如果您將新的節點新增到叢集,它將自動獲得一個排程的 Pod 副本。同樣,如果您從叢集中刪除一個節點,Pod 副本將被終止 – DaemonSet 將執行所有所需的操作。
介紹 DaemonSet 物件
DaemonSet 是 Kubernetes 中的一種控制器,用於確保每個節點上執行一個 Pod 副本。它通常用於執行具有支援功能的元件,例如日誌收集、監控代理或節點級別的儲存管理。
建立和管理 DaemonSets
要建立 DaemonSet,您需要建立一個 YAML 或 JSON 檔案,定義 DaemonSet 物件。以下是一個簡單的範例:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: example-daemonset
spec:
selector:
matchLabels:
name: example-daemonset
template:
metadata:
labels:
name: example-daemonset
spec:
containers:
- name: example-container
image: example/image
ports:
- containerPort: 8080
程式碼解密:
此 YAML 檔案定義了一個名為 example-daemonset 的 DaemonSet 物件。它指定了一個選擇器,用於匹配具有 name: example-daemonset 標籤的 Pods。範本部分定義了要建立的 Pod 的規格,包括容器映像和連線埠。
要建立 DaemonSet,請執行以下命令:
kubectl apply -f example-daemonset.yaml
要管理 DaemonSet,您可以使用各種 kubectl 命令,例如 kubectl get、kubectl describe 和 kubectl delete。
DaemonSets 的常見使用案例
DaemonSets 通常用於執行具有支援功能的元件,例如:
- 日誌收集:DaemonSet 可以用於在每個節點上執行日誌收集代理,將日誌傳送到中央日誌儲存。
- 監控代理:DaemonSet 可以用於在每個節點上執行監控代理,收集節點和應用程式的指標。
- 節點級別的儲存管理:DaemonSet 可以用於在每個節點上執行儲存管理代理,管理節點級別的儲存資源。
DaemonSets 的替代方案
在某些情況下,您可能不需要使用 DaemonSet。以下是一些替代方案:
- ReplicaSet 或 Deployment:如果您需要在叢集中執行固定數量的 Pods,您可以使用 ReplicaSet 或 Deployment。
- Job 或 CronJob:如果您需要執行批處理工作負載,您可以使用 Job 或 CronJob。
進一步閱讀
- DaemonSet:https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/
- ReplicaSet:https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/
- Deployment:https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
此圖示展示了 DaemonSet 的架構:
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333
title 進一步閱讀
rectangle "runs" as node1
rectangle "manages" as node2
node1 --> node2
@enduml
圖示解密:
此圖示展示了一個 DaemonSet 管理三個節點上的三個 Pods。每個節點執行一個 Pod 副本,DaemonSet 負責確保每個節點上執行一個 Pod 副本。
DaemonSet:維護節點上的Pod單例
DaemonSet是Kubernetes中的一種重要資源物件,用於確保在叢集中的每個節點(Node)上執行一個Pod副本。這種機制對於需要監控、記錄、儲存管理或網路管理的應用程式至關重要。DaemonSet會自動根據叢集節點的變化調整Pod的數量,確保每個節點都有所需的Pod在執行。
介紹DaemonSet物件
DaemonSet的概念源自Unix-like作業系統中的守護程式(daemon),這些程式在背景執行,負責處理維護任務、服務網路請求或監控硬體活動。在Kubernetes中,DaemonSet確保在每個節點上執行一個Pod副本,這些Pod處理著對整個叢集至關重要的任務。
DaemonSet的主要應用場景
- 監控:監控每個節點的健康狀態。
- 日誌收集:收集節點和執行其上的Pod的資訊。
- 儲存管理:處理應用程式的儲存空間請求。
- 網路管理:提供連線性,例如kube-proxy和CNI(例如Calico)。
DaemonSet的工作原理
DaemonSet控制器會根據節點的變化動態地建立或刪除Pod。當新的節點加入叢集時,DaemonSet會自動在該節點上建立一個Pod;當節點被移除時,相關的Pod也會被清理。這種機制確保了叢集的動態管理和資源的最佳利用。
DaemonSet Pod的排程
DaemonSet保證在每個符合條件的節點上執行一個Pod。DaemonSet控制器會建立具有節點親和性規則的Pod,以確保這些Pod只會被排程到符合特定條件的節點上。預設的排程器會將Pod繫結到目標節點,如果資源不足,可能會搶佔現有的Pod。
檢查DaemonSet資源
在佈署Kubernetes叢集後,您可能已經在使用一些由Kubernetes或叢集支援元件佈署的DaemonSet,例如DNS服務或CNI。您可以使用kubectl get daemonsets -A命令檢查目前叢集中的DaemonSet資源。
$ minikube start \
--driver=virtualbox \
--nodes 3 \
--cni calico \
--cpus=2 \
--memory=2g \
--kubernetes-version=v1.31.0 \
--container-runtime=containerd
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 3m28s v1.31.0
minikube-m02 Ready <none> 2m29s v1.31.0
minikube-m03 Ready <none> 91s v1.31.0
$ kubectl get daemonsets -A
NAMESPACE NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
DaemonSet與其他資源的比較
DaemonSet與ReplicaSet、Deployment和StatefulSet等資源物件有相似之處,都需要提供Pod範本和標籤選擇器。然而,DaemonSet主要關注在每個節點上執行一個Pod副本,這使得它在某些特定場景下非常有用。
DaemonSet Pod的通訊模式
根據使用場景,DaemonSet Pod可能需要與其他Pod或外部網路進行通訊。常見的通訊模式包括:
- 將容器埠對映到主機埠。
- 將資料推播到其他服務。
- 使用無頭服務(Headless Service)匹配DaemonSet Pod標籤選擇器。
- 使用正常服務(Normal Service)匹配DaemonSet Pod標籤選擇器。