Canary Deployment in Kubernetes #2: Argo Rollouts

We will use the k8s-native deployment controller Argo Rollouts and GitlabCI to launch a Canary deployment in Kubernetes

Canary Deployment in Kubernetes #2: Argo Rollouts

https://unsplash.com/photos/V41PulGL1z0

Articles in this series

Canary Deployment

We hope you read the first part, where we briefly explained what Canary Deployments are. We also showed how to implement it using standard Kubernetes resources.

Argo Rollouts

Argo Rollouts is a Kubernetes-native deployment controller. It provides a CRD (Custom Resource Definition) for Kubernetes. With it, we can use a new entity: Rollout, which manages blue-green and canary deployments with various configuration options.

The Argo Rollouts controller, using the custom resource Rollout, allows for additional deployment strategies like blue-green and canary for Kubernetes. The resource Rollout provides functionality equivalent to Deployment, just with additional deployment strategies.
The resource Deployments has two strategies for deployment: RollingUpdate and Recreate. Although these strategies are suitable for most cases, additional strategies like blue-green or canary, which are not available in the Deployment controller, are used for deployments on a very large scale. To use these strategies in Kubernetes, users had to write scripts on top of their Deployments. The Argo Rollouts controller provides these strategies as simple declarative configurable parameters.
https://argoproj.github.io/argo-rollouts

There is also Argo CI, which provides a convenient web interface to use alongside Rollouts; we will take a look at it in the next article.

Installing Argo Rollouts

On the server side

kubectl create namespace argo-rollouts kubectl apply -n argo-rollouts -f https://raw.githubusercontent.com/argoproj/argo-rollouts/stable/manifests/install.yaml

In our infrastructure repo (see below), we have already added install.yaml as i/k8s/argo-rollouts/install.yaml. Thus GitlabCI will install it in the cluster.

On the client side (kubectl plugin)

https://argoproj.github.io/argo-rollouts/features/kubectl-plugin

Sample application

A good practice is to have separate repositories for application code and infrastructure.

Repository for the application

Kim Wuestkamp / k8s-deployment-example-app

This is a very simple API in Python+Flask that returns a response in JSON format. We will build a package using GitlabCI and push the result to the Gitlab Registry. We have two different release versions in the registry:

  • wuestkamp/k8s-deployment-example-app:v1
  • wuestkamp/k8s-deployment-example-app:v2

The only difference between them is the returned JSON file. We use this application for the simplest possible visualization of which version we are interacting with.

Infrastructure Repository

In this repository, we will use GitlabCI for deployment to Kubernetes, .gitlab-ci.yml looks as follows:

image: traherom/kustomize-dockerbefore_script:
   - printenv
   - kubectl versionstages:
 - deploydeploy test:
   stage: deploy
   before_script:
     - echo $KUBECONFIG
   script:
     - kubectl get all
     - kubectl apply -f i/k8s    only:
     - master

To run it yourself, you will need a cluster, Gcloud can be used:

gcloud container clusters create canary --num-nodes 3 --zone europe-west3-b
gcloud compute firewall-rules create incoming-80 --allow tcp:80

You need to make a fork https://gitlab.com/wuestkamp/k8s-deployment-example-canary-infrastructure and create a variable KUBECONFIG in GitlabCI, which will contain the config for access kubectl to your cluster.

Here You can read about how to obtain credentials for the cluster (Gcloud).

Infrastructure Yaml

Inside the infrastructure repository, we have a service:

apiVersion: v1
kind: Service
metadata:
 labels:
   id: rollout-canary
 name: app
spec:
 ports:
 - port: 80
   protocol: TCP
   targetPort: 5000
 selector:
   id: app
 type: LoadBalancer

and rollout.yaml :

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
 name: rollout-canary
spec:
 replicas: 10
 revisionHistoryLimit: 2
 selector:
   matchLabels:
     id: rollout-canary
 template:
   metadata:
     labels:
       id: rollout-canary
   spec:
     containers:
     - name: rollouts-demo
       image: registry.gitlab.com/wuestkamp/k8s-deployment-example-app:v1
       imagePullPolicy: Always
 strategy:
   canary:
     steps:
     - setWeight: 10
     # Rollouts can be manually resumed by running `kubectl argo rollouts promote ROLLOUT`
     - pause: {}
     - setWeight: 50
     - pause: { duration: 120 } # two minutes

Rollout Works similarly to a Deployment. If we do not specify an update strategy (like canary here), it will behave like the default rolling-update Deployment.

We define two steps in the yaml for canary deployment:

  1. 10% traffic to canary (wait for manual OK)
  2. 50% traffic to canary (wait 2 minutes then continue to 100%)

Executing the initial deployment

After the initial deployment, our resources will look like this:

Canary Deployment in Kubernetes #2: Argo Rollouts

And we get a response only from the first version of the application:

Canary Deployment in Kubernetes #2: Argo Rollouts

Executing Canary Deployment

Step 1: 10% traffic

To begin the canary deployment, we simply need to change the image version, just as we usually do with deployments:

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
 name: rollout-canary
spec:
...
 template:
   metadata:
     labels:
       id: rollout-canary
   spec:
     containers:
     - name: rollouts-demo
       image: registry.gitlab.com/wuestkamp/k8s-deployment-example-app:v2
...

And we push the changes, so Gitlab CI performs the deployment and we see the changes:

Canary Deployment in Kubernetes #2: Argo Rollouts

Now, if we call the service:

Canary Deployment in Kubernetes #2: Argo Rollouts

Great! We're in the middle of our canary deployment. We can see the progress by running:

kubectl argo rollouts get rollout rollout-canary

Canary Deployment in Kubernetes #2: Argo Rollouts

Step 2: 50% traffic:

Now we move on to the next step: redirecting 50% of the traffic. We've set this step to be initiated manually:

kubectl argo rollouts promote rollout-canary # continue to step 2

Canary Deployment in Kubernetes #2: Argo Rollouts

And our application returned 50% responses from the new versions:

Canary Deployment in Kubernetes #2: Argo Rollouts

And the rollout overview:

Canary Deployment in Kubernetes #2: Argo Rollouts

Excellent.

Step 3: 100% traffic:

We've configured it so that after 2 minutes, the 50% step automatically completes and the 100% step begins:

Canary Deployment in Kubernetes #2: Argo Rollouts

And the application output:

Canary Deployment in Kubernetes #2: Argo Rollouts

And the rollout overview:

Canary Deployment in Kubernetes #2: Argo Rollouts

Canary deployment completed.

More examples with Argo Rollouts

Here are more examples, such as setting up environment previews and comparisons based on canary:

https://github.com/argoproj/argo-rollouts/tree/master/examples

Video on Argo Rollouts and Argo CI

I really recommend this video; it shows how Argo Rollouts and Argo CI work together:

Play video

Summary

I really like the idea of using CRDs that manage the creation of additional types of deployments or replicasets, redirect traffic, etc. Working with them goes smoothly. Next, I would like to test the integration with Argo CI.

However, it seems that a major merge of Argo CI and Flux CI is coming, so I might wait until the new release: Argo Flux.

Have you had experience with Argo Rollouts or Argo CI?

Also, read other articles in our blog:

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers 🔥 Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster