Cloud Parts

Rolling deployments

Replace the instances of a service a few at a time, so it keeps serving while the new version takes over.

Live model
What you’re watchingThe load balancer spreads requests over four instances while they are replaced one at a time: each leaves the pool, restarts on v2 and rejoins once healthy, so the other three keep serving. A request already on its way to an instance as it stops is lost; that is why real rollouts drain connections first.

How it works

A service runs as several identical instances behind a load balancer. A rolling deployment replaces them in batches: start one or more instances of the new version, wait until their health checks pass, take the same number of old instances out of the load balancer, stop them, and repeat until none of the old version is left. Two settings decide the pace. One says how many extra instances may run during the update (Kubernetes calls it maxSurge, Amazon ECS maximumPercent); the other says how many may be missing (maxUnavailable, or ECS minimumHealthyPercent). Kubernetes defaults to 25% for both, so a 4-pod service may briefly run 5 pods, or drop to 3 ready ones, while it moves. A readiness probe or load balancer health check is what stops a broken version: new instances that never report ready never get traffic, and the rollout stalls instead of replacing the healthy ones. For the minutes it takes, old and new versions serve side by side, so every change has to work alongside the previous version: database schema, message formats and APIs included. Rolling back means rolling forward to the old version, batch by batch, with the same wait.

Think of it as

Changing the tyres on a bus one wheel at a time while it keeps driving its route. It never stops, but for a while it runs on a mix of old and new tyres, and swapping back takes just as long.

Reach for it when

  • Stateless services with several instances behind a load balancer
  • You can’t afford a second full copy of the service during a release
  • Changes are backward compatible, so old and new versions can serve side by side

Think twice when

  • You need instant rollback; rolling back is another rollout of the same length
  • The new version can’t coexist with the old one, for example a breaking schema or protocol change
  • A single instance, where replacing it in place means downtime

A real example

A checkout API runs 8 pods on Kubernetes with maxSurge: 2 and maxUnavailable: 0. The deploy starts 2 new pods; once their readiness probes pass, the Deployment stops 2 old ones, and so on. Four batches of about 40 seconds each finish the release in under 3 minutes, and the service never drops below 8 ready pods. During those 3 minutes some requests hit version 41 and some version 42, so the team shipped the new optional field before the code that requires it.

What each provider calls it

AWS
ECS rolling update (`minimumHealthyPercent`, `maximumPercent`); Deployments on EKS; EC2 Auto Scaling instance refresh; CodeDeploy in-place (OneAtATime, HalfAtATime)
Google Cloud
Deployments on GKE; Compute Engine managed instance group rolling updates
Azure
Deployments on AKS; Virtual Machine Scale Sets rolling upgrade policy
Open source & others
Kubernetes Deployment with the RollingUpdate strategy (the default); Argo Rollouts for finer control

The same two knobs on different platforms#

Every rolling deployment trades speed against spare capacity: how many extra instances you may add, and how many you may lose, at any moment.

PlatformExtra capacity allowedCapacity you may loseDefaults
Kubernetes DeploymentmaxSurgemaxUnavailable25% and 25%
Amazon ECS rolling updatemaximumPercentminimumHealthyPercent200% and 100%: start new tasks before stopping old ones
EC2 Auto Scaling instance refreshMaximum healthy percentageMinimum healthy percentage100% and 90% without an instance maintenance policy
CodeDeploy in-place (EC2)None: instances are updated where they standMinimum healthy hostsOneAtATime
  • Setting extra capacity to zero (no surge) means each batch takes capacity away; setting the loss to zero means you need room for the extra instances. At least one of the two has to allow movement or the rollout can’t start.

In code · yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: checkout
spec:
  replicas: 8
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2          # up to 10 pods during the update
      maxUnavailable: 0    # never fewer than 8 ready pods
  selector:
    matchLabels: { app: checkout }
  template:
    metadata:
      labels: { app: checkout }
    spec:
      containers:
        - name: checkout
          image: registry.example.com/checkout:42   # change the tag to start a rollout
          readinessProbe:                          # no traffic until this passes
            httpGet: { path: /healthz, port: 8080 }
# kubectl rollout status deployment/checkout
# kubectl rollout undo deployment/checkout    # rollback is another rolling update

Often confused with

Where it came from2014–2025

Before services ran on fleets, a release often meant a maintenance window: stop the application, copy the new version, start it again. Once a service ran on many identical machines behind a load balancer, there was a cheaper way to stay up: take a few machines out, upgrade them, put them back, and move on to the next few.

Amazon built this into Apollo, the internal deployment engine its service teams shared after the company split its software into small services. In 2014 Werner Vogels described how Apollo could “perform a rolling update across a fleet where only a fraction of the hosts are taken offline at a time”, striping each batch across data centers and halting a deployment when too many hosts failed. It had handled 50 million deployments in the previous 12 months, and that November AWS released CodeDeploy, based on it, with one-at-a-time and half-at-a-time configurations.

Kubernetes made the pattern the default for containers. It added the Deployment object in version 1.2 in March 2016, handling rollouts and rollback for you, and its RollingUpdate strategy, with maxSurge and maxUnavailable, became the default way most teams ship to Kubernetes. Its limits are also why tools such as Argo Rollouts exist: a plain rolling update can stall on failing health checks but can’t check business metrics or shift traffic by percentage.

Why it’s built this way

Replace a fraction at a time instead of all at once
Keeping most of the fleet on the old version means the service stays up and a bad version only ever reaches one batch before health checks stop it.
Gate each batch on health checks
A new instance gets traffic only once it reports ready. If it never does, the rollout stops before it removes more healthy instances; Apollo halted deployments once failed hosts crossed a threshold.
Bound both extra and missing capacity
Teams with spare room want speed (surge ahead), teams at capacity can’t add instances (replace in place). Two percentages cover both cases without separate strategies.

Timeline

  1. 2014

    Werner Vogels describes Amazon’s Apollo and its rolling updates; AWS launches CodeDeploy in November

  2. 2016

    Kubernetes 1.2 adds the Deployment API (beta) for rollouts and rollback

  3. 2017

    Deployment reaches general availability in the apps/v1 API with Kubernetes 1.9

  4. 2025

    Amazon ECS adds built-in blue/green alongside its rolling updates

Sources12

Improve this page on GitHub