Creating Canary Resources with Flagger
In this lesson, we will learn how to create canary resources with Flagger.
Let’s say we want to deploy our new release only to 20% of the users and that we will monitor metrics for 60 seconds. During that period, we’ll be validating whether the error rate is within a predefined threshold and whether the time it takes to process requests is within some limits. If everything seems right, we’ll increase the percentage of users who can use our new release for another 20%, and continue monitoring metrics to decide whether to proceed. The process should repeat until the new release is rolled out to everyone, twenty percent at a time every thirty seconds.
Now that we have a general idea of what we want to accomplish and that all the tools are set up, all that’s missing is to create Flagger Canary
definition.
Fortunately, canary deployments with Flagger are available in Jenkins X build packs since January 2020. So, there’s not much work to do to convert our application to use the canary deployment process.
The Canary
resource definition #
Let’s take a look at the Canary
resource definition already available in our project.
cat charts/jx-progressive/templates/canary.yaml
The output is as follows.
{{- if .Values.canary.enabled }}apiVersion: flagger.app/v1alpha3kind: Canarymetadata:name: {{ template "fullname" . }}labels:draft: {{ default "draft-app" .Values.draft }}chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}"spec:provider: istiotargetRef:apiVersion: apps/v1kind: Deploymentname: {{ template "fullname" . }}progressDeadlineSeconds: {{ .Values.canary.progressDeadlineSeconds }}{{- if .Values.hpa.enabled }}autoscalerRef:apiVersion: autoscaling/v2beta1kind: HorizontalPodAutoscalername: {{ template "fullname" . }}{{- end }}service:port: {{ .Values.service.externalPort }}targetPort: {{ .Values.service.internalPort }}gateways:- {{ template "fullname" . }}hosts:- {{ .Values.canary.host }}analysis:interval: {{ .Values.canary.canaryAnalysis.interval }}threshold: {{ .Values.canary.canaryAnalysis.threshold }}maxWeight: {{ .Values.canary.canaryAnalysis.maxWeight }}stepWeight: {{ .Values.canary.canaryAnalysis.stepWeight }}metrics:- name: request-success-ratethreshold: {{ .Values.canary.canaryAnalysis.metrics.requestSuccessRate.threshold }}interval: {{ .Values.canary.canaryAnalysis.metrics.requestSuccessRate.interval }}- name: request-durationthreshold: {{ .Values.canary.canaryAnalysis.metrics.requestDuration.threshold }}interval: {{ .Values.canary.canaryAnalysis.metrics.requestDuration.interval }}---apiVersion: networking.istio.io/v1alpha3kind: Gatewaymetadata:name: {{ template "fullname" . }}spec:selector:istio: ingressgatewayservers:- port:number: {{ .Values.service.externalPort }}name: httpprotocol: HTTPhosts:- {{ .Values.canary.host }}{{- end }}
canary.enabled
The whole definition is inside an if
statement so that Canary
is created only if the value canary.enabled
is set to true
. That way, by default, we will not use canary deployments at all. Instead, we’ll have to specify when and under which circumstances they will be created. That might spark the question “why do we go into the trouble of making sure that canary deployments are enabled only in certain cases?” Why not use them always?
By their nature, it takes much more time to execute a canary deployment than most of the other strategies. The canaries roll out progressively and are pausing periodically to allow us to validate the result on a subset of users. That increased duration can be anything from seconds to hours or even days or weeks. In some cases, we might have an important release that we want to test with our users progressively over a ...