基于多集群实现跨地域容灾和流量负载均衡

服务网格ASM为应用服务提供了跨地域流量分布和跨地域故障转移能力。跨地域流量分布功能可以将流量按照设定的权重路由至多个集群,实现多地域负载均衡。跨地域故障转移功能可以在某地域服务发生故障时,将该地域流量转移至其他地域,实现跨地域容灾。以Bookinfo应用为例,本文介绍如何使用跨地域故障转移和流量分布能力实现跨地域容灾和流量负载均衡。

网络规划

在进行操作前,您需要对vSwitch、VPC和集群的网段、名称等信息进行规划,本文规划如下:

说明

关于数据平面多集群地址规划的详细介绍,请参见多集群网络规划

  • vSwich和VPC的网络规划

    • vSwitch网络规划

      重要

      为了避免使用CEN打通VPC网络后产生路由冲突,两个vSwitch不能使用相同的网段。

      对象

      vSwitch名称

      VPC

      IPv4网段

      集群

      vpc-hangzhou-switch-1

      vpc-hangzhou

      20.0.0.0/16

      vpc-shanghai-switch-1

      vpc-shanghai

      21.0.0.0/16

      服务网格

      vpc-hangzhou-switch-2

      vpc-hangzhou2

      192.168.0.0/24

    • VPC网络规划

      对象

      VPC名称

      Region

      IPv4网段

      集群

      vpc-hangzhou

      cn-hangzhou

      20.0.0.0/8

      vpc-shanghai

      cn-shanghai

      21.0.0.0/8

      服务网格

      vpc-hangzhou2

      cn-hangzhou

      192.168.0.0/16

  • 集群的Pod和Service网络规划

    集群名称

    Region

    VPC

    Pod CIDR

    Service CIDR

    ack-hangzhou

    cn-hangzhou

    vpc-hangzhou

    10.0.0.0/16

    172.16.0.0/16

    ack-shanghai

    cn-shanghai

    vpc-shanghai

    10.1.0.0/16

    172.17.0.0/16

步骤一:创建不同地域的集群

  1. 按照以上规划创建2个杭州和上海地域的vSwitch,然后使用vSwitch创建VPC。具体操作,请参见创建交换机创建专有网络和交换机

  2. 使用上文创建的VPC和网络规划创建杭州和上海地域的集群。具体操作,请参见创建ACK托管集群

  3. 根据以上规划创建1个杭州地域的ASM实例。具体操作,请参见创建ASM实例

步骤二:使用CEN实现跨地域VPC网络互通

使用CEN打通集群之间的VPC网络,以及集群和服务网格之间的VPC网络。

  1. 登录云企业网控制台,创建CEN实例。具体操作,请参见创建云企业网实例

  2. 创建转发路由器。

    1. 云企业网实例页面,单击步骤1创建的云企业网实例名称,然后在基本信息页签下方,单击创建转发路由器

    2. 创建转发路由器对话框,选择地域,输入名称,然后单击确认

    本示例配置了两个转发路由器:

    • 地域华东2(上海)名称shanghai-router

    • 地域华东1(杭州)名称hangzhou-router

  3. 将VPC添加到转发路由器,为上海和杭州两个转发路由器重复下列步骤,将VPC连接到转发路由器。

    1. 云企业网实例页面,单击步骤1创建的云企业网实例名称,然后在基本信息页签下方,单击刚创建的转发路由器ID,进入转发路由器页面。

    2. 单击地域内连接管理页签,然后单击创建网络实例连接实例类型选择专有网络(VPC)网络实例选择Region对应的VPC实例。

    3. 其他选项保持默认,单击确定创建

  4. 设置跨地域带宽。

    1. 单击步骤2创建的转发路由器名称,在页面右侧,单击创建网络实例连接

    2. 连接网络实例对话框,配置相关信息,然后单击确认创建

      下图为杭州到上海的示例。地域表示当前地域对端地域表示目标地域。关于配置项的说明,请参见跨地域连接2023-09-27_15-11-25.png

      创建完成后,您可以在跨地域连接管理页签,看到新创建的实例。

  5. 添加安全组规则。

    本文以Flannel网络插件为例,在两个集群的安全组内添加对方集群的Pod网络CIDR,允许对方集群的Pod网段地址的入向通信。

    说明

    Terway网络插件请使用集群vSwitch的CIDR。您可以登录专有网络管理控制台,在交换机页面的IPv4网段列,获取vSwitch的CIDR。

    1. 登录容器服务管理控制台,在左侧导航栏选择集群

    2. 集群列表页面,单击ack-shanghai集群名称,然后在集群信息页面的基本信息页签,查看ack-shanghai集群的Pod网络CIDR。

    3. 集群列表页面单击ack-hangzhou集群右侧操作列下的详情

    4. 集群信息页面单击基本信息页签,然后单击控制面安全组右侧的安全组ID。

    5. 安全组详情页签入方向下单击手动添加

    6. 设置协议类型全部为ack-shanghai集群的Pod网络CIDR,其他为默认值,然后单击操作列下的保存

    7. 重复执行以上步骤,查看ack-hangzhou集群的Pod网络CIDR,然后在ack-shanghai集群的安全组中,添加ack-hangzhou集群的Pod网络CIDR。

    8. 登录任意hangzhou集群的ECS, 使用ping命令测试与shanghai集群中的ECS是否连通。

