You can use Alibaba Cloud Service Mesh (ASM) to transfer traffic from one version of an application to another. This topic describes how to use ASM to transfer TCP traffic.

Prerequisites

Background information

This topic describes how to transfer TCP traffic between two versions of an application based on the TCP Traffic Shifting example given by Istio. In this example, an application named tcp-echo has two versions: v1 and v2. In version v1, the application adds the prefix "one" to the timestamps in the response before it returns the response. In version v2, the application adds the prefix "two" to the timestamps in the response before it returns the response.

Step 1: Deploy the two versions of the sample application

  1. Deploy the two versions of the tcp-echo application.
    1. Log on to the ACK console.
    2. In the left-side navigation pane of the ACK console, click Clusters.
    3. On the Clusters page, find the cluster that you want to manage and click the name of the cluster, or click Applications in the Actions column.
    4. At the top of the Deployments page, select a namespace from the Namespace drop-down list.
    5. In the upper-right corner of the Deployments page, click Create from YAML.
    6. Select Custom from the Sample Template drop-down list, copy the following YAML template to the code editor in the Template section, and then click Create.
      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
      Return to the Deployments page. Then, you can find the two versions of the tcp-echo application.
  2. Create a service named tcp-echo and expose the service.
    1. Log on to the ACK console.
    2. In the left-side navigation pane of the ACK console, click Clusters.
    3. On the Clusters page, find the cluster that you want to manage and click the name of the cluster, or click Applications in the Actions column.
    4. In the left-side navigation pane of the details page, choose Network > Services
    5. At the top of the Services page, select a namespace from the Namespace drop-down list and click Create in the upper-right corner.
    6. In the Create Service dialog box, set the following parameters and click Create.
      The following section describes the parameters:
      • Name: the name of the service. In this example, tcp-echo is used.
      • Type: the type of the service, which specifies how the service is exposed. Valid values: Cluster IP, Node Port, and Server Load Balancer.
        Note The Headless Service check box is displayed only when you set the Type parameter to Cluster IP. If you select this check box, you can use a headless service to interface with other service discovery mechanisms, without being tied to the implementation of service discovery in Kubernetes.
      • Backend: the Deployment to be associated with the service. In this example, tcp-echo-v1 is selected.
        Note The service uses the app label of the associated Deployment as the selector to determine to which Deployment the traffic is routed. The tcp-echo-v1 and tcp-echo-v2 Deployments share the same app label, which is app:tcp-echo. Therefore, the service can be associated with either one of the two Deployments.
      • External Traffic Policy: You can select Local or Cluster.
        Note The External Traffic Policy parameter is displayed only when you set the Type parameter to Node Port or Server Load Balancer.
      • Port Mapping: Set the Name parameter to tcp, the Service Port and Container Port parameters to 9000, and the Protocol parameter to TCP.
      • Annotations: Add annotations to the service. For example, you can add the LoadBalancer annotation service.beta.kubernetes.io/alicloud-loadbalancer-bandwidth:20, which sets the bandwidth limit of the service to 20 Mbit/s. This annotation limits the amount of traffic flows to the service. For more information about annotations, see Use annotations to configure load balancing.
      • Label: Add one or more labels to the service.
      After you create the service, the service appears on the Services page.

Step 2: Set routing rules for the ASM instance

You can create an Istio gateway, a virtual service, and a destination rule for the ASM instance to route all traffic to version v1 of the tcp-echo application.

  1. Log on to the ASM console.
  2. In the left-side navigation pane, choose Service Mesh > Mesh Management.
  3. On the Mesh Management page, find the ASM instance that you want to configure. Click the name of the ASM instance or click Manage in the Actions column.
  4. Create a service gateway.
    1. On the details page of the ASM instance, choose Traffic Management > Gateway in the left-side navigation pane. On the Gateway page, click Create from YAML.
    2. On the Create page, select default from the Namespace drop-down list and copy the following YAML template to the code editor. Then, click Create.
      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:
          - "*"
  5. Create a virtual service.
    1. On the details page of the ASM instance, choose Traffic Management > VirtualService in the left-side navigation pane. On the VirtualService page, click Create from YAML.
    2. On the Create page, select default from the Namespace drop-down list and copy the following YAML template to the code editor. Then, click Create.
      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
  6. Create a destination rule.
    1. On the details page of the ASM instance, choose Traffic Management > DestinationRule in the left-side navigation pane. On the DestinationRule page, click Create from YAML.
    2. On the Create page, select default from the Namespace drop-down list and copy the following YAML template to the code editor. Then, click Create.
      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

