8 min read | by Jordi Prats
Argo Rollouts is a Kubernetes controller and set of CRDs for progressive delivery. It can be used to orchestrate blue-green deployments, canary releases, and rollouts. We are going to take a look at how to use Argo Rollouts to perform a blue-green deployment.
You can also checkout canary deployments with Argo Rollouts.
First we'll have to make sure we have Argo Rollouts and it's CLI installed. In a nutshell, we can install it using kustomize
and brew
as follows:
kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
brew install argoproj/tap/kubectl-argo-rollouts
To get started with a blue-green deployment, we'll start with a regular Deployment object that we'll use as the base for our blue-green deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-deploy
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
To transform it into a blue-green rollout we will only need to change the apiVersion, kind and set the strategy to blueGreen:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: bg-rollout
spec:
replicas: 2
selector:
matchLabels:
app: bg-rollout
template:
metadata:
labels:
app: bg-rollout
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
strategy:
blueGreen:
previewService: rollout-preview
activeService: rollout-active
Before applying the blue-green rollout we'll have to create the preview and active services:
apiVersion: v1
kind: Service
metadata:
name: rollout-preview
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: bg-rollout
---
apiVersion: v1
kind: Service
metadata:
name: rollout-active
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: bg-rollout
As soon as we apply all these three objects we'll be able to see the blue-green rollout acting very similar to other Deployment objects:
$ kubectl describe rollout.argoproj.io/bg-rollout
Name: bg-rollout
Namespace: demo-rollout
Labels: <none>
Annotations: rollout.argoproj.io/revision: 1
API Version: argoproj.io/v1alpha1
Kind: Rollout
(...)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal RolloutAddedToInformer 12m rollouts-controller Rollout resource added to informer: demo-rollout/bg-rollout
Normal RolloutUpdated 27s rollouts-controller Rollout updated to revision 1
Normal NewReplicaSetCreated 27s rollouts-controller Created ReplicaSet bg-rollout-7f56bd89fc (revision 1)
Normal SwitchService 27s rollouts-controller Switched selector for service 'rollout-preview' from '' to '7f56bd89fc'
Normal ScalingReplicaSet 17s rollouts-controller Scaled up ReplicaSet bg-rollout-7f56bd89fc (revision 1) from 0 to 2
Normal RolloutCompleted 17s rollouts-controller Rollout completed update to revision 1 (7f56bd89fc): Initial deploy
Normal SwitchService 14s rollouts-controller Switched selector for service 'rollout-active' from '' to '7f56bd89fc'
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
bg-rollout-7f56bd89fc-4h7b7 1/1 Running 0 20s
bg-rollout-7f56bd89fc-vk5b7 1/1 Running 0 20s
We can now update the deployment to see how it will automatically switch the traffic between replicas:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: bg-rollout
spec:
replicas: 2
selector:
matchLabels:
app: bg-rollout
template:
metadata:
labels:
app: bg-rollout
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
env:
- name: UPDATE
value: "EXAMPLE"
strategy:
blueGreen:
previewService: rollout-preview
activeService: rollout-active
Once applied, it will automatically create a new ReplicaSet and switch the traffic to it:
$ kubectl describe rollout.argoproj.io/bg-rollout
Name: bg-rollout
Namespace: demo-rollout
Labels: <none>
Annotations: rollout.argoproj.io/revision: 2
API Version: argoproj.io/v1alpha1
Kind: Rollout
(...)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal RolloutAddedToInformer 13m rollouts-controller Rollout resource added to informer: demo-rollout/bg-rollout
Normal RolloutUpdated 2m1s rollouts-controller Rollout updated to revision 1
Normal NewReplicaSetCreated 2m1s rollouts-controller Created ReplicaSet bg-rollout-7f56bd89fc (revision 1)
Normal SwitchService 2m1s rollouts-controller Switched selector for service 'rollout-preview' from '' to '7f56bd89fc'
Normal ScalingReplicaSet 111s rollouts-controller Scaled up ReplicaSet bg-rollout-7f56bd89fc (revision 1) from 0 to 2
Normal RolloutCompleted 111s rollouts-controller Rollout completed update to revision 1 (7f56bd89fc): Initial deploy
Normal SwitchService 108s rollouts-controller Switched selector for service 'rollout-active' from '' to '7f56bd89fc'
Normal RolloutUpdated 4s rollouts-controller Rollout updated to revision 2
Normal NewReplicaSetCreated 4s rollouts-controller Created ReplicaSet bg-rollout-84bc9d88dc (revision 2)
Normal SwitchService 4s rollouts-controller Switched selector for service 'rollout-preview' from '7f56bd89fc' to '84bc9d88dc'
Normal RolloutNotCompleted 4s rollouts-controller Rollout not completed, started update to revision 2 (84bc9d88dc)
Normal ScalingReplicaSet 4s rollouts-controller Scaled up ReplicaSet bg-rollout-84bc9d88dc (revision 2) from 0 to 2
Normal SwitchService 1s rollouts-controller Switched selector for service 'rollout-active' from '7f56bd89fc' to '84bc9d88dc'
Normal RolloutCompleted 1s rollouts-controller Rollout completed update to revision 2 (84bc9d88dc): Completed blue-green update
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
bg-rollout-7f56bd89fc-4h7b7 1/1 Running 0 2m
bg-rollout-7f56bd89fc-vk5b7 1/1 Running 0 2m
bg-rollout-84bc9d88dc-lmvdf 1/1 Running 0 13s
bg-rollout-84bc9d88dc-q2lxr 1/1 Running 0 13s
We can also use the argo rollouts cli to better see the status of the rollout:
$ kubectl argo rollouts get rollout bg-rollout
Name: bg-rollout
Namespace: demo-rollout
Status: ✔ Healthy
Strategy: BlueGreen
Images: nginx:latest (stable, active)
Replicas:
Desired: 2
Current: 2
Updated: 2
Ready: 2
Available: 2
NAME KIND STATUS AGE INFO
⟳ bg-rollout Rollout ✔ Healthy 15m
├──# revision:2
│ └──⧉ bg-rollout-84bc9d88dc ReplicaSet ✔ Healthy 105s stable,active
│ ├──□ bg-rollout-84bc9d88dc-lmvdf Pod ✔ Running 105s ready:1/1
│ └──□ bg-rollout-84bc9d88dc-q2lxr Pod ✔ Running 105s ready:1/1
└──# revision:1
└──⧉ bg-rollout-7f56bd89fc ReplicaSet • ScaledDown 3m42s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
bg-rollout-84bc9d88dc-lmvdf 1/1 Running 0 119s
bg-rollout-84bc9d88dc-q2lxr 1/1 Running 0 119s
To manually promote the preview to active, we'll need to set autoPromotionEnabled to false:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: bg-rollout
spec:
replicas: 2
selector:
matchLabels:
app: bg-rollout
template:
metadata:
labels:
app: bg-rollout
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
env:
- name: UPDATE
value: "MANUAL PROMOTION"
strategy:
blueGreen:
previewService: rollout-preview
activeService: rollout-active
autoPromotionEnabled: false
Once applied it will pause the rollout, for us to manually verify and promote it:
$ kubectl argo rollouts get rollout bg-rollout
Name: bg-rollout
Namespace: demo-rollout
Status: ॥ Paused
Message: BlueGreenPause
Strategy: BlueGreen
Images: nginx:latest (active, preview, stable)
Replicas:
Desired: 2
Current: 4
Updated: 2
Ready: 2
Available: 2
NAME KIND STATUS AGE INFO
⟳ bg-rollout Rollout ॥ Paused 18m
├──# revision:3
│ └──⧉ bg-rollout-7956bb8bb6 ReplicaSet ✔ Healthy 16s preview
│ ├──□ bg-rollout-7956bb8bb6-gvrgj Pod ✔ Running 16s ready:1/1
│ └──□ bg-rollout-7956bb8bb6-sh8wx Pod ✔ Running 16s ready:1/1
├──# revision:2
│ └──⧉ bg-rollout-84bc9d88dc ReplicaSet ✔ Healthy 4m48s stable,active
│ ├──□ bg-rollout-84bc9d88dc-lmvdf Pod ✔ Running 4m48s ready:1/1
│ └──□ bg-rollout-84bc9d88dc-q2lxr Pod ✔ Running 4m48s ready:1/1
└──# revision:1
└──⧉ bg-rollout-7f56bd89fc ReplicaSet • ScaledDown 6m45s
As soon as we are happy with the preview we can promote it as follows:
$ kubectl argo rollouts promote bg-rollout
rollout 'bg-rollout' promoted
After a 30 seconds delay, the preview will be promoted to active:
$ kubectl argo rollouts get rollout bg-rollout
Name: bg-rollout
Namespace: demo-rollout
Status: ✔ Healthy
Strategy: BlueGreen
Images: nginx:latest (active, stable)
Replicas:
Desired: 2
Current: 4
Updated: 2
Ready: 2
Available: 2
NAME KIND STATUS AGE INFO
⟳ bg-rollout Rollout ✔ Healthy 19m
├──# revision:3
│ └──⧉ bg-rollout-7956bb8bb6 ReplicaSet ✔ Healthy 60s stable,active
│ ├──□ bg-rollout-7956bb8bb6-gvrgj Pod ✔ Running 60s ready:1/1
│ └──□ bg-rollout-7956bb8bb6-sh8wx Pod ✔ Running 60s ready:1/1
├──# revision:2
│ └──⧉ bg-rollout-84bc9d88dc ReplicaSet ✔ Healthy 5m32s delay:27s
│ ├──□ bg-rollout-84bc9d88dc-lmvdf Pod ✔ Running 5m32s ready:1/1
│ └──□ bg-rollout-84bc9d88dc-q2lxr Pod ✔ Running 5m32s ready:1/1
└──# revision:1
└──⧉ bg-rollout-7f56bd89fc ReplicaSet • ScaledDown 7m29s
$ kubectl argo rollouts get rollout bg-rollout
Name: bg-rollout
Namespace: demo-rollout
Status: ✔ Healthy
Strategy: BlueGreen
Images: nginx:latest (stable, active)
Replicas:
Desired: 2
Current: 2
Updated: 2
Ready: 2
Available: 2
NAME KIND STATUS AGE INFO
⟳ bg-rollout Rollout ✔ Healthy 19m
├──# revision:3
│ └──⧉ bg-rollout-7956bb8bb6 ReplicaSet ✔ Healthy 88s stable,active
│ ├──□ bg-rollout-7956bb8bb6-gvrgj Pod ✔ Running 88s ready:1/1
│ └──□ bg-rollout-7956bb8bb6-sh8wx Pod ✔ Running 88s ready:1/1
├──# revision:2
│ └──⧉ bg-rollout-84bc9d88dc ReplicaSet • ScaledDown 6m
└──# revision:1
└──⧉ bg-rollout-7f56bd89fc ReplicaSet • ScaledDown 7m57s
To be reach the correct ReplicaSet using the preview and active services, Argo Rollouts will automatically update the selector for each service:
$ kubectl get svc rollout-active -o yaml
apiVersion: v1
kind: Service
metadata:
(...)
spec:
(...)
ports:
- name: http
port: 80
protocol: TCP
targetPort: http
selector:
app: bg-rollout
rollouts-pod-template-hash: 7956bb8bb6
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
$ kubectl get replicaset bg-rollout-7956bb8bb6 -o yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
annotations:
rollout.argoproj.io/desired-replicas: "2"
rollout.argoproj.io/revision: "3"
creationTimestamp: "6T11:17:06Z"
generation: 2
labels:
app: bg-rollout
rollouts-pod-template-hash: 7956bb8bb6
name: bg-rollout-7956bb8bb6
(...)
spec:
replicas: 2
selector:
matchLabels:
app: bg-rollout
rollouts-pod-template-hash: 7956bb8bb6
template:
metadata:
creationTimestamp: null
labels:
app: bg-rollout
rollouts-pod-template-hash: 7956bb8bb6
spec:
(...)
$ kubectl get pods bg-rollout-7956bb8bb6-gvrgj -o yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2025-03-16T11:17:06Z"
generateName: bg-rollout-7956bb8bb6-
labels:
app: bg-rollout
rollouts-pod-template-hash: 7956bb8bb6
name: bg-rollout-7956bb8bb6-gvrgj
(...)
spec:
(...)
Posted on 17/03/2025