步骤三:添加集群到ASM实例并创建托管式的入口网关

  1. 将杭州地域和上海地域的两个集群添加到ASM实例。具体操作,请参见添加集群到ASM实例

  2. 使用以下YAML,创建一个托管式的入口网关。具体操作,请参见创建入口网关

    展开查看托管式的入口网关YAML

    apiVersion: istio.alibabacloud.com/v1beta1
    kind: IstioGateway
    metadata:
      annotations:
        asm.alibabacloud.com/managed-by-asm: 'true'
      name: ingressgateway
      namespace: istio-system
    spec:
      gatewayType: ingress
      dnsPolicy: ClusterFirst
      externalTrafficPolicy: Local
      hostNetwork: false
      ports:
      - name: http
        port: 80
        protocol: TCP
        targetPort: 80
      - name: https
        port: 443
        protocol: TCP
        targetPort: 443
      replicaCount: 1
      resources:
        limits:
          cpu: '2'
          memory: 2G
        requests:
          cpu: 200m
          memory: 256Mi
      rollingMaxSurge: 100%
      rollingMaxUnavailable: 25%
      runAsRoot: true
      serviceType: LoadBalancer

步骤四:部署演示应用Bookinfo

  1. 在ack-hangzhou集群部署Bookinfo应用。

    1. 使用kubectl连接到ack-hangzhou集群。具体操作,请参见获取集群KubeConfig并通过kubectl工具连接集群

    2. 使用以下内容,创建ack-hangzhou-k8s.yaml

      展开查看ack-hangzhou-k8s.yaml

      # Details service
      apiVersion: v1
      kind: Service
      metadata:
        name: details
        labels:
          app: details
          service: details
      spec:
        ports:
        - port: 9080
          name: http
        selector:
          app: details
      ---
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: bookinfo-details
        labels:
          account: details
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: details-v1
        labels:
          app: details
          version: v1
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: details
            version: v1
        template:
          metadata:
            labels:
              app: details
              version: v1
          spec:
            serviceAccountName: bookinfo-details
            containers:
            - name: details
              image: docker.io/istio/examples-bookinfo-details-v1:1.16.2
              imagePullPolicy: IfNotPresent
              ports:
              - containerPort: 9080
              securityContext:
                runAsUser: 1000
      ---
      # Ratings service
      apiVersion: v1
      kind: Service
      metadata:
        name: ratings
        labels:
          app: ratings
          service: ratings
      spec:
        ports:
        - port: 9080
          name: http
        selector:
          app: ratings
      ---
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: bookinfo-ratings
        labels:
          account: ratings
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: ratings-v1
        labels:
          app: ratings
          version: v1
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: ratings
            version: v1
        template:
          metadata:
            labels:
              app: ratings
              version: v1
          spec:
            serviceAccountName: bookinfo-ratings
            containers:
            - name: ratings
              image: docker.io/istio/examples-bookinfo-ratings-v1:1.16.2
              imagePullPolicy: IfNotPresent
              ports:
              - containerPort: 9080
              securityContext:
                runAsUser: 1000
      ---
      # Reviews service
      apiVersion: v1
      kind: Service
      metadata:
        name: reviews
        labels:
          app: reviews
          service: reviews
      spec:
        ports:
        - port: 9080
          name: http
        selector:
          app: reviews
      ---
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: bookinfo-reviews
        labels:
          account: reviews
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: reviews-v1
        labels:
          app: reviews
          version: v1
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: reviews
            version: v1
        template:
          metadata:
            labels:
              app: reviews
              version: v1
          spec:
            serviceAccountName: bookinfo-reviews
            containers:
            - name: reviews
              image: docker.io/istio/examples-bookinfo-reviews-v1:1.16.2
              imagePullPolicy: IfNotPresent
              env:
              - name: LOG_DIR
                value: "/tmp/logs"
              ports:
              - containerPort: 9080
              volumeMounts:
              - name: tmp
                mountPath: /tmp
              - name: wlp-output
                mountPath: /opt/ibm/wlp/output
              securityContext:
                runAsUser: 1000
            volumes:
            - name: wlp-output
              emptyDir: {}
            - name: tmp
              emptyDir: {}
      ---
      # Productpage services
      apiVersion: v1
      kind: Service
      metadata:
        name: productpage
        labels:
          app: productpage
          service: productpage
      spec:
        ports:
        - port: 9080
          name: http
        selector:
          app: productpage
      ---
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: bookinfo-productpage
        labels:
          account: productpage
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: productpage-v1
        labels:
          app: productpage
          version: v1
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: productpage
            version: v1
        template:
          metadata:
            labels:
              app: productpage
              version: v1
          spec:
            serviceAccountName: bookinfo-productpage
            containers:
            - name: productpage
              image: docker.io/istio/examples-bookinfo-productpage-v1:1.16.2
              imagePullPolicy: IfNotPresent
              ports:
              - containerPort: 9080
              volumeMounts:
              - name: tmp
                mountPath: /tmp
              securityContext:
                runAsUser: 1000
            volumes:
            - name: tmp
              emptyDir: {}
      ---
      
    3. 执行以下命令,在ack-hangzhou集群部署Bookinfo应用。

      kubectl apply -f ack-hangzhou-k8s.yaml
  2. 在ack-shanghai集群部署Bookinfo应用。

    1. 使用kubectl连接到ack-shanghai集群。具体操作,请参见获取集群KubeConfig并通过kubectl工具连接集群

      说明

      使用kubectl连接到ack-shanghai集群时,您需要将ack-hangzhou集群的kubeconfig切换成ack-shanghai集群的kubeconfig。

    2. 使用以下内容,创建ack-shanghai.yaml

      展开查看ack-shanghai.yaml

      # Details service
      apiVersion: v1
      kind: Service
      metadata:
        name: details
        labels:
          app: details
          service: details
      spec:
        ports:
        - port: 9080
          name: http
        selector:
          app: details
      ---
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: bookinfo-details
        labels:
          account: details
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: details-v1
        labels:
          app: details
          version: v1
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: details
            version: v1
        template:
          metadata:
            labels:
              app: details
              version: v1
          spec:
            serviceAccountName: bookinfo-details
            containers:
            - name: details
              image: docker.io/istio/examples-bookinfo-details-v1:1.16.2
              imagePullPolicy: IfNotPresent
              ports:
              - containerPort: 9080
              securityContext:
                runAsUser: 1000
      ---
      # Ratings service
      apiVersion: v1
      kind: Service
      metadata:
        name: ratings
        labels:
          app: ratings
          service: ratings
      spec:
        ports:
        - port: 9080
          name: http
        selector:
          app: ratings
      ---
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: bookinfo-ratings
        labels:
          account: ratings
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: ratings-v1
        labels:
          app: ratings
          version: v1
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: ratings
            version: v1
        template:
          metadata:
            labels:
              app: ratings
              version: v1
          spec:
            serviceAccountName: bookinfo-ratings
            containers:
            - name: ratings
              image: docker.io/istio/examples-bookinfo-ratings-v1:1.16.2
              imagePullPolicy: IfNotPresent
              ports:
              - containerPort: 9080
              securityContext:
                runAsUser: 1000
      ---
      # Reviews service
      apiVersion: v1
      kind: Service
      metadata:
        name: reviews
        labels:
          app: reviews
          service: reviews
      spec:
        ports:
        - port: 9080
          name: http
        selector:
          app: reviews
      ---
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: bookinfo-reviews
        labels:
          account: reviews
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: reviews-v2
        labels:
          app: reviews
          version: v2
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: reviews
            version: v2
        template:
          metadata:
            labels:
              app: reviews
              version: v2
          spec:
            serviceAccountName: bookinfo-reviews
            containers:
            - name: reviews
              image: docker.io/istio/examples-bookinfo-reviews-v2:1.16.2
              imagePullPolicy: IfNotPresent
              env:
              - name: LOG_DIR
                value: "/tmp/logs"
              ports:
              - containerPort: 9080
              volumeMounts:
              - name: tmp
                mountPath: /tmp
              - name: wlp-output
                mountPath: /opt/ibm/wlp/output
              securityContext:
                runAsUser: 1000
            volumes:
            - name: wlp-output
              emptyDir: {}
            - name: tmp
              emptyDir: {}
      ---
      # Productpage services
      apiVersion: v1
      kind: Service
      metadata:
        name: productpage
        labels:
          app: productpage
          service: productpage
      spec:
        ports:
        - port: 9080
          name: http
        selector:
          app: productpage
      ---
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: bookinfo-productpage
        labels:
          account: productpage
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: productpage-v1
        labels:
          app: productpage
          version: v1
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: productpage
            version: v1
        template:
          metadata:
            labels:
              app: productpage
              version: v1
          spec:
            serviceAccountName: bookinfo-productpage
            containers:
            - name: productpage
              image: docker.io/istio/examples-bookinfo-productpage-v1:1.16.2
              imagePullPolicy: IfNotPresent
              ports:
              - containerPort: 9080
              volumeMounts:
              - name: tmp
                mountPath: /tmp
              securityContext:
                runAsUser: 1000
            volumes:
            - name: tmp
              emptyDir: {}
      ---
      	  
    3. 执行以下命令,在ack-shanghai集群部署Bookinfo应用。

      kubectl apply -f ack-shanghai.yaml
    4. 使用kubectl连接到ASM。具体操作,请参见通过控制面kubectl访问Istio资源

      说明

      使用kubectl连接到ASM时,您需要将ack-shanghai集群的kubeconfig切换成ASM的kubeconfig。

  3. 在ASM中创建路由规则。

    1. 使用以下内容,创建asm.yaml

      展开查看asm.yaml

      apiVersion: networking.istio.io/v1alpha3
      kind: Gateway
      metadata:
        name: bookinfo-gateway
      spec:
        selector:
          istio: ingressgateway # use istio default controller
        servers:
        - port:
            number: 80
            name: http
            protocol: HTTP
          hosts:
          - "*"
      ---
      apiVersion: networking.istio.io/v1alpha3
      kind: VirtualService
      metadata:
        name: bookinfo
      spec:
        hosts:
        - "*"
        gateways:
        - bookinfo-gateway
        http:
        - match:
          - uri:
              exact: /productpage
          - uri:
              prefix: /static
          - uri:
              exact: /login
          - uri:
              exact: /logout
          - uri:
              prefix: /api/v1/products
          route:
          - destination:
              host: productpage
              port:
                number: 9080
      ---
      apiVersion: networking.istio.io/v1alpha3
      kind: DestinationRule
      metadata:
        name: productpage
      spec:
        host: productpage
        subsets:
        - name: v1
          labels:
            version: v1
      ---
      apiVersion: networking.istio.io/v1alpha3
      kind: DestinationRule
      metadata:
        name: reviews
      spec:
        host: reviews
        subsets:
        - name: v1
          labels:
            version: v1
        - name: v2
          labels:
            version: v2
        - name: v3
          labels:
            version: v3
      ---
      apiVersion: networking.istio.io/v1alpha3
      kind: DestinationRule
      metadata:
        name: ratings
      spec:
        host: ratings
        subsets:
        - name: v1
          labels:
            version: v1
        - name: v2
          labels:
            version: v2
        - name: v2-mysql
          labels:
            version: v2-mysql
        - name: v2-mysql-vm
          labels:
            version: v2-mysql-vm
      ---
      apiVersion: networking.istio.io/v1alpha3
      kind: DestinationRule
      metadata:
        name: details
      spec:
        host: details
        subsets:
        - name: v1
          labels:
            version: v1
        - name: v2
          labels:
            version: v2
      ---
      	  
    2. 执行以下命令,创建路由规则。

      kubectl apply -f asm.yaml
  4. 验证Bookinfo应用是否部署成功。

    1. 登录容器服务管理控制台

    2. 在控制台左侧导航栏,单击集群

    3. 集群列表页面单击ack-hangzhou集群右侧操作列下的详情

    4. 在集群管理页左侧导航栏,选择网络 > 服务

    5. 服务页面顶部设置命名空间为Istio-system,查看istio-ingressgateway右侧External IP下端口为80的IP地址。

    6. 在浏览器地址栏中输入入口网关IP地址/productpage

      多次刷新页面,可以看到以下图片轮流出现。review1review1

