本文已超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

Kubernetes 1.27:StatefulSet 啟動序數簡化遷移

Kubernetes v1.26 為 StatefulSets 引入了一個新的 alpha 級功能,用於控制 Pod 副本的序號編號。從 Kubernetes v1.27 開始,此功能現在為 beta 版。序號可以從任意非負數開始。此部落格文章將討論如何使用此功能。

背景

StatefulSets 序號為 pod 副本提供循序識別碼。當使用 OrderedReady Pod 管理時,Pod 是從序號索引 0N-1 建立的。

在現今的 Kubernetes 中,跨叢集協調 StatefulSet 遷移具有挑戰性。備份和還原解決方案存在,但這些方案需要應用程式在遷移之前縮減到零個副本。在當今完全連線的世界中,即使是計畫性的應用程式停機時間也可能無法讓您達到業務目標。您可以使用 串聯刪除On Delete 來遷移個別 pod,但是這容易出錯且難以管理。當您的 Pod 失敗或被逐出時,您會失去 StatefulSet 控制器的自我修復優勢。

Kubernetes v1.26 使 StatefulSet 能夠負責範圍 {0..N-1} 內的序號範圍(序號 0、1、... 到 N-1)。有了它,您可以縮減來源叢集中的範圍 {0..k-1},並擴展目的地叢集中的互補範圍 {k..N-1},同時保持應用程式可用性。這使您能夠在跨叢集協調遷移時,保留最多一個語義(表示在 StatefulSet 中最多只有一個具有給定身分識別的 Pod 執行)和 滾動更新 行為。

為何我會想要使用此功能?

假設您在一個叢集中執行 StatefulSet,並且需要將其遷移到另一個叢集。有很多原因會讓您需要這樣做

  • 擴展性:您的 StatefulSet 已擴展得太大,超出叢集的負荷,並已開始擾亂叢集中其他工作負載的服務品質。
  • 隔離:您正在多個使用者存取的叢集中執行 StatefulSet,而命名空間隔離不足以滿足需求。
  • 叢集組態:您想要將 StatefulSet 移動到不同的叢集,以使用目前叢集上不可用的某些環境。
  • 控制平面升級:您想要將 StatefulSet 移動到執行升級控制平面的叢集,並且無法處理就地控制平面升級的風險或停機時間。

我該如何使用它?

在叢集上啟用 StatefulSetStartOrdinal 功能閘道,並建立具有自訂 .spec.ordinals.start 的 StatefulSet。

試用看看

在此示範中,我將使用新的機制將 StatefulSet 從一個 Kubernetes 叢集遷移到另一個叢集。將使用 redis-cluster Bitnami Helm chart 安裝 Redis。

所需工具

先決條件

