全部產品
Search
文件中心

Container Service for Kubernetes:基於ACK One MSE多叢集網關實現同城容災

更新時間:Jan 26, 2025

多叢集網關(Multi-cluster Gateways)是ACK One為多雲、多叢集環境提供的雲原生網關,通過託管MSE Ingress並使用Ingress API以管理七層南北向流量。多叢集網關支援同城自動容災和基於Header的灰階發布,可以幫您簡化多叢集應用的營運和節省成本,結合ACK One GitOps的能力,您可以快速構建同城多活或主備容災系統(不包含資料容災)。

容災概述

目前雲上容災主要分為以下三類:

  • 同城跨AZ容災

    同城容災包含多活容災和主備容災,同城中心之間物理距離較近,網路延遲低,可防範AZ層級性質的災難損害,例如火災、斷網或斷電等。

  • 跨地區多活容災

    跨地區多活容災對於網路延遲相對較高,但可以防範地區性質的災難損害,例如地震、水災等。

  • 兩地三中心

    兩地三中心將同城雙中心和跨地區災備結合起來,兼具兩者的優點,適用於對應用與資料連續性和可用性要求高的情境。

而從實際情況考慮,同城容災相比於跨地區容災,在資料容災方面更容易實現,所以同城容災仍然具有非常重要的意義。

功能優勢

基於多叢集網關的容災方案與基於DNS流量分發的容災方案對比優勢如下:

  • 基於DNS流量分發的容災方案需要多個LB IP(每個叢集1個),而基於多叢集網關的容災方案在地區層級僅需要1個LB IP,且預設提供同地區多可用性區域的高可用性。

  • 基於多叢集網關的容災支援七層路由轉寄能力,而基於DNS流量分發的容災不支援七層路由轉寄。

  • 基於DNS流量分發的容災方案在IP切換時,通常會有用戶端緩衝而造成服務短暫不可用,而基於多叢集網關的容災方案則可以平滑地將流量Fallback到另一個叢集的服務後端。

  • 多叢集網關是地區層級的,所以所有操作都僅需在Fleet執行個體中操作(建立網關、Ingress資源等),無需在每個ACK叢集中都安裝Ingress Controller和建立Ingress資源,提供地區級全域流量管理能力的同時,還能減少多叢集管理成本。

方案架構

ACK One多叢集網關通過託管MSE Ingress來實現,結合ACK One GitOps的應用多叢集分發能力,可以協助您快速實現應用的同城容災系統。本文將通過GitOps部署樣本應用到中國(香港)地區的兩個不同可用性區域的ACK叢集(Cluster 1、Cluster 2)為例,介紹如何?同城多活容災和同城主備容災。

本文樣本應用為Web應用,包含Deployment、Service資源,通過多叢集網關實現同城容災的方案架構如下圖所示。image.png

  • 在ACK One Fleet中通過MseIngressConfig資源來建立MSE網關。

  • 在同一個地區的兩個不同可用性區域AZ 1和AZ 2中,分別建立一個ACK叢集Cluster 1和Cluster 2。

  • 通過ACK One GitOps將應用分發到已建立的Cluster 1和Cluster 2叢集中。

  • 建立多叢集網關後,通過設定流量規則可以實現按權重路由流量、根據Header將流量路由到指定叢集的能力,當其中一個叢集異常時,流量將自動路由到另一個叢集中。

前提條件

步驟一:使用GitOps部署應用到多個叢集

