通过ASM实现TCP应用流量迁移

当您需要优化网络拓扑、扩容应用服务器或调整业务流量时,可以通过ASM的流量管理中心实现TCP应用流量的平滑迁移,确保关键业务的连续性和服务的高可用性。以Istio官方Task TCP-Traffic-Shifting为例,本文介绍如何在一个TCP服务的两个版本之间进行流量灰度切换。该Task中的Echo服务有两个版本,v1版本响应时会在接收到的消息前添加前缀“one”,v2版本会添加“two”,您可以观察流量转移的效果,并对分流策略进行微调,以满足具体的业务需求和性能目标。

前提条件

步骤一:部署示例应用

  1. 部署TCP- Echo应用的2个版本。

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

    2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 无状态

    3. 无状态页面上方,选择目标命名空间,然后单击右上角的使用YAML创建资源

    4. 设置示例模板自定义,将下面的YAML粘贴到模板文本框,然后单击创建

      展开查看YAML

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: tcp-echo-v1
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: tcp-echo
            version: v1
        template:
          metadata:
            labels:
              app: tcp-echo
              version: v1
          spec:
            containers:
            - name: tcp-echo
              image: docker.io/istio/tcp-echo-server:1.1
              imagePullPolicy: IfNotPresent
              args: [ "9000", "one" ]
              ports:
              - containerPort: 9000
      ---
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: tcp-echo-v2
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: tcp-echo
            version: v2
        template:
          metadata:
            labels:
              app: tcp-echo
              version: v2
          spec:
            containers:
            - name: tcp-echo
              image: docker.io/istio/tcp-echo-server:1.1
              imagePullPolicy: IfNotPresent
              args: [ "9000", "two" ]
              ports:
              - containerPort: 9000

      无状态页面,可以看到新创建的两个版本的TCP-Echo应用。

  2. 创建一个服务,并将其对外暴露。

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

    2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择网络 > 服务

    3. 服务页面上方,选择目标命名空间,然后单击右上角的创建

    4. 创建服务对话框,配置服务的相关信息,然后单击确定

      配置项

      说明

      服务名称

      配置为tcp-echo

      服务类型

      选择服务类型,即服务访问的方式。支持虚拟集群IP节点端口负载均衡

      说明

      服务类型选择虚拟集群IP时,才能设置实例间发现服务(Headless Service)。您可以使用无头Service与其他服务发现机制进行接口,不与Kubernetes的实现捆绑在一起。

      服务关联

      配置名称apptcp-echo-v1

      说明

      将从关联的Deployment中提取app这个标签作为Service的Selector,这决定了Kubernetes service将流量转发到哪个Deployment。由于tcp-echo-v1和tcp-echo-v2两个Deployment拥有相同的标签,即app:tcp-echo,因此可以关联任一Deployment。

      外部流量策略

      支持LocalCluster

      说明

      当您的服务类型为节点端口负载均衡时,才能设置外部流量策略

      端口映射

      本文配置名称tcp服务端口容器端口9000协议TCP

      注解

      为该服务添加一个注解(annotation),配置负载均衡的参数。例如,设置service.beta.kubernetes.io/alicloud-loadbalancer-bandwidth:20表示将该服务的带宽峰值设置为20 Mbit/s,控制服务的流量。关于参数的说明,请参见通过Annotation配置传统型负载均衡CLB

      标签

      为服务添加一个标签,标识该服务。

      创建成功后,在服务页面,可以看到新创建的tcp-echo服务。

步骤二:设置路由规则

通过设置服务网格的Istio网关、虚拟服务和目标规则,将流量全部指向tcp-echo服务的v1版本。

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

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

  3. 创建服务网关。

    1. 在网格详情页面左侧导航栏,选择ASM网关 > 网关规则,然后在右侧页面,单击使用YAML创建

    2. 创建页面,命名空间选择default,选择任意场景模版,配置以下YAML,然后单击创建

      apiVersion: networking.istio.io/v1alpha3
      kind: Gateway
      metadata:
        name: tcp-echo-gateway
      spec:
        selector:
          istio: ingressgateway
        servers:
        - port:
            number: 31400
            name: tcp
            protocol: TCP
          hosts:
          - "*"
  4. 创建虚拟服务。

    1. 在网格详情页面左侧导航栏,选择流量管理中心 > 虚拟服务,然后在右侧页面,单击使用YAML创建

    2. 创建页面,命名空间选择default,选择任意场景模版,配置以下YAML,然后单击创建

      apiVersion: networking.istio.io/v1alpha3
      kind: VirtualService
      metadata:
        name: tcp-echo
      spec:
        hosts:
        - "*"
        gateways:
        - tcp-echo-gateway
        tcp:
        - match:
          - port: 31400
          route:
          - destination:
              host: tcp-echo
              port:
                number: 9000
              subset: v1
  5. 创建目标规则。

    1. 在网格详情页面左侧导航栏,选择流量管理中心 > 目标规则,然后在右侧页面,单击使用YAML创建

    2. 创建页面,命名空间选择default,选择任意场景模版,配置以下YAML,然后单击创建

      apiVersion: networking.istio.io/v1alpha3
      kind: DestinationRule
      metadata:
        name: tcp-echo-destination
      spec:
        host: tcp-echo
        subsets:
        - name: v1
          labels:
            version: v1
        - name: v2
          labels:
            version: v2