為此,我需要兩個 Kubernetes 叢集,它們都可以存取共用網路和儲存空間;我已將我的叢集命名為 sourcedestination。具體來說,我需要

  • 在兩個叢集上都啟用 StatefulSetStartOrdinal 功能閘道。
  • kubectl 的用戶端組態,讓我能夠以管理員身分存取這兩個叢集。
  • 在兩個叢集上都安裝相同的 StorageClass,並設定為兩個叢集的預設 StorageClass。此 StorageClass 應佈建可從任一或兩個叢集存取的底層儲存空間。
  • 允許 pod 與任一叢集中的 Pod 互相傳送和接收封包的平面網路拓撲。如果您在雲端供應商上建立叢集,則此組態可能稱為私有雲或私有網路。
  1. 在兩個叢集上建立示範命名空間

    kubectl create ns kep-3335
    
  2. 在來源叢集中部署具有六個副本的 Redis 叢集

    helm repo add bitnami https://charts.bitnami.com/bitnami
    helm install redis --namespace kep-3335 \
      bitnami/redis-cluster \
      --set persistence.size=1Gi \
      --set cluster.nodes=6
    
  3. 檢查來源叢集中的複製狀態

    kubectl exec -it redis-redis-cluster-0 -- /bin/bash -c \
      "redis-cli -c -h redis-redis-cluster -a $(kubectl get secret redis-redis-cluster -o jsonpath="{.data.redis-password}" | base64 -d) CLUSTER NODES;"
    
    2ce30362c188aabc06f3eee5d92892d95b1da5c3 10.104.0.14:6379@16379 myself,master - 0 1669764411000 3 connected 10923-16383                                                                                                                                              
    7743661f60b6b17b5c71d083260419588b4f2451 10.104.0.16:6379@16379 slave 2ce30362c188aabc06f3eee5d92892d95b1da5c3 0 1669764410000 3 connected                                                                                             
    961f35e37c4eea507cfe12f96e3bfd694b9c21d4 10.104.0.18:6379@16379 slave a8765caed08f3e185cef22bd09edf409dc2bcc61 0 1669764411000 1 connected                                                                                                             
    7136e37d8864db983f334b85d2b094be47c830e5 10.104.0.15:6379@16379 slave 2cff613d763b22c180cd40668da8e452edef3fc8 0 1669764412595 2 connected                                                                                                                    
    a8765caed08f3e185cef22bd09edf409dc2bcc61 10.104.0.19:6379@16379 master - 0 1669764411592 1 connected 0-5460                                                                                                                                                   
    2cff613d763b22c180cd40668da8e452edef3fc8 10.104.0.17:6379@16379 master - 0 1669764410000 2 connected 5461-10922
    
  4. 在目的地叢集中部署具有零個副本的 Redis 叢集

    helm install redis --namespace kep-3335 \
      bitnami/redis-cluster \
      --set persistence.size=1Gi \
      --set cluster.nodes=0 \
      --set redis.extraEnvVars\[0\].name=REDIS_NODES,redis.extraEnvVars\[0\].value="redis-redis-cluster-headless.kep-3335.svc.cluster.local" \
      --set existingSecret=redis-redis-cluster
    
  5. 將來源叢集中的 redis-redis-cluster StatefulSet 縮減 1 個副本,以移除副本 redis-redis-cluster-5

    kubectl patch sts redis-redis-cluster -p '{"spec": {"replicas": 5}}'
    
  6. 將相依性從來源叢集遷移到目的地叢集

    以下命令將資源從 source 複製到 destination。已移除與 destination 叢集無關的詳細資訊(例如:uidresourceVersionstatus)。

    來源叢集的步驟

    注意:如果使用組態為 reclaimPolicy: DeleteStorageClass,您應在刪除之前使用 reclaimPolicy: Retain 修補 source 中的 PV,以保留 destination 中使用的底層儲存空間。請參閱 變更 PersistentVolume 的回收策略 以取得更多詳細資訊。

    kubectl get pvc redis-data-redis-redis-cluster-5 -o yaml | yq 'del(.metadata.uid, .metadata.resourceVersion, .metadata.annotations, .metadata.finalizers, .status)' > /tmp/pvc-redis-data-redis-redis-cluster-5.yaml
    kubectl get pv $(yq '.spec.volumeName' /tmp/pvc-redis-data-redis-redis-cluster-5.yaml) -o yaml | yq 'del(.metadata.uid, .metadata.resourceVersion, .metadata.annotations, .metadata.finalizers, .spec.claimRef, .status)' > /tmp/pv-redis-data-redis-redis-cluster-5.yaml
    kubectl get secret redis-redis-cluster -o yaml | yq 'del(.metadata.uid, .metadata.resourceVersion)' > /tmp/secret-redis-redis-cluster.yaml
    

    目的地叢集的步驟

    注意:對於 PV/PVC,此程序僅在您的 PV 使用的底層儲存系統可以支援複製到 destination 時才有效。與特定節點或拓撲相關聯的儲存空間可能不受支援。此外,某些儲存系統可能會在 PV 物件外部儲存有關磁碟區的其他 metadata,並且可能需要更專業的順序來匯入磁碟區。

    kubectl create -f /tmp/pv-redis-data-redis-redis-cluster-5.yaml
    kubectl create -f /tmp/pvc-redis-data-redis-redis-cluster-5.yaml
    kubectl create -f /tmp/secret-redis-redis-cluster.yaml
    
  7. 將目的地叢集中的 redis-redis-cluster StatefulSet 擴展 1 個副本,起始序號為 5

    kubectl patch sts redis-redis-cluster -p '{"spec": {"ordinals": {"start": 5}, "replicas": 1}}'
    
  8. 檢查目的地叢集中的複製狀態

    kubectl exec -it redis-redis-cluster-5 -- /bin/bash -c \
      "redis-cli -c -h redis-redis-cluster -a $(kubectl get secret redis-redis-cluster -o jsonpath="{.data.redis-password}" | base64 -d) CLUSTER NODES;"
    

    我應該會看到新的副本(標記為 myself)已加入 Redis 叢集(IP 位址屬於與來源叢集中的副本不同的 CIDR 區塊)。

    2cff613d763b22c180cd40668da8e452edef3fc8 10.104.0.17:6379@16379 master - 0 1669766684000 2 connected 5461-10922
    7136e37d8864db983f334b85d2b094be47c830e5 10.108.0.22:6379@16379 myself,slave 2cff613d763b22c180cd40668da8e452edef3fc8 0 1669766685609 2 connected
    2ce30362c188aabc06f3eee5d92892d95b1da5c3 10.104.0.14:6379@16379 master - 0 1669766684000 3 connected 10923-16383
    961f35e37c4eea507cfe12f96e3bfd694b9c21d4 10.104.0.18:6379@16379 slave a8765caed08f3e185cef22bd09edf409dc2bcc61 0 1669766683600 1 connected
    a8765caed08f3e185cef22bd09edf409dc2bcc61 10.104.0.19:6379@16379 master - 0 1669766685000 1 connected 0-5460
    7743661f60b6b17b5c71d083260419588b4f2451 10.104.0.16:6379@16379 slave 2ce30362c188aabc06f3eee5d92892d95b1da5c3 0 1669766686613 3 connected
    
  9. 針對其餘副本重複步驟 #5 到 #7,直到來源叢集中的 Redis StatefulSet 縮減為 0,並且目的地叢集中的 Redis StatefulSet 運作正常且總共有 6 個副本。

下一步?

此功能為將 StatefulSet 分割到多個叢集提供了一個建構區塊,但並未規定應如何遷移 StatefulSet 的機制。遷移需要協調 StatefulSet 副本,以及協調儲存和網路層。這取決於 StatefulSet 安裝的應用程式的儲存和連線需求。此外,許多 StatefulSet 由 operator 管理,這為遷移增加了另一層複雜性。

如果您有興趣建構增強功能以使這些流程更輕鬆,請加入 SIG Multicluster 以做出貢獻!