通過ArgoCD UI部署

  1. 登入ACK One控制台,在左側導覽列選擇艦隊 > 多叢集應用

  2. GitOps頁面,單擊GitOps控制台跳轉至GitOps頁面。

    說明
    • ACK One艦隊的Fleet執行個體未開啟GitOps,請先單擊開啟GitOps,才能登入GitOps控制台

    • 如需通過公網訪問GitOps,請開通公網訪問GitOps

  3. 添加應用倉庫。

    1. 在ArgoCD UI左側導覽列選擇Settings,然後選擇Repositories > + Connect Repo

    2. 在彈出的面板中配置以下資訊,然後單擊CONNECT添加串連。

      地區

      參數

      參數值

      Choose your connection method

      VIA HTTPS

      CONNECT REPO USING HTTPS

      Type

      git

      Project

      default

      Repository URL

      https://github.com/AliyunContainerService/gitops-demo.git

      Skip server verification

      勾選

      image.png

      串連添加成功後會顯示Git的CONNECTION STATUSSuccessful。

      image.png

  4. 建立應用。

    在ArgoCD的Applications頁面中,單擊+ NEW APP,進行如下參數配置。

    地區

    參數

    說明

    GENERAL

    Application Name

    自訂應用程式名稱。

    Project Name

    default

    SYNC POLICY

    可根據實際情況選擇同步策略。取值:

    • Manual:當Git端有變更時,需手動執行同步動作將其部署至目的地組群。

    • Automatic:ArgoCD Server每隔3分鐘自動檢測Git端的變更並將其自動部署至目的地組群。

    SYNC OPTIONS

    勾選AUTO-CREATE NAMESPACE

    SOURCE

    Repository URL

    在下拉式清單選擇已有Git Repo,此處選擇上一步已添加的https://github.com/AliyunContainerService/gitops-demo.git

    Revision

    選擇Branches:gateway-demo

    Path

    manifests/helm/web-demo

    DESTINATION

    Cluster URL

    選擇叢集1或叢集2的URL。

    也可以單擊右側的URL,切換為根據CLUSTER NAME欄位選擇。

    Namespace

    本樣本使用gateway-demo。表示應用資源(Service、Deployment)將被建立在此Namespace下。

    Helm

    Parameters

    envCluster值設定為cluster-demo-1cluster-demo-2,用於區分請求由哪個叢集的後端處理。

通過ArgoCD CLI部署

  1. 在ACK One Fleet執行個體中開啟GitOps。具體操作,請參見在ACK One Fleet執行個體中開啟GitOps

  2. 訪問ArgoCD。具體操作,請參見通過ArgoCD CLI方式訪問ArgoCD

  3. 建立並發布應用。

    1. 執行以下命令,添加Git Repo。

      argocd repo add https://github.com/AliyunContainerService/gitops-demo.git --name ackone-gitops-demos

      預期輸出:

      Repository 'https://github.com/AliyunContainerService/gitops-demo.git' added
    2. 執行以下命令,查看已添加的Git Repo列表。

      argocd repo list

      預期輸出:

      TYPE  NAME  REPO                                                       INSECURE  OCI    LFS    CREDS  STATUS      MESSAGE  PROJECT
      git         https://github.com/AliyunContainerService/gitops-demo.git  false     false  false  false  Successful           default
    3. 執行以下命令,查看Clusters列表。

      argocd cluster list

      預期輸出:

      SERVER                          NAME                                        VERSION  STATUS      MESSAGE                                                  PROJECT
      https://1.1.XX.XX:6443      c83f3cbc90a****-temp01   1.22+    Successful
      https://2.2.XX.XX:6443      c83f3cbc90a****-temp02   1.22+    Successful
      https://kubernetes.default.svc  in-cluster                                           Unknown     Cluster has no applications and is not being monitored.
    4. 使用Application方式建立並發布Demo應用到目的地組群。

      1. 使用以下內容,建立apps-web-demo.yaml檔案。

        其中repoURL需替換為您實際的倉庫地址。

        展開查看apps-web-demo.yaml檔案

        apiVersion: argoproj.io/v1alpha1
        kind: Application
        metadata:
          name: app-demo-cluster1
          namespace: argocd
        spec:
          destination:
            namespace: gateway-demo
            # https://1.1.XX.XX:6443
            server: ${cluster1_url}
          project: default
          source:
            helm:
              releaseName: "web-demo"
              parameters:
              - name: envCluster
                value: cluster-demo-1
              valueFiles:
              - values.yaml
            path: manifests/helm/web-demo
            repoURL: https://github.com/AliyunContainerService/gitops-demo.git
            targetRevision: gateway-demo
          syncPolicy:
            syncOptions:
            - CreateNamespace=true
        ---
        apiVersion: argoproj.io/v1alpha1
        kind: Application
        metadata:
          name: app-demo-cluster1
          namespace: argocd
        spec:
          destination:
            namespace: gateway-demo
            server: ${cluster2_url}
          project: default
          source:
            helm:
              releaseName: "web-demo"
              parameters:
              - name: envCluster
                value: cluster-demo-2
              valueFiles:
              - values.yaml
            path: manifests/helm/web-demo
            repoURL: https://github.com/AliyunContainerService/gitops-demo.git
            targetRevision: gateway-demo
          syncPolicy:
            syncOptions:
            - CreateNamespace=true
      2. 執行以下命令,部署應用。

        kubectl apply -f apps-web-demo.yaml
      3. 執行以下命令,查看應用列表。

        argocd app list

        預期輸出:

        # app list
        NAME                      CLUSTER                  NAMESPACE  PROJECT  STATUS  HEALTH   SYNCPOLICY  CONDITIONS  REPO                                                       PATH                     TARGET
        argocd/web-demo-cluster1  https://10.1.XX.XX:6443             default  Synced  Healthy  Auto        <none>      https://github.com/AliyunContainerService/gitops-demo.git  manifests/helm/web-demo  main
        argocd/web-demo-cluster2  https://10.1.XX.XX:6443             default  Synced  Healthy  Auto        <none>      https://github.com/AliyunContainerService/gitops-demo.git  manifests/helm/web-demo  main