步骤三:部署入口网关

在入口网关中,添加端口31400,并指向Istio网关的31400端口。

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

  2. 网格管理页面,单击目标实例名称,然后在左侧导航栏,选择ASM网关 > 入口网关

  3. 入口网关页面,单击创建,进行相关配置,然后单击创建

    部分配置项说明如下。关于配置项的更多说明,请参见创建入口网关

    配置项

    说明

    部署集群

    选择要部署入口网关的集群。

    负载均衡CLB类型

    本文选择公网访问

    选择负载均衡

    • 使用已有负载均衡:从已有负载均衡列表中选择。

    • 新建负载均衡CLB:单击新建负载均衡CLB,从下拉列表中选择所需的负载均衡规格。

    说明

    建议您为每个Kubernetes服务分配一个CLB。如果多个Kubernetes服务复用同一个CLB,存在以下风险和限制:

    • 使用已有的CLB会强制覆盖已有监听,可能会导致您的应用不可访问。

    • Kubernetes通过Service创建的CLB不能复用,只能复用您手动在控制台(或调用OpenAPI)创建的CLB。

    • 复用同一个CLB的多个Service不能有相同的前端监听端口,否则会造成端口冲突。

    • 复用CLB时,监听的名字以及虚拟服务器组的名字被Kubernetes作为唯一标识符。请勿修改监听和虚拟服务器组的名字。

    • 不支持跨集群复用CLB。

    端口映射

    单击添加端口,配置名称tcp服务端口31400

步骤四:检查部署结果

通过Kubectl确认tcp-echo服务的流量指向是否符合预期。

  1. 通过Kubectl客户端连接至Kubernetes集群。具体操作,请参见步骤二:选择集群凭证类型

  2. 执行以下命令,获得服务的地址与端口。

    $ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    $ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="tcp")].port}')
  3. 使用telnet指令向tcp-echo服务发起连接请求。

    $ telnet $INGRESS_HOST $INGRESS_PORT
    Trying xxx.xxx.xxx.xxx...
    Connected to xxx.xxx.xxx.xxx.
    Escape character is '^]'
  4. 输入任意字符串,按Enter发送。

    返回的字符串前面带了“one”,说明tcp-echo服务已经成功部署,且流量全部指向了tcp-echo-v1版本。

步骤五:按比例将流量路由到tcp-echo-v2

此处将20%的流量指向tcp-echo-v2版本,其余80%仍然打到tcp-echo-v1。

  1. 修改ASM实例的虚拟服务配置。

    1. 在网格详情页面左侧导航栏,选择流量管理中心 > 虚拟服务

    2. 虚拟服务页面,单击tcp-echo所在操作列中的YAML

    3. 编辑实例页面的文本框中输入以下YAML文件内容,单击确定

      apiVersion: networking.istio.io/v1alpha3
      kind: VirtualService
      metadata:
        name: tcp-echo
      spec:
        hosts:
        - "*"
        gateways:
        - tcp-echo-gateway
        tcp:
        - match:
          - port: 31400
          route:
          - destination:
              host: tcp-echo
              port:
                number: 9000
              subset: v1
            weight: 80
          - destination:
              host: tcp-echo
              port:
                number: 9000
              subset: v2
            weight: 20
  2. 执行以下命令,向tcp-echo服务发起10次请求。

    $ for i in {1..10}; do \
    docker run -e INGRESS_HOST=$INGRESS_HOST -e INGRESS_PORT=$INGRESS_PORT -it --rm busybox sh -c "(date; sleep 1) | nc $INGRESS_HOST $INGRESS_PORT"; \
    done
    one Mon Nov 12 23:38:45 UTC 2018
    two Mon Nov 12 23:38:47 UTC 2018
    one Mon Nov 12 23:38:50 UTC 2018
    one Mon Nov 12 23:38:52 UTC 2018
    one Mon Nov 12 23:38:55 UTC 2018
    two Mon Nov 12 23:38:57 UTC 2018
    one Mon Nov 12 23:39:00 UTC 2018
    one Mon Nov 12 23:39:02 UTC 2018
    one Mon Nov 12 23:39:05 UTC 2018
    one Mon Nov 12 23:39:07 UTC 2018

    根据以上请求的分发情况,可以看到20%的流量指向了tcp-echo-v2。

    说明

    您的测试结果可能不一定总是10次中有2次打到tcp-echo-v2,但从较长时间范围的总体比例来看,将接近20%。