Kubernetes rolling updates are like changing the wheels on a bus while it is still driving. Sounds scary. But Kubernetes can do it safely. The trick is knowing how many old Pods can go away, and how many new Pods can show up, at the same time.
TLDR: A rolling update replaces old Pods with new Pods in small steps. maxUnavailable controls how many Pods can be offline during the update. maxSurge controls how many extra Pods can be created above the desired count. For near zero downtime, use readiness probes and choose values that keep enough healthy Pods serving traffic.
What is a rolling update?
A rolling update is the default update strategy for Kubernetes Deployments. It updates your app slowly, not all at once.
Imagine you have 10 Pods running version 1 of your app. You deploy version 2. Kubernetes does not delete all 10 old Pods at once. That would be chaos. Instead, it creates some new Pods, waits for them to be ready, and then removes some old Pods.
Step by step. Nice and calm.
This is great because users can keep using your app while the update happens. If done well, they may not even notice.
The two magic knobs
Rolling updates are controlled mostly by two settings:
- maxUnavailable
- maxSurge
These sound a bit robotic. But they are simple.
maxUnavailable asks: How many Pods are allowed to be unavailable during the update?
maxSurge asks: How many extra Pods are allowed during the update?
You can set them as numbers or percentages. For example:
maxUnavailable: 1maxUnavailable: 25%maxSurge: 2maxSurge: 50%
If your Deployment has 8 replicas, then 25% means 2 Pods. Kubernetes rounds values in a safe way, depending on the field.
Meet maxUnavailable
maxUnavailable is the “how much pain can we take?” setting.
Let’s say your app has 4 replicas:
- 4 desired Pods
maxUnavailable: 1
This means Kubernetes can allow 1 Pod to be unavailable while updating. So during the rollout, you should still have at least 3 available Pods.
That is useful if your app can handle traffic with 3 Pods. But if your app needs all 4 Pods to survive lunchtime traffic, this setting might hurt.
If you set:
maxUnavailable: 0
Then Kubernetes must keep all desired Pods available during the update. It cannot take an old Pod down until a new Pod is ready. This is often used when you want zero downtime.
But there is a catch. To keep all old Pods available while adding new ones, Kubernetes needs room to add extra Pods. That is where maxSurge enters the party.
Meet maxSurge
maxSurge is the “bring in reinforcements” setting.
Let’s use the same app:
- 4 desired Pods
maxSurge: 1
This means Kubernetes can temporarily run 5 Pods during the update. Four are the desired count. One is the extra helper Pod.
The new Pod starts. Kubernetes waits until it is ready. Then it removes an old Pod. Then it repeats.
This feels like a tiny relay race.
New runner joins. Old runner leaves. The team keeps moving.
How they work together
The real magic happens when maxUnavailable and maxSurge work as a pair.
Here is a common setup:
replicas: 4maxUnavailable: 0maxSurge: 1
This says:
- Never go below 4 available Pods.
- You may temporarily create 1 extra Pod.
- Update slowly and safely.
This is a strong choice for zero-downtime deployments. Kubernetes creates one new Pod. It waits for that Pod to become ready. Then it deletes one old Pod. Repeat until all Pods are new.
Now try this setup:
replicas: 4maxUnavailable: 1maxSurge: 0
This says:
- You cannot create extra Pods.
- You may remove 1 old Pod first.
- Then create a new Pod in its place.
This is more resource-friendly. It does not need extra CPU or memory. But it can reduce capacity during the rollout. If traffic is high, users may feel it.
A simple example
Here is a small Deployment strategy:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
This means Kubernetes should keep all desired Pods available. It can create one extra Pod during the update.
If you have 3 replicas, the rollout may look like this:
- Start with 3 old Pods.
- Create 1 new Pod. Now there are 4 Pods total.
- Wait until the new Pod is ready.
- Delete 1 old Pod. Back to 3 Pods.
- Repeat until all Pods are new.
Nice. Smooth. No drama.
But what does “ready” mean?
This part is huge.
Kubernetes does not magically know if your app is really ready. You must tell it. That is what a readiness probe does.
A readiness probe checks if your app can receive traffic. Maybe it calls an HTTP endpoint like:
/health
If your app says, “Yes, I am ready,” Kubernetes can send traffic to it. If not, Kubernetes waits.
Without readiness probes, Kubernetes may send users to a Pod that is still waking up. That can cause errors. Your rollout may be “technically complete” but still annoying for users.
So if you want zero downtime, do not only tune maxUnavailable and maxSurge. Add good readiness probes too.
Choosing good values
There is no perfect value for every app. Sorry. Kubernetes is powerful, not psychic.
But here are some friendly rules:
- For safer updates: use
maxUnavailable: 0andmaxSurge: 1. - For faster updates: increase
maxSurge. - For lower resource use: allow some
maxUnavailable. - For tiny apps: be careful with percentages. One Pod is a big deal.
- For busy apps: keep enough Pods available to handle peak traffic.
If you have only 1 replica, zero downtime is hard. Really hard. If that one Pod restarts, there may be a gap. For high availability, run at least 2 replicas. Usually more.
Common mistakes
Here are a few classic banana peels:
- No readiness probe. Kubernetes sends traffic too early.
- Too little capacity. The app cannot handle traffic during the update.
- No resource room.
maxSurgeneeds extra CPU and memory. - One replica only. There is no backup Pod.
- Bad startup behavior. The app starts before dependencies are ready.
Also remember this: zero downtime is not just a Kubernetes setting. Your app must support it too.
For example, database migrations can break old Pods. If version 2 changes the database in a way version 1 cannot understand, your rolling update may fail. Use backward-compatible changes when possible.
A good default recipe
For many web apps, a good starting point looks like this:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
Add a readiness probe. Make sure your cluster has enough resources for the extra Pod. Test during a quiet time. Watch metrics. Then adjust.
If rollouts are too slow, try a higher maxSurge. If your cluster is too tight on resources, maybe allow maxUnavailable: 1. But do that only if your app can handle fewer Pods for a short time.
Final thoughts
maxUnavailable and maxSurge are small settings with big effects. One protects availability. The other gives Kubernetes room to move.
Think of maxUnavailable as your safety line. Think of maxSurge as your extra stage space. Together, they decide how smooth your deployment feels.
For zero-downtime deployments, keep enough old Pods running until new Pods are truly ready. Use readiness probes. Run more than one replica. Give Kubernetes enough resources to create surge Pods.
Do that, and your users can keep clicking happily while your app changes costumes backstage.