[Canary Deployment] How to skip the Canary Phase in a Canary Workflow

Howdy Everyone :vulcan_salute:

Harness.io

Introduction

We have no doubt that Harness is the best CD platform in the universe and makes our deployment life easier for Kubernetes environments and proof of this is the ease and simplicity with which we can create a Canary deployment.

The point is that for Canary deployments, Harness only puts the label and selector below when the Canary phase is executed:

harness.io/track: stable

So, if the Canary phase is skipped then Harness does not add this label and selector to it, which causes failure because Kubernetes doesn’t allow selectors to be changed after the first deployment that creates the resources.

Let’s see how Harness can overcome the current design and conditionally skipping a Canary Phase of a Canary deployment.

Tutorial

Requirements

In this article we won’t have much complexity, the only requirement is a Workflow Canario and any service that will be deployed by it.

First Step

Let’s create our Service! In the service is where the magic is to enable the skip management of the canary phase, let’s add conditional logic for adding the selector that is automatically added when the canary phase is executed.

This is the conditional we’re going to use in our deployment:

{{- if .Values.skipCanary}}
        harness.io/track: stable
{{- end}} 

This is the full Deployment we’re going to use adding the conditionals

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{.Values.name}}-deployment
spec:
  replicas: {{int .Values.replicas}}
  selector:
    matchLabels:
      app: {{.Values.name}}
{{- if .Values.skipCanary}}
      harness.io/track: stable
{{- end}}
  template:
    metadata:
      labels:
        app: {{.Values.name}}
{{- if .Values.skipCanary}}
        harness.io/track: stable
{{- end}}
    spec:
      {{- if .Values.dockercfg}}
      imagePullSecrets:
      - name: {{.Values.name}}-dockercfg
      {{- end}}
      containers:
      - name: {{.Values.name}}
        image: {{.Values.image}}
        args:
        - -text="hello world"
        {{- if or .Values.env.config .Values.env.secrets}}
        envFrom:
        {{- if .Values.env.config}}
        - configMapRef:
            name: {{.Values.name}}
        {{- end}}
        {{- if .Values.env.secrets}}
        - secretRef:
            name: {{.Values.name}}
        {{- end}}
        {{- end}}

This is the complete values.yaml that we’re going to use in our manifest

name: harness-example
replicas: 1

dockercfg: ${artifact.source.dockerconfig}
image: hashicorp/http-echo:${artifact.buildNo}

createNamespace: true
namespace: ${infra.kubernetes.namespace}
skipCanary: ${workflow.variables.skipCanary}

# Service Type allow you to specify what kind of service you want.
# Possible values for ServiceType are:
# ClusterIP | NodePort | LoadBalancer | ExternalName
serviceType: LoadBalancer

# A Service can map an incoming port to any targetPort.
# targetPort is where application is listening on inside the container.
servicePort: 80
serviceTargetPort: 5678

# Specify all environment variables to be added to the container.
# The following two maps, config and secrets, are put into a ConfigMap
# and a Secret, respectively.
# Both are added to the container environment in podSpec as envFrom source.
env:
  config:
    key1: value1
  secrets:
    key2: value2

Second Step

Let’s create an environment where our service will be deployed, there’s no secret here, basically, you define your target deployment infrastructure using a Harness Environment. Environments represent your deployment infrastructures, such as Dev, QA, Stage, Production, etc.

Third Step

Finally let’s now create our Canary Workflow and Add two Phases under the Deployment Phases, Canary and Primary. The Canary Phase creates a Canary deployment using your Service Manifests files and the number of pods you specify in the Workflow’s Canary Deployment step and The Primary Phase runs the actual deployment as a rolling update with the number of pods you specify in the Service Manifests files.

Along with the steps we will also create a Required workflow variable called skipCanary.

Fourth Step

Now let’s access our Canary phase and add the conditional skip to all its steps:

Just stressing that all steps of the Canary phase must be conditionally skipped by the same query

Fifth Step

Now that everything is fine, we can fire up our workflow without worrying about skipping issues related to the Canary step anymore.

Workflow execution with the skip of the canary phase and the correct addition of the label

Outcome

So basically, the suggestion here is to use the same condition that is used for the skip condition to conditionally put the selector and label into the manifest. That way they get the same rendered manifest whether they skip the canary phase or not, which is exactly what we want.

This is a general solution to skipping the canary phase and will not cause any adverse effects.


Now you can start exploring more possibilities with Harness and the Canary Deployments :rocket:

2 Likes