An upgrade keeps the Kubernetes API and the control plane available the whole time. Your applications can stay up too, but only if you spread them across nodes and tell the cluster how much disruption they can take. The following pages apply the rules to stateless apps, to ingress and load balancers, and to databases. To understand the rollout mechanics first, read [Cluster upgrades](/docs/hetzner/apalla/concepts/operations/cluster-upgrades). ## What an upgrade does to your workload An upgrade replaces every node with a fresh, sealed machine. The control-plane side is the platform's job: control-plane nodes roll one at a time, etcd keeps its quorum, and the API server stays reachable throughout. You do not configure anything for the API to stay up. The part that touches your workload is the worker side. Each worker node is replaced one at a time: 1. The node is **cordoned**, so no new pods schedule onto it. 2. The node is **drained**: every pod on it is evicted and has to reschedule onto another node. 3. The node is **deleted** and a new node on the new version takes its place. So an upgrade is a rolling node drain. A workload survives an upgrade exactly when it survives having its nodes drained one at a time. Everything here is about surviving that drain. ## Why the defaults are not enough By default the cluster spreads pods across nodes with a **soft** rule (`whenUnsatisfiable: ScheduleAnyway`). Soft means best-effort: if the scheduler cannot honor the spread, it places the pod anyway rather than leaving it `Pending`. See [Steer workload placement](/docs/hetzner/apalla/workloads/placement/steer-workload-placement) for the default rules. That default is convenient, but it does not protect a workload through a drain. Two replicas can land on the same node, either at first scheduling or after an earlier drain shuffled them there. When that one node is drained next, both replicas go down at once, and the workload has an outage even though it was running two replicas. Consider a two-replica web app behind a load balancer: - **With the default soft spread**, both replicas can sit on the same worker. When that worker is replaced during the upgrade, the app is unreachable for as long as the replacement takes, often more than a minute. - **With a hard spread and a PodDisruptionBudget**, one replica always stays on another node while the first is drained. The app keeps serving through every node replacement, with only a few seconds of gap while the load balancer re-registers its targets on the new node. The API server answered every request in both cases. The difference was entirely in how the workload was configured. ## The four rules Every workload that must stay available needs all four. Missing any one of them reopens the outage. | # | Rule | Without it | | --- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | 1 | Run at least two replicas | A single replica is down for the whole time its node is replaced. | | 2 | Spread the replicas across nodes with a **hard** rule, so no two share a node | A drain can take two replicas down at once. | | 3 | Set a **PodDisruptionBudget** the drain can satisfy within 180 seconds | The drain gives up after `nodeDrainTimeoutSeconds: 180` and the node is removed anyway, so a PDB nothing can satisfy just loses the pods. | | 4 | Add a **readiness probe** and a **graceful shutdown**, so traffic reaches only ready pods and in-flight requests finish | Traffic hits a pod that is starting or already shutting down, and requests fail. | ## Apply the rules to your workload type - [Keep stateless workloads available](/docs/hetzner/apalla/clusters/availability/keep-stateless-workloads-available): the four rules in full, with a complete example. - [Keep ingress and load balancers available](/docs/hetzner/apalla/clusters/availability/keep-ingress-and-load-balancers-available): your ingress controller is a workload too, and the load balancer adds one more path to protect. - [Keep databases available](/docs/hetzner/apalla/clusters/availability/keep-databases-available): stateful workloads keep data across a move, and a single database instance still has a short gap unless it is replicated. ## Related - [Cluster upgrades](/docs/hetzner/apalla/concepts/operations/cluster-upgrades): how a rollout replaces nodes, surge rules, and etcd quorum. - [Plan maintenance and run prechecks](/docs/hetzner/apalla/clusters/upgrades/plan-maintenance-and-prechecks): check disruption budgets and control-plane health before you upgrade. - [Steer workload placement](/docs/hetzner/apalla/workloads/placement/steer-workload-placement): node selectors, affinity, and topology spread in depth.