Canary deployments for cloud-native apps with Citrix Ingress Controller
Author: Bharathi M
You work hard to mitigate the risks involved in delivering your applications. But despite all the automation, monitoring, alerts, notifications, and code review, sometimes things go wrong. You can’t always prevent issues from arising, but you can mitigate the risks with the strategy you choose for deploying updates to an application in a production environment.
In this blog post, we’ll look at canary deployments for cloud native applications and how Citrix Ingress Controller (CIC) can help to ensure you can deliver a great end-user experience, even while you’re making significant updates to your applications in a production environment.
What Are Canary Deployments?
A canary deployment involves deploying new versions of an app in phased, incremental steps. The purpose? You’re deploying these changes to a small set of users first so you can identify and correct any issues and determine whether you’re ready to roll out the deployment to your entire user base.
Canary deployments have many benefits, including:
- Reduced risk associated with software releases
- Simpler steps to execute
- Easy to automate
- Doesn’t create downtime
- Reduces the deployment cycle length by supporting earlier, more frequent product deployments
- Doesn’t disrupt the running application or the production environment
How Does a Canary Deployment Work?
A canary deployment has three stages. First you deploy the new version of your canary services to a small percentage of your users. Then you evaluate the canary deployment by collecting feedback from users, monitoring the errors, performance, and metrics using tools like Prometheus and Grafana. Finally, as you get comfortable with the evaluation results from your canary services, you can gradually migrate more and more users to the canary version.
Citrix Ingress Controller for Canary Deployments in Kubernetes
When you run the canary and production versions of an application in parallel, the traffic controlling mechanism is responsible for:
- Avoiding interruption to the service. For example, when a new version appears to misbehave, you can quickly divert traffic to the production version.
- Allowing percentage-based control (some percentage of the traffic is directed to the new version) and client-dependent control (traffic based on HTTP headers such as User-Agent and Referrer is directed to the new version).
- Ensuring that all HTTP requests from a client is directed to the same version-based traffic-control configuration.
Let’s look at how to achieve canary-based traffic routing at the ingress level using Citrix Ingress Controller (CIC). With CIC, the user must define an additional ingress object with canary annotations to indicate that the application requests need to be served based on canary type. The canary types you can configure using CIC are, by priority order, canary by header value; canary by header; and canary by weight.
Please note, if an ingress with canary-by-header value annotation is defined without canary by header, the canary deployment will not be considered.
Canary by Weight
Weight-based canary deployment is a widely used canary deployment approach. Here, you can set the weight from 0 to 100. That determines the percentage of traffic directed to the canary version (and the production version) of an application.
You can begin with the weight set to 0, which means no traffic is forwarded to the canary version. After you start your canary deployment you can change the weight so you are directing a percentage of traffic to the canary version. Then, after you’re ready to deploy your canary version to production, simply change the weight to 100 to ensure all the traffic is directed to the new version of your application.
To do this using CIC, create a new ingress with canary annotation “ingress.citrix.com/canary-weight:” and include the percentage of traffic to be directed to the canary version. Let’s consider an example guestbook application and deploy the application using the following deployment, service, and ingress YAMLs:
kubectl apply –f guestbook-deployment.yaml
deployment.extensions “guestbook” created
kubectl apply –f guestbook-service.yaml
service “guestbook” created
kubectl apply –f guestbook-ingress.yaml
ingress.extensions “guestbook” created
The production version of our guestbook service is now running.
Next, we’ll deploy the canary version of the same service using the following YAMLs:
kubectl apply –f canary-deployment.yaml
deployment.extensions “guestbook-canary” created
kubectl apply –f canary-service.yaml
service “guestbook-canary” created
kubectl apply –f canary-ingress.yaml
ingress.extensions “canary-by-weight” created
********canary-ingress.yaml*********apiVersion: extensions/v1beta1kind: Ingressmetadata: name: canary-by-weight annotations: kubernetes.io/ingress.class: "citrix" ingress.citrix.com/canary-weight: "10"spec: rules: - host: webapp.com http: paths: - path: / backend: serviceName: guestbook-canary servicePort: 80
Here, ingress.citrix.com/canary-weight: “10” tells the CIC to configure NetScaler ADC so that 10 percent of total requests destined to webapp.com go to guestbook-canary service (the canary version of our guestbook application).
Canary by Header
We can also use HTTP request headers to achieve our canary deployment. These headers are controlled by the client and notify the ingress to route the request to the service specified in the canary ingress. The request will be routed to the service specified in the canary ingress if the request header contains the value mentioned in the ingress annotation “ingress.citrix.com/canary-by-header:”.
For a canary-by-header deployment using CIC, simply replace the canary annotation “ingress.citrix.com/canary-weight:” with “ingress.citrix.com/canary-by-header:” in the canary-ingress.yaml in our above example.
Canary by Header Value
A canary-by-header-value approach helps us to achieve our canary deployment using the value of the HTTP request header. Along with the request header from the canary ingress annotation ( “ingress.citrix.com/canary-by-header:”), when the request header value matches the value specified in the ingress annotation “ingress.citrix.com/canary-by-header-value:”, the request will be routed to the service specified in the canary Ingress.
For a canary-by-header-value-based deployment using CIC, just replace the canary annotation “ingress.citrix.com/canary-weight:” with “ingress.citrix.com/canary-by-header:” and “ingress.citrix.com/canary-by-header-value:” in the canary-ingress.yaml shown in our example above.
Canary deployments provide the flexibility you need to support deployment of your cloud-native apps. When you combine a canary deployment strategy with a fast CI/CD workflow, you end up with a productive, feature-rich release cycle that helps you deliver a great user experience. Take a look at these examples and try your own canary deployment using CIC. And check out our blog post on using NetScaler ADC to implement canary deployments for your applications.