Skip to main content
Cloud· · 8 min read

Kubernetes Deployment Strategies: Rolling Updates, Blue-Green, and Canary Deployments

Zero-downtime Kubernetes deployments in practice -- rolling updates, blue-green cutover, canary releases with Flagger, and GitOps with ArgoCD.

IBIFACE Team
All publications

One of our clients was deploying their API once a week – on Saturdays at 3 AM, with two engineers on call and a rollback plan taped to someone’s monitor. After we implemented canary deployments with automated metric analysis, they moved to 15 deploys per day, during business hours, with zero incidents in six months.

The deployment strategy you choose determines whether shipping to production is a non-event or a fire drill. Here’s a practical breakdown of the strategies that matter, when to use each, and how to implement them in Kubernetes.

The Decision Matrix

Strategy Downtime Risk Complexity Best For
Recreate Yes High Low Dev/staging environments
Rolling Update No Medium Low Most applications
Blue-Green No Low Medium Critical apps needing instant rollback
Canary No Very Low High High-traffic services with observable SLOs

Rolling Updates

Rolling updates are Kubernetes’ default strategy, and for good reason – they work well for the vast majority of applications. Old pods are replaced with new ones incrementally, so the service never goes fully offline.

The two key tuning knobs are maxSurge and maxUnavailable. For a fast rollout, allow extra pods during the transition. For a risk-averse rollout, set maxSurge: 1 and maxUnavailable: 0 so you always maintain full capacity, at the cost of a slower rollout. Adding minReadySeconds forces each new pod to remain healthy for a set period before the rollout proceeds, giving you time to catch issues early.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app
spec:
  replicas: 6
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2        # Allow up to 2 extra pods during the rollout
      maxUnavailable: 1  # At most 1 pod can be down at any time
  minReadySeconds: 30    # Pod must be healthy for 30s before proceeding
  template:
    spec:
      containers:
      - name: app
        image: myapp:2.0.0
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 10

Operating rollouts day-to-day is straightforward with kubectl rollout. You can watch progress in real time, view history to understand what changed, pause mid-rollout if you spot errors in logs, and roll back to any previous revision with a single command. The instant rollback – kubectl rollout undo deployment/web-app – is what makes rolling updates practical even for teams without sophisticated monitoring.

Blue-Green Deployments

Blue-green gives you something rolling updates can’t: instant, atomic traffic cutover. You run two full environments – the live “blue” and the staged “green” – and switch between them by updating a Service selector.

# Blue deployment (currently serving production traffic)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app-blue
spec:
  replicas: 5
  selector:
    matchLabels: { app: web-app, version: blue }
  template:
    metadata:
      labels: { app: web-app, version: blue }
    spec:
      containers:
      - name: app
        image: myapp:1.0.0
---
# Green deployment (new version, staged and tested)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-app-green
spec:
  replicas: 5
  selector:
    matchLabels: { app: web-app, version: green }
  template:
    metadata:
      labels: { app: web-app, version: green }
    spec:
      containers:
      - name: app
        image: myapp:2.0.0
---
# Service: the selector determines which deployment gets traffic
apiVersion: v1
kind: Service
metadata:
  name: web-app
spec:
  selector:
    app: web-app
    version: blue  # Change to 'green' to cut over
  ports:
  - port: 80
    targetPort: 8080

The cutover sequence is deliberate: deploy green, wait for all pods to pass readiness checks, smoke test green directly via kubectl port-forward, then patch the Service selector to point to green. If something breaks, rollback is a single kubectl patch command pointing the selector back to blue. Once stable, tear down the old deployment.

The trade-off is resource cost: blue-green requires double the compute during deployment. For most teams, that’s a reasonable price for sub-second rollback on critical services. In our experience, the confidence it gives teams – especially during business-hours deployments – pays for itself quickly.

Canary Deployments

Canary is the strategy for teams that deploy frequently to high-traffic services and need mathematical confidence that a release is safe. You route a small percentage of traffic to the new version, monitor key metrics, and gradually increase the percentage.

Manual canary works by running a small canary deployment alongside the stable one, with NGINX Ingress annotations controlling the traffic split. But manual canary doesn’t scale – someone has to watch dashboards and adjust weights by hand. For production use, we recommend Flagger, which automates the entire process:

apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
  name: web-app
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web-app
  service:
    port: 80
    targetPort: 8080
  analysis:
    interval: 1m          # Check metrics every minute
    threshold: 5           # Roll back after 5 failed checks
    maxWeight: 50          # Cap canary traffic at 50%
    stepWeight: 10         # Increase by 10% each interval
    metrics:
    - name: request-success-rate
      thresholdRange:
        min: 99            # Abort if success rate drops below 99%
      interval: 1m
    - name: request-duration
      thresholdRange:
        max: 500           # Abort if p99 latency exceeds 500ms
      interval: 1m

With this configuration, a deployment that causes error rate to spike or latency to degrade is automatically rolled back before it affects more than 50% of users. No human intervention required. The key design decision is choosing the right metrics and thresholds – too aggressive and you’ll get false rollbacks, too lenient and bad releases slip through.

GitOps With ArgoCD

For teams that want every deployment to be auditable, reproducible, and triggered by a Git commit, ArgoCD is the standard. You define an Application resource that points to a Git repository containing your Kubernetes manifests. ArgoCD watches the repo and syncs the cluster to match, with automated pruning of deleted resources and self-healing for manual drift.

ArgoCD also supports Argo Rollouts, which gives you blue-green and canary as first-class deployment primitives with features like manual promotion gates and configurable scale-down delays. The combination of GitOps workflow with progressive delivery gives you both auditability and safety – every deployment is a Git commit, and every promotion is metric-validated.

Health Checks Done Right

Every deployment strategy depends on accurate health checks. Get these wrong, and Kubernetes will route traffic to broken pods or kill healthy ones. The three probe types serve distinct purposes:

containers:
- name: app
  image: myapp:2.0.0
  # Readiness: "Can this pod handle requests?"
  # Failing removes the pod from the Service endpoint
  readinessProbe:
    httpGet: { path: /readyz, port: 8080 }
    initialDelaySeconds: 5
    periodSeconds: 5
    failureThreshold: 3
  # Liveness: "Is this pod fundamentally healthy?"
  # Failing triggers a pod restart
  livenessProbe:
    httpGet: { path: /healthz, port: 8080 }
    initialDelaySeconds: 15
    periodSeconds: 10
    failureThreshold: 3
  # Startup: "Has the app finished initializing?"
  # Protects slow-starting apps from premature liveness kills
  startupProbe:
    httpGet: { path: /healthz, port: 8080 }
    periodSeconds: 5
    failureThreshold: 30

A common and dangerous mistake: making the liveness probe hit a dependency like a database or external API. If that dependency goes down, Kubernetes restarts all your pods – cascading the outage instead of isolating it. Liveness should check the process itself, not its dependencies. Use readiness probes for dependency checks so unhealthy pods stop receiving traffic without being killed.

Monitoring and Operational Best Practices

Set up Prometheus queries for three signals during every deployment: error rate (should stay below your SLO threshold), p95 latency (watch for regression), and pod restart count (any restart during a rollout is a red flag). These three metrics will catch the vast majority of deployment-related issues before they impact users.

Beyond monitoring, a few operational patterns make a significant difference. Label every resource with app, version, commit, and team – labels are how you query, filter, and debug in production. Always set resource requests and limits so a noisy pod can’t starve its neighbors. Use Pod Disruption Budgets to prevent cluster maintenance from taking down your service. And add a pre-stop hook with a short sleep to drain in-flight connections gracefully before pod termination.

Choosing Your Strategy

The decision is simpler than it seems:

  • Rolling updates are the right default. Use them unless you have a specific reason not to.
  • Blue-green when your team needs the confidence of instant rollback and can afford double the resources during deployment.
  • Canary when you deploy frequently to high-traffic services and want automated, metric-driven promotion.
  • GitOps when auditability and reproducibility matter – every deployment is a Git commit, every rollback is a revert.

Most teams should start with rolling updates, add health checks and monitoring, then graduate to canary when their observability stack is mature enough to support automated analysis. The strategy matters less than the fundamentals: good health checks, proper resource limits, and metrics you actually watch.

|b| Share