雲原生場景下高可用架構的最佳實踐

作者:劉佳旭(花名:佳旭),阿里雲容器服務技術專家

01 引言

隨着雲原生技術的快速發展以及在企業 IT 領域的深入應用,雲原生場景下的高可用架構,對於企業服務的可用性、穩定性、安全性越發重要。通過合理的架構設計和雲平臺的技術支持,雲原生高可用架構可以提供高可用性、彈性擴展性、簡化運維管理、提升可靠性和安全性等方面的優勢,爲企業提供了更加可靠和高效的應用運行環境。

Kubernetes 是雲原生的核心技術之一,提供了容器編排和管理的能力,包括基礎設施自動化、彈性擴展性、微服務架構和自動化運維等,所以 Kubernetes 的應用高可用架構是雲原生高可用的基石。本文會以阿里雲容器服務 ACK(Alibaba Cloud Container Service for Kubernetes)爲例,介紹基於 ACK 的應用高可用架構和治理的最佳實踐。

02 應用高可用架構設計

雲原生應用的高可用架構設計,是應用高可用開發、部署和治理的重要前提,可以從如下方面考慮:

1. 集羣設計: 集羣控制面和數據面的組件和節點,使用多節點、多副本高可用部署,保證 K8s 集羣的高可用性。以 ACK 爲例,提供了覆蓋控制面和數據面的集羣高可用能力。在控制面,ACK Pro 託管版集羣的控制面組件使用多副本跨可用區部署,並基於對控制面的負載壓力自動彈性;ACK 專有版可以配置 3 個或者 5 個 master 節點。在數據面,ACK 支持用戶自行選擇跨可用區以及 ECS 部署集來部署、添加節點的能力。

2. 容器設計: 應用在集羣中多副本部署,基於 Deployment、Statefulset 以及 OpenKruise CRD 等來管理應用的副本,實現應用的高可用性;爲應用配置自動彈性策略,以應對負載的動態變化。在多副本 Pod 的場景下,根據是否有主備角色的副本,可以分爲主備形態高可用和多活形態高可用。

3. 資源調度: 使用 K8s 的調度器來實現應用的負載均衡和故障轉移。使用標籤和選擇器來指定應用的部署節點範圍,並使用親和性、反親和性、拓撲調度約束規則來控制應用的調度策略,實現 Pod 的按節點、可用區、部署集、拓撲域等不同類別的高可用。

4. 存儲設計: 使用持久化存儲來保存應用的數據,例如 K8s 的持久化捲來掛載存儲等,以避免數據丟失。對於有狀態應用,使用 StatefulSet 來管理有狀態應用的副本和存儲卷。

5. 故障恢復: 使用 K8s 的自動恢復機制來處理應用的故障。可以使用健康檢查和自動重啓來監測應用的健康狀態,並在應用故障時自動重啓或遷移應用。

6. 網絡設計: 使用 K8s 的服務發現和負載均衡功能來實現應用的網絡訪問,可以使用 Service 和 Ingress 來暴露應用的服務。

7. 監控告警: 使用 K8s 的監控和告警系統(例如 Prometheus、Thanos、AlertManager 等)來監控應用的運行狀態,並及時發現和處理故障。

8. 全鏈路高可用設計: 全鏈路高可用是指雲原生應用的系統和服務中,所有涉及到的組件、模塊、服務和網絡等環節都具備高可用性。全鏈路高可用是一個綜合性的考慮,需要從整個系統的架構設計、組件的選擇和配置、服務的部署和運維等方面進行綜合考慮和實施。同時,需要根據具體的業務需求和技術要求,進行適度的折中和權衡。

總之,設計 K8s 應用的高可用架構需要綜合考慮集羣、容器、資源調度、存儲、故障恢復、網絡以及監控告警等方面的因素,實現可靠穩定的應用高可用性架構和功能。對於已有系統的高可用改造也可以參考如上原則實施。

下面會介紹一下,基於如上設計原則,Kubernetes 提供的多種高可用技術,以及基於 ACK 的相關產品化實現。

03 K8s 高可用技術和在 ACK 的運用

Kubernetes 提供了多種高可用技術和機制,以確保集羣和應用的高可用性。包括拓撲分佈約束、PodAntiAffinity、容器健康檢查和自動重啓、存儲冗餘和持久化、服務發現和負載均衡等。這些技術和機制可以幫助構建高可用的 Kubernetes 集羣和應用,提供穩定、可靠的服務,下面會展開介紹。