Step 3: Deploy an ingress gateway service

Add port 31400 to the Ingress gateway and map the port to port 31400 of the Istio gateway.

  1. Log on to the ASM console.
  2. In the left-side navigation pane, choose Service Mesh > Mesh Management.
  3. On the Mesh Management page, find the ASM instance that you want to configure. Click the name of the ASM instance or click Manage in the Actions column.
  4. On the details page of the ASM instance, click ASM Gateways in the left-side navigation pane. On the ASM Gateways page, click Create.
  5. Set the parameters about the ingress gateway. Use the default values for other parameters.
    1. Select the cluster in which you want to deploy the Ingress gateway from the Cluster drop-down list.
    2. Set the SLB Instance Type parameter to Internet Access.
    3. Configure an SLB instance.
      • Use Existing SLB Instance: Select an SLB instance from the drop-down list.
      • Create SLB Instance: Click Create SLB Instance and select an SLB instance type from the drop-down list.
      Note We recommend that you assign a dedicated SLB instance to each Kubernetes service in the cluster. If multiple Kubernetes services share the same SLB instance, the following risks and limits exist:
      • If you assign a Kubernetes service with an SLB instance that is used by another Kubernetes service, the existing listeners of the SLB instance are forcibly overwritten. This may interrupt the original Kubernetes service and make your application unavailable.
      • If you create an SLB instance when you create a Kubernetes service, the SLB instance cannot be shared among Kubernetes services. Only SLB instances that you create in the SLB console or by calling API operations can be shared.
      • Kubernetes services that share the same SLB instance must use different frontend listening ports. Otherwise, port conflicts may occur.
      • If multiple Kubernetes services share the same SLB instance, you must use the listener names and the vServer group names as unique identifiers in Kubernetes. Do not modify the names of listeners or vServer groups.
      • You cannot share SLB instances across clusters.
    4. Click Add Port and set the Name parameter to tcp and the Service Port and Container Port parameters to 31400.
      Note The service port exposes the ASM instance to external access. The ASM instance distributes inbound traffic received on the service port to the container port, which refers to the specified port on the Istio gateway. Make sure that the container port is the same as the specified port on the Istio gateway.
    5. Click OK.

Step 4: Verify the result

Use a kubectl client to check whether the tcp-echo service distributes traffic to the application.

  1. Use the kubectl client to connect to the ACK cluster. For more information, see Step 2: Select a type of cluster credentials.
  2. Run the following commands to query the IP address and port number of the tcp-echo service:
    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. Run the telnet command to connect to the tcp-echo service.
    telnet $INGRESS_HOST $INGRESS_PORT
    Trying xxx.xxx.xxx.xxx...
    Connected to xxx.xxx.xxx.xxx.
    Escape character is '^]'
  4. Enter a random string and press Enter. If the return string is prefixed with "one", the tcp-echo service is properly deployed and all of the traffic is routed to the tcp-echo-v1 application.

Step 5: Transfer a specific proportion of traffic to the tcp-echo-v2 version

In this example, 20% of the traffic is routed to the tcp-echo-v2 version and the remaining 80% is routed to the tcp-echo-v1 version.

  1. Modify the configuration of the virtual service of the ASM instance.
    1. On the details page of the ASM instance, choose Traffic Management > VirtualService in the left-side navigation pane.
    2. On the VirtualService page, find the tcp-echo virtual service and click YAML in the Actions column.
    3. In the Edit panel, copy the following YAML template to the code editor and click OK:
      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. Run the following command to send 10 requests to the tcp-echo service:
     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
    The preceding output indicates that 20% of the traffic is routed to the tcp-echo-v2 version.
    Note If you send 10 requests in a test, the traffic may not always be routed to the tcp-echo-1 and tcp-echo-v2 versions at the specified ratio. However, the actual ratio is close to 80:20 when the sample size increases.