diff --git a/k8s/deployment-backfill.yaml b/k8s/deployment-backfill.yaml index aef28a46..935b7f58 100644 --- a/k8s/deployment-backfill.yaml +++ b/k8s/deployment-backfill.yaml @@ -4,11 +4,18 @@ metadata: name: prop-backfill namespace: prop spec: - # Single replica. podAntiAffinity on app=prop / physical-host means - # this pod lands on whichever physical host the hot replicas aren't on - # (currently talos4 / node4); no nodeSelector or taint is needed to - # pin it — the antiaffinity is sufficient and keeps talos4 available - # as a normal scheduling target for the rest of the cluster. + # Single replica. podAntiAffinity targets `tier: hot` (not `app: prop`) + # so backfill only repels the web pods, not itself. An `app: prop` + # selector would also match backfill pods — fine at steady state, but + # during a rolling hot-pod rollout with HPA at max replicas the old + # RS's requiredDuringScheduling/IgnoredDuringExecution stays pinned on + # already-running hot pods, backfill's rule excludes the new hot pod + # from every physical host backfill hasn't touched, and the rollout + # deadlocks because maxUnavailable=1 can't bring an old hot pod down + # until a new one is Ready. Matching only `tier: hot` avoids that: + # backfill never constrains itself, and hot pods have no anti-affinity + # of their own so they can co-locate freely if HPA scales past the + # physical-host count. replicas: 1 minReadySeconds: 5 strategy: @@ -35,6 +42,7 @@ spec: - labelSelector: matchLabels: app: prop + tier: hot topologyKey: topology.kubernetes.io/physical-host serviceAccountName: prop imagePullSecrets: