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