Written by
Halkwinds Editorial Team
Halkwinds Research & Editorial

Zero-Downtime Deployments: Patterns and Implementation
Blue-green, canary, rolling, and feature-flag deployments — when to use each and how to implement them in Kubernetes and cloud environments.
Every engineering manager knows the sinking feeling: a deployment goes out, alerts start firing, and suddenly you're on a bridge call at 2 a.m. explaining to leadership why checkout was down for eleven minutes. Zero-downtime deployments exist to make that scenario obsolete. The goal is straightforward — ship changes continuously without users ever noticing — but the implementation requires deliberate architectural choices, the right tooling, and a team culture that treats deployment as a routine event rather than a high-risk ritual. This article walks through the four dominant patterns (blue-green, canary, rolling, and feature flags), when each makes sense, and how to implement them in Kubernetes and cloud environments like AWS.
- Background / Why This Matters
- Prerequisites and Planning
- Step-by-Step Implementation
- Testing and Validation
- Common Mistakes / What to Avoid
- Frequently Asked Questions
- Conclusion
Background / Why This Matters
Downtime is expensive in ways that go beyond lost revenue. It erodes customer trust, burns out on-call engineers, and creates a deployment culture where teams batch changes into large, infrequent releases — which paradoxically makes each release riskier. The DevOps research community has consistently found that high-performing teams deploy more frequently and have lower change-failure rates, precisely because small, safe deployments are easier to reason about and roll back.
Zero-downtime deployments are the mechanism that lets you deploy often without accepting the risk that usually comes with it. Instead of stopping the old version and starting the new one (which guarantees a gap), you run both versions simultaneously and shift traffic gradually or atomically. The core patterns differ in how they manage that overlap:
- Rolling: Replace instances incrementally, a few at a time.
- Blue-green: Stand up a full parallel environment, then switch traffic all at once.
- Canary: Route a small percentage of traffic to the new version, then increase gradually while watching metrics.
- Feature flags: Deploy code dark, then enable behavior for specific users at runtime — decoupling deployment from release.
Takeaway: The point of zero-downtime deployment isn't zero risk — it's small, observable, reversible risk. Choose the pattern that gives you the fastest path back to a known-good state.
Prerequisites and Planning
Before you pick a pattern, verify that your application and infrastructure can actually support running two versions concurrently. Most failed "zero-downtime" projects fail here, not in the deployment tooling.
Application-level readiness
- Backward-compatible database migrations. If v2 renames a column, v1 breaks the moment v2 writes to it. Use the expand-and-contract pattern: add new columns/tables, deploy code that writes to both, migrate data, then remove the old schema in a later release.
- Stateless services. Session state should live in Redis, DynamoDB, or a signed token — not in-process memory. Otherwise shifting traffic logs users out.
- Graceful shutdown. Your service must handle SIGTERM, stop accepting new connections, and drain in-flight requests before exiting.
- Health checks. Distinguish liveness (is the process alive?) from readiness (is it ready to serve traffic?). Kubernetes uses these to avoid routing traffic to pods that aren't warmed up.
Infrastructure readiness
- A load balancer or service mesh that supports weighted routing (AWS ALB, NGINX Ingress, Istio, or Linkerd).
- Observability: metrics (Prometheus/CloudWatch), distributed tracing, and structured logs. You cannot run a canary without a definition of "healthy."
- Automated rollback triggers tied to those metrics.
Estimates vary, but a large share of production incidents trace back to database schema changes that weren't backward compatible. Getting migrations right is the single highest-leverage prerequisite.
Takeaway: Write down which of the four patterns your database migration strategy currently supports. If the answer is "none," fix expand-and-contract first — everything else depends on it.
Step-by-Step Implementation
Below are concrete implementations for each pattern, weighted toward Kubernetes and AWS since that's where most teams operate.
Choosing the right pattern
| Pattern | Rollback speed | Infra cost | Blast radius on failure | Best for |
|---|---|---|---|---|
| Rolling | Moderate (roll back = redeploy) | Low | Medium (partial fleet affected) | Stateless services, default CI/CD |
| Blue-green | Instant (flip traffic back) | High (2x during cutover) | High if not caught pre-switch | Releases needing atomic cutover, easy rollback |
| Canary | Fast (shift traffic back) | Medium | Low (small % exposed) | High-traffic services, risky changes |
| Feature flags | Instant (toggle off) | Low | Very low (targeted users) | Decoupling deploy from release, A/B testing |
Rolling deployments in Kubernetes
This is the default Kubernetes Deployment strategy and requires almost no extra tooling. Configure it via strategy.rollingUpdate with maxUnavailable: 0 and maxSurge: 1 so Kubernetes always adds a healthy new pod before removing an old one. Combine with a readiness probe:
- Set maxUnavailable: 0 to guarantee capacity never drops during the roll.
- Define a readiness probe (e.g., HTTP GET on
/healthz) so traffic only routes to warmed pods. - Add a preStop lifecycle hook with a short sleep to let the load balancer deregister the pod before shutdown.
- Roll back with
kubectl rollout undo deployment/my-app.
Blue-green on AWS
Blue-green runs two identical environments. "Blue" serves production; "green" runs the new version. Once green passes validation, you switch traffic atomically.
- Provision the green environment (a second target group behind an AWS ALB, or a duplicate ECS/EKS service).
- Deploy v2 to green and run smoke tests against its internal endpoint.
- Update the ALB listener rule to point 100% of traffic to the green target group.
- Keep blue running for a defined bake period (often 15–60 minutes) so rollback is a single listener change back to blue.
- Decommission blue once confident.
AWS CodeDeploy automates this for ECS and Lambda, including automatic rollback on CloudWatch alarm breaches.
Canary deployments
Canary is the safest pattern for high-traffic, high-risk changes. Tools like Argo Rollouts or Flagger (with Istio, Linkerd, or an AWS ALB) automate progressive traffic shifting.
- Deploy v2 alongside v1 and route a small slice — say 5% — of traffic to it.
- Define success criteria: error rate below 1%, p99 latency within threshold, no spike in 5xx responses.
- The controller queries Prometheus at each step. If metrics stay healthy, it advances (5% → 25% → 50% → 100%). If not, it automatically rolls back.
- Set analysis intervals long enough to capture real traffic patterns — a 30-second window rarely catches a memory leak.
Feature flags with LaunchDarkly
Feature flags decouple deploying code from releasing behavior. You ship v2 with the new feature wrapped in a flag defaulting to off, then enable it at runtime — for internal users first, then 1%, then everyone.
- Wrap the new code path in a flag check (e.g.,
if (ldClient.boolVariation("new-checkout", user, false))). - Deploy with the flag off, using any of the patterns above — the deployment carries no user-facing risk.
- In LaunchDarkly, target the flag to internal users, then percentage-roll to the wider audience while monitoring.
- If something breaks, toggle the flag off. No redeploy needed — this is the fastest rollback available.
At Halkwinds, our Engineering teams frequently combine canary rollouts with feature flags: the canary de-risks the infrastructure change, while the flag de-risks the behavioral change. The two patterns solve different problems and work well together.
Takeaway: Don't standardize on a single pattern. Use rolling as your baseline, canary for risky backend changes, and feature flags for anything user-facing.
Testing and Validation
A deployment strategy is only as good as your ability to detect that the new version is misbehaving. Validation happens at three points: before the switch, during the rollout, and after.
- Pre-switch smoke tests. Hit the new version's internal endpoint with a scripted set of critical-path requests before any real user touches it.
- Automated canary analysis. Compare the canary's golden signals — latency, traffic, errors, saturation — against the stable version, not against static thresholds. A 2% error rate might be normal for one service and catastrophic for another.
- Synthetic monitoring. Run continuous synthetic transactions (e.g., a scripted login-and-checkout via CloudWatch Synthetics) so you detect failures even during low-traffic hours.
- Rollback drills. Practice rollbacks in staging. The first time you roll back should never be during a real incident.
Takeaway: Define your automated rollback trigger before you deploy. If you can't articulate the exact metric and threshold that aborts the release, you're doing manual deployment with extra steps.
Common Mistakes / What
Explore Further