Skip to content

Canary release

This tutorial shows how Iter8 can be used to release a basic Kubernetes application using a canary release strategy.

In a canary release, requests that match a particular pattern, for example those that have a particular header, are directed to the candidate version of the model. The remaining requests go to the primary, or initial, version of the model.

Canary release

The user declaratively describes the desired application state at any given moment. An Iter8 release chart assists users who describe the application state at any given moment. The chart provides the configuration needed for Iter8 to automatically deploy application versions and configure the routing to implement the canary release strategy.


Before you begin
  1. Ensure that you have a Kubernetes cluster and the kubectl and helm CLIs. If using a local cluster (for example, Kind or Minikube), we recommend providing the cluster with at least 16GB of memory.
  2. Install Istio. It suffices to install the demo profile, for example by using:
    istioctl install --set profile=demo -y
    

Install the Iter8 controller

Iter8 can be installed and configured to watch resources either in a single namespace (namespace-scoped) or in the whole cluster (cluster-scoped).

helm install --repo https://iter8-tools.github.io/iter8 --version 1.1 iter8 controller
helm install --repo https://iter8-tools.github.io/iter8 --version 1.1 iter8 controller \
--set clusterScoped=true

For additional install options, see Iter8 Installation.

Deploy initial version

Deploy the initial version of the application using the Iter8 release chart by identifying the environment into which it should be deployed, a list of the versions to be deployed (only one here), and the release strategy to be used:

cat <<EOF | helm upgrade --install httpbin --repo https://iter8-tools.github.io/iter8 release --version 1.1 -f -
environment: deployment-istio
application: 
  versions:
  - metadata:
      labels:
        app.kubernetes.io/version: v0
    image: kennethreitz/httpbin
  strategy: canary
EOF
What happens?

Because environment is set to deployment-istio, a Deployment and a Service object are created. - The namespace default is inherited from the Helm release namespace since it is not specified in the version or in application.metadata. - The name httpbin-0 is derived from the Helm release name since it is not specified in the version or in application.metadata. The name is derived by appending the index of the version in the list of versions; -0 in this case. - Alternatively, a deploymentSpecification and/or a serviceSpecification could have been specified.

To support routing, a Service (of type ExternalName) named default/httpbin pointing at the Istio gateway, istio-ingressgateway.istio-system, is deployed. The name is the Helm release name since it not specified in application.metadata. Further, an Iter8 routemap is created.

Once the application components are ready, the Iter8 controller automatically configures the routing by creating an Istio VirtualService. It is configured to route all traffic to the only deployed version, httpbin-0.

Verify routing

You can verify the routing configuration by inspecting the VirtualService:

kubectl get virtualservice httpbin -o yaml

You can also send requests from a pod within the cluster:

  1. Create a sleep pod in the cluster from which requests can be made:

    curl -s https://raw.githubusercontent.com/iter8-tools/docs/v0.18.4/samples/kserve-serving/sleep.sh | sh -
    

  2. Exec into the sleep pod:

    kubectl exec --stdin --tty "$(kubectl get pod --sort-by={metadata.creationTimestamp} -l app=sleep -o jsonpath={.items..metadata.name} | rev | cut -d' ' -f 1 | rev)" -c sleep -- /bin/sh
    

  3. Send requests:

    curl httpbin.default -s -D - | grep -e '^HTTP' -e app-version
    

The output includes the success of the request (the HTTP return code) and the version of the application that responded (in the app-version response header). In this example:

HTTP/1.1 200 OK
app-version: httpbin-0
To send requests from outside the cluster

To configure the release for traffic from outside the cluster, a suitable Istio Gateway is required (for example). When using the Iter8 release chart, set the gateway field to the name of your Gateway. Finally, to send traffic:

(a) In a separate terminal, port-forward the ingress gateway:

kubectl -n istio-system port-forward svc/istio-ingressgateway 8080:80
(b) Send requests using the Host header:
curl -H 'Host: httpbin.default' localhost:8080 -s -D - | grep -e '^HTTP' -e app-version

Deploy candidate

A candidate can deployed by simply adding a second version to the list of versions comprising the application:

cat <<EOF | helm upgrade --install httpbin --repo https://iter8-tools.github.io/iter8 release --version 1.1 -f -
environment: deployment-istio
application: 
  versions:
  - metadata:
      labels:
        app.kubernetes.io/version: v0
    image: kennethreitz/httpbin
  - metadata:
      labels:
        app.kubernetes.io/version: v1
    image: kennethreitz/httpbin
  strategy: canary
EOF
About the candidate version

In this tutorial, the candidate image is the same as the one for the primary version. In a real world example, it would be different. The version label (app.kubernetes.io/version) can be used to distinguish between versions.

When the candidate version is ready, the Iter8 controller will Iter8 will automatically reconfigure the routing so that requests with the header traffic set to test will be sent to the candidate model:

HTTP/1.1 200 OK
app-version: httpbin-1

All other requests will be sent to the primary model (httpbin-0):

HTTP/1.1 200 OK
app-version: httpbin-0

Verify routing

You can verify the routing configuration by inspecting the VirtualService and/or by sending requests as described above. Those with header traffic set to test will be handled by the candidate model (httpbin-1) while all others will be handled by the primary version.

Promote candidate

The candidate can be promoted by redefining the primary version and removing the candidate:

cat <<EOF | helm upgrade --install httpbin --repo https://iter8-tools.github.io/iter8 release --version 1.1 -f -
environment: deployment-istio
application: 
  versions:
  - metadata:
      labels:
        app.kubernetes.io/version: v1
    image: kennethreitz/httpbin
  strategy: canary
EOF
What is different?

The version label (app.kubernetes.io/version) of the primary version was updated. In a real world example, the image would also have been updated (with that from the candidate version).

Once the (reconfigured) primary version ready, the Iter8 controller will automatically reconfigure the routing to send all requests to it.

Verify routing

You can verify the routing configuration by inspecting the VirtualService and/or by sending requests as described above. They will all be handled by the primary version. Output will be something like:

HTTP/1.1 200 OK
app-version: httpbin-0

Cleanup

Delete the application and its routing configuration:

helm delete httpbin

If you used the sleep pod to generate load, remove it:

kubectl delete deploy sleep

Uninstall Iter8 controller:

helm delete iter8

For additional uninstall options, see Iter8 Uninstall.