feat(stalwart): spread each node group over nodes and give each one a PDB
A two-replica node group was redundancy on paper: nothing kept both pods off one node, and no PodDisruptionBudget kept a drain from taking both at once. Both objects are now rendered per node group, gated on that group's COMPUTED replica count being >= 2. The distribution is a promise, not an effort: maxSkew 1 on kubernetes.io/hostname with whenUnsatisfiable DoNotSchedule, selecting only this group's own pods, so an "mx" and a "full" pod may share a node. The selector comes from the chart (stalwart.groupLabels), never from the operator - a spread constraint whose selector matches no pod is trivially satisfied, distributes nothing and reports nothing. nodeAffinityPolicy: Ignore is set explicitly, and that is the load-bearing detail. Its API default is Honor, under which a narrowing nodeSelector shrinks the set of counted domains until both replicas fit into one: skew 0, both pods co-located, no Pending, no event, and a selector that is correct - so no check can see it. With Ignore the same narrowing gives skew 2 and the second pod is Pending. A render abort was the alternative and would also have forbidden a nodeSelector spanning five nodes, which is legal. A user entry colliding with the chart's own on (topologyKey, whenUnsatisfiable) aborts the render naming both values, because the API rejects the duplicate with a message about a list index and an apply-based path merges the two over patchMergeKey: topologyKey silently, dropping one selector. Minor rather than major, proved with a diff rather than argued: with the shipped defaults (full: 1, mx: 0) and with ci/stalwart/test-values.yaml, helm template renders byte-for-byte what 1.0.1+upv0.16.24 rendered - both diffs empty. New in CI, over every chart on every PR: ci/run-selector-match-test.sh holds every rendered PodDisruptionBudget selector and every topologySpreadConstraints labelSelector against the labels of the pod templates in the same render. Helm itself is the YAML parser (ci/yaml2json), because the runners have neither pyyaml nor yq and a hand-written parser could read nothing and report nothing. podAffinity/podAntiAffinity are out of scope; matchExpressions-only selectors are reported as not checked rather than counted as passing. Two anti-vacuum guards: a chart with an overlay under ci/selector-match/ that renders no selector fails, and a run that checks no selector at all fails. Fixes #96
This commit was merged in pull request #97.
This commit is contained in:
1 parent
1698fc0aeb
commit
6ade74db80
14 files changed
+1125
-8
No files matched your search
@@ -0,0 +1,38 @@
|
||||
# Overlay for ci/run-selector-match-test.sh, applied ON TOP of
|
||||
# ci/stalwart/test-values.yaml and nowhere else - not by the install-test, not by
|
||||
# the Trivy scan, not by the quantity render test.
|
||||
#
|
||||
# WHY IT EXISTS. Both objects this test looks at are rendered only while a node
|
||||
# group's COMPUTED replica count is >= 2, and the install-test fixture runs
|
||||
# full: 1 / mx: 0 deliberately (a second pod would need a real in-memory store,
|
||||
# and a running "mx" pod would fail-open into a second full node against an
|
||||
# empty database). So without this file stalwart renders no PodDisruptionBudget
|
||||
# and no topologySpreadConstraints, and the test would be green for the chart it
|
||||
# was written for, having looked at nothing. ci/run-selector-match-test.sh
|
||||
# therefore FAILS a chart that has an overlay and still renders no selector.
|
||||
#
|
||||
# This is a RENDER-ONLY overlay. Nothing here is installed anywhere, so the two
|
||||
# reasons the install-test keeps mx at 0 do not apply.
|
||||
nodes:
|
||||
full:
|
||||
replicas: 2
|
||||
exposedPorts: [smtp, submissions, imaps, http]
|
||||
mx:
|
||||
# Two as well, so BOTH groups' selectors are checked. The per-group split is
|
||||
# the whole point of this chart's version of the rule: one object per group,
|
||||
# each selecting only its own pods. A single group would leave the case where
|
||||
# a group's selector accidentally matches the OTHER group's pods untested.
|
||||
replicas: 2
|
||||
exposedPorts: [smtp, http]
|
||||
|
||||
externalServices:
|
||||
valkey:
|
||||
# REQUIRED HERE, and not cosmetic: with more than one Stalwart pod and no
|
||||
# in-memory store address the chart ABORTS THE RENDER ("this release runs N
|
||||
# Stalwart pods, which is a cluster, but no in-memory store has an
|
||||
# address"). Nothing connects to this name - the render never resolves it -
|
||||
# but without it this overlay would turn the whole job red instead of
|
||||
# exercising it. valkeySubchart.enabled: true would be the other way out and
|
||||
# is deliberately not taken: it would add a network fetch of the published
|
||||
# valkey chart to a test that otherwise needs none.
|
||||
host: valkey-selector-match-fixture
|
||||
Reference in new issue
Block a user