步骤五:使用跨地域流量分布和跨地域故障转移

设置跨地域流量分布

  1. 登录ASM控制台,在左侧导航栏,选择服务网格 > 网格管理

  2. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择网格实例 > 基本信息

  3. 基本信息页面,单击跨地域负载均衡右侧的启用跨地域流量分布

    说明

    如果您已经启用跨地域故障转移,您需要禁用跨地域故障转移后,才能启用跨地域流量分布。

  4. 跨地域流量分布对话框设置策略为cn-hangzhou,然后单击新建策略

  5. 单击展开图标,然后单击添加图标,设置目标为cn-hangzhou,权重为90%。

  6. 单击添加图标,设置目标为cn-shanghai,权重为10%,单击确认

  7. 执行以下命令,循环请求10次Bookinfo应用,验证跨地域流量分布是否成功。

    for ((i=1;i<=10;i++));do curl http://<ack-hangzhou集群中80端口的入口网关地址>/productpage 2>&1|grep full.stars;done

    预期输出:

    <!-- full stars: -->
    <!-- full stars: -->

    可以看到访问10次,输出2行full stars,说明10次请求中9次路由到了ack-hangzhou集群的v1版本reviews服务,1次路由到了ack-shanghai集群的v2版本reviews服务,流量按照权重路由到多个集群成功。

