Zero-Downtime Cluster Upgrades in Kubernetes
How to replace the engine of a flying airplane: the order of steps, the safety nets, the traps and the habits that let a cluster grow up without its users ever noticing.
Imagine a busy train station where trains arrive every minute. Now imagine the station manager says, “Tonight we are replacing the tracks, the signals and the platforms, and the trains will keep running.” That sounds impossible, yet it is exactly what railway crews do, one section at a time, with careful plans and plenty of spare tracks.
A Kubernetes cluster upgrade is much the same job. The cluster has a control plane that makes decisions, nodes that run your applications, and many helper components in between. All of them have versions, and all of them must be replaced over time, because old versions stop receiving security fixes. Yet your customers expect the shop to stay open the whole time.
This guide shows how that is done. We will look at what gets upgraded and in what order, how traffic is moved away from a machine before it is touched, how applications must be prepared to be moved, how to test and watch an upgrade, and what to do when something goes wrong. Each idea comes with an everyday comparison, and there is no code to copy, only the thinking that makes the commands safe.
1Why Upgrades Feel Scary, and Why They Do Not Have To
Most teams fear upgrades because they are rare, large and poorly rehearsed. The cure is to make them small, frequent and boring.
The fear is understandable
A cluster runs everything: the website, the payments, the background jobs. If an upgrade goes wrong, many things break at once. People remember the one terrible upgrade night and decide to postpone the next one. The postponement makes the next upgrade bigger, because more versions have piled up, and a bigger upgrade is scarier. This loop is how teams end up running a cluster that is years old and nobody dares touch.
Why you cannot simply stand still
Fixes stop arriving
Only recent versions receive patches. An old cluster collects known holes that attackers can read about in public.
Help disappears
Community and cloud providers support a limited window of versions. Outside it, you are on your own, or you pay extra.
Better tools wait
New releases bring improvements in scheduling, networking, storage and cost control that your teams cannot use until you upgrade.
Add-ons move on
Operators, ingress controllers and monitoring tools eventually require newer Kubernetes versions, trapping you if you wait.
Interest grows
The longer you wait, the more removed features you must migrate away from at once.
What “zero downtime” really means
Zero downtime does not mean that nothing changes. Machines are stopped, Pods are moved, and components restart. It means that users never see an error or a long pause. To reach that, three things must all be true:
- The cluster itself keeps working, so existing applications continue to run and be reachable while the control plane is upgraded.
- Each application can be moved without dropping requests, because it has several copies, shuts down politely and starts quickly.
- The upgrade is observed and reversible, so that a problem is spotted early and the damage stays small.
A helpful distinction
The control plane being briefly unreachable is not the same as the applications being down. Running Pods keep serving traffic even if the API server restarts, because the nodes and the network keep working by themselves. What you lose temporarily is the ability to change things. That is why a well-built upgrade can be invisible to users even when the control plane is not perfectly available the whole time.
Think of repainting a long bridge. You never close the whole bridge. You close one lane, paint it, reopen it, then move to the next. Drivers see a slower road, not a closed one. Cluster upgrades work the same way: one small part at a time, with the rest carrying the load.
2The Kubernetes Release Rhythm and Support Windows
Kubernetes ships on a steady calendar. Knowing the rhythm tells you how often you must upgrade and how much time you have.
Version numbers
A Kubernetes version has three parts: major, minor and patch. For example, in “1.31.4” the major version is 1, the minor is 31 and the patch is 4. The major number has stayed at 1 for years. The minor number changes with each release that brings new features and sometimes removes old ones. The patch number changes with bug and security fixes only, and patch upgrades are low risk.
The cadence
The project publishes about three minor releases a year, roughly one every four months. Each new minor version receives patch releases for around a year, and then it is declared end of life. In practice, the community maintains the three most recent minor versions at any time. Exact dates move a little from release to release, so check the official release page for the current schedule.
| Kind of upgrade | Example | Typical risk | How often |
|---|---|---|---|
| Patch | 1.31.3 to 1.31.4 | Low, mostly fixes | Monthly or when security fixes appear |
| Minor | 1.31 to 1.32 | Medium, can remove or change features | At least two or three times per year to stay supported |
| Skipping a minor | 1.30 to 1.32 in one jump | Not supported; must go through 1.31 | Avoid |
What this means for planning
- If you upgrade every minor release, you do about three small upgrades a year.
- If you upgrade every second release, you do about two per year, but you hop across more changes at once. You still pass through each minor version in between.
- If you fall more than a year behind, you leave the community support window and begin a catch-up marathon of several sequential upgrades.
Cloud provider calendars
Managed services such as Amazon EKS, Google GKE and Azure AKS publish their own calendars. They usually offer a version for a while after the community release, and then support it for a fixed period. Some offer extended support for a fee. When a version leaves support, the provider may upgrade your control plane automatically. A cluster that you do not plan for will eventually be upgraded on the provider’s schedule, which is the worst time to find problems.
Think of the phone software on your pocket device. Small updates arrive often and install quickly. Big annual updates change how things look and work. If you ignore the updates for three years, your apps stop working and the next jump is painful. Cluster versions behave in the same way.
Put the end-of-life date of your current version in the team calendar, and schedule the upgrade at least two months before. Treat it like renewing a passport, not like an emergency.
3Version Skew: Who May Be Older Than Whom
During an upgrade, different parts of the cluster run different versions for a while. Kubernetes defines exactly how far apart they may be.
Why skew exists
You cannot upgrade a whole cluster in one instant. The control plane is replaced first, then the nodes, one by one. For hours, or even days, parts of the cluster speak different versions. Kubernetes makes this safe by publishing a version skew policy: a set of rules about which components may lag behind which.
The rules in plain terms
| Component | Allowed relation to the API server |
|---|---|
| API server instances (in a highly available setup) | May differ from each other by one minor version, so you can upgrade them one at a time |
| Controller manager, scheduler, cloud controller manager | Must not be newer than the API server; may be one minor version older |
| Kubelet on nodes | Must not be newer than the API server; may be older by several minor versions (three in recent releases, two in older ones) |
| Kube-proxy on nodes | Same age rules as kubelet, and should not be newer than the kubelet by more than one minor version |
| kubectl and other clients | May be one minor version newer or older than the API server |
The golden rule
The API server must always be the newest component. Nothing talks to a server that is older than itself, because it might ask for features that the server does not know. That single rule explains the whole upgrade order: control plane first, then workers.
Why the kubelet allowance matters
Because kubelets may lag, you can upgrade the control plane quickly and then take your time with the nodes. For a large fleet, this gap is a relief. It also lets you take a break in the middle of an upgrade if something looks wrong. Do not abuse it, though. Running nodes far behind for months makes the next upgrade harder, and some features only work when nodes are current. Check the exact numbers in the official policy for your version, since the allowed gap has changed over time.
Skew in add-ons
The skew policy covers the core components. Add-ons such as the network plugin, the storage drivers, ingress controllers and operators have their own compatibility tables. These are often more restrictive than the core rules and are a frequent source of surprises. Always read the compatibility table of each add-on before upgrading Kubernetes.
Think of a company that rolls out a new rulebook. The head office gets the new book first. Branch offices may still follow the old book for a few weeks, but a branch must never follow a newer book than head office, since it would be quoting rules that head office does not understand yet.
Installing a newer kubectl or a newer node image than the control plane is a quiet violation. Node pools created from a “latest” image after the control plane upgrade may be fine, but a node pool created before it with a newer kubelet than the API server is not allowed.
4What Is Actually Being Upgraded
“Upgrading the cluster” hides many separate parts. Listing them makes the plan concrete.
flowchart TB
subgraph CP["Control plane"]
API["API server"]
ETCD[("etcd - the cluster's memory")]
SCH["Scheduler"]
CM["Controller manager"]
CCM["Cloud controller manager"]
end
subgraph NODES["Worker nodes"]
KL["Kubelet"]
KP["Kube-proxy"]
RT["Container runtime"]
OS["Operating system and kernel"]
end
subgraph ADD["Add-ons"]
CNI["Network plugin"]
DNS["CoreDNS"]
CSI["Storage drivers"]
ING["Ingress controller"]
MET["Metrics and monitoring agents"]
end
subgraph APPS["Your workloads"]
P1["Applications"]
P2["Operators and custom resources"]
end
API --> ETCD
SCH --> API
CM --> API
KL --> API
KP --> API
ADD --> API
APPS --> NODES
Reading the diagram
The four boxes are four layers. The control plane holds the decision-makers and the memory. The worker nodes run containers. The add-ons are helpers installed on top, often as ordinary Pods. Your own workloads sit on the nodes. Arrows show who talks to whom: nearly everything talks to the API server, which is the front door of the cluster, and only the API server talks to etcd.
What each layer means for an upgrade
| Layer | What changes | User impact if done well |
|---|---|---|
| Control plane | Binaries for API server, scheduler, controllers; sometimes etcd | None for running apps; changes briefly unavailable |
| Nodes | Kubelet, proxy, runtime, node image and kernel | Pods are moved; none if apps are prepared |
| Add-ons | Network, DNS, storage, ingress, metrics | Possible short network or storage blips if mishandled |
| Workloads | Usually nothing, but removed APIs may require manifest changes | None if migrated in advance |
Three kinds of “upgrade” people mix up
- Control plane upgrade: new versions of the decision-making components.
- Node upgrade: new kubelet and often a new machine image, which usually replaces or restarts the machines.
- Add-on upgrade: new versions of helpers, which are managed separately and sometimes by a different team.
A complete plan covers all three, and a good plan assigns an owner to each.
A city has a town hall (control plane), buildings where people live (nodes), roads, water and power (add-ons), and the residents themselves (your workloads). “Upgrading the city” means upgrading all of these, and each has different people responsible and a different effect on the residents.
5The Upgrade Order: A Safe Sequence
The order of steps is not a matter of taste. Each step prepares for the next, and each has a way back.
flowchart LR A["1. Read release notes and deprecations"] --> B["2. Fix removed APIs and check add-on compatibility"] B --> C["3. Back up etcd and key resources"] C --> D["4. Upgrade control plane"] D --> E["5. Verify control plane health"] E --> F["6. Upgrade add-ons that require it"] F --> G["7. Upgrade nodes in small batches"] G --> H["8. Verify workloads and metrics"] H --> I["9. Upgrade remaining add-ons and clean up"]
Walking through the order
Read the notes
The release notes list new features, removed features and special instructions. This takes an hour and saves a night.
Prepare the ground
Find workloads that use APIs about to be removed, and check each add-on supports the target version.
Take a backup
Create a restorable copy of etcd, and export the important resource definitions to version control.
Upgrade the control plane
Replace the decision-making components, one instance at a time if there are several.
Check health
Confirm the API answers, controllers work, and nothing unusual appears in logs.
Add-ons that must go first
Some helpers, such as the network plugin or DNS, may need a version bump to work with the new control plane.
Nodes in batches
Move workloads off a few nodes, upgrade them, return them to service, then repeat.
Verify
Watch error rates, latency and restarts as each batch finishes, not only at the end.
Finish and tidy
Upgrade the remaining helpers, remove temporary settings, and write down what you learned.
Why control plane before nodes
Because the API server must be at least as new as everything that talks to it, workers can never go first. And because nodes may lag, there is no rush to finish them right after the control plane. You have the freedom to pause between steps.
Why small batches
If you upgrade ten percent of the nodes and something looks wrong, ninety percent of the fleet is still healthy and you can stop. If you upgrade everything at once, a hidden problem hits everywhere together. Small batches turn a possible disaster into a minor, containable incident.
Moving house goes best in a similar order. You read the new lease first, pack carefully, make a copy of the important papers, move the heavy furniture, check that the water and lights work, and only then move the rest, room by room, rather than throwing everything in the truck at once.
Write the order as a checklist in your runbook, with “stop here if” conditions after each step. A checklist that says when to stop is more valuable than one that only says what to do.
6Upgrading the Control Plane Without Interruption
The control plane is the cluster’s brain. Upgrading it safely depends mostly on having more than one of everything.
High availability is the foundation
A highly available control plane runs at least three copies of the API server and the memory store, spread over different machines or zones. A load balancer sits in front of the API servers and sends requests only to healthy ones. With this setup, you can upgrade one instance at a time: the others keep answering while one is replaced. Without it, a single control plane machine means a short but real period when nobody can change the cluster.
The one-at-a-time dance
- Remove one API server from the load balancer, or let health checks do it when it restarts.
- Upgrade it and wait until it reports healthy.
- Return it to service and check logs and metrics.
- Move to the next instance.
During this time, two versions of the API server run together. That is allowed by the skew policy, as long as they differ by at most one minor version.
The other control plane components
The scheduler and the controller manager use a leader election system. Several copies run, but only one is active at a time. When the active one restarts for the upgrade, another takes over within seconds. During these seconds, no new Pods are placed and no controllers react, but running Pods are unaffected. Their short pause is generally invisible to users.
What users may notice, and what they will not
| Event | Effect on running applications | Effect on changes |
|---|---|---|
| One API server restarts | None | Brief errors only for requests that hit that instance |
| Leader scheduler changes | None | New Pods wait a few seconds for placement |
| Controller manager changes | None | Scaling and repairs are delayed for a few seconds |
| Whole control plane unavailable | Existing Pods keep serving, but cannot be repaired or scaled | No changes accepted |
Clients that talk to the API server
Your own operators, autoscalers, CI systems and tools call the API server constantly. They should retry on errors, and reconnect when a watch connection drops. An upgrade is a good test of whether they do. Controllers written with standard libraries handle this well. Hand-written scripts often do not.
Managed control planes
On managed services, the provider runs and upgrades the control plane for you, usually with high availability built in. You press a button or update a setting, and wait. You still own the planning: choosing the time, preparing the workloads and checking compatibility. And you cannot easily roll back a managed control plane, so the preparation matters even more.
A hospital with three doctors on duty can let one go for a break at a time, and patients are always seen. A hospital with a single doctor has to close the door when that doctor steps out. High availability is simply having someone else covering for the one being replaced.
Running three control plane machines in one zone feels safe but is not. If the zone goes down, or if you upgrade the machines together by mistake, the redundancy vanishes. Spread them across zones and upgrade them separately.
7etcd: Protecting the Cluster’s Memory
Everything Kubernetes knows is stored in etcd. If it is lost and you have no backup, the cluster forgets what it was running.
What etcd holds
etcd is a small, reliable database. It stores every object in the cluster: Deployments, Services, Secrets, configuration, custom resources and more. It does not hold your application data, such as customer records in a database, but it holds the instructions that tell Kubernetes how to run everything. Lose it, and the running Pods continue for a while, but the cluster can no longer manage them.
Why it matters during upgrades
Some upgrades change the version of etcd, or the format in which objects are stored. A new Kubernetes version may also migrate stored objects to newer API versions. If something fails halfway, the stored data is what you must restore. That is why a verified backup is the first safety step.
The backup rules
- Take a snapshot right before the upgrade, not last week. A recent one loses the least.
- Store it outside the cluster, in a separate account or location, so that it survives a cluster failure.
- Protect it, because it contains secrets in a readable form unless encryption at rest is turned on.
- Test a restore at least once, in a scratch environment. A backup that has never been restored is a hope, not a plan.
- Record the version of etcd and Kubernetes the snapshot belongs to.
Cluster health and quorum
etcd uses a voting system called quorum. With three members, two must agree for changes to be accepted, so one member can fail safely. With five members, two can fail. During an upgrade of a three-member etcd, upgrading one member at a time keeps quorum, but taking two down together stops the cluster from writing. Always upgrade etcd members one by one, and wait for each to rejoin and sync before touching the next.
Managed services and backups
On managed services you cannot reach etcd directly, and the provider handles its safety. You should still keep your own copies of the important resources, usually by storing manifests in version control or using a backup tool that exports cluster objects, so that you can rebuild if needed. Note that stored cloud volumes and databases need their own backups as well.
etcd is like the master ledger of a company, recording who owns what and who does what. Before a major renovation of the office, you make a photocopy of the ledger and store it in a different building. You also check that the photocopy is readable, since discovering it is blank after a fire would be too late.
Automate daily etcd snapshots, and make “restore test passed this quarter” one of the checks on your upgrade readiness list.
8Three Ways to Upgrade Worker Nodes
Nodes are the machines that carry your applications. How you replace them decides how smooth the upgrade feels.
Strategy one: in-place
You take an existing node out of service, upgrade the software on it, and bring it back. This keeps the same machine, the same address and local disks. It is the traditional method for self-managed clusters. It is simple, but the machine’s history accumulates over time, and a failed upgrade leaves a half-changed machine that is hard to reason about.
Strategy two: rolling replacement
You create a new node from a fresh image with the new version, join it to the cluster, move workloads over, and delete the old node. Each machine is new and clean, and the old one is thrown away. This is the usual method on managed services and with auto scaling groups. It needs a little extra capacity during the process, often called “surge.”
Strategy three: blue/green node pools
You create a whole new group of nodes at the new version, called the green pool, while the old blue pool continues to run. Then you move workloads across in controlled steps, watching the results. If something is wrong, you can send workloads back to the blue pool, which still exists. When satisfied, you delete the blue pool. This costs the most in temporary capacity, but it gives the best way back.
| Strategy | Extra capacity needed | Rollback ease | Machine cleanliness | Best for |
|---|---|---|---|---|
| In-place | Little | Hard | Drifts over time | Small or bare-metal clusters |
| Rolling replacement | A few extra nodes | Moderate | Always fresh | Most cloud clusters |
| Blue/green pools | A full second pool for a while | Easy until old pool is deleted | Always fresh | Critical workloads and big version jumps |
Surge and unavailable settings
Managed node groups and similar tools let you set two numbers. The surge says how many extra nodes may be created above the normal count while upgrading. The max unavailable says how many nodes may be out of service at once. A larger surge makes the upgrade faster and safer for workloads, because capacity is never reduced. A larger unavailable count makes it faster but cheaper, at more risk. For production, a common safe default is a surge of at least one node, with no more than one node unavailable per zone.
Immutable nodes
The more your nodes are treated as disposable, the easier upgrades become. If nodes are built from an image and nobody logs in to change them by hand, then replacing a node is a routine event, and every node of a given pool is identical. Teams that keep hand-tuned “pet” machines find upgrades far harder.
Changing a team of workers can be done in three ways. You can retrain each worker in place, which is quick but uneven. You can hire a new worker, train them alongside the old one and then let the old one go, which is clean. Or you can bring a complete new team and run both side by side for a while, which costs the most but lets you go back if the new team is not ready.
Managed services handle much of this for you, but the choices of surge, unavailable count and timing are yours, and they decide whether your users notice the upgrade.
9Cordon, Drain and Eviction: Emptying a Node Politely
Before a node is touched, its Pods must be moved away. Kubernetes has a gentle, well-defined way to do that.
Cordon: no new guests
Cordoning marks a node as unschedulable. Pods already there keep running, but the scheduler will not place any new Pods on it. It is like putting a “no vacancy” sign on a hotel: current guests stay, no new ones are admitted.
Drain: please move out
Draining cordons the node and then asks every Pod on it to leave. It does so using the eviction process, not by simply deleting Pods. The difference is crucial: eviction checks the rules you have set for each application, especially the PodDisruptionBudget, and refuses to remove a Pod if doing so would break the budget. The drain tool then waits and retries until the Pod can leave safely.
What drain does and does not move
- Moves: ordinary Pods managed by Deployments, StatefulSets, Jobs and similar controllers. The controller recreates them elsewhere.
- Skips: Pods managed by DaemonSets, since they are meant to run on every node. Drain is usually told to ignore them.
- Refuses by default: Pods that are not managed by any controller, since they would be lost forever, and Pods using local temporary storage, unless you allow it explicitly.
- Waits for: a Pod’s termination grace period, so that it can finish its work.
The eviction journey of a single Pod
sequenceDiagram autonumber participant OP as Operator or upgrade tool participant API as API server participant PDB as Disruption budget check participant KL as Kubelet on the node participant POD as Pod participant CTL as Deployment controller participant SCH as Scheduler OP->>API: Cordon node OP->>API: Request eviction of Pod API->>PDB: Would this break the budget? PDB-->>API: Allowed API->>POD: Mark for deletion KL->>POD: Run preStop step, send termination signal POD-->>KL: Finishes in-flight work and exits CTL->>API: Create replacement Pod SCH->>API: Place it on another node Note over OP,SCH: If the budget forbids, the request is refused and retried later
Reading the diagram
The tool first asks the API server to evict a Pod. The server consults the disruption budget; if the answer is no, the request is refused and the tool tries again later. If yes, the Pod is marked for deletion and the kubelet on the node tells it to stop politely. Meanwhile, the controller notices a missing replica and creates a new one, and the scheduler puts it on another node. The ideal is that the replacement is ready before the original has finished leaving.
Timeouts and stuck drains
A drain can hang when a budget blocks eviction forever, for example when an application has a single replica and a budget that allows zero disruptions, or when a Pod refuses to terminate. Tools let you set a timeout. When a drain gets stuck, investigate why, instead of forcing it. Forcing a delete bypasses the safety checks and is the usual cause of user-visible errors during upgrades.
Emptying a node is like closing one floor of a store for renovation. You put up a sign so that no new shoppers enter, ask the customers politely to move to the other floors, wait for them to finish what they are doing, and make sure the other floors still have enough staff. You do not switch off the lights while customers are at the counter.
Using a “force” option to get through a blocked drain skips the safety net. If a drain is blocked, that is the system telling you that your application is not ready to be moved. Fix the application, then continue.
10PodDisruptionBudgets: The Promise Each App Makes
A PodDisruptionBudget is the way an application tells the cluster how many of its copies may be taken away at once during planned maintenance.
What it says
A PodDisruptionBudget, usually shortened to PDB, selects a group of Pods by label and states one of two rules: “at least this many must stay available,” or “at most this many may be unavailable.” The number can be a count or a percentage. When a drain tries to evict a Pod, the cluster counts how many Pods of the group are healthy and refuses the eviction if it would break the rule.
Choosing the right number
| Replicas | Reasonable budget | Effect during a drain |
|---|---|---|
| 1 | None really works; the service needs more replicas | Either the drain blocks forever or the service goes down |
| 2 | At most 1 unavailable | One Pod moves at a time; capacity halves briefly |
| 3 to 5 | At most 1 unavailable | Steady, safe movement |
| 10 or more | At most 10 to 20 percent unavailable | Several move at once, faster upgrade |
Two ways to get it wrong
A budget that is just right
- Allows at least one Pod to move at a time
- Reflects real capacity needs
- Lets upgrades complete in reasonable time
- Reviewed whenever replica counts change
Budgets that cause trouble
- “Zero disruptions allowed” blocks every drain forever
- Missing budgets let all copies vanish at once
- Percentages that round to zero for small deployments
- Selectors matching the wrong Pods
The budget covers voluntary disruptions only
PDBs protect against planned actions: drains, upgrades and similar requests that go through the eviction process. They cannot protect against a node crashing or a machine being removed without warning. For those, you need more replicas and good spreading, which later chapters cover.
Budgets and health
A Pod counts as available only when it is ready. If an application is already struggling, with several Pods not ready, a budget may refuse any further eviction. This is good behavior: it stops the upgrade from making a bad situation worse. It also means that a broken application can block an upgrade until it is fixed.
An audit worth doing before every upgrade
- Find all workloads with only one replica, and decide whether to scale them up for the upgrade.
- Find all budgets that allow zero disruptions.
- Find all workloads that are important but have no budget.
- Check that each budget selects the right Pods.
A budget is like the rule at a lifeguard station: “at least two lifeguards must always be on duty.” When one wants a break, the manager checks the rule. If only two are present, the break must wait until a replacement arrives. The rule protects swimmers even when everyone is busy.
Let a policy engine require a budget for every workload with more than one replica. It turns a manual audit into a permanent guardrail.
11Graceful Shutdown: How a Pod Leaves Without Dropping Requests
Moving a Pod is easy. Moving it without losing a single customer request needs a precise choreography.
The two things that happen at once
When a Pod is told to terminate, two processes begin at the same time, and they do not wait for each other. First, the Pod is marked as terminating and removed from the lists of endpoints that Services use to send traffic. Second, the kubelet tells the container to shut down. The trouble is that removal from the endpoint lists takes a moment to reach every proxy and load balancer. If the container exits too quickly, some requests are still sent to it and fail.
sequenceDiagram
autonumber
participant API as API server
participant EP as Endpoint update
participant LB as Proxies and load balancers
participant KL as Kubelet
participant APP as Application container
API->>KL: Pod marked as terminating
API->>EP: Remove Pod from service endpoints
par Traffic side
EP->>LB: New endpoint list spreads
Note over LB: Takes a few seconds to reach everyone
and Container side
KL->>APP: preStop pause begins
Note over APP: Keeps serving while traffic drains away
end
KL->>APP: Send termination signal
APP->>APP: Finish in-flight requests, close connections
APP-->>KL: Exits cleanly
Note over KL,APP: If the grace period ends first, a forced kill follows
The ingredients of a clean exit
A short preStop delay
A few seconds of waiting before the shutdown signal, so that the traffic lists update first. The application keeps serving during this wait.
Handle the termination signal
The application must notice the signal, stop accepting new work, and finish what it has started.
Enough grace period
The time Kubernetes waits before forcing a kill must be longer than the pause plus the longest normal request.
Fail readiness on shutdown
Some applications flip their own readiness check to failing as soon as shutdown begins, which helps pull them out of rotation faster.
Close long-lived connections politely
Applications with persistent connections, such as streaming or websockets, should tell clients to reconnect elsewhere.
Receive the signal at all
If the container starts through a wrapper script that does not pass signals on, the real application never hears the request to stop.
Reading the diagram
Step through the picture from the top. The two branches in the middle are the heart of the matter. On the left, the news that the Pod is leaving spreads to proxies and load balancers. On the right, the container is told to wait a little. The termination signal is sent only after that pause, by which time most of the traffic has already gone elsewhere. The final note shows the safety limit: if the application takes longer than the grace period, it is killed anyway, and any request still running is lost.
Slow-starting replacements
Graceful exit is only half of the story. The replacement Pod must start and become ready quickly, or capacity will sag. Long start-up times, large images, heavy cache warming or slow health checks all lengthen the period when you are short of capacity. Startup probes can protect slow starters from being killed too early, and pre-pulled images shorten start time.
Test it before the upgrade
You can test graceful shutdown in staging by deleting a Pod during a steady load test and watching for errors. If a single deletion causes failed requests, a full upgrade will cause many. This one test finds a large share of upgrade problems.
A waiter finishing a shift does not walk out mid-meal. First the manager stops seating new guests at his tables (traffic removal). The waiter keeps serving the current guests, then hands over the keys and leaves (graceful shutdown). If the waiter leaves the instant the shift is announced over, the dishes at his tables never arrive.
Many teams set a long grace period and assume they are safe, but the application ignores the termination signal. It then sits idle until the time runs out and is killed, making every upgrade slow and still dropping requests.
12Spreading Pods So No Single Machine Matters
An application with ten replicas is not safe if all ten live on one machine. Spreading makes sure that losing any one place costs only a small slice.
The tools for spreading
- Topology spread constraints tell the scheduler to distribute Pods evenly across zones, nodes or other groupings, with a limit on how uneven the spread may be.
- Pod anti-affinity says that Pods of a certain kind should not share a node or zone with each other.
- Node selectors and affinity place Pods on certain kinds of nodes, which also affects what happens when those nodes are upgraded.
Why spreading matters for upgrades
During a node upgrade, the machines go out of service one at a time, or a few at a time. If an application has three replicas, and two of them sit on the same node, draining that node removes two thirds of the capacity at once. A PDB would block the drain, which is safe but slow. Good spreading means every drain removes at most one replica of any application, and the upgrade flows steadily.
A small worked picture
| Placement of 3 replicas | Drain of node A | Outcome |
|---|---|---|
| All on node A | All three evicted together | Budget blocks; or outage if no budget |
| Two on node A, one on B | Two evicted | Budget blocks; drain waits |
| One on each of A, B and C | One evicted | Budget allows; replacement starts elsewhere |
Zones
Spread across at least three zones for important services, so that a zone-wide problem or a zone-by-zone upgrade never removes more than a third. Remember that spread rules apply at scheduling time. After nodes are replaced, Pods may drift into an uneven layout. A descheduler tool, or simply the natural churn from regular upgrades, helps re-balance them.
Do not over-constrain
Strict rules, such as “never two Pods on one node,” can leave Pods unschedulable when nodes are few, especially during a node upgrade when capacity is already reduced. Use “preferred” rules for secondary goals, and strict rules only for the real requirements. Check that the cluster has room for the spread you demand.
A smart traveler does not pack all money in one bag. If a bag is lost, only a share is gone. Spreading replicas across machines and zones follows the same logic, and makes each upgrade step lose only a small, replaceable share.
Before upgrading, list for each critical service how many of its Pods run on each node. If any node holds more than one Pod of a service that has only a few replicas, rebalance first.
13Capacity Planning for the Upgrade Itself
An upgrade temporarily removes machines. If the rest cannot carry the load, users feel it, no matter how clever your drain is.
The simple arithmetic
If you drain one node out of ten, you lose ten percent of capacity. If you drain three at once, you lose thirty percent. If the cluster normally runs at 80 percent of capacity, losing 30 percent takes it past 100 percent, and Pods will stay pending or compete for resources. Your cluster’s headroom, which is the spare capacity above normal use, decides how fast you can safely go.
Ways to create room
Add temporary nodes
Create extra nodes at the start of the upgrade, and remove them at the end. This is the simplest and safest approach.
Reduce how many at once
Upgrade one node, or one node per zone, at a time. It takes longer but removes little capacity.
Choose a quiet time
Upgrade when traffic is lowest, but remember that “quiet” varies by region and business.
Add replicas for the window
Raise replica counts of key services before starting, so that losing a few still leaves enough.
Autoscalers during upgrades
Cluster autoscalers add and remove nodes in response to pending Pods and idle capacity. During an upgrade they can help, by adding capacity when drained Pods have nowhere to go. They can also cause confusion, by removing a node you just added because it looks idle, or by creating nodes with the old version. Decide before starting whether to pause the autoscaler, or to make sure it uses the new node image. Horizontal Pod autoscalers, which scale replica counts by load, may react to the brief rise in load as Pods move; ensure their limits allow it.
Resource requests matter
The scheduler places Pods by their declared requests, not by actual usage. If requests are wildly too large, nodes look full when they are mostly empty, and drained Pods cannot find space. If requests are too small, nodes are overpacked and Pods squeeze each other when they are all moved together. Realistic requests are a quiet prerequisite for smooth upgrades.
Quota, limits and cloud limits
Surge nodes need room in your cloud account: enough instance quota, IP addresses in the subnets and capacity in the chosen instance type. Many upgrades stall because the account could not create the extra machines. Check the quotas, and have a fallback instance type, before the maintenance window.
A restaurant renovating its dining room in sections can only do so if the other sections can seat the diners. On a night when every table is full, closing a section means turning people away. You either bring in extra tables, renovate on a quiet night, or close fewer tables at a time.
Use Case: The stalled upgrade
A team began a node upgrade late on a Friday afternoon, during the weekly sales peak. The first node drained fine, but the replacement could not start because the subnet had run out of free IP addresses. Pods stayed pending, the next drain was blocked by budgets, and the whole upgrade froze with one node missing. The team paused, added address space and resumed on Monday morning. Their runbook now includes an address and quota check, and upgrades happen on quiet weekday mornings.
14Stateful Workloads and Storage During Upgrades
Applications with data attached are harder to move than those without. The upgrade must respect where the data lives.
How stateful sets move
A StatefulSet gives each Pod a stable identity and its own storage volume. When a Pod is drained, it is recreated with the same name and reconnects to the same volume. The default update behavior replaces Pods one at a time, in reverse order, waiting for each to become ready. This is the natural rhythm of a safe upgrade, but it also means a slow one, particularly if each Pod takes minutes to start.
Volumes and where they live
- Zone-bound volumes: Many cloud disks can only attach to machines in the same zone. A Pod with such a volume can only move to another node in the same zone. If that zone has no spare node, the Pod stays pending.
- Attach and detach time: Moving a volume from one node to another takes time, sometimes a minute or more, and occasionally gets stuck.
- Local disks: Volumes on the node’s own disk disappear when the node is replaced. Replicated databases can rebuild from peers, but that takes time and load.
- Shared file systems: Network file storage moves easily, but performance and locking behavior vary.
Databases and replication
For replicated databases, the golden rule is to move one replica at a time and wait for it to catch up before touching the next. Moving a leader requires a failover, which causes a short pause for writes. Plan for that by upgrading followers first, and then switching leadership deliberately at a calm moment. Use budgets that prevent more than one member from leaving at once, and probes that report a replica as ready only when it is in sync.
Storage drivers and snapshots
Storage is connected to Kubernetes through drivers that run as Pods and DaemonSets. They must be compatible with the new version, and they should be upgraded in the order their documentation says. Before upgrading, take volume snapshots or database backups of important data. A Kubernetes upgrade should not harm data, but the combination of an upgrade and an unfortunate detach can.
Operators
Many stateful systems are run by operators, which are controllers with specialized knowledge, such as how to fail over a database cluster. Their behavior during node drains varies. Some handle them intelligently, while others need special annotations or a maintenance mode. Read the operator’s upgrade notes, and test a drain in staging.
| Concern | What to do before the upgrade |
|---|---|
| Data safety | Fresh backups or snapshots, with restore tested |
| Replica health | All replicas in sync and ready |
| Zone capacity | Spare nodes available in each zone that holds volumes |
| Leader movement | Plan a controlled failover, not a surprise one |
| Start time | Know how long each Pod takes to become ready |
| Operator guidance | Read the vendor’s upgrade notes |
Moving a stateless service is like moving a rented chair: pick it up and put another one in its place. Moving a stateful service is like moving a piano. It must be wrapped, carried slowly, placed on the right floor, and tuned afterwards. You also move only one piano at a time.
Using local disks for important data and then replacing nodes as part of the upgrade can erase that data. Make sure that the data is replicated and recoverable elsewhere before the old node is deleted.
15Managed Kubernetes: What the Provider Does and What You Do
On Amazon EKS, Google GKE and Azure AKS, much of the heavy lifting is done for you, but the responsibility for a smooth experience still has a split.
Shared responsibility
| Area | Typically the provider | Typically you |
|---|---|---|
| Control plane upgrade | Runs the upgrade, keeps it highly available | Chooses version and timing; checks compatibility |
| etcd | Operates and protects it | Keeps your own manifests and backups of important resources |
| Node images | Publishes new images | Chooses to adopt them, and sets surge and unavailable counts |
| Add-ons | Manages some core add-ons, depending on service | Upgrades add-ons you installed; checks managed ones follow |
| Workloads | Nothing | Budgets, graceful shutdown, spread, capacity, testing |
Common patterns across providers
- Control plane first, node pools next. The provider upgrades the control plane on request, then you upgrade each node group separately.
- Surge-based node upgrades. Managed node groups create new nodes, drain old ones and respect disruption budgets, up to a time limit. If a drain exceeds the limit, some services may force the upgrade to continue or mark it failed, so know your provider’s behavior.
- Auto-upgrade channels. Some providers offer release channels or automatic upgrades. These are convenient but can surprise you; use maintenance windows and exclusions to control the timing.
- Extended support. Some providers keep older versions alive for an additional fee, which can buy time but not safety forever.
- Limited rollback. You generally cannot downgrade a managed control plane. Plan on rolling forward or switching to a second cluster.
Provider-specific details to check
Each provider has its own particulars, such as how the add-ons for networking and DNS are versioned, how long a node drain is allowed to take, what the default surge setting is, and whether nodes may be upgraded straight to the control plane version. These details change over time. Read the current documentation of your provider before every minor upgrade, instead of relying on habit.
Serverless and autopilot modes
Some offerings run nodes entirely for you, so there are no node pools to upgrade. The provider replaces nodes on its own schedule, which makes your workloads’ tolerance for moves even more important. You control the timing mostly through budgets and maintenance windows.
Living in a rented apartment, the landlord repairs the building structure and the pipes. You still decide when to be at home, how to protect your furniture, and whether your own appliances work with the new wiring. The landlord’s work does not remove your own preparation.
Set maintenance windows and exclusion periods, such as around sales events, so that an automatic upgrade never lands on your busiest day.
16Self-Managed Clusters: The Hands-On Path
If you run Kubernetes on your own machines, you perform what the managed services do for you. The sequence is well established.
The shape of the process with common tooling
Installers such as kubeadm provide a guided upgrade path. In outline, the process runs like this:
Plan
The tool reads the current state and tells you which versions you may upgrade to, and which components will change.
First control plane node
Upgrade the package for the tooling, apply the upgrade on the first control plane machine, then upgrade its kubelet and restart it.
Other control plane nodes
Repeat on each remaining control plane machine, using the lighter “node” form of the upgrade, one at a time.
Workers
For each worker: cordon and drain, upgrade the tooling and kubelet, restart, then uncordon.
Verify
Check node versions, Pod health and add-on status.
Things you must handle yourself
- Load balancing of the API server: your own load balancer must remove a control plane node while it restarts.
- Certificates: control plane certificates are renewed during upgrades, and the upgrade is a good time to check their expiry dates.
- Package repositories: Kubernetes packages are published in repositories per minor version, so the repository setting must be changed before each minor step.
- Container runtime: the runtime may need its own upgrade, and it should be compatible with the kubelet version.
- Operating system: kernel and system updates often arrive with node maintenance; decide whether to combine them with the Kubernetes upgrade or keep them separate.
- Configuration drift: check that kubelet settings are the same across nodes, and that custom flags are still valid in the new version.
Automation tools for self-managed fleets
Cluster API treats clusters as declared objects, so changing the version in a definition triggers a rolling replacement of control plane and worker machines. Other tools, such as configuration management systems and image-based approaches, let you rebuild nodes from a fresh image. The more of the process is declared in files and automated, the less one-off human work remains, and the lower the risk of a typing mistake at midnight.
Rehearsal is worth more here
With no provider safety net, rehearse the entire procedure on a copy of the cluster, including the control plane load balancer and certificate behavior. Time each step, and write down surprises. The runbook that comes out of a rehearsal is the best insurance you can buy.
Servicing your own car in a garage lets you do everything exactly as you wish, but there is no mechanic to catch your mistakes. A written checklist, the right tools laid out in advance, and a practice run on an old car beforehand make the difference between a smooth job and a Sunday spent beside a broken engine.
17Add-ons: The Helpers That Also Need Care
The network plugin, DNS, storage drivers and ingress controllers are Pods like any other, but a mistake with them affects everything at once.
The big add-ons and their risk
| Add-on | What it does | What can go wrong during upgrades |
|---|---|---|
| Network plugin (CNI) | Gives Pods network addresses and connects them | Pods on new nodes cannot reach others, or lose connectivity during agent restarts |
| CoreDNS | Resolves service names | All name lookups slow or fail if too few replicas or a bad configuration |
| Kube-proxy or replacement | Implements service routing on each node | Rules differ between versions; routing gaps while restarting |
| Storage drivers (CSI) | Create, attach and mount volumes | Volumes fail to mount or detach during node moves |
| Ingress or gateway controller | Brings outside traffic into the cluster | Dropped connections, mis-routed requests, changed behavior of annotations |
| Metrics and monitoring agents | Collect numbers and logs | Blind spots in dashboards exactly when you need them |
| Policy and security agents | Enforce rules, scan workloads | Strict new defaults blocking Pods that used to be accepted |
| Autoscalers | Adjust Pods and nodes | Incorrect decisions while the cluster is in flux |
Rules for add-on upgrades
- Read compatibility tables first. Each add-on lists which Kubernetes versions it supports. Check both the current and target versions.
- Know the order. Some add-ons must be upgraded before the control plane, others after. The vendor documentation says which.
- Run more than one copy. DNS, ingress and similar critical add-ons should have several replicas, spread across nodes, with budgets and graceful shutdown.
- Roll out slowly. DaemonSet add-ons, which run on every node, should update with a limit on how many nodes are changed at once.
- Watch the basics. After each add-on change, test name resolution, Pod-to-Pod connectivity, an external request and a volume mount.
- Keep a way back. Know the previous version and how to return to it quickly.
A smoke test for the platform
Create a small set of canary checks that run continuously: one that resolves a name, one that calls a service in another namespace, one that reaches an outside address, one that writes to a volume, and one that sends a request through the ingress. After each upgrade step, these tell you in seconds whether the platform basics are intact, long before any customer reports a problem.
Add-ons are the water, electricity and roads of the city. Residents rarely notice them until they fail, and then nothing else works. City crews therefore test each repaired pipe before reconnecting the next street, and keep a few spare crews on standby.
Upgrading Kubernetes and the network plugin on the same night, to “save time,” removes your ability to tell which one caused a problem. Change one thing at a time and test after each.
18API Deprecations and Removals: The Hidden Tripwire
The most common reason an upgrade breaks applications is not the machines. It is a Kubernetes feature that your manifests still use but the new version no longer offers.
How Kubernetes retires an API
Kubernetes objects have versions in their names, such as a beta version and a stable version. When a better version arrives, the older one is marked deprecated, which means “still working, but please move.” After a promised period, spanning several releases, the old version is removed. After removal, any request that uses it fails. Objects already stored in the cluster are converted, but your deployment files, charts and tools that still name the old version will break.
Where old APIs hide
Files in repositories
Old deployment definitions that nobody has touched for years.
Packaged templates
Third-party and in-house charts that hard-code old versions.
CI and deploy scripts
Scripts that create objects directly with an outdated format.
Controllers and agents
Software running in the cluster that calls removed APIs at runtime.
Dashboards and scripts
Monitoring, backup and admin tools with their own client libraries.
Finding them before they find you
- Read the deprecation guide published for each release. It lists exactly which versions are removed.
- Ask the API server about use of deprecated versions. The server records metrics and warnings every time a deprecated API is called, which reveal who is still using them.
- Scan your repositories and charts with a static checking tool that flags removed versions for a chosen target release.
- Scan live objects in the cluster, including those created by tools and operators, using a similar checker.
- Watch the warnings printed by your tools. Deprecation warnings appear on the command line and in logs for months before removal. Teams that read them are rarely surprised.
Fixing them
For each finding, update the manifest or template to the newer version, check whether the shape of the object changed between versions, apply it to a test cluster, and confirm that it works. Do this at least one release before the upgrade, so that the change itself is not mixed with the upgrade. Third-party charts and operators may require their own upgrade, which in turn has its own compatibility needs.
Changes that are not API versions
Besides removed versions, releases sometimes remove whole features, change default behavior or tighten security settings. Examples across past releases include removal of old volume plugin types, changes to default security profiles and removal of built-in cloud integrations in favor of external ones. These are in the release notes, in sections about urgent upgrade notes and deprecations. Read those sections line by line.
An old road sign tells drivers to use a bridge that the city has announced will close next spring. The announcement has been public for a year, but a driver who never reads notices will arrive on the day to find the bridge gone. Reading the notices early is far cheaper than finding another route in a hurry.
Make a deprecation scan part of every pull request and every weekly build. Then upgrade day brings no surprises, because the code has been staying up to date all along.
19The Pre-Upgrade Readiness Checklist
A good checklist turns worry into a list of small questions with yes or no answers.
The checklist, by theme
| Theme | Question | Ready when |
|---|---|---|
| Knowledge | Have we read the release notes and deprecation guide? | A short summary of impacts exists and has been reviewed |
| APIs | Do any workloads use removed APIs? | Scans of repositories and live objects are clean |
| Add-ons | Does every add-on support the target version? | Compatibility table checked and upgrade order decided |
| Backups | Do we have a recent, tested backup? | etcd snapshot or resource export taken, and restore proved this quarter |
| Health | Is the cluster healthy right now? | No failing nodes, no crash-looping Pods, no pending Pods without reason |
| Budgets | Do critical services have sensible PodDisruptionBudgets? | No zero-disruption budgets; no single-replica critical service |
| Shutdown | Do services shut down gracefully? | Tested by deleting a Pod under load with no errors |
| Capacity | Do we have room for surge and for lost nodes? | Quotas, addresses and headroom confirmed |
| Spread | Are replicas spread across nodes and zones? | No node holds most of any important service |
| Observability | Can we see errors, latency and restarts live? | A dedicated upgrade dashboard and alerts exist |
| Rehearsal | Have we done this on a non-production cluster? | Timings and surprises recorded |
| People | Is everyone informed and on call? | Window announced; responders named; stop rules agreed |
| Rollback | Do we know what to do if it goes wrong? | Written plan with owner, including a point of no return |
Health first
Never start an upgrade on a cluster that is already unhealthy. If nodes are flapping, if Pods are crashing or a controller is stuck, the upgrade will make a confusing situation worse and hide the cause. Fix the baseline problems first, even if it means a delay. An upgrade should begin from green.
Go and no-go criteria
Write down, before the window opens, what would make you stop. For example: “if error rate doubles for more than three minutes after any batch, pause,” or “if two nodes fail to rejoin within ten minutes, stop and investigate.” Decisions made calmly in advance are better than those made at 2 a.m. under stress.
Pilots run through a checklist before every flight, even though they have done it thousands of times. Not because they forget how to fly, but because the list catches the one item that human memory sometimes drops. An upgrade checklist is the same kind of tool.
Keep the checklist in version control, and update it after every upgrade with the lesson you learned. After a few rounds it becomes the most valuable document your team owns.
20Rehearsing in a Test Cluster
The first time you do something should never be on production. A rehearsal environment turns surprises into lessons.
What makes a good rehearsal cluster
It should resemble production in the ways that matter: the same Kubernetes version, the same add-ons and versions, similar node types and counts per zone, similar policies and admission rules, and representative workloads. It need not be as large, but it should have more than one node per zone and several replicas of key services, because the interesting behavior of upgrades is how things move, which a single-node playground cannot show.
The rehearsal plan
Mirror production
Bring the test cluster to the same version and configuration as production, using the same automation.
Apply realistic traffic
Run a load generator or replay of typical requests so that errors from moving Pods become visible.
Run the real procedure
Follow the production runbook step by step, with timings, and no shortcuts.
Measure the user impact
Count failed requests, latency spikes and restarts during each step.
Practice the bad day
Deliberately stall a node, block a drain, or break an add-on, and rehearse your response.
Fix and repeat
Update the runbook and the applications, then run again until the upgrade is boring.
Upgrade tests as automation
Teams with mature practices create a fresh cluster on demand at the old version, deploy a standard set of workloads, upgrade, and run a battery of checks, all automatically, every time a new Kubernetes version is released. This gives early warning about incompatibilities, weeks before the production upgrade is due.
Canary clusters
If you have many clusters, upgrade the least critical first and let it run for a week or two while you observe. Then proceed to more important ones in waves. The first cluster plays the role of the coal-mine canary: if something is wrong, it shows there, before it can hurt the important ones.
Limits of rehearsal
No test cluster has exactly the same traffic, data size or odd corners as production. Rehearsal finds most problems but not all. Therefore even a well-rehearsed production upgrade is done in small steps with active watching.
A theater company holds dress rehearsals with costumes, lights and a few invited guests before opening night. The rehearsal is not the same as the real audience, but it catches the broken props and the missed cues, and the actors walk on stage knowing the order of every scene.
The cost of a rehearsal cluster is small compared with one hour of production downtime. Create it from the same automation as production, and delete it afterwards to save money.
21Admission Webhooks, CRDs and Operators
The extra machinery you have added to your cluster is often the part that breaks during an upgrade. Three things deserve special attention.
Admission webhooks
An admission webhook is a service that the API server calls whenever someone creates or changes an object, to approve, reject or modify it. Policy engines, certificate managers, and service meshes use them. The risks during upgrades are:
- A webhook that is down can block everything. If its failure policy is “fail,” then when the webhook Pods are being moved, no new Pods can be created anywhere, including the replacements for the Pods being drained. This can freeze an upgrade.
- Webhooks that call the API they guard. A circular dependency can make recovery impossible.
- Webhooks that use removed API versions in their registration, and so stop working after the upgrade.
- Short timeouts that fail when the system is busy during node moves.
Good practice includes running several replicas of every webhook, spreading them, giving them disruption budgets, excluding system namespaces from their scope, and choosing the failure policy thoughtfully: “ignore” for convenience checks, “fail” only for essential security rules and then only with high availability.
Custom resource definitions
CRDs extend Kubernetes with new object types. They bring their own versions and conversion rules. When Kubernetes is upgraded, CRDs themselves keep working, but their conversion webhooks must be reachable, and any CRD that used a now-removed definition API version needs updating. Before upgrading, list all CRDs, note which controller owns each and check that controller’s compatibility.
Operators and controllers
Operators are programs that watch objects and act on them. During a control plane upgrade they reconnect and resync, so they must handle dropped connections. During node drains, they are moved like any other Pods, but their own work, such as failing over a database, may be interrupted. Questions to ask for each operator:
| Question | Why it matters |
|---|---|
| Which Kubernetes versions does it support? | An old operator may not run on the new version |
| Does it hold a leader lock and run several copies? | A single copy leaves a gap while it is being moved |
| Does it do special work when nodes are drained? | It may need a maintenance mode |
| Should it be upgraded before or after the cluster? | Order matters for conversion and for API changes |
| What happens to its managed resources if it is down for a few minutes? | Usually nothing, but verify |
The deadlock to avoid
One notorious situation: a webhook Pod that must be running for new Pods to be admitted is itself evicted and cannot restart, because its own creation requires the webhook. The upgrade freezes with the webhook missing. Prevent it by exempting the webhook’s own namespace from its checks and keeping at least one replica on a node that is upgraded last.
An admission webhook is like the security guard at a building who must approve every visitor. If the guard steps out and the rule says “nobody enters without the guard’s approval,” then even the replacement guard cannot enter. Cities solve this with a spare guard or a rule that lets the guard’s relief through a side door.
Policy webhooks with a “fail closed” setting and a single replica are the number one hidden cause of stuck upgrades. Check each webhook’s replicas, failure policy and namespace exclusions before you start.
22Watching the Upgrade: Observability and Stop Rules
An upgrade without monitoring is a journey with the lights off. What you watch decides how quickly you notice trouble.
Three layers of signals
What customers feel
Request success rate, response time at the 95th and 99th percentile, and key business actions such as completed checkouts. These are the final judge.
What services do
Pod restarts, readiness changes, queue depth, connection errors, retry counts, and latency between services.
What the cluster does
Node readiness, pending Pods, API server errors and latency, scheduler delay, drain progress, and add-on health.
The upgrade dashboard
Build a single page that shows, side by side: the number of nodes at each version, the count of ready and not-ready nodes, Pods pending and recently restarted, API server error rate and latency, and the main user-facing success rate and latency. Mark the start and end of each step on the graphs. During the window, the whole team looks at this one page, not at twenty separate ones.
Alerts that suit upgrades
- Nodes not ready for more than a few minutes.
- Pods pending for longer than expected.
- Crash loops and image pull failures.
- Rise in 5xx errors or latency of any critical service.
- Webhook call failures and API server errors.
- DNS lookup failures.
Stop rules
Agree on explicit thresholds that cause a pause. A pause means you stop starting new steps and investigate; it does not mean rollback. Examples: user error rate above the normal level for three minutes after a batch, any node stuck unready beyond ten minutes, more than a set number of pending Pods, or anything unexplained in the control plane logs. When a stop rule triggers, the person leading the upgrade pauses, and the group decides on next steps together.
Logs and events
Keep a running view of Kubernetes events and of the logs of the API server, scheduler, controller manager, kubelets and add-ons. Many problems announce themselves in events, such as failed mounts, failed scheduling or failed probes, minutes before they become visible to users. Centralized logging that survives node replacement is vital, since the logs on an old node vanish with it.
A timeline kept by a scribe
Ask one person to write down what happens and when: step started, step finished, anything odd. This record becomes the basis of the review afterwards and is invaluable if you need to reconstruct what caused a problem.
Surgeons operate with monitors showing the heartbeat, breathing and blood pressure, and the team agrees in advance what readings will make them stop and reassess. An upgrade team needs the same kind of monitors and the same kind of agreement.
23Rollback: The Honest Truth
People ask, “What if we need to go back?” The answer depends on what part of the cluster you ask about, and it is often less comforting than hoped.
What can be undone and what cannot
| Part | Can you go back? | How |
|---|---|---|
| Worker nodes | Often yes | Keep the old node pool (blue/green), or recreate nodes from the old image, while the skew rules still allow it |
| Add-ons | Usually yes | Redeploy the previous version, if it is compatible with the control plane |
| Self-managed control plane | Sometimes, with care | Restore from the etcd backup and reinstall old binaries; this is a difficult and risky procedure |
| Managed control plane | Generally no | Providers do not support downgrades; your option is a replacement cluster |
| Stored data format | May not be reversible | After objects are rewritten in a newer storage format, older versions may not read them |
Roll forward is the usual answer
In practice, most problems are solved by fixing the issue and moving on, not by going back. A removed API is fixed by updating a manifest. A broken add-on is fixed by upgrading it further or reverting only that add-on. A misbehaving node is replaced. This is why small, observable steps are so important: a small step has a small, quick fix.
The point of no return
Identify in your plan the moment after which going back to the old version is no longer feasible. For many clusters, it is the upgrade of the control plane. Before this point, the decision to continue should be careful and well informed, with all checks complete. After it, the plan changes from “go back” to “make the new version work.”
The real safety nets
- A tested backup of etcd and your resource definitions.
- Infrastructure as code, so a cluster can be recreated from files.
- Blue/green node pools, so the old workers still exist during early observation.
- A second cluster, in the most critical environments, to which you can shift traffic. The next chapter describes this.
- Rehearsal, since a problem found in the test cluster never needs a rollback.
Do not over-promise
Do not tell stakeholders that the upgrade is “reversible” unless you have actually tested the reversal. Honest wording is better: “We can pause at any step, we can replace the worker nodes with old-version machines for a limited time, and we have a plan to rebuild the cluster from backup in a few hours if something catastrophic occurs.”
A mountain climber has several camps. Up to the last camp, retreat is easy. Past a certain ridge, turning back is as risky as going forward, so the climber checks the weather and the supplies carefully before crossing it. Good teams know where their ridge is.
Assuming that you can “just downgrade” a control plane after the upgrade is the most dangerous belief in this whole topic. Treat the control plane upgrade as one-way, and prepare accordingly.
24Blue/Green Clusters: Upgrade by Replacement
Instead of changing a running cluster, build a new one at the new version and move the traffic across. It costs more, but it gives the best safety.
flowchart TB
U["Users"] --> DNS["Traffic entry: DNS or global load balancer"]
DNS -->|"100 percent at start"| BLUE["Blue cluster - current version"]
DNS -.->|"0 percent at start"| GREEN["Green cluster - new version"]
GIT["Git repository - declared state"] --> BLUE
GIT --> GREEN
DATA[("Shared or replicated data stores")] --> BLUE
DATA --> GREEN
GREEN --> CHK["Smoke tests and canary checks"]
CHK -->|"healthy"| SHIFT["Shift traffic in steps: 1, 10, 50, 100 percent"]
SHIFT --> DONE["Retire blue cluster after observation"]
SHIFT -.->|"problem found"| BACK["Shift traffic back to blue"]
How it works
- Create a brand new cluster at the target version, from the same declared configuration as the old one.
- Deploy all workloads and add-ons to it using the same pipeline that deploys to the old cluster.
- Run smoke tests and canary checks on the new cluster, with no user traffic.
- Move a small share of traffic, for example one percent, to the new cluster using DNS weights or a global load balancer.
- Increase the share in steps while watching error rates and latency.
- When all traffic is on the new cluster and has been stable for an agreed period, delete the old one.
Why teams like it
Advantages
- The old cluster remains untouched, so rollback is a traffic shift
- No in-place surprises; the new cluster is tested before use
- Can jump over awkward combinations by testing the whole thing
- Forces good habits: everything must be reproducible from code
- Version jumps and big changes can be tested gradually
Costs and challenges
- Double infrastructure cost while both exist
- State is hard: databases, volumes and queues must be shared or replicated
- Clients with cached DNS take time to move
- Secrets, certificates and external allow-lists must be duplicated
- Requires mature automation and a global traffic layer
The data problem
The hardest part is state. If your databases live outside the cluster, such as managed cloud databases, both clusters can use the same ones, and the migration is simple. If state lives in the cluster, you must replicate it to the new cluster, or move it with snapshots and a cut-over, which is complex. Teams often choose blue/green clusters for stateless tiers and in-place upgrades for clusters that hold heavy state.
Other dependencies to duplicate
- Certificates and domain names for ingress.
- Network rules and firewall allow-lists that mention cluster addresses.
- Identity and permission bindings for workloads that call cloud services.
- Monitoring, logging and alert routes.
- Scheduled jobs, which should not run in both clusters at once.
Instead of renovating your shop while customers browse, you build an identical new shop next door, stock it, test the till, invite a few customers first, and then move everyone over. If the new shop has a leaky roof, you walk customers back to the old one. It is more work and more rent, but customers never stand in a building site.
Even if you upgrade in place most of the time, practice building a cluster from scratch once a quarter. It proves that your automation works and gives you the disaster recovery path for free.
25Automation, GitOps and Cluster API
Humans typing commands at night make mistakes. Automation makes upgrades repeatable, reviewable and boring.
Cluster definitions as code
Describe your clusters in files: versions, node pools, add-ons and settings. Tools for infrastructure as code create and change clusters from these files. An upgrade becomes a change to a version number in a file, reviewed by colleagues, tested in a pipeline and applied by automation. The history of changes is in version control, so you can always see what was done and by whom.
GitOps for what runs inside
GitOps tools keep the cluster’s workloads and add-ons in sync with a repository. For upgrades, this has two benefits. First, rebuilding after a problem, or filling a new green cluster, is just pointing the tool at the repository. Second, changes to manifests that fix removed APIs go through the same reviewed path as any other change.
Cluster API and similar controllers
Cluster API lets you manage clusters as Kubernetes objects. A cluster’s control plane and machine pools have a version field. Changing it makes controllers create new machines at the new version, wait until they are ready, and delete the old ones, honoring settings for surge and maximum unavailable. It works with many infrastructure providers, and it brings the same declare-and-reconcile model to cluster upgrades that Kubernetes brings to application deployment.
Guardrails in the automation
| Guardrail | What it prevents |
|---|---|
| Pre-flight checks | Starting when cluster health, budgets, backups or quotas are not ready |
| Batch limits | Replacing too many nodes at once |
| Health gates between batches | Continuing when metrics show a problem |
| Timeouts and automatic pause | Hanging forever or forcing past a blocked drain |
| Approval steps | Applying a production upgrade without a human decision at key moments |
| Audit log | Unknown changes with no record |
Where to keep humans in the loop
Automate the routine, and keep people for the judgment calls: approving the start of the production window, approving the move from control plane to nodes, and deciding what to do when a stop rule triggers. A fully automatic upgrade is attractive for non-critical clusters, but critical ones deserve a human hand on the pause button.
Upgrade as a regular pipeline
Treat the upgrade as a pipeline that runs through environments in order: ephemeral test cluster, development, staging, a small production cluster, and finally the rest. Each stage must pass health checks and wait for a soak period before the next begins. Over time, the pipeline absorbs lessons: each failure adds a new check.
An airline does not rely on a pilot’s memory to prepare a plane. Checklists, automated tests and maintenance logs keep every aircraft consistent. Humans are still in the cockpit for judgment, but the routine is written down and often performed by machines.
Whatever automation you choose, the principles in this guide still apply. Automation makes mistakes faster as well as good steps, so the guardrails matter even more.
26People, Communication and the Maintenance Window
Technology is half of a smooth upgrade. The other half is making sure that people know what is happening and what to do.
Tell the right people at the right time
Application teams
Tell them about the target version, deprecations that affect them, and what they must prepare: budgets, graceful shutdown, replica counts.
Everyone on call
Share the timetable, the runbook, the dashboard link and the stop rules. Ask teams to avoid risky releases that week.
A status channel
Post short updates at each step, so people can see progress without interrupting the operators.
A short summary
Report what changed, what went well, any incidents, and the next planned upgrade.
Roles during the window
- Upgrade lead: runs the steps and makes the call to pause or continue.
- Observer: watches the dashboards and calls out anything unusual.
- Scribe: records the timeline.
- Communicator: posts updates and fields questions, so the lead can focus.
- Application contacts: reachable engineers from important services, in case a service misbehaves.
Choosing the window
Pick a time when traffic is moderate and the team is rested and available, and not at the end of the week or just before a holiday or a business peak. For global businesses, there may be no truly quiet hour, so zero-downtime techniques matter even more. Avoid starting a long upgrade that you cannot pause safely at the end of the working day.
Pace and fatigue
Long upgrades tire people. Plan breaks, hand-offs and clear points where it is safe to stop for the night. A cluster with its control plane upgraded and nodes half done is a perfectly valid stopping place, since the skew policy allows it, as long as you have documented the state.
Learn afterwards
Within a few days, hold a short, blameless review. What surprised us? Which checks would have caught it sooner? What did the runbook not say? Update the checklist and the automation. An upgrade that taught nothing was a wasted chance.
Roadworks are far less annoying when the city has put up signs weeks ahead, posted the detours and kept a crew on hand for questions. The road is the same, but the experience of the drivers is completely different. Communication is part of the work, not an extra.
27Common Failure Modes and How to Recognize Them
Upgrades go wrong in a small number of repeating ways. Knowing the patterns shortens the time between “something is off” and “I know why.”
| Symptom | Likely cause | First things to check |
|---|---|---|
| Drain hangs and never finishes | A budget allows no disruption, a Pod will not terminate, or a replacement cannot start | Budgets of the stuck Pods, replica counts, pending Pods, termination handling |
| Replacement Pods stay pending | No capacity, zone-bound volume without a node in that zone, strict spread rules, or quota exhausted | Scheduling events, node capacity per zone, volume zones, cloud quotas |
| New nodes never become ready | Network plugin not working on the new node, wrong image settings, blocked access to the control plane, or certificate problems | Kubelet logs, network plugin Pod on that node, security group rules, bootstrap settings |
| Brief burst of errors on each drain | Pods exit before traffic is removed, or start too slowly | PreStop delay, signal handling, readiness checks, load balancer deregistration delay |
| Nobody can create or change anything | An admission webhook is down and set to fail closed | Webhook Pods, failure policy, namespace exclusions |
| Name lookups fail or are slow | DNS Pods moved all at once, or the DNS configuration changed in the new version | DNS replica count and spread, logs, node-local caches |
| A tool or pipeline suddenly errors | It uses a removed API version | Error messages naming versions; deprecation scan results |
| Autoscaler behaves oddly | Old node image, metrics gap, or conflicts with the upgrade tool | Autoscaler logs, node group settings, metrics availability |
| Storage volumes fail to attach | Old attachment not released, driver incompatible, zone mismatch | Volume attachment objects, driver logs, node zone |
| Metrics or logs vanish | Agents not upgraded, node labels changed, or permissions changed | Agent Pods and their rules |
| Performance drops after upgrade | Changed defaults, throttling, new kernel behavior or a different runtime version | Release notes, resource usage compared to before, node image changes |
A disciplined way to investigate
- Pause further steps, so that the situation does not change while you look.
- Ask what changed last and where. Most problems relate to the most recent step.
- Look at events for the affected objects, since Kubernetes often states the reason in plain words.
- Compare a healthy example with a broken one: a node that works with one that does not.
- Fix the smallest thing that solves the problem, and write it down.
- Resume only after the signals are green again.
The “one change at a time” habit
Many long incidents come from changing several things in the middle of a problem: tuning a budget, restarting an add-on and replacing a node at once. When things improve, nobody knows why. Keep to one change at a time, and note it.
A mechanic who hears a strange noise from the engine does not replace six parts at once. They stop, listen, narrow it down and change one thing. If the noise stops, they know what the cause was, and can tell the owner honestly.
Keep this table in the runbook and extend it with your own cluster’s real incidents. A short list of problems you have actually seen is worth more than any general advice.
28Traffic, Load Balancers and Draining Connections
Between your users and your Pods sit load balancers and proxies. Their behavior decides whether a Pod’s departure is smooth or abrupt.
The traffic path
A typical request travels from the user to a cloud load balancer, then to a node, then through the service routing rules to a Pod, perhaps through an ingress controller on the way. Each hop keeps its own list of healthy destinations, and each list updates at its own speed. When a Pod or node is removed, the lists must catch up before the destination disappears.
Key settings and behaviors
| Element | What to know | Safe practice |
|---|---|---|
| Cloud load balancer targets | Nodes or Pods are registered as targets, with health checks and a deregistration delay | Set a deregistration delay long enough for in-flight requests, and align it with the Pod’s shutdown pause |
| External traffic policy | With the “local” policy, traffic goes only to nodes holding a Pod for the service | Ensure every node being drained is removed from the load balancer first, and that health checks work properly |
| Direct-to-Pod load balancing | Some setups register Pods directly, skipping the node hop | Use readiness gates so a new Pod receives traffic only when the load balancer is ready for it |
| Ingress controller | Keeps its own list of backends and reloads its configuration | Run several replicas; test configuration reload behavior under traffic |
| Keep-alive connections | Clients reuse connections, so traffic sticks to old Pods | Limit connection lifetime; let servers close connections politely during shutdown |
| Long-lived connections | Websockets and streams stay open for hours | Have clients reconnect with backoff; notify them before shutdown |
| Session stickiness | Users pinned to specific Pods lose sessions when moved | Store sessions outside the Pod, or accept re-login for a few users |
Why node drains drop traffic if you are not careful
When a node is replaced, the cloud load balancer may still send requests to it for a few seconds or more, until its health check fails or the node is deregistered. If the node disappears first, those requests are lost. The remedy is to deregister the node, wait for connections to drain, and only then stop it. Managed node group tools usually do this, but check that your load balancer settings, such as the deregistration delay and the health check interval, are in agreement with the drain timing.
Clients that help
Good clients also help to produce zero downtime. Clients that retry idempotent requests with backoff, that use timeouts and that reconnect when a connection breaks, hide small disruptions. Your internal services should do this too, since service-to-service calls face the same moves. A request that fails once and succeeds on a quick retry is often invisible to the user.
Idempotency
Retries are only safe when repeating a request does no harm. A “create order” request that is retried may create two orders unless it carries a unique key that lets the server notice the repeat. Making important operations idempotent is a valuable design habit that pays back during every upgrade and incident.
A taxi dispatcher keeps a list of drivers on shift. When a driver goes off duty, the dispatcher must remove the name from the list before the driver leaves. If the driver simply disappears, the next customer is sent to an empty car. Draining connections is the act of crossing the name off the list and letting current trips finish.
Health check intervals and thresholds on the load balancer that are slower than your Pod shutdown give a window where traffic still goes to dying Pods. Do the arithmetic: the time to detect and remove a target must be shorter than the time the Pod stays alive after the signal.
29Upgrading Many Clusters: Fleet Strategy
One cluster is an event. Fifty clusters are a program. The same principles apply, but order, pace and standardization matter even more.
Waves and rings
Group clusters into rings by importance and risk, and upgrade ring by ring:
Ring zero: ephemeral test clusters
Created and destroyed by automation to catch incompatibilities early, as soon as a new version is available.
Ring one: development and internal tools
Users are employees; failures are tolerated and teach us.
Ring two: staging and low-risk production
Real traffic of a small kind, or cloned traffic.
Ring three: main production, region by region
One region at a time, with a soak period between regions.
Ring four: the most critical clusters
Upgraded last, after the version has proved itself everywhere else.
Standardize to make it tractable
- Few versions at once. Allow at most two or three Kubernetes versions across the fleet at any time.
- Same add-on sets. A standard platform bundle per version, tested together, is easier than a different mix per cluster.
- Same automation. One pipeline, one runbook, parameterized for each cluster.
- Clear ownership. A platform team owns the cluster and add-ons; product teams own their workloads and their readiness.
- Visible inventory. A dashboard listing every cluster, its version, its end-of-life date and its upgrade status.
Soak time
Between rings, wait long enough to see slow problems, such as memory leaks and rare errors, which do not show up in the first hour. A week in the lower rings is common. This soak period is the cheapest protection a fleet has.
Exceptions and the long tail
Some clusters will be hard to upgrade: they host special software, belong to teams that are slow to respond, or hold unusual configurations. Make exceptions visible and time-limited, with an executive sponsor and a date. Without that, the “just one old cluster” turns into a permanent risk.
Measuring the program
These are goals to aim at, not promises. Track them over time and ask why when they slip.
A hotel chain updating the booking system rolls it out to a small branch first, then a few cities, then everywhere, with staff on hand to spot problems. The chain never switches all two hundred hotels in a single night.
30A Worked Story: A Ticketing Company Goes from Fear to Routine
This is an illustrative story, not a report about a real company. It shows how the ideas in this guide fit together over a year.
The starting point
“Gatepass,” a fictional company that sells event tickets online, ran one big production cluster on a cloud provider. The cluster was two and a half years old, four minor versions behind, and the provider had announced that support for its version would end in three months. The team of six platform engineers had avoided upgrading because an earlier attempt had caused an hour of failed purchases.
Month one: understand the risks
The team did not touch the cluster. They read the release notes for each of the four versions in between, and made a list of every removed API and changed feature. They ran scans of all repositories and live objects, finding 37 objects using removed versions, several of them in third-party charts. They checked every add-on’s compatibility table and found that the ingress controller and the storage driver both needed upgrades first.
Month two: fix the foundations
They discovered that eleven services had only one replica, nine services had no disruption budget, and five had budgets that allowed no disruption at all. Six services ignored the termination signal. The application teams fixed these over four weeks, supported by a short guide and a policy that warned about missing budgets. The team also built an upgrade dashboard and a set of canary checks.
Month three: rehearse
The team created a copy of the cluster at the old version, loaded it with a traffic replay and rehearsed the first upgrade. They found that the first drain failed because a policy webhook with a single replica and a “fail closed” setting blocked its own replacement. They added replicas and namespace exclusions. They rehearsed three times, until the process produced fewer than a handful of failed requests, and the runbook had grown from one page to six.
Months four to six: one step at a time
Rather than build a giant jump, they upgraded one minor version about every five weeks, starting with the less important development cluster and then production on a Tuesday morning with a surge of three extra nodes. The first production upgrade took five hours, mostly waiting for careful drains. A single increase in checkout errors, lasting about a minute, was caused by a load balancer deregistration delay that was shorter than the Pod shutdown pause. They aligned the numbers, and the next step produced no visible blip.
Months seven to twelve: routine
With the cluster current, the team adopted a rhythm: test every new version in an automated ephemeral cluster in the first weeks after release, upgrade development a month later, and production a month after that. Upgrades dropped to two hours. They moved node upgrades to a blue/green pool method for the busiest season, which let them hold the old nodes for two days as a safety net. By the end of the year, they upgraded three times with no customer-visible incident.
What made the difference
Lessons from the story
- The first month’s work was reading and scanning, not upgrading.
- Most of the risk lived in applications, not in the cluster: replicas, budgets, signals and timing.
- Rehearsal found the single most dangerous problem, the webhook, in a place where it cost nothing.
- Small steps, taken often, made each upgrade smaller than the one before.
- Numbers that agree with each other, such as delays and shutdown pauses, mattered more than any clever trick.
31Anti-Patterns: How Upgrades Go Wrong
Many painful upgrades follow the same few mistakes. Naming them helps you notice them in your own plans.
Postponing until the cliff
The cluster falls out of support, and the team must perform several upgrades in a rush. Instead: upgrade on a regular rhythm, a little behind the newest release, well before end of life.
Skipping the release notes
Removed features surprise the team in the middle of the night. Instead: read the deprecation guide and urgent notes for each version, and scan your manifests early.
Upgrading unhealthy clusters
Hidden problems get mixed up with upgrade effects. Instead: start only from a green state.
Forcing past blocked drains
Using force to get through a stuck eviction deletes Pods ungracefully and causes errors. Instead: fix the application that blocks, and let the budget do its job.
Single replicas and no budgets
Critical services have one copy, so any move is an outage. Instead: at least two replicas, spread, with a sensible budget.
Changing many things at once
Kubernetes, the network plugin, the node image and an application release arrive on the same night. Instead: one change at a time, with checks in between.
No rehearsal
The first run happens on production, and surprises are expensive. Instead: rehearse in a realistic test cluster with traffic.
Believing in an easy rollback
The plan says “we can go back” without testing it. Instead: state honestly what is reversible, keep old nodes during early observation, and make backups real.
Ignoring capacity and quotas
The upgrade stalls because there is no room for surge nodes or addresses. Instead: check headroom, quotas and addresses beforehand.
Flying blind
No dashboard, no stop rules, no one watching. Instead: a single upgrade dashboard, agreed thresholds and named roles.
Fail-closed webhooks without redundancy
A single policy Pod can freeze the whole cluster during a drain. Instead: several replicas, spread, with exclusions for system namespaces.
Treating every upgrade as unique
No runbook, no automation, no review of lessons. Instead: make the process a repeatable pipeline that improves after every run.
32A Maturity Roadmap for Upgrades
Teams improve in stages. Knowing where you stand lets you pick the next step instead of trying to do everything at once.
flowchart LR S0["Stage 0: Fear - upgrades are rare and manual"] --> S1["Stage 1: Planned - checklist, backups, release notes read"] S1 --> S2["Stage 2: Prepared apps - budgets, graceful shutdown, spread"] S2 --> S3["Stage 3: Rehearsed - test clusters with traffic"] S3 --> S4["Stage 4: Automated - pipeline with health gates"] S4 --> S5["Stage 5: Continuous - small, frequent, boring upgrades"]
Reading the diagram
The boxes read from left to right, each building on the last. At the far left is a team afraid of upgrades, doing them rarely and by hand. At the far right is a team whose upgrades are small and frequent, so that nobody pays them much attention. The path between them is not about learning new tools. It is about adding preparation, practice and automation, one stage at a time.
What each stage looks like
| Stage | Typical behavior | Next step |
|---|---|---|
| 0. Fear | Upgrades are put off; the cluster is far behind; knowledge sits in one person’s head | Write a checklist, take backups, read the release notes |
| 1. Planned | Each upgrade has a plan and a backup; deprecations are scanned; there is a runbook | Make applications ready to be moved |
| 2. Prepared apps | Budgets, graceful shutdown, spread and capacity are standard practice | Rehearse in a test cluster |
| 3. Rehearsed | Every upgrade is tried first with load; surprises appear in tests | Automate the steps with guardrails |
| 4. Automated | A pipeline upgrades through rings with health gates and approvals | Shorten the cycle and upgrade more often |
| 5. Continuous | Clusters stay near current; upgrades are routine and measured | Keep improving; share the practice across teams |
Questions to place yourself
- How many minor versions behind are we, and when does our version leave support?
- When did we last restore a backup in a test?
- If we drain a node right now, will users notice?
- Do we know every deprecated API we still use?
- How long would it take to rebuild this cluster from files?
- Who has done an upgrade, and who could do it next time?
Do not try to leap from stage 0 to stage 4. Each stage removes a particular kind of risk, and the later stages depend on the earlier ones to be safe.
33Frequently Asked Questions
Short answers to questions that come up again and again.
Is true zero downtime really possible?
For well-prepared applications, yes. Users see no errors because Pods are moved gracefully, several copies are always running and traffic is shifted before machines are touched. For poorly prepared applications, such as single-replica services, short outages are unavoidable until they are fixed.
How often should we upgrade?
Often enough to stay within the supported versions with a safe margin, which for most teams means two to three minor upgrades a year, plus regular patch updates. Smaller, more frequent steps are safer than rare large ones.
Should we always move to the newest version immediately?
Not necessarily. Many teams wait a few weeks after a minor release, so that early patch releases and add-on compatibility catch up, and test it in lower environments in the meantime. Just do not wait so long that you approach end of life.
Can we skip a minor version?
No. Kubernetes supports upgrading one minor version at a time. You may pause between steps or take them close together, but each one must be passed through.
Do we upgrade the nodes right after the control plane?
You must not leave nodes outside the skew policy, but you have some freedom of timing. Many teams finish nodes within days. A short pause between control plane and nodes for observation is reasonable.
Is in-place or blue/green better?
Blue/green, for nodes or whole clusters, has the safest rollback but costs more and makes state harder. In-place or rolling replacement is cheaper and common. Choose by how much risk and cost you can accept, and use blue/green for the highest-stakes changes.
What if an application cannot run more than one replica?
Treat it as a known risk. Schedule maintenance for it, tell its users, or redesign it so that it can run multiple copies or fail over quickly. Do not use a budget of zero disruptions as a workaround, since that blocks the upgrade for everyone.
Do managed services remove the need for planning?
They remove much of the control plane work, but not your responsibility for workloads, add-ons, timing and compatibility. Providers also retire versions on their own timetable, so planning stays essential.
How long does an upgrade take?
It varies widely. A control plane upgrade on a managed service may take from tens of minutes to an hour. Node upgrades depend on the number of nodes, batch size and how long each drain takes, from a couple of hours to a few days for large fleets. Rehearsal shows your real numbers.
What is the single most useful thing to do first?
Find your single-replica services and missing budgets, and test what happens when you delete one Pod under load. That one test reveals most of what would go wrong in an upgrade.
How do we deal with long-running jobs?
Give them a long grace period, or make them resumable with checkpoints. For batch work, schedule upgrades of the relevant node pools between runs, or use dedicated pools that are upgraded at quiet times.
What if the upgrade fails halfway?
Pause and assess. A cluster in a partly upgraded state is generally valid, within the skew rules, so you can stop, investigate and fix. Then continue forward. Only in rare cases is a restore from backup needed, which is why backups and rehearsal are essential.
Does using a service mesh change the plan?
It adds another component to upgrade and more places where connections are held. Follow the mesh’s compatibility and upgrade order, check that sidecars shut down gracefully, and test traffic during Pod moves.
34Key Takeaways and Next Steps
You have followed the whole path from the first worry to a routine. Here is the guide in a nutshell.
What to remember
- Upgrades feel scary when they are rare and large. Make them small, frequent and rehearsed.
- Kubernetes ships about three minor versions a year, and supports only the most recent few. Plan around the end-of-life date.
- Upgrade one minor version at a time. The API server is always the newest component, so the control plane goes first and nodes follow.
- A highly available control plane is upgraded one instance at a time, and running applications keep serving while it changes.
- Back up etcd and your resource definitions, store them away from the cluster, and prove that you can restore them.
- Replace nodes in small batches with surge capacity, or use blue/green pools for the best way back.
- Drain uses eviction, which respects disruption budgets. Never force past a blocked drain.
- Applications must be ready to move: several replicas, spread across nodes and zones, sensible budgets, a pause before shutdown, signal handling and fast, honest readiness.
- Scan for removed APIs a release ahead, and read the deprecation notes line by line.
- Check add-ons, webhooks, CRDs and operators for compatibility, redundancy and order.
- Rehearse with traffic, watch a single upgrade dashboard, and agree stop rules before you begin.
- Be honest about rollback: most fixes go forward, and the control plane upgrade is effectively one-way.
- Automate with guardrails, communicate early, and learn from each upgrade.
Your first month
Week one: look
Find your current version and its end-of-life date. List services with one replica, missing or zero-disruption budgets, and fail-closed webhooks.
Week two: read and scan
Read the release notes for the next version. Scan manifests and live objects for removed APIs and check add-on compatibility.
Week three: prepare
Fix budgets, signals, spread and capacity for the key services. Take a backup and test a restore. Build the upgrade dashboard.
Week four: rehearse
Run the full upgrade in a test cluster with traffic. Record the timings, fix the surprises, and update the runbook.
Kubernetes releases, provider features and add-on behaviors change quickly. The principles in this guide stay stable: prepare the applications, move in small steps, observe, and keep a way forward. Always confirm specific version rules, skew limits and provider behavior against the official documentation for the versions you use.