In this article, we will learn how to automate Blue/Green Deployment with Argo Rollouts.
Argo Rollouts
Argo Rollouts is a Kubernetes Controller and set of Custom Resource Definitions (CRDs) that provide advanced features for application deployment on Kubernetes compared to the native Kubernetes Deployment Object.
Argo Rollouts provide deployment capabilities such as blue-green, canary, canary analysis, experimentation, and progressive delivery features to Kubernetes.
Because Argo Rollouts are a set of CRDs, we need to install them into the Kubernetes Cluster. Run the following commands to install Argo Rollouts.
1 2 3 4 | kubectl create namespace argo-rollouts namespace/argo-rollouts created |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml customresourcedefinition.apiextensions.k8s.io/analysisruns.argoproj.io created customresourcedefinition.apiextensions.k8s.io/analysistemplates.argoproj.io created customresourcedefinition.apiextensions.k8s.io/clusteranalysistemplates.argoproj.io created customresourcedefinition.apiextensions.k8s.io/experiments.argoproj.io created customresourcedefinition.apiextensions.k8s.io/rollouts.argoproj.io created serviceaccount/argo-rollouts created clusterrole.rbac.authorization.k8s.io/argo-rollouts created clusterrole.rbac.authorization.k8s.io/argo-rollouts-aggregate-to-admin created clusterrole.rbac.authorization.k8s.io/argo-rollouts-aggregate-to-edit created clusterrole.rbac.authorization.k8s.io/argo-rollouts-aggregate-to-view created clusterrolebinding.rbac.authorization.k8s.io/argo-rollouts created secret/argo-rollouts-notification-secret created service/argo-rollouts-metrics created deployment.apps/argo-rollouts created |
Check if we installed it successfully.
1 2 | kubectl get pod -n argo-rollouts |
1 2 3 | NAME READY STATUS RESTARTS AGE argo-rollouts-76fcfc8d7f-k6mth 1/1 Running 0 58s |
Argo Rollouts Deployment Strategy
To use Argo Rollouts, we declare a resource with the apiVersion attribute as argoproj.io/v1alpha1
and the kind as Rollout
, like below:
1 2 3 | <span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> argoproj.io/v1alpha1 <span class="token key atrule">kind</span><span class="token punctuation">:</span> Rollout |
The configuration of Argo Rollouts has a strategy property for us to choose the deployment strategy we want, with two values of blueGreenand canary.
See detail here Rollout Specification. Don’t try to understand all properties for now.
In this article, we will learn about blue/green.
Practice
I use Minikube to run Kubernetes Cluster for the demo. Create a file named bluegreen-rollout.yaml
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> argoproj.io/v1alpha1 <span class="token key atrule">kind</span><span class="token punctuation">:</span> Rollout <span class="token key atrule">metadata</span><span class="token punctuation">:</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">labels</span><span class="token punctuation">:</span> <span class="token key atrule">app</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">spec</span><span class="token punctuation">:</span> <span class="token key atrule">replicas</span><span class="token punctuation">:</span> <span class="token number">2</span> <span class="token key atrule">revisionHistoryLimit</span><span class="token punctuation">:</span> <span class="token number">1</span> <span class="token key atrule">selector</span><span class="token punctuation">:</span> <span class="token key atrule">matchLabels</span><span class="token punctuation">:</span> <span class="token key atrule">app</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">template</span><span class="token punctuation">:</span> <span class="token key atrule">metadata</span><span class="token punctuation">:</span> <span class="token key atrule">labels</span><span class="token punctuation">:</span> <span class="token key atrule">app</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">spec</span><span class="token punctuation">:</span> <span class="token key atrule">containers</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">image</span><span class="token punctuation">:</span> argoproj/rollouts<span class="token punctuation">-</span>demo<span class="token punctuation">:</span>green <span class="token key atrule">imagePullPolicy</span><span class="token punctuation">:</span> Always <span class="token key atrule">ports</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> http <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">8080</span> <span class="token key atrule">protocol</span><span class="token punctuation">:</span> TCP <span class="token key atrule">strategy</span><span class="token punctuation">:</span> <span class="token key atrule">blueGreen</span><span class="token punctuation">:</span> <span class="token key atrule">autoPromotionEnabled</span><span class="token punctuation">:</span> <span class="token boolean important">false</span> <span class="token key atrule">activeService</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">previewService</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo<span class="token punctuation">-</span>preview |
All properties of Rollout are the same as a native Deployment Object, only the strategy attribute is different. In the file above, we declare 3 properties:
autoPromotionEnabled: false
– Indicates if the rollout should automatically promote the new ReplicaSet to the active service or enter a paused state. If not specified, the default value is true.activeService: bluegreen-demo
– Reference to service that the rollout modifies as the active service.previewService: bluegreen-demo-preview
– Name of the service that the rollout modifies as the preview service.
Next, we create a file named service.yaml
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1 <span class="token key atrule">kind</span><span class="token punctuation">:</span> Service <span class="token key atrule">metadata</span><span class="token punctuation">:</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">labels</span><span class="token punctuation">:</span> <span class="token key atrule">app</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">spec</span><span class="token punctuation">:</span> <span class="token key atrule">type</span><span class="token punctuation">:</span> NodePort <span class="token key atrule">selector</span><span class="token punctuation">:</span> <span class="token key atrule">app</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">ports</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">80</span> <span class="token key atrule">targetPort</span><span class="token punctuation">:</span> http <span class="token key atrule">protocol</span><span class="token punctuation">:</span> TCP <span class="token key atrule">name</span><span class="token punctuation">:</span> http <span class="token punctuation">---</span> <span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1 <span class="token key atrule">kind</span><span class="token punctuation">:</span> Service <span class="token key atrule">metadata</span><span class="token punctuation">:</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo<span class="token punctuation">-</span>preview <span class="token key atrule">labels</span><span class="token punctuation">:</span> <span class="token key atrule">app</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">spec</span><span class="token punctuation">:</span> <span class="token key atrule">type</span><span class="token punctuation">:</span> NodePort <span class="token key atrule">selector</span><span class="token punctuation">:</span> <span class="token key atrule">app</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">ports</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">80</span> <span class="token key atrule">targetPort</span><span class="token punctuation">:</span> http <span class="token key atrule">protocol</span><span class="token punctuation">:</span> TCP <span class="token key atrule">name</span><span class="token punctuation">:</span> http |
The two Services properties are the same except for the name property. Next, we create a Rollout Object.
1 2 3 4 | kubectl apply -f bluegreen-rollout.yaml rollout.argoproj.io/bluegreen-demo created |
1 2 3 4 5 | kubectl get rollout NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE bluegreen-demo 2 2 2 2 30s |
When we create a Rollout, the Argo Rollouts implicit create a ReplicaSet for a current revision. Let’s check:
1 2 3 4 5 | kubectl get rs NAME DESIRED CURRENT READY AGE bluegreen-demo-fbc7b7f55 2 2 2 4m37s |
1 2 3 4 5 6 | kubectl get pod NAME READY STATUS RESTARTS AGE bluegreen-demo-fbc7b7f55-g6fst 1/1 Running 0 37s bluegreen-demo-fbc7b7f55-vvdth 1/1 Running 0 37s |
Ensure that Replica Set and Pod are running, next, we create a Service.
1 2 3 4 5 | kubectl apply -f service.yaml service/bluegreen-demo created service/bluegreen-demo-preview created |
At this time, both the bluegreen-demo
and bluegreen-demo-preview
are pointing to the same ReplicaSet as bluegreen-demo-fbc7b7f55
.
Let’s test, we run the following commands to get the URL of both services.
1 2 3 | minikube service bluegreen-demo --url 172.26.123.245:30000 |
1 2 3 | minikube service bluegreen-demo-preview --url 172.26.123.245:30001 |
Open the browser, we will see the UI below.
Now, we change the image
property of Rollout Object.
1 2 3 4 5 6 7 | <span class="token punctuation">...</span> <span class="token key atrule">spec</span><span class="token punctuation">:</span> <span class="token key atrule">containers</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">image</span><span class="token punctuation">:</span> argoproj/rollouts<span class="token punctuation">-</span>demo<span class="token punctuation">:</span>blue <span class="token punctuation">...</span> |
Updating Rollout Object.
1 2 3 4 | kubectl apply -f bluegreen-rollout.yaml rollout.argoproj.io/bluegreen-demo configured |
At this point, Argo Rollouts will create a new ReplicaSet for the new configuration.
1 2 3 4 5 | kubectl get rs bluegreen-demo-7d6459646d 2 2 2 2m11s bluegreen-demo-fbc7b7f55 2 2 2 41m |
1 2 3 4 5 6 7 8 | kubectl get pod NAME READY STATUS RESTARTS AGE bluegreen-demo-7d6459646d-2zm56 1/1 Running 0 2m13s bluegreen-demo-7d6459646d-xz9bj 1/1 Running 0 2m13s bluegreen-demo-fbc7b7f55-g6fst 1/1 Running 0 41m bluegreen-demo-fbc7b7f55-vvdth 1/1 Running 0 41m |
Then the bluegreen-demo-preview
service is modified to point to the new ReplicaSet. Accessing the preview service address will see a different UI.
And the bluegreen-demo
service does not change.
After we check the new ReplicaSet and see that all is well, next, we promote the new revision of ReplicaSet by updating the bluegreen-demo
service to point to it, we run the following command (don’t follow, we will use another way).
1 2 3 4 | kubectl argo rollouts promote bluegreen-demo rollout 'bluegreen-demo' promoted |
Now, Argo Rollouts update the bluegreen-demo
service to point to the new ReplicaSet, after waiting (default 30 seconds), the old ReplicaSet is scaled down.
UI Dashboard
In my opinion, DevOps Engineers should not do the work “promotes” the new ReplicaSet, our task is just to build the CI/CD so that the Rollout can be updated when a new version of the application is available. Leave it to QC Engineer.
But QC can’t run CLI so we need to have a dashboard for QC to do this. Fortunately, Argo Rollout provides us with a dashboard, which we can enable using kubectl or using quay.io/argoproj/kubectl-argo-rollouts
container image.
1 2 3 4 | kubectl argo rollouts dashboard INFO[0000] Argo Rollouts Dashboard is now available at localhost 3100 |
Go to localhost:3100
we will see the dashboard of Argo Rollouts.
Choose to bluegreen-demo
.
You will see the Promote button, the person who clicks this button will be the QC, if anything is wrong, the QC will be responsible =)))), let’s click on the promote button.
Click Sure.
Now you access both the bluegreen-demo
and the bluegreen-demo-preview
service we will see the same UI.
Ingress
Ingress configuration for public access if you need.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> networking.k8s.io/v1beta1 <span class="token key atrule">kind</span><span class="token punctuation">:</span> Ingress <span class="token key atrule">metadata</span><span class="token punctuation">:</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">annotations</span><span class="token punctuation">:</span> <span class="token key atrule">ingress.kubernetes.io/proxy-body-size</span><span class="token punctuation">:</span> 100M <span class="token key atrule">kubernetes.io/ingress.class</span><span class="token punctuation">:</span> nginx <span class="token key atrule">ingress.kubernetes.io/app-root</span><span class="token punctuation">:</span> / <span class="token key atrule">spec</span><span class="token punctuation">:</span> <span class="token key atrule">rules</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">host</span><span class="token punctuation">:</span> blue<span class="token punctuation">-</span>green.example.com <span class="token key atrule">http</span><span class="token punctuation">:</span> <span class="token key atrule">paths</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">path</span><span class="token punctuation">:</span> / <span class="token key atrule">backend</span><span class="token punctuation">:</span> <span class="token key atrule">serviceName</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo <span class="token key atrule">servicePort</span><span class="token punctuation">:</span> <span class="token number">80</span> <span class="token punctuation">---</span> <span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> networking.k8s.io/v1beta1 <span class="token key atrule">kind</span><span class="token punctuation">:</span> Ingress <span class="token key atrule">metadata</span><span class="token punctuation">:</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo<span class="token punctuation">-</span>preview <span class="token key atrule">annotations</span><span class="token punctuation">:</span> <span class="token key atrule">ingress.kubernetes.io/proxy-body-size</span><span class="token punctuation">:</span> 100M <span class="token key atrule">kubernetes.io/ingress.class</span><span class="token punctuation">:</span> nginx <span class="token key atrule">ingress.kubernetes.io/app-root</span><span class="token punctuation">:</span> / <span class="token key atrule">spec</span><span class="token punctuation">:</span> <span class="token key atrule">rules</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">host</span><span class="token punctuation">:</span> blue<span class="token punctuation">-</span>green<span class="token punctuation">-</span>preview.example.com <span class="token key atrule">http</span><span class="token punctuation">:</span> <span class="token key atrule">paths</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">path</span><span class="token punctuation">:</span> / <span class="token key atrule">backend</span><span class="token punctuation">:</span> <span class="token key atrule">serviceName</span><span class="token punctuation">:</span> bluegreen<span class="token punctuation">-</span>demo<span class="token punctuation">-</span>preview <span class="token key atrule">servicePort</span><span class="token punctuation">:</span> <span class="token number">80</span> |
Done.
Conclusion
So we have learned how to automate Blue/Green Deployment with Argo Rollouts, as you can see, it’s also simple. If you have any questions or need further clarification, you can ask in the comment section below.