步驟二:在Fleet執行個體中通過kubectl建立多叢集網關

通過在ACK One Fleet中建立MseIngressConfig對象來建立一個多叢集網關,並將關聯集群添加至多叢集網關。

  1. 擷取ACK One Fleet執行個體的虛擬交換器ID並記錄。具體操作,請參見擷取交換器ID

  2. 使用以下內容,建立gateway.yaml檔案。

    說明
    • 請將${vsw-id1}${vsw-id2}替換為您上一步擷取的交換器ID,${cluster1}${cluster2}替換為您待添加的關聯集群ID。

    • 子叢集${cluster1}${cluster2}的安全性群組的入方向需要允許該交換器網段的IP和所有連接埠通過。

    apiVersion: mse.alibabacloud.com/v1alpha1
    kind: MseIngressConfig
    metadata:
      annotations:
        mse.alibabacloud.com/remote-clusters: ${cluster1},${cluster2}
      name: ackone-gateway-hongkong
    spec:
      common:
        instance:
          replicas: 3
          spec: 2c4g
        network:
          vSwitches:
          - ${vsw-id}
      ingress:
        local:
          ingressClass: mse
      name: mse-ingress

    參數

    說明

    mse.alibabacloud.com/remote-clusters

    表示待添加到多叢集網關的叢集。此處所填的是已經關聯到Fleet執行個體的叢集ID。

    spec.name

    網關執行個體名稱。

    spec.common.instance.spec

    可選,網關執行個體規格。預設為4c8g

    spec.common.instance.replicas

    可選,網關執行個體副本數。預設為3個。

    spec.ingress.local.ingressClass

    可選,待監聽的ingressClass名稱,表示監聽Fleet執行個體中所有ingressClass欄位設定為mse的Ingress。

  3. 執行以下命令,部署多叢集網關。

    kubectl apply -f gateway.yaml
  4. 執行以下命令,驗證多叢集網關是否建立成功並處於監聽狀態。

    kubectl get mseingressconfig ackone-gateway-hongkong

    預期輸出:

    NAME                      STATUS      AGE
    ackone-gateway-hongkong   Listening   3m15s

    預期輸出中網關狀態為Listening,表明雲原生網關建立成功處於運行狀態,並自動監聽叢集中IngressClass為mse的Ingress資源。

    通過MseIngressConfig建立的多叢集網關會按照Pending、Running、Listening的狀態依次變化。各狀態說明如下:

    • Pending:表明雲原生網關正在建立中,需等待3分鐘左右。

    • Running:表明雲原生網關建立成功,並處於運行狀態。

    • Listening:表明雲原生網關處於運行狀態,並監聽叢集中Ingress資源。

    • Failed:表明雲原生網關處於非法狀態,可以查看Status欄位中的Message來進一步明確原因。

  5. 執行以下命令,確認關聯集群是否添加成功。

    kubectl get mseingressconfig ackone-gateway-hongkong -ojsonpath="{.status.remoteClusters}"

    預期輸出:

    [{"clusterId":"c7fb82****"},{"clusterId":"cd3007****"}]

    預期輸出中已包含指定的Cluster ID,並且無Failed資訊,表明關聯集群已成功添加至多叢集網關。

