Skip to content

fix(k8s): default PodDisruptionBudget to maxUnavailable:1#307

Closed
Cre-eD wants to merge 1 commit into
mainfrom
chore/pdb-default-maxunavailable
Closed

fix(k8s): default PodDisruptionBudget to maxUnavailable:1#307
Cre-eD wants to merge 1 commit into
mainfrom
chore/pdb-default-maxunavailable

Conversation

@Cre-eD

@Cre-eD Cre-eD commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Problem

DeploySimpleContainer defaults every Deployment's PodDisruptionBudget to
minAvailable: 1 when the stack doesn't configure one. On a single-replica
Deployment that resolves to disruptionsAllowed: 0: the eviction API refuses to
evict the only pod, so the cluster autoscaler can never drain the node it runs on.

On GKE Autopilot this is expensive — such a node can never be consolidated and
stays provisioned regardless of utilization, so every single-replica service
effectively pins (and bills) a node. Empty nodes are still reclaimed, but any node
hosting one of these pods reports scaleDown: NoCandidates.

Fix

Default to maxUnavailable: 1 instead of minAvailable: 1:

  • single-replicadisruptionsAllowed: 1: the pod can be evicted and
    rescheduled, so the autoscaler can drain and consolidate the node (a brief
    restart during the drain, same as a rolling update).
  • multi-replica → still bounds voluntary disruptions to one pod at a time
    (equal-or-safer than the old minAvailable:1, which permitted up to N-1).
  • an explicitly configured disruptionBudget is honored unchanged.

The default is extracted into a small pure helper (defaultDisruptionBudget) with
a unit test, so a regression back to the node-pinning default fails CI.

Compatibility

Stacks that set disruptionBudget explicitly are unaffected. Stacks relying on the
default pick up the new value on their next deploy.

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown

Semgrep Scan Results

Repository: api | Commit: a451da6

Check Status Details
✅ Semgrep Pass 0 total findings (no error/warning)

Scanned at 2026-06-01 21:02 UTC

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown

Security Scan Results

Repository: api | Commit: a451da6

Check Status Details
✅ Secret Scan Pass No secrets detected
✅ Dependencies (Trivy) Pass 0 total (no critical/high)
✅ Dependencies (Grype) Pass 0 total (no critical/high)
📦 SBOM Generated 527 components (CycloneDX)

Scanned at 2026-06-01 21:03 UTC

The default PDB was minAvailable:1, which on a single-replica Deployment
resolves to disruptionsAllowed:0. That forbids the eviction API, so the
cluster autoscaler can never drain the pod's node — on GKE Autopilot the
node can never be consolidated and stays pinned regardless of utilization,
billing an underutilized node per single-replica service.

Default to maxUnavailable:1 instead: disruptionsAllowed:1 lets the pod be
evicted and rescheduled for consolidation, while still bounding voluntary
disruptions to one pod at a time for multi-replica deployments. Explicitly
configured budgets are honored unchanged. Default extracted into a testable
helper with coverage.

Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
@Cre-eD
Cre-eD force-pushed the chore/pdb-default-maxunavailable branch from 627640f to 6b6c9b9 Compare June 1, 2026 21:02
@Cre-eD

Cre-eD commented Jun 1, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favor of a contained per-repo config sweep (cloudExtras.disruptionBudget: maxUnavailable:1) across the PAY-SPACE app stacks, to avoid an org-wide SC version bump. May revisit the default later.

@Cre-eD Cre-eD closed this Jun 1, 2026
@Cre-eD
Cre-eD deleted the chore/pdb-default-maxunavailable branch June 1, 2026 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant