Last updated: October 30, 2026
Your deployment strategy decides what happens in the worst five minutes of a release: how many users see the new version, whether old and new code must run together, how quickly you can retreat, and whether rollback restores service or only changes the image back.
Kubernetes makes deployment look simple: change the image, apply the manifest, and pods move. But that default is not a complete release strategy. A stateless API, a public service, a database-backed application, and a personal project carry different risks and should not automatically roll out the same way.
This guide compares rolling updates, recreate, blue-green, canary, A/B releases, and shadow deployments in 2026: what Kubernetes provides natively, where routing or progressive-delivery tools become necessary, and how to choose without adding complexity you cannot operate.
TL;DR
- Rolling update is the sensible default for most stateless services. Tune
maxSurge,maxUnavailable, probes, and revision history instead of accepting every default.- Recreate is simple but causes downtime. Use it only when old and new versions cannot run together and an interruption is acceptable, such as some batch, development, or single-instance workloads.
- Blue-green runs two full versions and switches traffic after validating the new one. Rollback is conceptually simple, but duplicate capacity and database compatibility still need planning.
- Canary exposes a small share of traffic first and expands in stages. It offers the best controlled blast radius for important user-facing services, but it needs reliable metrics, traffic control, and a rollback rule.
- A/B is not simply another name for canary. A/B routing selects users by header, cookie, geography, account, or another attribute so you can compare behaviour between groups.
- Shadow mirrors live requests to the new version without returning its responses to users. It is a validation technique, not a normal rollout, and it is unsafe for uncontrolled writes or side effects.
- No strategy makes a breaking database migration safe. Backward-compatible changes and a tested rollback path matter more than the traffic pattern.
My own deployment lessons come from my 3D portfolio and this website: uploads and quick fixes that behaved differently live than they did locally taught me that the deployment strategy matters less than knowing exactly which version is running — and being able to get back to the previous one.
Originally published on DevOps Enginer.
First, Separate Three Ideas That Are Often Confused
A useful deployment decision has three layers.
1. How pods are replaced
A native Kubernetes Deployment supports only two spec.strategy.type values: RollingUpdate and Recreate. Blue-green and canary are not extra values for that field; they are release patterns built from Deployments, Services, routing rules, controllers, and procedures.
2. How traffic reaches each version
A Service sends traffic to pods matching its selectors; by itself, it does not provide percentage routing. If stable and canary pods share a selector, distribution follows ready endpoints, not an exact percentage setting. Weighted routing, header routing, mirroring, and staged promotion normally need an ingress controller, Gateway API configuration, a service mesh, or a tool such as Argo Rollouts or Flagger.
3. How the release is governed
GitOps, approvals, analysis, alerts, and rollback rules determine whether a technically possible rollout is safe to operate. Argo CD can reconcile manifests from Git, but it is not by itself a weighted-traffic canary controller. Teams often store Argo Rollouts or Flagger objects in Git and let Argo CD apply them: Git describes the release, the controller executes the steps, and metrics or approvers decide whether to continue, pause, or abort.
Many failed “canary deployments” are really failures of routing precision, observability, database compatibility, or decision-making.
For the delivery side of that model, see this guide to GitOps vs Traditional CI/CD. For probes, replacement, and recovery inside the cluster, pair it with Self-Healing Infrastructure in Kubernetes.
Strategy 1: Rolling Update
What happens
A rolling update replaces old pods incrementally. Kubernetes creates pods from the new ReplicaSet, waits for readiness, and removes old pods within the strategy limits. Old and new versions normally serve traffic together during the transition. This is the Deployment default and the right starting point for many stateless services.
Tune these fields, do not merely copy them
-
maxSurge— extra pods allowed above the desired count. More surge can preserve capacity and speed an update, but temporarily uses more resources. -
maxUnavailable— pods allowed to be unavailable.0protects capacity but can stall the rollout if new pods never become ready. -
minReadySeconds— how long a new pod must remain ready before counting as available. It does not replace application metrics. -
progressDeadlineSeconds— how long Kubernetes tries to progress before reporting failure. It does not automatically roll back a native Deployment. -
revisionHistoryLimit— old ReplicaSets retained for rollback history.
Readiness probes are part of the strategy: a new pod should not receive traffic until it is ready to serve. Liveness probes have a different job — identifying a stuck process that should restart. Using a dependency check as a liveness probe can cause cascading restarts during a downstream outage, so keep the meanings separate.
Example: a conservative rolling update
The example uses five replicas, allows one extra pod, and does not intentionally reduce ready capacity. Adapt the image, endpoints, resources, and labels before using it.
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
labels:
app.kubernetes.io/name: myapp
spec:
replicas: 5
revisionHistoryLimit: 5
minReadySeconds: 10
progressDeadlineSeconds: 600
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
terminationGracePeriodSeconds: 30
containers:
- name: app
image: registry.example.com/myapp:2.0.0
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /ready
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 20
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
Apply and watch it like an operator, not like a file upload:
kubectl apply -f myapp-deployment.yaml
kubectl rollout status deployment/myapp --timeout=10m
kubectl rollout history deployment/myapp
kubectl get pods -l app=myapp -w
If the new version is bad, a native Deployment rollback returns to a previous ReplicaSet configuration:
kubectl rollout undo deployment/myapp
# Or select a specific recorded revision:
kubectl rollout undo deployment/myapp --to-revision=3
kubectl rollout status deployment/myapp
That command helps only if the previous version still works with the current database schema, configuration, queues, caches, and external contracts. Test that assumption before an incident.
When rolling is the right choice
Choose rolling updates for:
- Stateless services and ordinary APIs.
- Internal tools and CRUD applications.
- Workloads whose old and new versions are compatible.
- Teams that need a built-in, understandable process.
- Cost-sensitive workloads that cannot justify duplicate environments.
Where rolling becomes weak
Rolling gives no precise traffic percentages, user segmentation, or automatic metric-based promotion. A bad version can gradually reach every user, and rollback is another rollout that can be slowed by image pulls, scheduling, readiness, or broken configuration. For low-risk services, that trade-off is acceptable; for high-value releases, it may not be.
Strategy 2: Recreate
What happens
Recreate terminates all old pods before creating new ones, leaving a period with no available pod. It is simple, and sometimes exactly what a workload requires.
apiVersion: apps/v1
kind: Deployment
metadata:
name: single-writer
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: single-writer
template:
metadata:
labels:
app: single-writer
spec:
containers:
- name: app
image: registry.example.com/single-writer:2.0.0
ports:
- containerPort: 8080
When recreate makes sense
Use it when two versions cannot run at the same time, when a single-writer process would corrupt work if duplicated, or for a development, batch, or maintenance workload with an accepted interruption window. Do not choose it merely because it feels cleaner: for a user-facing service, the downtime is real. Consider whether a queue, leader election, migration job, or maintenance page solves the underlying problem better.
Strategy 3: Blue-Green
What happens
Blue-green keeps two complete versions available. Deploy green beside live blue, validate green without normal production traffic, then switch the Service or routing rule to green. Keep blue for a defined period in case you need to switch back.
Call it a fast traffic switch, not magic instant recovery. Ingress propagation, connection draining, caches, workers, and database writes can complicate the return path.
Example: two Deployments and one Service
The key detail is that the Deployments select different version labels while the Service selects only one active version.
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-blue
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: blue
template:
metadata:
labels:
app: myapp
version: blue
spec:
containers:
- name: app
image: registry.example.com/myapp:1.9.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-green
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: green
template:
metadata:
labels:
app: myapp
version: green
spec:
containers:
- name: app
image: registry.example.com/myapp:2.0.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
selector:
app: myapp
version: blue
ports:
- name: http
port: 80
targetPort: 8080
Deploy green, test it through an internal route or port-forward, then switch the selector:
kubectl apply -f myapp-blue-green.yaml
kubectl rollout status deployment/myapp-green
kubectl patch service myapp -p '{"spec":{"selector":{"app":"myapp","version":"green"}}}'
To retreat, patch the selector back to blue — provided blue is still running, its configuration is valid, and it can safely process data written while green was active.
In a GitOps workflow, make that selector change as a reviewed Git change rather than an untracked manual patch; reserve manual commands for understanding the mechanism and emergencies.
When blue-green is the right choice
Choose blue-green when a release is difficult to validate through gradual exposure alone, when a fast, understandable traffic retreat matters more than temporary duplicate cost, when you need to test a complete environment before promotion, and when the data model tolerates two versions during the switch.
Costs and traps
Blue-green can require roughly two copies of the workload during release, although real cost depends on existing node capacity, autoscaling, and how long blue is retained. Delete blue too early and rollback disappears; keep it too long and you pay for idle resources and risk drift.
The database is harder. If green performs a destructive migration, blue may no longer understand the data. Use backward-compatible migrations and decide in advance whether rollback means code only, traffic only, data repair, or a restore.
Strategy 4: Canary
What happens
A canary release introduces the new version to a limited portion of traffic, watches agreed signals, and then expands, pauses, or retreats. Stage percentages are operational choices, not universal safe values. Sparse traffic may teach you almost nothing; on a busy service, even a small percentage can expose many users.
Before release, a serious canary process defines the eligible traffic, the metrics that count as acceptable, how long each step must run for a meaningful signal, who or what can pause or abort, and what data state rollback must handle.
The native-Kubernetes limitation
You can run stable and canary Deployments behind routing infrastructure, but a standard Deployment has no canary: 10% field. Replica ratio affects ready endpoints; request distribution also depends on the Service, ingress implementation, connection reuse, and session affinity. Treat the result as approximate unless a routing layer enforces the weight.
For precise staged delivery, use a tool designed for it. Argo Rollouts and Flagger are the two names you will see most often in Kubernetes progressive delivery. Neither statement means the author has used both in production, and neither tool removes the need to understand your traffic layer.
- Argo Rollouts provides a Rollout resource with blue-green and canary strategies, steps, pauses, analysis, and traffic-provider integrations.
- Flagger automates progressive delivery through existing ingress controllers or service meshes and metric providers.
If Git stores the Rollout or Flagger configuration, a GitOps controller such as Argo CD can reconcile it. That does not make Argo CD and Argo Rollouts the same product.
Example: canary steps with Argo Rollouts
The following is a structural example. It requires the Argo Rollouts controller and a compatible environment. The trafficRouting section is intentionally not invented for a specific ingress here because the correct fields depend on whether you use NGINX, Istio, ALB, Gateway API, or another provider. Without a traffic-routing integration, analyse carefully what the step weights mean in your setup; they may control canary pod share rather than precise request share.
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: myapp
spec:
replicas: 10
revisionHistoryLimit: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: app
image: registry.example.com/myapp:2.0.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
strategy:
canary:
canaryService: myapp-canary
stableService: myapp-stable
steps:
- setWeight: 5
- pause:
duration: 10m
- setWeight: 20
- pause:
duration: 15m
- setWeight: 50
- pause: {}
You also need stable and canary Services whose selectors match the pod labels managed by the Rollout. Do not copy only the Rollout object and assume routing exists. Install and configuration instructions vary by controller version and traffic provider, so verify them against the version you deploy.
Analysis should compare outcomes, not celebrate green dashboards
Analyse indicators connected to user harm and correctness: canary versus stable error ratio; latency on changed endpoints, not only the application average; saturation such as throttling, memory pressure, queue depth, and connection pools; domain failures such as rejected submissions; and new exception patterns. Log volume alone is not a health metric.
An AnalysisTemplate can query Prometheus and express a success condition, but the metric names, labels, and threshold must come from your own instrumentation and error budget. Do not copy a universal success-rate target: on a low-traffic endpoint, one request can swing the percentage. Use minimum request counts, comparison with stable behaviour, and pauses long enough to collect evidence.
When canary is the right choice
Choose canary when:
- The service has enough traffic for staged exposure to reveal problems.
- The cost of a bad full release is high.
- You can measure canary and stable behaviour separately.
- Rollback or abort can happen quickly and safely.
- The organisation is willing to pause a release rather than promote on schedule pressure.
Avoid canary theatre: tiny percentages, no separated metrics, no authority to stop, and promotion on a fixed timer regardless of evidence — canary complexity without canary protection.
Strategy 5: A/B Releases
How A/B differs from canary
Canary asks, “Is the new version safe enough to expand?” A/B asks, “Which version produces the better outcome for a defined group?”
An A/B release routes users by an attribute rather than a random traffic percentage: a test-client header, an application cookie, internal or beta accounts, a region or tenant, or users who opted into a preview.
The patterns can overlap, but the intent differs. A canary is a deployment-risk control. A/B is an experiment or product-decision mechanism, so it needs consistent assignment, experiment tracking, and analysis that does not confuse release health with product behaviour.
A/B routing normally belongs in an ingress, Gateway API, service mesh, edge proxy, or application logic; a basic Deployment does not know which customer belongs in group A. Use A/B for controlled product comparison or a beta cohort, not as a fashionable label for canary.
Strategy 6: Shadow Deployment
What happens
A shadow deployment copies live requests to the new version while the stable version answers users. The shadow response is compared, logged, timed, or discarded. It can reveal crashes under realistic request shapes, latency and resource differences, unexpected response changes, and missing configuration.
The warning that matters
Mirroring is dangerous when requests cause side effects: a copied request might send an email, charge a card, write a record, publish a message, or call a third-party API. Classify endpoints first, then mirror only safe reads, replace sensitive data where required, route shadow writes to an isolated database or disable them, mark shadow traffic so downstream services can suppress external effects, and apply strict timeouts and resource limits so the shadow cannot harm the live path.
A mirroring feature does not make the workload safe. Stateful and write-heavy systems need explicit design; for many teams, replaying sanitised historical traffic in staging is safer. Use shadow deployment for selected pre-release validation, not as a default step for every application.
Comparison Table
| Strategy | User exposure | Rollback style | Traffic control | Extra capacity / cost | Complexity | Main risk |
|---|---|---|---|---|---|---|
| Rolling update | Gradually reaches all users as pods are replaced | Roll out previous revision | Pod replacement only; no precise user percentage | Low; optional surge capacity | Low | Bad version eventually reaches everyone; rollback is another rollout |
| Recreate | No users served during replacement | Start previous version again | None | Low | Low | Planned downtime and failed startup extend the outage |
| Blue-green | All at once after green validation | Switch traffic back to blue if it remains healthy and compatible | Full-version switch; preview routing can be added | High during release because two full versions run | Medium | Database incompatibility, idle duplicate cost, keeping old version too long or removing it too early |
| Canary | Limited share first, then staged expansion | Reduce canary weight or abort rollout | Percentage stages with suitable routing/controller | Medium; canary capacity plus tooling, usually less than full duplication | High | Weak metrics, imprecise routing, or promotion despite poor evidence |
| A/B | Defined user cohort | Remove routing rule or disable feature path | Header, cookie, tenant, geography, or other attribute | Medium; duplicate version plus experiment analysis | High | Inconsistent assignment, biased measurement, confusing product results with release health |
| Shadow | No user responses from new version | Stop mirroring; stable version was never promoted | Mirrored percentage or selected routes | Medium to high; duplicate processing without direct user value | High | Side effects, sensitive-data exposure, shadow load affecting production |
“Fastest rollback” depends on what must be reversed. A selector switch beats waiting for pods only if the old version is still present and compatible; reducing canary traffic helps only if the harmful version has not already changed shared data. Reversing an image tag is not reversing the release.
Decision Guide: Which Strategy for Which Situation?
Start with rolling if the service is ordinary and stateless
For most internal services, APIs, and small applications, a tuned rolling update is enough. Improve the basics first: probes, resource requests, graceful shutdown, alerts, and a rehearsed rollback. A simple strategy everyone understands beats an advanced one nobody wants to touch during an incident.
For my own projects, my default is a plain rolling update. The projects are small, the traffic is forgiving, and simplicity wins. I would only reach for blue-green or canary when a change is risky enough — or an audience big enough — to justify the extra machinery.
Choose recreate only when coexistence is the problem
If two versions create duplicate writers or unsafe concurrent processing, a controlled interruption may be safer than a rolling update. Make the window explicit, automate startup verification, and prepare the previous version.
Choose blue-green when you need a full environment decision
Blue-green suits releases where the whole candidate environment must be inspected before users move, and where a binary go/no-go decision with a clear retreat path is worth duplicate resources. Decide in advance how long blue remains available. If green changes data blue cannot read, blue is a picture of rollback, not a working rollback.
Choose canary when blast radius matters and evidence is real
Canary is the strongest option for important public services with enough traffic and observable behaviour — provided you have separated metrics, a routing mechanism, a decision rule, and an abort path. Build those pieces before the highest-risk release, not during it.
Add A/B when the question is product behaviour
Use A/B when product owners need outcome comparisons for stable cohorts, with disciplined assignment and analysis. If the question is only “Will this version break?”, canary is the clearer tool.
Add shadow when realistic load matters but writes are controlled
Shadow validation suits read-heavy services, inference endpoints, search changes, and response comparison. Start with safe endpoints and isolated effects; if you cannot prove mirrored traffic is harmless, do not mirror production.
Consider the application platform, not only Kubernetes
Not every workload should solve release strategy inside the cluster. A small application may be better served by platform deployments, previews, or a managed service. This is the same trade-off explored in Serverless vs Containers: choose the operating model you can run well, not the longest feature list.
Database and State Rules for Every Strategy
Deployment diagrams often show stateless pods because state is where the clean story becomes difficult. Use these rules regardless of the traffic pattern:
Prefer expand, migrate, contract
- Expand: add the new column, table, index, or message field while old code still works.
- Deploy compatible code: release code that can read old and new shapes and may write both during transition.
- Migrate: backfill or copy data in controlled batches.
- Contract: remove the old shape only after old code is gone and the rollback window has closed.
Treat configuration, queues, and backups as part of the release
A rollback can fail because a ConfigMap, Secret structure, feature-flag default, API contract, or IAM permission changed with the code. Check whether the previous version understands them. Old and new queue consumers may process the same messages during a rollout, so message formats need compatibility where coexistence is possible; a poison message can also outlive a pod rollback. Finally, do not call a backup a rollback plan: a backup supports restore, which can involve downtime and data loss after the backup point. Document both procedures.
Common Mistakes
1. Treating maxUnavailable: 0 as a guarantee of safety
It protects the available replica count during normal replacement, but it cannot make a broken application healthy. If new pods never become ready, the rollout stalls; if readiness is superficial, broken pods become available anyway. Combine conservative settings with meaningful readiness and post-release checks.
2. Using the same shallow endpoint for readiness and liveness
Readiness asks whether this instance should receive traffic; liveness asks whether the process is stuck and needs restart. A shared /health endpoint may suit a very simple application, but if it fails whenever a downstream database is unavailable, using it for liveness can restart every pod without fixing the database.
3. Ignoring pod termination behaviour
Applications should stop accepting new work, finish in-flight requests within a sensible limit, close connections cleanly, and respect terminationGracePeriodSeconds. A pre-stop delay sometimes helps endpoint propagation, but it is not universal; test your ingress and Service behaviour rather than copying a sleep command into every pod.
4. Assuming replica percentage equals traffic percentage
Three canary pods out of ten do not guarantee 30 percent of requests. Long-lived connections, load balancing, session affinity, retries, and uneven request cost distort the result. Use a routing layer when precision matters.
5. Keeping blue forever
Old images accumulate vulnerabilities, configuration drifts, and operators forget which environment is authoritative. Set a retention window and a cleanup owner.
6. Automating promotion without automating judgement
A timer is not an analysis. Automatic promotion should depend on relevant indicators and enough traffic to evaluate them. Automatic rollback needs care too: an unrelated dependency failure can trigger churn if the rule is too sensitive.
7. Forgetting non-HTTP workloads
Workers, stream processors, cron jobs, and controllers do not fit traffic percentages. Think in partitions, consumer groups, leader election, concurrency policy, idempotency, and duplicate processing. “Canary one pod” can still duplicate side effects.
8. Using mutable image tags
If latest can point to different content over time, nobody can reliably know which build is running or reproduce a previous state. Pin a release version or digest in the manifest.
9. Testing rollback only in a slide deck
Run rollback drills in a non-production environment and, where safe, in controlled production exercises. Identify missing permissions and check application behaviour after the return. Do not invent a recovery-time claim from a command's apparent simplicity.
The rollback I know best is the unglamorous one: redeploying the last known-good version. During my 3D portfolio fixes, going back to the previous working build was often faster than debugging a bad upload in place — and that experience is why rollback speed sits so high in my comparison table.
Frequently Asked Questions
What is the default Kubernetes deployment strategy?
The default is RollingUpdate: Kubernetes incrementally replaces pods according to maxSurge and maxUnavailable. It suits compatible, stateless workloads, but provides neither exact traffic percentages nor metric-based promotion by itself.
Is canary safer than blue-green?
Canary usually limits the first user exposure to a smaller group, while blue-green exposes all users at the switch after candidate validation. Neither is universally safer. Canary safety depends on routing and metrics; blue-green safety depends on validation quality and whether the old version remains data-compatible after the switch.
Does Argo CD perform canary deployments by itself?
Argo CD reconciles manifests from Git and can apply resources for Argo Rollouts or Flagger, but it is not by itself a weighted-traffic canary controller. Those are separate systems. The author has used Argo CD; that does not imply production use of every tool discussed here.
Can I roll back only the image?
You can return the workload to a previous pod template, but a release may also include database, configuration, queue, cache, and external-contract changes. Image rollback is sufficient only when the previous code remains compatible with the current state of those dependencies. Test the full rollback path, not just the command.
Which strategy is best for a small personal project?
Start with the platform's normal deployment or a tuned rolling update. Add complexity only when a real failure mode justifies it. For a personal project, fast diagnosis and a simple way to redeploy the previous version usually beat buying a service mesh with operational time.
Can strategies be combined?
Yes. A team might validate a candidate with shadow traffic, release it through a canary, and keep a blue-green-style previous environment for a major migration. Combine only where each pattern solves a distinct risk; stacking everything makes ownership and rollback less clear.
Conclusion
The best Kubernetes deployment strategy is the simplest one that controls the release risk you actually have.
Use rolling updates as the default for compatible stateless services. Use recreate only when coexistence is unsafe and downtime is acceptable. Use blue-green when full-candidate validation and a clear retreat justify duplicate capacity. Use canary when staged exposure and measurable evidence matter. Use A/B for defined cohorts and product questions. Use shadow carefully for realistic validation without giving the new version responsibility for user responses.
Then spend at least as much effort on the foundations: backward-compatible data changes, meaningful probes, immutable images, separated metrics, clear stop authority, and rehearsed rollback. Those decide whether a strategy works when the release stops going to plan.
Rabin Adhikari writes practical Kubernetes, GitOps, and CI/CD guides at DevOps Enginer, based on general engineering practice and his own projects.
Top comments (0)