步驟三:使用Ingress實現同城容災

多叢集網關通過Ingress對多叢集流量進行管理,您可以在ACK One Fleet執行個體中建立Ingress對象來實現同城多活容災和同城主備容災。

重要

確認您已經在Fleet執行個體中建立Namespacegateway-demo,此處建立的Ingress需要和上一步部署的Demo應用中Service的Namespace保持一致為gateway-demo

同城多活容災

建立Ingress實現同城多活容災

在ACK One Fleet執行個體中建立以下Ingress對象,可以實現同城多活容災。

預設將流量負載平衡到已添加到多叢集網關的兩個叢集的同名服務後端的每個副本中,如果其中的Cluster 1後端異常,網關自動將流量全都路由到Cluster 2。Cluster 1和Cluster 2的副本數比為9:1,所以預設90%流量被路由到Cluster 1, 10%流量被路由到Cluster 2,在Cluster 1後端全部異常後,100%流量自動被路由到Cluster 2。拓撲如下所示:image.png

  1. 使用以下內容,建立ingress-demo.yaml檔案。

    以下代碼中,通過網域名稱example.com下的/svc1路由規則暴露後端服務service1

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: web-demo
    spec:
      ingressClassName: mse
      rules:
      - host: example.com
        http:
          paths:
          - path: /svc1
            pathType: Exact
            backend:
              service:
                name: service1
                port: 
                  number: 80
  2. 執行以下命令,在ACK One Fleet執行個體中部署Ingress。

    kubectl apply -f ingress-demo.yaml -n gateway-demo

實現灰階發布驗證

在多活容災情境下,不影響業務的前提下,您可以通過以下方式對應用進行灰階發布驗證。

在已有叢集中建立應用,僅將Service和Deployment的nameselector與原應用進行區分,之後基於Header在建立的應用上進行驗證。

  1. 使用以下內容,在Cluster 1中建立new-app.yaml檔案。僅Service和Deployment與原應用有差異,其他均一致。

    apiVersion: v1       
    kind: Service
    metadata:
      name: service1-canary-1
      namespace: gateway-demo
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        app: web-demo-canary-1
      sessionAffinity: None
      type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: web-demo-canary-1
      namespace: gateway-demo
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: web-demo-canary-1
      template:
        metadata:
          labels:
            app: web-demo-canary-1
        spec:
          containers:
            - env:
                - name: ENV_NAME
                  value: cluster-demo-1-canary
              image: 'registry-cn-hangzhou.ack.aliyuncs.com/acs/web-demo:0.6.0'
              imagePullPolicy: Always
              name: web-demo
  2. 執行以下命令,在Cluster 1中部署新的應用。

    kubectl apply -f new-app.yaml
  3. 使用以下內容,建立new-ingress.yaml檔案。

    在Fleet執行個體中建立基於Header的Ingress。通過添加Annotations開啟Canary,並指定Header,在請求中使用Header: canary-dest: cluster1來將流量路由到灰階版本進行驗證。

    • nginx.ingress.kubernetes.io/canary:設定為"true",表示開啟灰階發布能力。

    • nginx.ingress.kubernetes.io/canary-by-header:請求到該叢集的header key。

    • nginx.ingress.kubernetes.io/canary-by-header-value:請求到該叢集的header value。

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: web-demo-canary-1
        namespace: gateway-demo
        annotations:
          nginx.ingress.kubernetes.io/canary: "true"
          nginx.ingress.kubernetes.io/canary-by-header: "canary-dest"
          nginx.ingress.kubernetes.io/canary-by-header-value: "cluster1"
      spec:
        ingressClassName: mse
        rules:
        - host: example.com
          http:
            paths:
            - path: /svc1
              pathType: Exact
              backend:
                service:
                  name: service1-canary-1
                  port: 
                    number: 80
  4. 執行以下命令,在Fleet執行個體中部署基於Header的Ingress。

    kubectl apply -f new-ingress.yaml

