Canary Deployment in Kubernetes #2: Argo Rollouts

We will be using k8s native deployment controller Argo Rollouts and GitlabCI to run a Canary deployment to 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 CRD (Custom Resource Definition) for Kubernetes. Thanks to him, we can use the new entity: Rollout, which manages blue-green and canary deployments with various customization options.

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

There is also Argo CI which provides a nice web interface to use with Rollouts, we'll take a look at it in the next article.

Installing Argo Rollouts

Server Side

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

In our infrastructure turnip (see below), we have already added install.yaml as i/k8s/argo-rollouts/install.yaml. This way GitlabCI will install it on the cluster.

Client side (kubectl plugin)

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

Example Application

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

Application repository

Kim Wuestkamp/k8s-deployment-example-app

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

  • 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 app to visualize as easily as possible which version we are talking to.

infrastructure repository

In this repository we will be using GitlabCI to deploy to Kubernetes, .gitlab-ci.yml looks like this:

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 need a cluster, you can use Gcloud:

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 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 get the credentials for the cluster (Gcloud).

Infrastructural 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 the same way as Deployment. If we don't set an update strategy (like canary here) it will behave like the default rolling-update Deployment.

We define two steps in 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%)

Performing an 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 start a canary deployment, we just need to change the version of the image, 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 does deploy 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 are 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 let's move on to the next step: redirecting 50% of the traffic. We have configured this step to be run manually:

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

Canary Deployment in Kubernetes #2: Argo Rollouts

And our app returned 50% responses from new versions:

Canary Deployment in Kubernetes #2: Argo Rollouts

And an overview of rollout:

Canary Deployment in Kubernetes #2: Argo Rollouts

Perfectly.

Step 3: 100% traffic:

We set it up so that after 2 minutes the step with 50% ends automatically and the step starts with 100%:

Canary Deployment in Kubernetes #2: Argo Rollouts

And the application output:

Canary Deployment in Kubernetes #2: Argo Rollouts

And an overview of rollout:

Canary Deployment in Kubernetes #2: Argo Rollouts

Canary deployment completed.

More examples with Argo Rollouts

There are more examples here, such as how to set up environment previews and comparisons based on canary:

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

Video about Argo Rollouts and Argo CI

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

Сonclusion

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, there appears to be a big merger between Argo CI and Flux CI, so I might wait until a new release comes out: Argo Flux.

Have you had any experience with Argo Rollouts or Argo CI?

Also read other articles on our blog:

Source: habr.com

Add a comment