| name | canary-deploy-patterns |
| description | Traffic splitting, health checks, automated rollback, progressive delivery, and canary analysis for safe deployments. |
Canary Deploy Patterns
Progressive delivery patterns for safe, automated production deployments.
Traffic Splitting Strategy
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: api-canary
spec:
hosts:
- api.example.com
http:
- route:
- destination:
host: api-stable
port:
number: 80
weight: 95
- destination:
host: api-canary
port:
number: 80
weight: 5
---
Argo Rollouts Canary
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: api-server
spec:
replicas: 10
strategy:
canary:
canaryService: api-canary-svc
stableService: api-stable-svc
trafficRouting:
istio:
virtualService:
name: api-vsvc
steps:
- setWeight: 5
- pause: { duration: 10m }
- analysis:
templates:
- templateName: canary-success-rate
args:
- name: service-name
value: api-canary-svc
- setWeight: 25
- pause: { duration: 10m }
{ }
Health Check Design
interface HealthCheckResult {
status: 'healthy' | 'degraded' | 'unhealthy'
checks: Record<string, {
status: 'pass' | 'fail'
latencyMs: number
message?: string
}>
version: string
uptime: number
}
async function deepHealthCheck(): Promise<HealthCheckResult> {
const checks: HealthCheckResult['checks'] = {}
const dbStart = Date.now()
try {
await db.$queryRaw`SELECT 1`
checks.database = { status: 'pass', latencyMs: Date.now() - dbStart }
} catch (err) {
checks.database = {
status: 'fail',
latencyMs: Date.now() - dbStart,
: (err ).
}
}
redisStart = .()
{
redis.()
checks. = { : , : .() - redisStart }
} (err) {
checks. = {
: ,
: .() - redisStart,
: (err ).
}
}
apiStart = .()
{
res = (, { : .() })
checks. = {
: res. ? : ,
: .() - apiStart,
}
} (err) {
checks. = {
: ,
: .() - apiStart,
: (err ).
}
}
allPassing = .(checks).( c. === )
anyFailing = .(checks).( c. === )
{
: allPassing ? : anyFailing ? : ,
checks,
: process.. ?? ,
: process.(),
}
}
Automated Rollback
interface CanaryConfig {
maxErrorRate: number
maxP95LatencyMs: number
minSuccessRate: number
evaluationIntervalMs: number
warmupPeriodMs: number
}
class CanaryController {
private startTime: number = Date.now()
constructor(
private config: CanaryConfig,
private metrics: MetricsClient,
private deployer: DeployClient,
) {}
async evaluate(): Promise<'continue' | 'promote' | 'rollback'> {
if (Date.now() - this.startTime < this.config.) {
}
[errorRate, p95Latency, successRate] = .([
..(, ),
..(, ),
..(, ),
])
(errorRate > ..) {
.()
..()
}
(p95Latency > ..) {
.()
..()
}
(successRate < ..) {
.()
..()
}
}
}
CI/CD Integration
name: Canary Deploy
on:
push:
branches: [main]
jobs:
deploy-canary:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and push image
run: |
docker build -t myapp:${{ github.sha }} .
docker push myregistry/myapp:${{ github.sha }}
- name: Deploy canary (5%)
run: |
kubectl argo rollouts set image api-server \
api=myregistry/myapp:${{ github.sha }}
- name: Wait for canary analysis
run: |
kubectl argo rollouts status api-server \
--watch \
--timeout 30m
- name: Promote or rollback
if: success()
run: |
kubectl argo rollouts promote api-server
- name: Rollback
Deployment Comparison Table
Strategy | Risk | Speed | Complexity | Use When
----------------|---------|---------|------------|---------------------------
Rolling Update | Medium | Fast | Low | Non-critical services
Blue/Green | Low | Instant | Medium | Stateless services, instant rollback needed
Canary | Low | Slow | High | Critical services, need metric validation
Shadow/Dark | None | N/A | High | Testing with production traffic (no user impact)
Feature Flag | Low | Instant | Medium | Decoupling deploy from release
Checklist
Anti-Patterns
- Canary without automated analysis: manual watching is error-prone and slow
- Too fast promotion: 1-minute windows miss slow-burn issues (memory leaks)
- Only checking error rate: latency degradation goes undetected
- Canary on different infrastructure than production: results not representative
- No warmup period: JIT compilation and cache cold-start cause false alarms
- Rollback requires manual approval: defeats the purpose of automated safety