3.1 控制面 / 數據面按多可用區高可用

集羣通過在不同的可用區部署控制面和數據面節點 / 組件來實現高可用性,是一種重要的高可用架構設計方法。可用區是指雲提供商在一個地理區域內提供的邏輯獨立數據中心。通過在不同的可用區部署節點,可以確保即使在一個可用區出現故障或不可用的情況下,集羣仍然可以繼續提供服務。

以下是 K8s 集羣節點按可用區高可用設計的關鍵點,可用於在 Kubernetes 中實現控制面 / 數據面節點按可用區高可用的配置:

通過按多可用區部署控制面節點 / 組件和數據面節點,可以提高 Kubernetes 集羣的可用性和容錯能力,確保即使在單個可用區或節點發生故障時,集羣仍然能夠繼續提供服務。

ACK 提供了覆蓋控制面和數據面的集羣高可用能力。ACK 容器服務採用 Kubernetes on Kubernetes 架構來託管用戶 Kubernetes 集羣控制面組件,包括 etcd,API Server,Scheduler 等等,每種控制面組件的多實例均採用高可用架構部署和管理。如果 ACK Pro 集羣所在區域的可用區數量爲 3 個及以上,ACK Pro 託管集羣控制面的 SLA 是 99.95%;如果 ACK Pro 集羣所在區域的可用區數量爲 2 個及以下,ACK Pro 託管集羣控制面的 SLA 是 99.50%。

ACK 容器服務負責託管面組件的高可用性,安全性以及彈性擴縮容。ACK Pro 集羣對託管組件提供了完備的可觀測能力,幫助用戶對集羣狀態進行監控、告警。

下面介紹常見的控制按可用區高可用打散的技術以及 ACK 場景下的使用,在數據面高可用場景廣泛使用。

3.1.1 拓撲分佈約束 Topology Spread Constraints

拓撲分佈約束(Topology Spread Constraints)是一種在 Kubernetes 集羣中管理 Pod 分佈的功能。它可以確保 Pod 在不同的節點和可用區之間均勻分佈,以提高應用程序的高可用性和穩定性。該技術適用於工作負載 Deployment、StatefulSet、DaemonSet 和 Job/CronJob。

通過使用拓撲分佈約束,可以設置以下配置來控制 Pod 的分佈:

通過使用這些配置,可以創建拓撲分佈約束的策略,以確保 Pod 在集羣中按照期望的拓撲分佈進行部署。這對於需要在不同的可用區或節點之間均勻分佈負載的應用程序非常有用,以提高可靠性和可用性。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-run-per-zone
spec:
  replicas: 3
  selector:
    matchLabels:
      app: app-run-per-zone
  template:
    metadata:
      labels:
        app: app-run-per-zone
    spec:
      containers:
        - name: app-container
          image: app-image
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: "topology.kubernetes.io/zone"
          whenUnsatisfiable: DoNotSchedule

在上述示例中,創建了一個拓撲分佈約束,其中 maxSkew 設置爲 1,topologyKey 設置爲 "topology.kubernetes.io/zone",whenUnsatisfiable 設置爲 DoNotSchedule。這意味着 Pod 按由節點的 label "topology.kubernetes.io/zone"(對應到雲廠商的可用區)定義的拓撲域進行按可用區強制打散,且拓撲域之間 Pod 數量最大差值爲 1。通過這種方式,可以將 Workload 的 Pod 儘量按可用區打散調度。

ACK K8s 集羣控制面默認採用了多可用區的高可用架構,進一步我們需要實現數據面的多可用區架構。ACK 集羣的數據面由節點池和虛擬節點組成。每個節點池是一組 ECS 實例,通過節點池,用戶可以對節點進行管理、擴縮容與日常運維。虛擬節點可以通過彈性容器實例 ECI 來提供 Serverless 化的容器運行環境。

每個節點池背後是一個彈性伸縮組(ESS),支持節點的手動擴縮容與自動化彈性伸縮。ACK 節點池支持部署集,可以將同一部署集中的 ECS 實例打散部署在不同的物理服務器上,從而避免由於一臺物理機失效導致多臺 ECS 實例宕機。ACK 也支持多 AZ 節點池:在創建和運行過程中,可以爲節點池選擇多個跨不同 AZ 的 vSwitch。並選擇均衡分佈策略,這樣可以在伸縮組指定的多可用區(即指定多個專有網絡交換機)之間均勻分配 ECS 實例。如果由於庫存不足等原因可用區之間變得不平衡,您可以再進行均衡操作來平衡資源的可用區分佈。

