管理南北

ACK One多集群网关基于MSE Ingress提供了强大的多集群南北向流量的管理,可以快速帮您实现同城应用多活容灾、流量多集群负载均衡、基于Header路由流量到指定集群等能力。本文介绍如何通过多集群网关管理多集群应用的南北流量。

背景信息

多集群网关优势

在容器服务领域,管理集群内服务的南北向流量的常用方式是使用Ingress资源进行管理。但Ingress为单集群维度,无法独立为多个集群中的应用流量进行管理,因此,ACK One基于MSE Ingress实现地域级的Global Ingress来统一处理多集群应用的南北向流量,并提供强大的流量管理能力,帮助您快速、低成本地实现同城应用多活容灾、流量多集群负载均衡、基于Header路由流量到指定集群等能力。此外,多集群网关使用易上手的Ingress API进行管理,极大地降低了使用门槛。

重要

使用多集群网关会产生一定的费用,关于多集群网关的计费信息,请参见普通实例计费概述

MSE相关文档

  • MseIngressConfig是由MSE Ingress Controller提供的CRD资源,用于管理MSE云原生网关实例的生命周期,配置Ingress监听选项以及全局配置。MseIngressConfig的常见用法,请参见配置MseIngressConfig

  • MSE Ingress已支持Nginx-Ingress核心和常用的Annotation,并推出额外的Annotation来弥补Nginx-Ingress的不足。更多信息,请参见MSE Ingress支持的Annotation

前提条件

步骤一:在ACK One Fleet实例中创建多集群网关

在ACK One Fleet实例中创建一个多集群网关(网关默认可用区高可用),并将关联集群添加至多集群网关

通过控制台创建

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

  2. 多集群网关页面右上角单击创建网关

  3. 在弹出的面板中,根据实际情况修改创建多集群网关的YAML文件,然后单击创建。

通过命令行创建

  1. 获取ACK One Fleet实例的虚拟交换机ID并记录。

    1. 执行以下命令,获取交换机实例ID。

    aliyun adcp DescribeHubClusterDetails --ClusterId <YOUR_FLEET_CLUSTERID>
    1. 从预期输出的VSwitches中复制一个交换机实例ID。

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

    替换以下${vsw-id1}为您上一步获取的交换机ID。您也可以在创建网关时,通过添加Annotation同步指定待添加到多集群网关的关联集群。

    apiVersion: mse.alibabacloud.com/v1alpha1
    kind: MseIngressConfig
    metadata:
      name: ackone-gateway
      # 添加关联集群到MSE网关。
      #annotations:
      #  mse.alibabacloud.com/remote-clusters: ${cluster1},${cluster2}
    spec:
      common:
        instance:
          replicas: 3
          spec: 2c4g
        network:
          # 公网SLB和内网SLB,可都配置,如果2个字段都不配置则默认使用公网SLB。
          #publicSLBSpec: slb.s2.small
          #privateSLBSpec: slb.s2.small
          vSwitches:
          - ${vsw-id1}
      ingress:
        local:
          ingressClass: mse
      name: mse-ingress
  3. 执行以下命令,在ACK One Fleet实例中创建一个名为mse-ingress的网关。

    kubectl apply -f mseingressconfig.yaml
  4. 执行以下命令,验证网关是否创建成功。

    kubectl get mseingressconfig ackone-gateway

    预期输出:

    NAME             STATUS      AGE
    ackone-gateway   Listening   3m15s

    预期输出中网关状态为Listening,表明云原生网关创建成功处于运行状态,并自动监听集群中IngressClass为mse的Ingress资源。

    通过MseIngressConfig创建的多集群网关会按照Pending、Running、Listening的状态依次变化。各状态说明如下:

    • Pending:表明云原生网关正在创建中,需等待3分钟左右。

    • Running:表明云原生网关创建成功,并处于运行状态。

    • Listening:表明云原生网关处于运行状态,并监听集群中Ingress资源。

    • Failed:表明云原生网关处于非法状态,可以查看Status字段中的Message来进一步明确原因。

步骤二:在多集群网关中添加关联集群

通过控制台添加

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

  2. 多集群网关页面上方的下拉框中选择要修改的目标多集群网关,然后在页面右上角单击编辑

  3. 在弹出的面板中修改MseIngresConfig.yaml文件,修改annotations参数中的集群ID,然后单击更新

    示例如下:

    annotations:
      mse.alibabacloud.com/remote-clusters: ${cluster1-id},${cluster2-id}
    • ${cluster1-id}${cluster2-id}为添加的关联集群的ID,多个关联集群以英文半角逗号(,)间隔,您可以通过修改集群ID来添加或删除关联的集群。

    • 若创建多集群网关时未添加关联集群,则MseIngresConfig.yaml文件中没有annotations参数,添加关联集群时,您需要将以上示例添加到MseIngresConfig.yaml文件的metadata对象中,再修改集群ID。

通过命令行方式添加

  1. 在ACK One Fleet实例中,通过mseingressconfig对象的Annotation控制多集群网关中添加或删除关联集群。替换以下${cluster1-id}${cluster2-id}为您待添加的关联集群的ID,添加多个关联集群时,中间以英文半角逗号(,)间隔。

    annotations:
      mse.alibabacloud.com/remote-clusters: ${cluster1-id},${cluster2-id}
  2. 执行以下命令,查看关联集群是否已成功添加至多集群网关。

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

    预期输出:

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

    预期输出中已包含指定的ClusterID,并且无Failed信息,表明关联集群已成功添加至多集群网关。

步骤三:使用GitOps部署Demo应用

  1. 使用GitOps将Demo应用部署到两个关联的ACK集群中。具体操作,请参见GitOps快速入门

    1. 创建2个GitOps Application,分别对应2个关联集群。示例:web-demo-cluster1、web-demo-cluster2。

    2. Source配置如下:

      • Repository URL设置为https://github.com/AliyunContainerService/gitops-demo.git

      • Revision设置为HEAD

      • Path设置为manifests/helm/web-demo

    3. DESTINATION分别选择2个关联集群,namespace设置为web-demo

    4. Helm Values Files中的参数名称为envNamevalue分别为cluster1cluster2

    部署后的Deployment和Service的YAML文件如下。

    展开查看Deployment和Service的YAML文件

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: web-demo
        app.kubernetes.io/instance: web-demo-cluster1
      name: web-demo
      namespace: web-demo
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: web-demo
      template:
        metadata:
          labels:
            app: web-demo
        spec:
          containers:
          - name: web-demo
            image: acr-multiple-clusters-registry.cn-hangzhou.cr.aliyuncs.com/ack-multiple-clusters/web-demo:0.4.0
            env:
            - name: ENV_NAME
              value: cluster1
    ---
    apiVersion: v1       
    kind: Service
    metadata:
      name: service1
      namespace: web-demo
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        app: web-demo
      sessionAffinity: None
      type: ClusterIP

步骤四:使用MSE Ingress管理多集群流量

通过在Ingress中指定IngressClass来使用MSE Ingress,并且使用不同的Annotation实现不同的流量管理能力。MSE Ingress不仅支持Nginx-Ingress核心和常用的Annotation,还针对Nginx-Ingress Annotation未支持的流量治理配置,推出额外的Annotation以弥补Nginx-Ingress的不足。MSE Ingress支持的Annotations请参见MSE Ingress支持的Annotation。下文以典型的多集群流量管理场景为例说明。

重要

Ingress对象和Demo应用中Service对象的Namespace需要保持一致。

示例1:默认负载均衡到所有服务后端

在ACK One Fleet实例中创建以下Ingress对象,可以默认将流量负载均衡到所有集群的同名服务后端,所有副本均衡。路由到不同集群的流量比例等同于集群中的副本数量的比例,例如,Cluster 1和Cluster 2中副本数比例为9:1,则流量在Cluster 1和Cluster 2中的流量比也为9:1。本例使用1:1的副本数演示。拓扑如下所示:image.png

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

    以下Ingress对象的YAML文件中,通过域名example.com下的/svc1路由规则暴露后端服务service1

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: web-demo
      namespace: 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
  3. 执行以下命令,获取多集群网关对外IP。

    kubectl get ingress web-demo -nargocd -ojsonpath="{.status.loadBalancer}"
  4. 执行以下命令,查看流量的路由情况。

    替换以下XX.XX.XX.XX为上一步获取的多集群网关对外IP。

    for i in {1..50}; do curl -H "host: example.com" XX.XX.XX.XX/svc1; sleep 1;  done

    预期输出:

    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster2 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 

    预期输出表明,流量被路由到所有集群上。

示例2:流量仅路由到指定集群

在ACK One Fleet实例中创建以下Ingress对象,可以将流量仅路由到Cluster 1的服务后端。拓扑如下所示:image.png

  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
        namespace: 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-one.yaml
  3. 执行以下命令,获取多集群网关对外IP。

    kubectl get ingress web-demo -nargocd -ojsonpath="{.status.loadBalancer}"
  4. 执行以下命令,查看流量的路由情况。

    替换以下XX.XX.XX.XX为上一步获取的多集群网关对外IP。

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

    预期输出:

    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    ...

    预期输出表明,固定的流量被路由到Cluster 1上。

示例3:根据Header将流量路由到指定集群

如需根据自定义Header将流量路由到指定集群的服务后端,您可以在ACK One Fleet实例中创建Example 1或者Example 2Ingress对象,然后再创建以下Ingress对象(此Ingress对象无法单独生效)。拓扑如下所示:

重要

基于Header方式进行流量调度时,您需要在Ingress的注解上配置Canary注解和Header匹配策略,同时需确保已存在另一个Ingress中不包含Canary注解且存在相同的Host + Path访问另一个集群中的服务。即Header方式的Ingress不能单独生效,需搭配使用另一个不指定Header的Ingress指向另一个集群中的服务。