设置跨地域故障转移

  1. 停用ack-hangzhou集群的review。

    1. 登录容器服务管理控制台

    2. 在控制台左侧导航栏,单击集群

    3. 在集群管理页左侧导航栏,选择工作负载 > 无状态

    4. 无状态页面设置命名空间为default,单击reviews-v1右侧操作列下的伸缩

    5. 伸缩页面设置所需容器组数量为0,然后单击确定

  2. 配置DestinationRule。

    配置DestinationRule,当1s内无法请求到reviews服务,该reviews服务将被移除1min。

    1. 登录ASM控制台

    2. 在左侧导航栏,选择服务网格 > 网格管理

    3. 网格管理页面,找到待配置的实例,单击实例的名称或在操作列中单击管理

    4. 在网格详情页面左侧导航栏,选择流量管理中心 > 目标规则

    5. 目标规则页面单击reviews右侧操作列下的YAML

    6. 编辑面板增加以下内容,然后单击确定

      spec:
        ......
        trafficPolicy:
          connectionPool:
            http:
              maxRequestsPerConnection: 1
          outlierDetection:
            baseEjectionTime: 1m
            consecutive5xxErrors: 1
            interval: 1s
      • maxRequestsPerConnection:最大连接数量。

      • baseEjectionTime:最小的移除时间长度。

      • consecutive5xxErrors:连续错误数量。

      • interval:移除检测的时间间隔。

  3. 启用跨地域故障转移。

    1. 在网格详情页面左侧导航栏,选择网格实例 > 基本信息

    2. 基本信息页面单击跨地域负载均衡右侧的启用跨地域故障转移

      说明

      如果您已经启用跨地域流量分布,您需要禁用跨地域流量分布后,才能启用跨地域故障转移。

    3. 跨地域故障转移对话框中设置当策略源是cn-shanghai,源故障转移至cn-hangzhou,当策略源是cn-hangzhou,源故障转移至cn-shanghai,然后单击确认

  4. 执行以下命令,循环请求10次Bookinfo应用,并对路由到v2版本reviews服务的结果数量进行统计。

    for ((i=1;i<=10;i++));do curl http://<ack-hangzhou集群中80端口的入口网关地址>/productpage 2>&1|grep full.stars;done|wc -l

    预期输出:

    20

    可以看到访问10次,返回20(每次路由到v2版本reviews服务会返回两行包含full stars的结果),说明10次请求全部路由到了ack-shanghai集群的v2版本reviews服务,跨地域故障转移成功。

FAQ

为什么通过云企业网CEN打通了集群VPC网络,在ASM中加入K8s集群仍然提示失败?

当您的集群处于不同地域,在打通集群VPC网络时,您若未购买跨地域流量包,或者未正确设置跨地域流量,ASM控制平面将无法连接到数据平面集群,导致ASM添加集群失败。

针对以上这个问题,您需要重新在云企业网CEN中设置跨地域流量打通集群VPC网络,具体操作,请参见步骤二:使用CEN实现跨地域VPC网络互通