基於節點、部署集、AZ,這樣不同故障域的元信息,結合 K8s 調度中的拓撲分佈約束(Topology Spread Constraints),我們可以實現不同級別的故障域隔離能力。首先 ACK 節點池上所有節點會自動添加拓撲相關的 label,比如 “kubernetes.io/hostname”, “topology.kubernetes.io/zone”,“topology.kubernetes.io/region” 等。開發者可以使用拓撲分佈約束來控制 Pod 在不同故障域間的分佈,提升對底層基礎設施故障的容忍能力。

3.1.2 拓撲分佈約束與 NodeAffinity/NodeSelector 的關係

拓撲分佈約束與 NodeAffinity/NodeSelector 的關係是,Node Affinity 和 Node Selectors 主要用於控制 Pod 調度到特定範圍的節點上,而拓撲分佈約束則更專注於控制 Pod 在不同拓撲域之間的分佈。可以通過結合使用這些機制,來更精細地控制 Pod 的調度和分佈。

NodeAffinity 和 NodeSelector 可以與拓撲分佈約束一起使用。可以先使用 NodeAffinity 和 NodeSelector 來選擇滿足特定條件的節點,然後使用拓撲分佈約束來確保 Pod 在這些節點上的分佈符合預期的拓撲分佈要求。

具體可以參考 [1]。

關於混合使用 Node Affinity 和 Node Selectors 可以與拓撲分佈約束,可以參考 [2]。

3.1.3 拓撲分佈約束的不足

拓撲分佈約束存在一些限制和不足,需要注意:

  1. 可用區數量限制:如果可用區的數量非常有限,或者只有一個可用區可用,那麼使用拓撲分佈約束可能無法發揮其優勢。在這種情況下,無法實現真正的可用區故障隔離和高可用性。

  2. 當 Pod 被移除時,並不能保證約束條件仍然得到滿足。例如,縮減一個 Deployment 可能會導致 Pods 分佈不均衡。

  3. 調度器並沒有對集羣中的所有區域或其他拓撲域有先前的瞭解。它們是根據集羣中現有的節點確定的。這可能會導致在自動擴展集羣中出現問題,當一個節點池(或節點組)被縮減到零個節點時,而用戶期望集羣能夠擴展時,此時這些拓撲域將不被考慮,直到至少有一個節點在其中。

更多詳細內容參考 [3]。

3.1.4 多可用區實現同時快速彈性擴容

ACK 節點自動伸縮組件可通過預調度判斷服務能否部署在某個伸縮組上,然後將擴容實例個數的請求發給指定伸縮組,最終由 ESS 伸縮組生成實例。但這種在一個伸縮組上配置多個可用區 vSwtich 的模型特點,會導致以下問題:

當多可用區業務 Pod 出現由於集羣資源不足無法調度時,節點自動伸縮服務會觸發該伸縮組擴容,但是無法將需要擴容的可用區與實例的關係傳遞到 ESS 彈性伸縮組,因此可能會連續彈出某一個地域的多個實例,而非在多個 vSwtich 同時彈出,這樣無法滿足在多可用區同時擴容的需求。

多可用區均衡是數據類型業務高可用場景下常用的部署方式。當業務壓力增大時,有多可用區均衡調度策略的應用希望可以自動擴容出多個可用區的實例來滿足集羣的調度水位。

爲了解決同時擴容多可用區節點的問題,容器服務 ACK 引入了 ack-autoscaling-placeholder 組件,通過少量的資源冗餘方式,將多可用區的彈性伸縮問題轉變爲併發節點池的定向伸縮問題。

具體原理如下:

  1. 首先爲每個可用區創建一個節點池,並分別在各個節點池打上可用區的標籤。

  2. 通過配置可用區標籤 nodeSelector 的方式,使用 ack-autoscaling-placeholder 爲每個可用區創建佔位 Pod,默認的佔位 Pod 具有比較低權重的 PriorityClass,應用 Pod 的優先級高於佔位 Pod。

  3. 這樣業務應用 Pod Pending 後,會搶佔各個可用區佔位 Pod,帶有可用區 nodeSelector 的多可用區佔位 Pod 處於 Pending 後,節點自動伸縮組件感知到的調度策略就從多個可用區的 anti-affinity 變成了可用區的 nodeSelector,從而可以輕鬆處理發出擴容區域的節點的請求。