image.png

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

    以下Ingress对象的YAML文件中,通过域名example.com下的/service1路由规则暴露后端服务service1

    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 c15d48ca9d1fd43f9bbb89c56a474843c
        nginx.ingress.kubernetes.io/canary: "true"
        nginx.ingress.kubernetes.io/canary-by-header: "stage"
        nginx.ingress.kubernetes.io/canary-by-header-value: "gray"
      name: web-demo-cluster-second
      namespace: 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-header.yaml
  3. 执行以下命令,获取多集群网关对外IP。

    kubectl get ingress web-demo -nargocd -ojsonpath="{.status.loadBalancer}"
  4. 执行以下命令,查看流量的路由情况。

    替换以下XX.XX.XX.XX为上一步获取的多集群网关对外IP。

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

    预期输出:

    This is env cluster2 !
    Config file is 
    This is env cluster2 !
    Config file is 
    This is env cluster2 !
    Config file is 
    This is env cluster2 !
    Config file is 
    This is env cluster2 !
    Config file is 
    ...

    预期输出表明,流量根据Header stage: gray被路由到Cluster 2上。

示例4:多集群应用跨集群容灾

多集群网关具备多集群应用跨集群容灾的能力,无需额外配置。例如,上述配置的多集群网关管理了两个关联的ACK集群的流量,如果其中一个集群的服务异常或被删除,流量会自动转到另一个可用集群。上述示例1示例2示例3均一样,即使已经指定路由到某个集群,但当此集群上的应用异常后,也会被容灾到其他集群上。

以下以示例3为例说明,在正常情况下,添加Header stage: gray,您可以访问到Cluster 2的后端,当Cluster 2的Deployment副本数被缩为0时,请求会切换至Cluster 1的后端。拓扑如下所示:image.png

  1. 执行以下命令,获取多集群网关对外IP。

    kubectl get ingress web-demo -nargocd -ojsonpath="{.status.loadBalancer}"
  2. 执行以下命令,查看流量的路由情况。

    替换以下XX.XX.XX.XX为上一步获取的多集群网关对外IP。

    for i in {1..50}; do curl -H "host: example.com" -H "stage: gray" XX.XX.XX.XX/service1; sleep 1;  done

    预期输出:

    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    ...

    预期输出表明,流量被自动容灾到Cluster 1上。

示例5:根据权重进行流量路由

示例1中,您可以通过调节集群中副本数的比例,实现按比例路由流量到不同的集群。本示例介绍如何在Annotations中配置权重来按比例路由流量到不同的集群,也可以使用该方式进行灰度发布。您可以在ACK One Fleet实例中创建以下2个Ingress对象实现该能力,拓扑如下所示:

重要

基于权重方式进行流量调度时,您需要在Ingress的注解上配置Canary注解和Header匹配策略,同时需保证已存在另一个Ingress不含有Canary注解且存在相同的Host + Path访问另一个集群中的服务。即权重方式的Ingress不能单独生效,需搭配使用另一个不指定权重的Ingress指向另一个集群中的服务。

image.png

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

    以下Ingress对象的YAML文件中,替换YAML中的${cluster1-id}为目标集群ID。通过添加Annotations以实现域名example.com下的/svc1-w路由规则暴露后端服务service1

    • mse.ingress.kubernetes.io/service-subset:服务的子版本名称。建议定义为与目标集群相关且可读性强的值。

    • mse.ingress.kubernetes.io/subset-labels:目标ACK集群的ID。

    • nginx.ingress.kubernetes.io/canary:设置为"true",表示开启灰度发布能力。

    • nginx.ingress.kubernetes.io/canary-weight:请求到该集群的流量百分比(值为0~100的整数)。

      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-weight
        namespace: web-demo
      spec:
        ingressClassName: mse
        rules:
        - host: example.com
          http:
            paths:
            - path: /svc1-w
              pathType: Exact
              backend:
                service:
                  name: service1
                  port: 
                    number: 80
      ---
      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-weight: "10"
        name: web-demo-weight-canary
        namespace: web-demo
      spec:
        ingressClassName: mse
        rules:
        - host: example.com
          http:
            paths:
            - path: /svc1-w
              pathType: Exact
              backend:
                service:
                  name: service1
                  port: 
                    number: 80
  2. 执行以下命令,在ACK One Fleet实例中部署Ingress。

    kubectl apply -f ingress-weight.yaml -nargocd
  3. 执行以下命令,获取多集群网关对外IP。

    kubectl get ingress web-demo -nargocd -ojsonpath="{.status.loadBalancer}"
  4. 执行以下命令,查看流量的路由情况。

    替换以下XX.XX.XX.XX为上一步获取的多集群网关对外IP。

    for i in {1..50}; do curl -H "host: example.com" XX.XX.XX.XX/svc1-w; sleep 1;  done

    预期输出:

    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster2 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster1 !
    Config file is 
    This is env cluster2 !
    Config file is 
    This is env cluster1 !
    Config file is 
    ...

    预期输出表明,根据权重进行流量路由,90%的流量被路由到Cluster 1上,10%的流量被路由到Cluster 2上。