Syself Autopilot replaces nodes on every upgrade and repair, and a stateful pod feels that differently depending on where its data lives. The rule to internalize: a local volume does not survive its node. Place replicas so that losing one node, and its local data, never costs you the workload.
## What replacement does to each storage kind
Only one storage kind makes node replacement a design problem. Local NVMe (TopoLVM) is pinned to a physical node, so when the node goes, the volume goes with it and the pod comes back on the replacement with a fresh, empty disk. Hetzner Cloud volumes detach and reattach; JuiceFS lives on object storage and simply follows the pod. Both of those move their data for free. [Run a StatefulSet with storage](/docs/hetzner/apalla/workloads/stateful/run-a-statefulset-with-storage) walks through all three in full.
So the whole design question is about local volumes: replacement means one replica rebuilds from empty, and your job is to guarantee that never happens to a majority at once.
## Place replicas so a rebuild never breaks quorum
For a quorum-based application such as a three-member database, an etcd cluster, or a raft group, two settings turn a node replacement into a non-event:
- **One replica per node**, with required pod anti-affinity on `kubernetes.io/hostname`, so no two members share a machine. See [Affinity and anti-affinity](/docs/hetzner/apalla/workloads/placement/affinity-and-anti-affinity).
- **A PodDisruptionBudget sized for quorum**, `maxUnavailable: 1` for three members, so a drain evicts one member and blocks until it rejoins before touching the next. See [Add a PodDisruptionBudget](/docs/hetzner/apalla/workloads/production/pod-disruption-budgets).
Put together, a single replacement can only ever take one member down. It rebuilds from the surviving two, and quorum holds the entire time:
```mermaid
flowchart LR
A[Node marked for
replacement] --> B[PDB admits
one eviction]
B --> C[Pod reschedules
to new node]
C --> D[Fresh empty
local volume]
D --> E[Resync from
two live peers]
E --> F[Member rejoins
quorum]
F --> G[Next node
now eligible]
```
The guarantee is the ordering: no second node becomes eligible until the first member is back.
> [!WARNING]
> Without one-per-node placement, two members can land on the same machine. A single replacement then takes two of three at once, which loses quorum and, with local storage, loses their data. On a local-storage workload this is the failure to design against.
## Draining a stateful node on purpose
When you take a stateful node out yourself for hardware maintenance or a manual move, drain it rather than deleting the pod: `kubectl drain ` respects the PodDisruptionBudget, evicts one member, and waits. Let it rebuild and rejoin before you drain the next.
One timing edge is worth knowing. The platform's own upgrade drain waits `nodeDrainTimeoutSeconds` for a node to empty, 180 seconds per pool by default, overridable per pool under `spec.topology.workers.machineDeployments[].deletion.nodeDrainTimeoutSeconds`. If a member rebuilds slower than that window, the drain can move on before it has rejoined, so a large local dataset is a reason to raise the timeout on that pool.
## Restore from a replica, or from backup
A rebuilt member resyncs from a healthy peer, which the database's own replication handles as long as quorum survived. If you lose more than quorum, say two of three replaced at once, the fallback is a restore from [backup](/docs/hetzner/apalla/storage/backup/disaster-recovery-stateful). Replication protects you against one node; backups protect you against the mistake that takes several.