以下圖兩個可用區爲例,介紹利用現有架構上能滿足多可用區同時擴容的方法。

詳細內容請參考 [4]。

3.1.5 可用區容量受損後的自動恢復

多可用區高可用集羣,當面臨着 AZ 失效時,往往意味着應用容量受損,K8s 會根據應用的副本數或者 HPA(水平 Pod 伸縮)配置進行自動化的擴容。這裏面需要集羣配置 Cluster AutoScaler 或者虛擬節點實現集羣資源的自動擴容。當使用 Cluster AutoScaler 時,可以通過對資源的超額分配進行預留,這樣可以實現容器應用的快速拉起,並且避免因爲底層擴容緩慢或者失敗導致的業務中斷。詳細內容請參考 [5]。

3.2 應用 Pod 按節點反親和(PodAntiAffinity)

Pod 反親和(PodAntiAffinity)是一種 Kubernetes 中的調度策略,用於在調度 Pod 時確保它們不會被調度到同一個節點上。這可以用於實現對 Pod 的節點打散,以提高應用程序的高可用性和故障隔離能力。

通過使用 Pod 反親和策略,您可以配置以下方式來控制 Pod 的節點打散:

1. RequiredDuringSchedulingIgnoredDuringExecution

這是一種強制執行的策略,它要求 Pod 之間的反親和關係在調度時得到滿足。這意味着 Kubernetes 調度器會盡力確保在調度 Pod 時,它們不會被調度到同一個節點上。然而,在調度後,如果節點資源不足或其他原因導致在同一節點上運行這些 Pod 成爲必要,Kubernetes 會忽略這個反親和策略。

2. PreferredDuringSchedulingIgnoredDuringExecution

這是一種偏好性的策略,它建議 Pod 之間保持反親和關係,但不是強制要求。當調度器有多個選擇時,它會盡量避免在同一個節點上調度這些 Pod。然而,如果沒有其他可行的選擇,調度器仍然可以在同一節點上調度這些 Pod。

通過使用 Pod 反親和策略,您可以控制集羣中 Pod 的分佈,避免將它們調度到同一節點上,從而實現節點的打散。這對於需要在不同的節點上運行 Pod 的應用程序非常有用,以提高可用性和故障隔離能力。

以下是一個 Pod 反親和的示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-run-per-node
spec:
  replicas: 3
  selector:
    matchLabels:
      app: app-run-per-node
  template:
    metadata:
      labels:
        app: app-run-per-node
    spec:
      containers:
        - name: app-container
          image: app-image
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: app
                    operator: In
                    values:
                      - app-run-per-node
              topologyKey: "kubernetes.io/hostname"

在上述示例中,對 Pod 進行了反親和設置,要求調度器在調度時確保這些 Pod 不會被調度到同一個節點上。拓撲鍵設置爲 "kubernetes.io/hostname",使得調度器能夠在不同的節點之間進行打散。

請注意,Pod 反親和和節點親和性(Node Affinity)是不同的概念。節點親和性用於指定 Pod 偏好於調度到具有特定標籤的節點上,而 Pod 反親和則用於確保 Pod 不會調度到同一個節點上。結合使用這兩個調度策略可以實現更靈活和具有容錯能力的調度和節點分佈。

基於 TopologySpreadConstraints 也可以實現 Pod 按節點高可用的調度效果,指定 topologyKey: "kubernetes.io/hostname" 相當於每個節點就是一個拓撲域,實現節點之間 skew 的比較。以下是一個拓撲分佈約束的示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app-container
          image: my-app-image
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: "kubernetes.io/hostname"
          whenUnsatisfiable: DoNotSchedule

在上述示例中,創建了一個拓撲分佈約束,其中 maxSkew 設置爲 1,topologyKey 設置爲 "kubernetes.io/hostname",whenUnsatisfiable 設置爲 DoNotSchedule。這意味着在每個節點上最多隻能運行 1 個 Pod 實現強制 Pod 按節點高可用打散。

3.3 應用多副本高可用

