Traffic Shifts with a VirtualService

The default deployment strategy on Kubernetes is a rolling update. Rolling updates allow a Deployment update to take place with zero downtime by incrementally updating Pod instances with new ones. But most likely in a real production environment you need a more advanced deployment strategy.

Traffic Shifts are a microservice pattern to shift traffic or parts of traffic to specific services. Traffic Shifts are especially useful for deployment strategies like:

  • A/B Testing is a randomized experiment with two variants, A and B. Version B is released to a subset of users under specific condition.

  • Blue/Green is a technique that reduces downtime and risk by running two identical production environments called Blue and Green. At any time, only one of the environments is live, with the live environment serving all production traffic and the idle environment being used for final testing. Version B is released alongside version A, then the traffic is switched to version B.

  • Shadowing allows version B alongside version A to receive live traffic without impacting the response.

  • Canary, in a Canary release, version B is released to a subset of users, before rolling it out to the entire platform and making it available to everybody.

This section will roughly implement the instructions from the official Istio documentation about Traffic Shifting at https://istio.io/docs/tasks/traffic-management/traffic-shifting/.

This section uses the example application Bookinfo to shift traffic. See the architecture of the microservices for the Bookinfo app.

  • Create a temporary working directory, e.g. istio101-test,

$ mkdir istio101-test
$ cd istio101-test
  • Download the Istio release v1.3.2, corresponding to the release of Istio installed on IKS, which includes the bookinfo application, and add the istio path to your current PATH environment,

$ curl -L https://git.io/getLatestIstio | ISTIO_VERSION=1.3.2 sh -
$ cd istio-1.3.2
$ export PATH=$PWD/bin:$PATH
  • The bookinfo application was already pre-installed in the Setup Istio on IKS section,

  • Check your current-context, it should correspond with the cluster name you created in the Setup Istio on IKS section,

$ kubectl config current-context
remkohdev-standard-iks-cluster
  • Check the current bookinfo deployment, wait until all deployments are ready 1/1,

$ kubectl get deployments
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
details-v1       1/1     1            1           112m
productpage-v1   1/1     1            1           112m
ratings-v1       1/1     1            1           112m
reviews-v1       1/1     1            1           112m
reviews-v2       1/1     1            1           112m
reviews-v3       1/1     1            1           112m
  • Note that the reviews deployment has 3 concurrent versions running: reviews-v1, reviews-v2, and reviews-v3,

  • Make sure that your system has an external load balancer. If the EXTERNAL-IP value is set, your cluster has an external load balancer that you can use for the ingress gateway.

$ kubectl get svc istio-ingressgateway -n istio-system
NAME                   TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)   AGE
istio-ingressgateway   LoadBalancer   172.21.123.4   123.45.678.90   15020:32461/TCP,
80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:31599/TCP,15030:32349/TCP,
15031:32405/TCP,15032:30296/TCP,15443:30522/TCP   111s
  • An ingress Gateway in a service mesh describes a load balancer operating at the edge of the mesh. Unlike Kubernetes Ingress Resources, an ingress Gateway in a service mesh does not include any traffic routing configuration. Traffic routing for ingress traffic is instead configured using Istio routing rules, using a VirtualService.

  • Get the VirtualServices for the Bookinfo app,

$ kubectl get virtualservice
NAME       GATEWAYS             HOSTS   AGE
bookinfo   [bookinfo-gateway]   [*]     21m
  • Describe the bookinfo VirtualService,

$ kubectl describe virtualservice bookinfo
Name:         bookinfo
Namespace:    default
API Version:  networking.istio.io/v1alpha3
Kind:         VirtualService
Spec:
  Gateways:
    bookinfo-gateway
  Hosts:
    *
  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
  • Review the VirtualService spec samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml,

  • Version 3 of the VirtualService for the reviews service uses weight-based routing,

$ cat samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: reviews
spec:
  hosts:
    - reviews
  http:
  - route:
    - destination:
        host: reviews
        subset: v1
      weight: 50
    - destination:
        host: reviews
        subset: v3
      weight: 50
  • Create the Traffic Shifts where 50% of traffic is routed to v1 and 50% of traffic is routed to v3,

$ kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-50-v3.yaml
virtualservice.networking.istio.io/reviews created
  • Now, if you refresh your browser with the productpage of the Bookinfo app, you will see that 2 different versions load 50-50 percent of the time, namely a version with the reviews-v1 that has no review stars, and a version with the reviews-v3 that has 5 red stars for the review.

  • An HttpMatchRequest specifies a set of criteria to be met in order for the rule to be applied to the HTTP request.

  • To create a Canary release based on a logged in user's email domain stored in a cookie, you would add the following HTTPMatchRequest to the VirtualService spec,

spec:
  hosts:
    - reviews
  http:
  - match:
    - headers:
        cookie:
          regex: "^(.*?;)?(email=[^;]*@companyA.com)(;.*)?$"
  • To route traffic based on the platform of the mobile client, add the followingHTTPMatchRequest to the VirtualService spec,

- match:
  - headers: 
      user-agent: 
        regex: '^.*(Android|iPhone).*$'

Last updated