构建同城容灾系统

通过ACK One ALB多集群网关,结合ACK One GitOps或多集群应用分发,可以快速实现应用的同城多活容灾,保证应用高可用,并在故障发生时自动平滑迁移。本文介绍如何通过多集群网关构建同城容灾系统。

容灾概述

目前云上容灾主要分为以下三类:

  • 同城跨AZ容灾:同城容灾包含同城多活容灾和同城主备容灾2种策略,同城中心之间物理距离较近,网络延迟低,可防范AZ级别性质的灾难损害,例如火灾、断网或断电等。此方案在实现数据备份和快速恢复方面相对简单,仍具备较强的实用意义。

  • 跨地域多活容灾:跨地域多活容灾对于网络延迟相对较高,但可以防范地域性质的灾难损害,例如地震、水灾等。

  • 两地三中心:两地三中心将同城双中心和跨地域灾备结合起来,兼具两者的优点,适用于应用与数据连续性和可用性要求高的场景。

从业务架构上来说,企业的业务系统自上而下通常分为接入层、应用层和数据层。

  • 接入层:流量入口,负责接收流量,根据路由转发规则将流量转发到后端应用层。

  • 应用层:应用服务,根据请求对数据进行处理,并返回给上游。

  • 数据层:数据存储服务,为应用层提供数据和存储数据。

为了实现整个业务容灾,需对上述每一层实施相应的容灾处理措施。

  • 接入层:ACK One多集群网关作为接入层,其自身支持同城跨AZ高可用。

  • 应用层:ACK One多集群网关处理应用层容灾,可实现应用的同城多活/主备容灾、跨地域容灾。

  • 数据层:数据层容灾和数据同步,需要依赖于中间件自身。

功能优势

基于ACK One多集群网关的容灾方案与基于DNS流量分发的容灾方案对比优势如下:

  • 基于DNS流量分发的容灾方案需要多个LB IP(每个集群1个),而基于多集群网关的容灾方案在地域级别仅需要1个LB IP,且默认提供同地域多可用区的高可用性。

  • 基于多集群网关的容灾支持七层路由转发能力,而基于DNS流量分发的容灾不支持七层路由转发。

  • 基于DNS流量分发的容灾方案在IP切换时,通常会因客户端缓存造成服务短暂不可用,而基于多集群网关的容灾方案则可以更平滑地将流量Fallback到另一个集群的服务后端。

  • 多集群网关是地域级别的,所有操作都仅需在Fleet实例中进行,无需在每个ACK集群中安装Ingress Controller和创建Ingress资源。它提供地域级全局流量管理能力的同时,还能减少多集群管理成本。

方案架构

本文以Web应用为示例,展示了通过ALB多集群网关实现同城容灾的方案架构,包括Deployment和Service资源,具体结构如下图所示。

image
  • 在同一个地域两个不同可用区AZ 1和AZ 2中,分别创建一个ACK集群Cluster 1和Cluster 2。

  • 通过ACK One GitOps将应用分发到已创建的Cluster 1和Cluster 2集群中。

  • ACK One Fleet实例中通过AlbConfig资源来创建ALB多集群网关。

  • 创建ALB多集群网关后,通过创建Ingress来实现按权重路由流量、根据Header将流量路由到指定集群的能力,当其中一个集群异常时,流量将自动路由到另一个集群中。

  • RDS数据同步需要依赖中间件自身能力。

前提条件

步骤一:使用GitOps或应用分发部署应用到多个集群