在 Kubernetes 中可以基於多種工作負載實現應用多副本高可用,比如 Deployment、Statefulset 以及 OpenKruise 等 CRD 高級資源。以 Deployment 爲例,Deployment 資源是一種用於定義 Pod 副本數量的控制器,它負責確保指定數量的副本一直在運行,並在副本失敗時自動創建新的副本。

3.3.1 應用多活高可用

應用的多活高可用,是應用的多個副本均可以接收流量並獨立處理業務,可以通過 HPA 方式配置副本數根據負載壓力觸發的自動彈性實現對動態流量的自適應,例如 API Server、Nginx Ingress Controller。這種形態的高可用設計,需要考慮多副本的數據一致性和性能等問題。

3.3.2 應用主備高可用

應用的主備高可用,是應用多副本中存在主副本和備副本,最常見的是一主一備,也存在一主多從等更復雜的形態,基於搶鎖等方式來選主,適用於控制器等形態的組件。比如 Etcd,KubeControllerManager,KubeScheduler 都是主備形態的高可用應用。

用戶可以根據自己的業務形態和場景,來設計控制器使用多活或者主備。

3.3.3 PDB 提升應用高可用

爲了進一步提高應用的可用性,在 Kubernetes 中還可以使用 Pod Disruption Budget(PDB)配置。PDB 允許使用者定義一個最小可用副本數,當進行節點維護或故障時,Kubernetes 將確保至少有指定數量的副本保持運行。PDB 可以防止過多的副本同時終止,尤其適合多活副本處理流量型的場景,例如 MessageQueue 產品,從而避免服務中斷。

要使用 PDB,可以在 Deployment 或 StatefulSet 的配置中添加一個 PDB 資源,並指定最小可用副本數。例如,以下是一個使用 PDB 的 Deployment 配置示例:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-with-pdb
spec:
  replicas: 3
  selector:
    matchLabels:
      app: app-with-pdb
  template:
    metadata:
      labels:
        app: app-with-pdb
    spec:
      containers:
        - name: app-container
          image: app-container-image
          ports:
            - containerPort: 80
  ---
  apiVersion: policy/v1beta1
  kind: PodDisruptionBudget
  metadata:
    name: pdb-for-app
  spec:
    minAvailable: 2
    selector:
      matchLabels:
        app: app-with-pdb

在上述示例中,Deployment 配置定義了 3 個副本,PDB 配置指定了至少要保持 2 個副本可用。這意味着,即使在節點維護或故障時,Kubernetes 也會確保至少有 2 個副本一直在運行,提高應用程序在 Kubernetes 集羣中的可用性,並減少可能的服務中斷。

3.4 健康檢測與自愈

在 Kubernetes 中,可以通過配置不同類型的探針來監測和管理容器的狀態和可用性。以下是 Kubernetes 中常用的探針配置和策略:

可以通過在 Pod 或 Deployment 的配置中添加相應的探針和重啓策略來進行配置,例如:


apiVersion: v1
kind: Pod
metadata:
  name: app-with-probe
spec:
  containers:
    - name: app-container
      image: app-image
      livenessProbe:
        httpGet:
          path: /health
          port: 80
        initialDelaySeconds: 10
        periodSeconds: 5
      readinessProbe:
        tcpSocket:
          port: 8080
        initialDelaySeconds: 15
        periodSeconds: 10
      startupProbe:
        exec:
          command:
            - cat
            - /tmp/ready
        initialDelaySeconds: 20
        periodSeconds: 15
      restartPolicy: Always

在上述示例中,配置了一個存活探針(通過 HTTP GET 請求檢測路徑爲 /health 的端口 80)、一個就緒探針(通過 TCP 套接字檢測端口 8080)、一個啓動探針(通過執行命令 cat /tmp/ready 來檢測容器是否啓動完成)和重啓策略爲 Always。根據實際需求,可以根據容器的特性和健康檢查的要求進行適當的配置。

3.5 應用與數據解耦

在 Kubernetes 中,實現應用與數據解耦可以通過使用 Persistent Volumes(PV)和 Persistent Volume Claims(PVC)來實現,也可以選擇合適的後端數據庫服務存儲。

PV 和 PVC 提供了一種抽象層,使應用程序可以獨立於底層存儲技術使用。Persistent Volumes 是集羣中的存儲資源,它們獨立於 Pod 和節點。Persistent Volume Claims 是對 Persistent Volumes 的請求,用於將存儲資源綁定到應用程序的 Pod 中。

