Adds minAvailable: 1 PodDisruptionBudgets for the data-bearing single-replica StatefulSets that had zero eviction protection:
Workload
Kind
Namespace
Selector
gitea
StatefulSet
apps
name=gitea
woodpecker-server
StatefulSet
apps
name=woodpecker, component=server
protonmail-bridge
StatefulSet
paperless
name=protonmail-bridge
syncthing
StatefulSet
paperless
name=syncthing
On a 1-replica workload, minAvailable: 1 makes the eviction API refuse voluntary evictions, so kubectl drain / node maintenance blocks and surfaces the pod instead of yanking a live SQLite DB or RWO-PVC pod mid-write. Involuntary disruptions (node crash, OOM) are unaffected — as intended.
The woodpecker selector deliberately includes component: server so it does not also cover the stateless woodpecker agents.
Deliberately excluded (with rationale)
CNPG im-pg and gf-pg (instances:1) — CloudNativePG intentionally creates no primary PDB for single-instance clusters (no failover target) and handles graceful primary shutdown itself (smartShutdownTimeout/stopDelay, already tuned on im-pg). A manual maxUnavailable: 0 would only wedge node drains with no HA benefit and fight the operator design. im-pg is single-instance only during the pgvecto.rs→VectorChord migration window.
Ceph mons — the Rook operator self-manages quorum-preserving mon/OSD PDBs (disruptionManagement.managePodBudgets, default-on; no override in this repo). A hand-written PDB would be redundant or overwritten each reconcile.
Stateless single-replica Deployments (paperless redis/tika/gotenberg, whisper, etc.) — a blocking PDB gives no recoverability benefit, only blocks drains.
Validation
kubectl kustomize builds clean for all three app dirs; renders exactly 4 PDBs (gitea 1, woodpecker 1, paperless 2) with the correct selectors.
Note: minAvailable: 1 on a single-replica workload blocks voluntary evictions entirely (drains need --disable-eviction or a scale-down first) — that friction is the intended protection for these data-bearing pods. If you would rather not block drains at all for some of these, say so and I can drop that one.
Fixes #201
Adds `minAvailable: 1` PodDisruptionBudgets for the data-bearing single-replica StatefulSets that had zero eviction protection:
| Workload | Kind | Namespace | Selector |
|---|---|---|---|
| `gitea` | StatefulSet | apps | `name=gitea` |
| `woodpecker-server` | StatefulSet | apps | `name=woodpecker, component=server` |
| `protonmail-bridge` | StatefulSet | paperless | `name=protonmail-bridge` |
| `syncthing` | StatefulSet | paperless | `name=syncthing` |
On a 1-replica workload, `minAvailable: 1` makes the eviction API refuse **voluntary** evictions, so `kubectl drain` / node maintenance blocks and surfaces the pod instead of yanking a live SQLite DB or RWO-PVC pod mid-write. Involuntary disruptions (node crash, OOM) are unaffected — as intended.
The woodpecker selector deliberately includes `component: server` so it does not also cover the stateless `woodpecker` agents.
### Deliberately excluded (with rationale)
- **CNPG `im-pg` and `gf-pg` (instances:1)** — CloudNativePG *intentionally* creates no primary PDB for single-instance clusters (no failover target) and handles graceful primary shutdown itself (`smartShutdownTimeout`/`stopDelay`, already tuned on `im-pg`). A manual `maxUnavailable: 0` would only wedge node drains with no HA benefit and fight the operator design. `im-pg` is single-instance only during the pgvecto.rs→VectorChord migration window.
- **Ceph mons** — the Rook operator self-manages quorum-preserving mon/OSD PDBs (`disruptionManagement.managePodBudgets`, default-on; no override in this repo). A hand-written PDB would be redundant or overwritten each reconcile.
- **Stateless single-replica Deployments** (paperless redis/tika/gotenberg, whisper, etc.) — a blocking PDB gives no recoverability benefit, only blocks drains.
### Validation
`kubectl kustomize` builds clean for all three app dirs; renders exactly 4 PDBs (gitea 1, woodpecker 1, paperless 2) with the correct selectors.
Note: `minAvailable: 1` on a single-replica workload blocks voluntary evictions entirely (drains need `--disable-eviction` or a scale-down first) — that friction is the intended protection for these data-bearing pods. If you would rather not block drains at all for some of these, say so and I can drop that one.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Adds minAvailable:1 PDBs for the data-bearing single-replica StatefulSets
that had no eviction protection: gitea, woodpecker-server, and paperless's
protonmail-bridge + syncthing sidecars. On a 1-replica workload this makes
the eviction API refuse *voluntary* evictions, so a node drain blocks and
surfaces the pod instead of yanking a live SQLite DB / RWO-PVC pod mid-write.
Involuntary disruptions (node crash, OOM) are unaffected.
Deliberately excluded, with rationale:
- CNPG clusters im-pg and gf-pg (instances:1): CloudNativePG intentionally
omits a primary PDB for single-instance clusters (no failover target), and
handles graceful primary shutdown itself. A manual maxUnavailable:0 would
only wedge node drains with no HA benefit.
- Ceph mons: the Rook operator self-manages quorum-preserving mon/OSD PDBs
(disruptionManagement.managePodBudgets default). A hand-written PDB would
be redundant or fight the operator on each reconcile.
- Stateless single-replica Deployments (redis/tika/gotenberg caches, etc.):
a blocking PDB gives no recoverability benefit, only blocks drains.
Refs #201
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes #201
Adds
minAvailable: 1PodDisruptionBudgets for the data-bearing single-replica StatefulSets that had zero eviction protection:giteaname=giteawoodpecker-servername=woodpecker, component=serverprotonmail-bridgename=protonmail-bridgesyncthingname=syncthingOn a 1-replica workload,
minAvailable: 1makes the eviction API refuse voluntary evictions, sokubectl drain/ node maintenance blocks and surfaces the pod instead of yanking a live SQLite DB or RWO-PVC pod mid-write. Involuntary disruptions (node crash, OOM) are unaffected — as intended.The woodpecker selector deliberately includes
component: serverso it does not also cover the statelesswoodpeckeragents.Deliberately excluded (with rationale)
im-pgandgf-pg(instances:1) — CloudNativePG intentionally creates no primary PDB for single-instance clusters (no failover target) and handles graceful primary shutdown itself (smartShutdownTimeout/stopDelay, already tuned onim-pg). A manualmaxUnavailable: 0would only wedge node drains with no HA benefit and fight the operator design.im-pgis single-instance only during the pgvecto.rs→VectorChord migration window.disruptionManagement.managePodBudgets, default-on; no override in this repo). A hand-written PDB would be redundant or overwritten each reconcile.Validation
kubectl kustomizebuilds clean for all three app dirs; renders exactly 4 PDBs (gitea 1, woodpecker 1, paperless 2) with the correct selectors.Note:
minAvailable: 1on a single-replica workload blocks voluntary evictions entirely (drains need--disable-evictionor a scale-down first) — that friction is the intended protection for these data-bearing pods. If you would rather not block drains at all for some of these, say so and I can drop that one.🤖 Generated with Claude Code