驗證同城多活容災實現效果

修改部署到Cluster 1的副本數為9,Cluster 2的副本數為1,即期望預設流量按照9:1路由到Cluster 1和Cluster 2,並且在Cluster1異常後,自動將所有流量路由到Cluster 2。

執行以下命令,擷取多叢集網關的對外IP。

kubectl get ingress web-demo -n gateway-demo -ojsonpath="{.status.loadBalancer}"
  • 預設流量按比例路由到兩個叢集

    執行以下命令,查看流量的路由情況。

    替換以下XX.XX.XX.XX為上一步擷取的多叢集網關的對外IP。

    for i in {1..100}; do curl -H "host: example.com" XX.XX.XX.XX done

    預期輸出:image.png預期輸出表明,流量被負載平衡到了Cluster 1和Cluster 2,到Cluster 1和Cluster 2的流量比為9:1。

  • Cluster 1異常後流量全部容災到Cluster 2

    如果將Cluster 1的Deployment的replica縮為0時,得到的輸出結果如下,表明流量已被自動容災到Cluster 2。image.png

  • 通過Header將請求路由到灰階版本

    執行以下命令,查看流量的路由情況。

    替換以下XX.XX.XX.XX實現灰階發布驗證中的應用和Ingress部署完成後查詢到的IP。

    for i in {1..100}; do curl -H "host: example.com" -H "canary-dest: cluster1" xx.xx.xx.xx/svc1; sleep 1;  done  

    預期輸出:image.png預期輸出表明,添加了header:canary-dest: cluster1的請求都被路由到了Cluster 1中的灰階版本。

同城主備容災

在ACK One Fleet執行個體中建立以下Ingress對象,可以實現同城主備容災。

當兩個叢集後端都正常時,流量僅路由到Cluster 1的服務後端;如果其中一個Cluster 1後端異常,網關會自動將流量路由到Cluster 2。拓撲如下所示:image.png

建立Ingress實現同城主備容災

  1. 使用以下內容,建立ingress-demo-cluster-one.yaml檔案。

    以下Ingress對象的YAML檔案中,通過添加兩個Annotations mse.ingress.kubernetes.io/service-subsetmse.ingress.kubernetes.io/subset-labels以實現網域名稱example.com下的/service1路由規則暴露後端服務service1。關於MSE Ingress支援的Annotations詳情,請參見MSE Ingress支援的Annotation

    • mse.ingress.kubernetes.io/service-subset:服務的子版本名稱。建議定義為與目的地組群相關且可讀性強的值。

    • mse.ingress.kubernetes.io/subset-labels:指定目的地組群的ID。

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        annotations:
          mse.ingress.kubernetes.io/service-subset: cluster-demo-1
          mse.ingress.kubernetes.io/subset-labels: |
            topology.istio.io/cluster ${cluster1-id}
        name: web-demo-cluster-one
      spec:
        ingressClassName: mse
        rules:
        - host: example.com
          http:
            paths:
            - path: /service1
              pathType: Exact
              backend:
                service:
                  name: service1
                  port: 
                    number: 80
  2. 執行以下命令,在ACK One Fleet執行個體中部署Ingress。

    kubectl apply -f ingress-demo-cluster-one.yaml -ngateway-demo