要選擇合適的 Persistent Volume Claims 和 Persistent Volumes,需要考慮以下幾個因素:

選擇合適的後端數據服務,如 RDS 等,需要考慮以下因素:

3.6 負載均衡高可用配置

傳統型負載均衡 CLB 已在大部分地域部署了多可用區以實現同地域下的跨機房容災。可以通過 Service Annoation 來指定 SLB/CLB 的主備可用區,主備可用區應該與節點池中 ECS 可用區保持一致,可以減少跨可用區數據轉發,提升網絡訪問性能。


apiVersion: v1
kind: Service
metadata:
  annotations:
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-master-zoneid: "cn-hangzhou-a"
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-slave-zoneid: "cn-hangzhou-b"
  name: nginx
  namespace: default
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: nginx
  type: LoadBalancer

爲了減少跨可用區網絡流量,提升網絡性能。我們可以使用在 Kubernetes 1.23 中引入拓撲感知提示 (Topology Aware Hints) 實現了拓撲感知的就近路由功能。

3.7 雲盤高可用配置

目前阿里云云盤只能在單可用區進行創建和掛載,在多可用區集羣中使用雲盤作爲持久化應用的數據存儲,需要選擇 ACK 提供的拓撲感知的雲盤存儲類型 alicloud-disk-topology [6] 來創建 PersistentVolumeClaim,此存儲類 Volume Binding Mode 默認是 WaitForFirstConsumer 支持延遲綁定直至 PersistentVolumeClaim 被在對應的可用區創建出來。可以創建更精細化的指定多可用區拓撲感知的 ESSD 雲盤存儲類來生成存儲卷,存儲聲明和持久化應用如下示例,更多內容詳見文檔 [7]。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: alicloud-disk-topology-essd
provisioner: diskplugin.csi.alibabacloud.com
parameters:
  type: cloud_essd
  fstype: ext4
  diskTags: "a:b,b:c"
  zoneId: “cn-hangzhou-a,cn-hangzhou-b,cn-hangzhou-c” #指定可用區範圍來生成雲盤
  encrypted: "false"
  performanceLevel: PL1 #指定性能類型
  volumeExpandAutoSnapshot: "forced" #指定擴容編配的自動備份開關,該設置僅在type爲"cloud_essd"時生效。
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
allowVolumeExpansion: true
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: topology-disk-pvc
spec:
  accessModes:
  - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 100Gi
  storageClassName: alicloud-disk-topology-essd
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: "mysql"
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:5.6
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "mysql"
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: topology-disk-pvc

3.8 虛擬節點高可用配置

虛擬節點(Virtual Node)支持 Kubernetes 應用部署在彈性容器實例 ECI 之中,無需進行節點運維,按需創建,降低了預留資源浪費。爲應對突發流量而進行業務的快速水平擴容,或者啓動大量實例進行 Job 任務處理時,可能會遇到可用區對應規格實例庫存不足或者指定的交換機 IP 耗盡等情況,從而導致 ECI 實例創建失敗。使用 ACK Serverless 的多可用區特性可以提高 ECI 實例的創建成功率。

虛擬節點可以通過 ECI Profile 配置跨不同 AZ 的 vSwitch 實現跨多 AZ 應用部署。

根據實際需求修改 kube-system/eci-profile configmap 中的 vswitch 字段,修改後即時生效。

kubectl -n kube-system edit cm eci-profile
apiVersion: v1
data:
  kube-proxy: "true"
  privatezone: "true"
  quota-cpu: "192000"
  quota-memory: 640Ti
  quota-pods: "4000"
  regionId: cn-hangzhou
  resourcegroup: ""
  securitygroupId: sg-xxx
  vpcId: vpc-xxx
  vswitchIds: vsw-xxx,vsw-yyy,vsw-zzz
kind: ConfigMap

相關內容可以參考 [8]。

3.9 監控告警配置

通過 K8s 自身以及 kube-state-metrics 等組件透出的指標,可以有效監控 Pod、Node 等資源高可用性以及可用區分佈情況,這對於快速發現、定位問題有積極重要的意義。在生產環境,監控告警系統是持續建並根據 K8s 版本、組件版本升級而迭代更新的,建議持續關注新指標並根據業務場景引入到監控告警系統中。下面列舉兩個資源高可用的告警配置做參考。

