What You'll Build
In this lesson you will deploy the india-squad-api using Argo Rollouts with a canary strategy that automatically tests new versions against a Prometheus error-rate metric before promoting them to full traffic. The rollout uses two analysis steps—one at 10% traffic and one at 50%—that query the canary pods' error rate from Prometheus every minute. If the error rate exceeds 5% twice in a row, the rollout is automatically aborted and all traffic returns to the stable version.
You will also test the auto-rollback mechanism by deploying a version that returns HTTP 500 errors, watching the AnalysisRun detect the elevated error rate, and confirming that the Rollout transitions to Degraded while the stable pods continue serving all production traffic uninterrupted. This end-to-end test is the capstone's verification that the observability layer and the delivery layer are connected.
Prerequisites
- Argo Rollouts installed on the EKS cluster: helm install argo-rollouts argo/argo-rollouts --namespace argo-rollouts --create-namespace.
- The kube-prometheus-stack from M5 Lab 35 deployed with the india-squad-api ServiceMonitor scraping metrics from the squad-prod namespace.
- The ALB ingress controller installed on EKS with the india-squad-api ingress resource configured, since ALB traffic splitting is required for precise canary weight control.
- The Kyverno ClusterPolicy from M3 Lab 21 deployed in Enforce mode, so the Rollout will only admit the Cosign-signed image from Lesson 37's pipeline.
- The kubectl Argo Rollouts plugin installed locally for the watch and set-image commands.
Step 1 — Deploy AnalysisTemplate and Rollout
Apply the AnalysisTemplate that queries Prometheus for the canary pods' error rate, and the Rollout resource that defines the six-step canary promotion. The AnalysisTemplate uses the `pod_template_hash` label—injected automatically by Kubernetes on every pod—to scope the Prometheus query to only the canary pods rather than the full deployment, ensuring the stable pods' traffic does not dilute the canary's error rate signal.
# Argo Rollouts: canary strategy with Prometheus AnalysisTemplate.
# Deploys the signed image from Lesson 37 with automated error-rate gate.
# ── 1. AnalysisTemplate: queries Prometheus for canary error rate ─────────
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: india-squad-error-rate
namespace: squad-prod
spec:
args:
- name: canary-hash
metrics:
- name: error-rate
interval: 1m
successCondition: result[0] <= 0.01 # pass if error rate <= 1%
failureCondition: result[0] > 0.05 # fail immediately if > 5%
failureLimit: 2
provider:
prometheus:
address: http://prometheus-operated.monitoring.svc.cluster.local:9090
query: |
sum(rate(http_requests_total{
namespace='squad-prod',
pod_template_hash='{{args.canary-hash}}',
status=~'5..'
}[2m]))
/
sum(rate(http_requests_total{
namespace='squad-prod',
pod_template_hash='{{args.canary-hash}}'
}[2m]))
---
# ── 2. Rollout: canary strategy referencing the AnalysisTemplate ──────────
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: india-squad-api
namespace: squad-prod
spec:
replicas: 5
selector:
matchLabels: { app: india-squad-api }
template:
metadata:
labels: { app: india-squad-api }
spec:
containers:
- name: api
image: 123456789.dkr.ecr.ap-south-1.amazonaws.com/india-squad-api:latest
ports: [{containerPort: 8000}]
strategy:
canary:
canaryService: india-squad-api-canary
stableService: india-squad-api-stable
trafficRouting:
alb:
ingress: india-squad-ingress
servicePort: 80
steps:
- setWeight: 10
- pause: {duration: 2m}
- analysis:
templates:
- templateName: india-squad-error-rate
args:
- name: canary-hash
valueFrom:
podTemplateHashValue: Latest
- setWeight: 50
- pause: {duration: 3m}
- analysis:
templates:
- templateName: india-squad-error-rate
args:
- name: canary-hash
valueFrom:
podTemplateHashValue: Latest
- setWeight: 100Step 2 — Trigger a Rollout and Monitor
Trigger a new rollout by updating the image reference to the signed image digest produced by Lesson 37's CI pipeline. Use the kubectl Argo Rollouts plugin to watch the rollout progress through its steps in real time. Observe the AnalysisRun being created when the analysis step is reached and the measurements being collected every minute. A successful rollout should take approximately 12 minutes to complete all six steps.
# Verify the canary rollout and test auto-rollback.
# 1. Apply the Rollout and AnalysisTemplate to the cluster
kubectl apply -f analysis-template.yaml
kubectl apply -f rollout.yaml
# 2. Install Argo Rollouts kubectl plugin
# brew install argoproj/tap/kubectl-argo-rollouts
# OR: curl -LO https://github.com/argoproj/argo-rollouts/releases/latest/download/kubectl-argo-rollouts-linux-amd64
# 3. Watch the rollout status in real time
kubectl argo rollouts get rollout india-squad-api -n squad-prod --watch
# Expected: shows current weight, steps progress, and AnalysisRun status
# 4. Trigger a new rollout by updating the image
kubectl argo rollouts set image india-squad-api \
api=123456789.dkr.ecr.ap-south-1.amazonaws.com/india-squad-api:$(git rev-parse HEAD) \
-n squad-prod
# 5. Monitor the AnalysisRun during the analysis step
kubectl get analysisrun -n squad-prod --watch
# Expected: AnalysisRun created, measurements taken every minute
# 6. Test auto-rollback by deploying a version that returns HTTP 500
# (In the application code, temporarily add: raise HTTPException(500, 'test'))
# Rebuild and push: the pipeline will still sign it (500s are app errors, not CVEs)
# kubectl argo rollouts set image ... (new SHA with the 500 error)
# Watch: the AnalysisRun should detect error rate > 5% and abort the rollout
# kubectl argo rollouts get rollout india-squad-api -n squad-prod
# Expected: Phase: Degraded, weight returns to 0%, stable pods continue serving
# 7. Verify the rollback
kubectl get rollout india-squad-api -n squad-prod \
-o jsonpath='{.status.currentStepIndex}'
# Expected: 0 (rolled back to the beginning of the step sequence)Step 3 — Test Auto-Rollback
Deploy a deliberately broken version of the application that returns HTTP 500 errors for all requests. When the canary receives its 10% traffic allocation and the AnalysisRun begins measuring its error rate, the Prometheus query will return a value above the 5% failure threshold. After two consecutive failure measurements—matching the `failureLimit: 2` configuration—the AnalysisRun transitions to Failed and the Rollout automatically aborts, setting the traffic weight back to 0% and scaling down the canary pods. The stable version continues serving 100% of traffic throughout.
Warning: The AnalysisTemplate's Prometheus query uses `pod_template_hash` as a label to scope to canary pods only. This label is automatically set by Kubernetes and its value changes with every new pod template—which is exactly what happens when the Rollout deploys a new image. If you test the query manually in the Prometheus expression browser before a rollout is active, you may get 'no data' because no pods with the active canary hash are running yet. This is correct behaviour: the analysis template is valid; it just has no data to evaluate until the canary pods are running and receiving traffic.
Capstone Tip: Add a `SyncFail` ArgoCD hook that calls the Argo Rollouts abort API when an ArgoCD sync fails before the Rollout reaches a stable state. This ensures that a failed Rollout during a GitOps sync is automatically cleaned up rather than leaving the cluster in an intermediate state where the Rollout is neither progressing nor aborted. The hook is a Kubernetes Job with an ArgoCD annotation: `argocd.argoproj.io/hook: SyncFail`.