ACK One支持多集群GitOps和多集群应用资源分发两种方式,方便您将应用部署到多个集群。请参见GitOps快速入门创建多集群应用应用分发快速入门。本步骤以GitOps的多集群应用分发为例。

  1. 登录ACK One控制台,在左侧导航栏选择舰队 > 多集群应用

  2. 多集群应用页面左上角,单击舰队名称后的Dingtalk_20231226104633.jpg按钮,在下拉列表中选择目标舰队。

  3. 单击创建多集群应用 > GitOps进入创建多集群应用 - GitOps页面。

    说明
  4. YAML创建页签,将以下YAML内容复制到控制台,然后点击确定进行创建和部署应用。

    说明

    以下YAML内容是将web-demo部署到所有关联集群中,您也可以通过快捷创建选择集群,变化会同步到YAML创建的内容。

    apiVersion: argoproj.io/v1alpha1
    kind: ApplicationSet
    metadata:
      name: appset-web-demo
      namespace: argocd
    spec:
      template:
        metadata:
          name: '{{.metadata.annotations.cluster_id}}-web-demo'
          namespace: argocd
        spec:
          destination:
            name: '{{.name}}'
            namespace: gateway-demo
          project: default
          source:
            repoURL: https://github.com/AliyunContainerService/gitops-demo.git
            path: manifests/helm/web-demo
            targetRevision: main
            helm:
              valueFiles:
                - values.yaml
              parameters:
                - name: envCluster
                  value: '{{.metadata.annotations.cluster_name}}'
          syncPolicy:
            automated: {}
            syncOptions:
              - CreateNamespace=true
      generators:
        - clusters:
            selector:
              matchExpressions:
                - values:
                    - cluster
                  key: argocd.argoproj.io/secret-type
                  operator: In
                - values:
                    - in-cluster
                  key: name
                  operator: NotIn
      goTemplateOptions:
        - missingkey=error
      syncPolicy:
        preserveResourcesOnDeletion: false
      goTemplate: true

步骤二:在舰队中通过kubectl创建ALB多集群网关

通过在ACK One Fleet实例中创建AlbConfig对象来创建一个ACK One ALB多集群网关,并为ALB多集群网关添加关联集群。

  1. 从ACK One舰队所在VPC,获取两个虚拟交换机ID。

  2. 使用以下内容,创建gateway.yaml文件。

    说明
    • 请将${vsw-id1}${vsw-id2}替换为您上一步获取的交换机ID,${cluster1}${cluster2}替换为您待添加的关联集群ID。

    • 子集群${cluster1}${cluster2}的安全组的入方向需要允许该交换机网段的IP和所有端口通过。

    apiVersion: alibabacloud.com/v1
    kind: AlbConfig
    metadata:
      name: ackone-gateway-demo
      annotations:
        # 添加要处理流量的关联集群到ALB多集群实例。
        alb.ingress.kubernetes.io/remote-clusters: ${cluster1},${cluster2}
    spec:
      config:
        name: one-alb-demo
        addressType: Internet
        addressAllocatedMode: Fixed
        zoneMappings:
        - vSwitchId: ${vsw-id1}
        - vSwitchId: ${vsw-id2}
      listeners:
      - port: 8001
        protocol: HTTP
    ---
    apiVersion: networking.k8s.io/v1
    kind: IngressClass
    metadata:
      name: alb
    spec:
      controller: ingress.k8s.alibabacloud/alb
      parameters:
        apiGroup: alibabacloud.com
        kind: AlbConfig
        name: ackone-gateway-demo

    需要同步的参数及其说明如下表所示:

    参数

    是否必填

    说明

    metadata.name

    AlbConfig的名称。

    metadata.annotations:

    alb.ingress.kubernetes.io/remote-clusters

    表示待添加到ALB多集群网关的关联集群列表。此处所填的是已经关联到舰队实例的集群ID。

    spec.config.name

    ALB实例的名称。

    spec.config.addressType

    ALB实例的网络类型。取值如下:

    • Internet(默认值):公网类型。面向公网提供应用型负载均衡服务,公网可访问。

      说明

      应用型负载均衡通过绑定弹性公网IP进行公网服务,使用公网类型ALB实例将收取弹性公网IP的实例费与带宽、流量费用,详情参见按量付费

      Intranet:私网类型。面向VPC内部提供应用型负载均衡服务,公网不可访问。

    spec.config.zoneMappings

    设置ALB交换机ID。创建交换机具体操作请参见创建和管理交换机

    说明
    • 指定的交换机必须在ALB当前所支持的可用区内,且与集群处于同一VPC。关于ALB支持的地域与可用区,请参见ALB支持的地域与可用区

    • 应用型负载均衡支持多可用区部署,若当前地域支持2个及以上可用区,为保障业务高可用,请至少选择2个或以上不同可用区的交换机。

    spec.listeners

    配置ALB的监听端口和协议。本文配置示例为端口8001的HTTP监听。

    监听定义了流量进入负载均衡的方式和规则,此处建议保留该配置,否则您需要另行创建监听才可使用ALB Ingress。

  3. 执行以下命令,部署gateway.yaml,创建ALB多集群网关和IngressClass。

    kubectl apply -f gateway.yaml
  4. 执行以下命令,查看ALB多集群网关是否创建成功(1~3min)。

    kubectl get albconfig ackone-gateway-demo

    预期输出如下:

    NAME      		      ALBID      DNSNAME                               PORT&PROTOCOL   CERTID   AGE
    ackone-gateway-demo           alb-xxxx   alb-xxxx.<regionid>.alb.aliyuncs.com                           4d9h
  5. 确认关联集群是否添加成功,执行以下命令查看状态。

    kubectl get albconfig ackone-gateway-demo -ojsonpath='{.status.loadBalancer.subClusters}'

    预期输出为集群ID列表。