3.9.1 應用負載副本不可用的監控告警

K8s 的 kube-state-metrics 可以聚合分析應用負載 Deployment/Statefulset/Daemonset 的不可用副本數、副本總數等,基於該類指標可以發現應用是否存在不可用副本以及不可用副本佔總副本數的百分比,實現服務部分受影響、全部影響的監控告警。

以 Deployment 爲例,AlertManager/Thanos Ruler 的告警示例如下:


# kube-system或者monitoring中的Deployment存在不可用副本,持續1m,則觸發告警,告警serverity配置爲L1
- alert: SystemPodReplicasUnavailable
  expr: kube_deployment_status_replicas_unavailable{namespace=~"kube-system|monitoring",deployment!~"ack-stub|kubernetes-kdm"} > 0
  labels:
    severity: L1
  annotations:
    summary: "namespace={{$labels.namespace}}, deployment={{$labels.deployment}}: Deployment存在不可用Replica"
  for: 1m
# kube-system或者monitoring中的Deployment副本總數>0,且全部副本不可用,持續1m,則觸發告警,告警serverity配置爲L1
- alert: SystemAllPodReplicasUnavailable
  expr: kube_deployment_status_replicas_unavailable{namespace=~"kube-system|monitoring"} == kube_deployment_status_replicas{namespace=~"kube-system|monitoring"} and kube_deployment_status_replicas{namespace=~"kube-system|monitoring"} > 0
  labels:
    severity: L1
  annotations:
    summary: "namespace={{$labels.namespace}}, deployment={{$labels.deployment}}: Deployment全部Replicas不可用"
  for: 1m
3.9.2 集羣可用區內不健康節點百分比的監控告警

K8s 的 kube-controller-manager 組件有統計可用區內的不健康節點數、健康節點百分比和節點總數,可以配置相關告警。

# HELP node_collector_unhealthy_nodes_in_zone [ALPHA] Gauge measuring number of not Ready Nodes per zones.
# TYPE node_collector_unhealthy_nodes_in_zone gauge
node_collector_unhealthy_nodes_in_zone{zone="cn-shanghai::cn-shanghai-e"} 0
node_collector_unhealthy_nodes_in_zone{zone="cn-shanghai::cn-shanghai-g"} 0
node_collector_unhealthy_nodes_in_zone{zone="cn-shanghai::cn-shanghai-l"} 0
node_collector_unhealthy_nodes_in_zone{zone="cn-shanghai::cn-shanghai-m"} 0
node_collector_unhealthy_nodes_in_zone{zone="cn-shanghai::cn-shanghai-n"} 0
# HELP node_collector_zone_health [ALPHA] Gauge measuring percentage of healthy nodes per zone.
# TYPE node_collector_zone_health gauge
node_collector_zone_health{zone="cn-shanghai::cn-shanghai-e"} 100
node_collector_zone_health{zone="cn-shanghai::cn-shanghai-g"} 100
node_collector_zone_health{zone="cn-shanghai::cn-shanghai-l"} 100
node_collector_zone_health{zone="cn-shanghai::cn-shanghai-m"} 100
node_collector_zone_health{zone="cn-shanghai::cn-shanghai-n"} 100
# HELP node_collector_zone_size [ALPHA] Gauge measuring number of registered Nodes per zones.
# TYPE node_collector_zone_size gauge
node_collector_zone_size{zone="cn-shanghai::cn-shanghai-e"} 21
node_collector_zone_size{zone="cn-shanghai::cn-shanghai-g"} 21
node_collector_zone_size{zone="cn-shanghai::cn-shanghai-l"} 21
node_collector_zone_size{zone="cn-shanghai::cn-shanghai-m"} 21
node_collector_zone_size{zone="cn-shanghai::cn-shanghai-n"} 21

AlertManager/Thanos Ruler 的告警示例如下:

# node_collector_zone_health <= 80 如果可用區內健康節點比例小於80%,就觸發告警。
- alert: HealthyNodePercentagePerZoneLessThan80
  expr: node_collector_zone_health <= 80
  labels:
    severity: L1
  annotations:
    summary: "zone={{$labels.zone}}: 可用區內健康節點與節點總數百分比 <= 80%"
  for: 5m

04 應用的單 / 多集羣高可用架構