實現叢集層級灰階發布

多叢集網關支援建立基於Header的Ingress以實現將請求路由到指定叢集,基於該能力與建立Ingress實現同城主備容災中Ingress對象實現的全副本負載平衡的能力,可以實現基於Header的灰階發布。

  1. 建立Ingress實現同城主備容災中的Ingress。

  2. 在ACK One Fleet執行個體中建立包含Header相關Annotation的Ingress,實現叢集層級的灰階發布。請求的Header與Ingress中的配置相匹配時,請求將被路由到灰階版本的後端。

    1. 使用以下內容,建立ingress-demo-cluster-gray.yaml檔案。

      以下Ingress對象的YAML檔案中,替換YAML中的${cluster1-id}為目的地組群ID。除了mse.ingress.kubernetes.io/service-subsetmse.ingress.kubernetes.io/subset-labels兩個Annotation之外,您還需要添加以下Annotation以實現網域名稱example.com下的/service1路由規則暴露後端服務service1

      • nginx.ingress.kubernetes.io/canary:設定為"true",表示開啟灰階發布能力。

      • nginx.ingress.kubernetes.io/canary-by-header:表示請求到該叢集的header key。

      • nginx.ingress.kubernetes.io/canary-by-header-value:表示請求到該叢集的header value。

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        annotations:
          mse.ingress.kubernetes.io/service-subset: cluster-demo-2
          mse.ingress.kubernetes.io/subset-labels: |
            topology.istio.io/cluster ${cluster2-id}
          nginx.ingress.kubernetes.io/canary: "true"
          nginx.ingress.kubernetes.io/canary-by-header: "app-web-demo-version"
          nginx.ingress.kubernetes.io/canary-by-header-value: "gray"
        name: web-demo-cluster-gray
        name: web-demo
      spec:
        ingressClassName: mse
        rules:
        - host: example.com
          http:
            paths:
            - path: /service1
              pathType: Exact
              backend:
                service:
                  name: service1
                  port: 
                    number: 80
    2. 執行以下命令,在ACK One Fleet執行個體中部署Ingress。

      kubectl apply -f ingress-demo-cluster-gray.yaml -n gateway-demo

驗證同城主備容災實現效果

為便於驗證,修改部署到Cluster 1和Cluster 2的副本數都為1,期望預設流量只被路由到Cluster 1,加灰階Header的流量被路由到Cluster 2,當Cluster 1應用異常後,預設流量也被路由到Cluster 2。

執行以下命令,擷取多叢集網關的對外IP。

kubectl get ingress web-demo -n gateway-demo -ojsonpath="{.status.loadBalancer}"
  • 預設流量路由到Cluster 1

    執行以下命令,查看預設流量是否被路由到Cluster 1。

    替換以下XX.XX.XX.XX為上一步擷取的多叢集網關的對外IP。

    for i in {1..100}; do curl -H "host: example.com" xx.xx.xx.xx/service1; sleep 1;  done

    預期輸出:image.png預期輸出表明,預設流量全都被路由到Cluster 1了。

  • 通過header將請求路由到灰階版本

    執行以下命令,查看Header的請求是否被路由到灰階版本。

    替換以下XX.XX.XX.XX為上一步擷取的多叢集網關的對外IP。

    for i in {1..50}; do curl -H "host: example.com" -H "app-web-demo-version: gray" xx.xx.xx.xx/service1; sleep 1;  done

    預期輸出:image.png預期輸出表明,添加了Header:app-web-demo-version: gray的請求都被路由到了Cluster 2(灰階版本)。

  • Cluster 1異常後流量被容災到Cluster 2

    如果將Cluster 1的Deployment的replica縮為0時,得到的輸出結果如下,表明流量已被自動容災到Cluster 2。image.png

相關文檔