步骤三:使用Ingress实现同城容灾

多集群网关通过Ingress对多集群流量进行管理,您可以在ACK One Fleet实例中创建Ingress对象来实现同城多活容灾。

  1. 在舰队实例中创建Service所在的Namespace,本示例为gateway-demo

  2. 使用以下内容,创建ingress-demo.yaml文件。

    说明
    • 多个alb.ingress.kubernetes.io/cluster-weight注解权重总和必须等于100。

    • 通过域名example.com下的/svc1路由规则暴露后端服务service1。请先替换${cluster1-id}${cluster2-id}

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        alb.ingress.kubernetes.io/listen-ports: |
         [{"HTTP": 8001}]
        alb.ingress.kubernetes.io/cluster-weight.${cluster1-id}: "20"
        alb.ingress.kubernetes.io/cluster-weight.${cluster2-id}: "80"
      name: web-demo
      namespace: gateway-demo
    spec:
      ingressClassName: alb
      rules:
      - host: alb.ingress.alibaba.com
        http:
          paths:
          - path: /svc1
            pathType: Prefix
            backend:
              service:
                name: service1
                port:
                  number: 80
  3. 执行以下命令,在ACK One舰队中部署Ingress。

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

步骤四:验证同城多活容灾效果

流量按设置比例路由到各集群处理

访问服务的格式如下:

curl -H "host: alb.ingress.alibaba.com" alb-xxxx.<regionid>.alb.aliyuncs.com:<listeners port>/svc1

需要同步的参数及其说明如下表所示:

参数

说明

alb-xxxx.<regionid>.alb.aliyuncs.com

步骤二中获取的AlbConfig的DNSNAME

<listeners port>

AlbConfig中定义及Ingress中annotations声明的8001。

执行以下命令后,从结果可以看出,请求按照20:80的比例发送到集群1(poc-ack-1)和集群2(poc-ack-2)处理。

for i in {1..500}; do curl -H "host: alb.ingress.alibaba.com" alb-xxxx.cn-beijing.alb.aliyuncs.com:8001/svc1; done > res.txt

image

某个集群应用异常时流量自动平滑迁移

执行以下命令后,我们手动将集群2的应用副本数设置为0,此时流量自动平滑迁移至集群1。

for i in {1..500}; do curl -H "host: alb.ingress.alibaba.com" alb-xxxx.cn-beijing.alb.aliyuncs.com:8001/svc1; sleep 1; done

image