Exercise 3: Manage Traffic with Istio

In this exercise, you will expose the demo application through the Istio ingress gateway and use Istio routing rules to shift traffic between the two application versions.

Info

This exercise uses an Istio Gateway because we are exposing the application to traffic from outside the cluster. The traffic splitting itself is done by the VirtualService and DestinationRule, which would also work for service-to-service traffic inside the mesh without any gateway. The Gateway is only here to provide an external entry point so you can reach the app from your browser - it is not a requirement of traffic management.

Task 1: Create Istio Routing Resources

  1. Create an Istio Gateway, DestinationRule, and VirtualService.

    @"
    apiVersion: networking.istio.io/v1beta1
    kind: Gateway
    metadata:
      name: web-gateway
      namespace: istio-demo
    spec:
      selector:
        istio: aks-istio-ingressgateway-external
      servers:
      - port:
          number: 80
          name: http
          protocol: HTTP
        hosts:
        - "*"
    ---
    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: web
      namespace: istio-demo
    spec:
      host: web
      subsets:
      - name: v1
        labels:
          version: v1
      - name: v2
        labels:
          version: v2
    ---
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: web
      namespace: istio-demo
    spec:
      hosts:
      - "*"
      gateways:
      - web-gateway
      http:
      - route:
        - destination:
            host: web
            subset: v1
          weight: 80
        - destination:
            host: web
            subset: v2
          weight: 20
    "@ | kubectl apply -f -
    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1beta1
    kind: Gateway
    metadata:
      name: web-gateway
      namespace: istio-demo
    spec:
      selector:
        istio: aks-istio-ingressgateway-external
      servers:
      - port:
          number: 80
          name: http
          protocol: HTTP
        hosts:
        - "*"
    ---
    apiVersion: networking.istio.io/v1beta1
    kind: DestinationRule
    metadata:
      name: web
      namespace: istio-demo
    spec:
      host: web
      subsets:
      - name: v1
        labels:
          version: v1
      - name: v2
        labels:
          version: v2
    ---
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: web
      namespace: istio-demo
    spec:
      hosts:
      - "*"
      gateways:
      - web-gateway
      http:
      - route:
        - destination:
            host: web
            subset: v1
          weight: 80
        - destination:
            host: web
            subset: v2
          weight: 20
    EOF

Task 2: Test the Traffic Split

  1. Get the public IP address for the Istio ingress gateway.

    $INGRESS_IP = kubectl get service aks-istio-ingressgateway-external `
      -n aks-istio-ingress `
      -o jsonpath="{.status.loadBalancer.ingress[0].ip}"
    
    Write-Host "http://$INGRESS_IP"
    INGRESS_IP=$(kubectl get service aks-istio-ingressgateway-external \
      -n aks-istio-ingress \
      -o jsonpath="{.status.loadBalancer.ingress[0].ip}")
    
    echo "http://$INGRESS_IP"
  2. Send repeated requests and observe the traffic split between versions.

    1..20 | ForEach-Object {
      Invoke-WebRequest -UseBasicParsing "http://$INGRESS_IP" | Select-Object -ExpandProperty Content
    }
    for i in {1..20}; do
      curl -s "http://$INGRESS_IP" | grep -E "Hello|Version|Hostname" || true
    done

    Most responses should come from v1, with some responses from v2. This is controlled by the 80/20 weights in the VirtualService.

Task 3: Shift All Traffic to v2

  1. Update the VirtualService to send all traffic to v2.

    @"
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: web
      namespace: istio-demo
    spec:
      hosts:
      - "*"
      gateways:
      - web-gateway
      http:
      - route:
        - destination:
            host: web
            subset: v2
          weight: 100
    "@ | kubectl apply -f -
    cat <<EOF | kubectl apply -f -
    apiVersion: networking.istio.io/v1beta1
    kind: VirtualService
    metadata:
      name: web
      namespace: istio-demo
    spec:
      hosts:
      - "*"
      gateways:
      - web-gateway
      http:
      - route:
        - destination:
            host: web
            subset: v2
          weight: 100
    EOF
  2. Test the application again. All responses should now be served by v2.

    1..10 | ForEach-Object {
      Invoke-WebRequest -UseBasicParsing "http://$INGRESS_IP" | Select-Object -ExpandProperty Content
    }
    for i in {1..10}; do
      curl -s "http://$INGRESS_IP" | grep -E "Hello|Version|Hostname" || true
    done