基於如上第三章介紹的高可用技術和阿里雲產品能力提供的產品能力,可以全面實現單個集羣範圍內的高可用架構。多集羣高可用架構是在單集羣高可用架構上進步升級的高可用架構,提供了跨集羣 / 地域的高可用服務能力。

通過多地域、多集羣的部署和單元化應用架構,可以在保證高可用性的前提下,克服跨地域網絡傳輸延遲、成本和故障率的挑戰。這樣可以爲用戶提供更好的使用體驗,同時確保業務的穩定性和可靠性。

4.1 單地域多可用區高可用集羣

基於如上第三章介紹的高可用技術和阿里雲產品能力提供的能力,可以實現單個集羣維度內的高可用架構,這裏不再贅述。

4.2 單地域多集羣高可用 + 多地域多集羣高可用

首先每個 ACK 集羣均採用多可用區高可用架構,業務應用採用多可用區部署模式,通過 SLB 對外提供服務。

多地域部署和多可用區部署在本質上是相似的,但由於地域間網絡傳輸延遲、成本和故障率的差異,需要採用不同的部署和應用架構來適應。對於平臺層來說,不建議實現跨地域的 Kubernetes 集羣,而是推薦採用多地域多集羣的方式,並結合單元化應用架構來實現多地域的高可用架構。在不同的地域部署多個獨立的 Kubernetes 集羣,每個集羣管理自己的節點和應用。每個地域的集羣都是獨立的,具有自己的 Master 節點和工作節點。這樣可以降低跨地域的網絡延遲和故障率,提高應用的可用性和性能。

同時,採用單元化應用架構,將應用拆分爲獨立的單元,每個單元在多個地域的集羣中部署副本。通過負載均衡和 DNS 解析技術,可以實現用戶請求的就近路由,將流量分發到最近的地域,減少網絡延遲,並提供高可用性和容災能力。

跨地域 ACK 集羣如果需要網絡互聯,可以通過雲企業網 CEN 實現多地域 VPC 間的互聯互通。地域間業務流量調度通過全局流量關了 GTM 與雲解析服務實現。

如果希望對多地域多集羣進行統一管理,比如可觀測、安全策略,以及實現應用的跨集羣統一交付。我們可以利用 ACK One 進行實現。分佈式雲容器平臺 ACK One(Distributed Cloud Container Platform for Kubernetes)是阿里雲面向混合雲、多集羣、分佈式計算、容災等場景推出的企業級雲原生平臺。ACK One 可以連接並管理用戶在任何地域、任何基礎設施上的 Kubernetes 集羣,並提供一致的管理和社區兼容的 API,支持對計算、網絡、存儲、安全、監控、日誌、作業、應用、流量等進行統一運維管控。如您想要了解更多關於 ACK One 的信息 ,歡迎釘釘搜索羣號:35688562 進羣交流。

ACK One 構建應用系統的兩地三中心容災方案,相關內容可以參考 [9]。

05 鏈接總結

雲原生場景下的應用高可用架構和設計,對於企業服務的可用性、穩定性、安全性至關重要,可以有效提高應用可用性和用戶體驗,提供故障隔離和容錯能力等。本文介紹了雲原生應用高可用架構設計的關鍵原則、K8s 高可用技術以及在 ACK 場景下的使用和實現、單集羣和多集羣高可用架構的使用,希望爲有相關需求的企業提供參考和幫助,ACK 會繼續爲客戶提供安全、穩定、性能、成本持續優化升級的雲原生產品和服務!

本文參考了阿里雲容器服務負責人易立對於 ACK 高可用架構分析的精彩分享,在此表示誠摯感謝!

相關鏈接:

[1] https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/#interaction-with-node-affinity-and-node-selectors

[2] https://kubernetes.io/blog/2020/05/introducing-podtopologyspread/

[3] https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/#known-limitations

[4] https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/configure-auto-scaling-for-cross-zone-deployment

[5] https://help.aliyun.com/document_detail/184995.html

[6] https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/dynamically-provision-a-disk-volume-by-using-the-cli-1#section-dh5-bd8-x0q

[7] https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/use-dynamically-provisioned-disk-volumes

[8] https://help.aliyun.com/zh/ack/serverless-kubernetes/user-guide/create-ecis-across-zones

[9] https://developer.aliyun.com/article/913027

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/qnaRwQmaZx4K2xcSGixaow