From 9ab046eb9e8a9d8cb13d0392542a149a800085f5 Mon Sep 17 00:00:00 2001 From: Aleksei Sviridkin Date: Sat, 4 Jul 2026 13:57:38 +0300 Subject: [PATCH] fix(seaweedfs): soften master anti-affinity for small clusters The vendored subchart pins the master to a hard hostname anti-affinity (requiredDuringSchedulingIgnoredDuringExecution). With the master StatefulSet at three replicas, the surplus Pods stay Pending forever on clusters with fewer than three nodes, so `helm install --wait` never returns and the S3 stack never comes up. Soften the term to a strong preference (weight 100) so the masters still spread across distinct nodes when the cluster has them, while single- and dual-node clusters can bring the master up. Mirrors the posture already used for the s3 component. Selector and topologyKey are unchanged; only required -> preferred. Assisted-By: Claude Signed-off-by: Aleksei Sviridkin --- .../seaweedfs/tests/master_affinity_test.yaml | 33 +++++++++++++++++++ packages/system/seaweedfs/values.yaml | 22 +++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 packages/system/seaweedfs/tests/master_affinity_test.yaml diff --git a/packages/system/seaweedfs/tests/master_affinity_test.yaml b/packages/system/seaweedfs/tests/master_affinity_test.yaml new file mode 100644 index 000000000..8fd4eaba5 --- /dev/null +++ b/packages/system/seaweedfs/tests/master_affinity_test.yaml @@ -0,0 +1,33 @@ +suite: seaweedfs master anti-affinity + +# Pins the master anti-affinity override that keeps the 3-replica master +# StatefulSet schedulable on clusters with fewer than three nodes. The upstream +# subchart ships a HARD hostname anti-affinity +# (requiredDuringSchedulingIgnoredDuringExecution); with three replicas that +# leaves the surplus master Pods Pending forever on a single- or dual-node +# cluster, so `helm install --wait` never returns. The overlay softens it to a +# strong preference (weight 100) so the masters still spread across distinct +# nodes when the cluster has them. This guards against a subchart bump silently +# re-hardening the term back to required. + +templates: + - charts/seaweedfs/templates/master/master-statefulset.yaml + +release: + name: seaweedfs + namespace: cozy-seaweedfs + +tests: + - it: softens the master hostname anti-affinity to a preference + asserts: + - notExists: + path: spec.template.spec.affinity.podAntiAffinity.requiredDuringSchedulingIgnoredDuringExecution + - equal: + path: spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].weight + value: 100 + - equal: + path: spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey + value: kubernetes.io/hostname + - equal: + path: spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchLabels["app.kubernetes.io/component"] + value: master diff --git a/packages/system/seaweedfs/values.yaml b/packages/system/seaweedfs/values.yaml index 488fca098..c363dc3ed 100644 --- a/packages/system/seaweedfs/values.yaml +++ b/packages/system/seaweedfs/values.yaml @@ -45,6 +45,28 @@ seaweedfs: timeoutSeconds: 30 readinessProbe: timeoutSeconds: 30 + # The upstream subchart pins the master to a HARD hostname anti-affinity + # (requiredDuringSchedulingIgnoredDuringExecution). With the 3-replica + # StatefulSet above, that makes the master unschedulable on clusters with + # fewer than three nodes: the surplus master Pods stay Pending forever, so + # `helm install --wait` never returns and Flux loops install/uninstall — + # the whole S3 stack never comes up. Soften it to a strong preference + # (weight 100) so the masters still spread across distinct nodes whenever + # the cluster has them, while single- and dual-node clusters can still + # bring the master up. Same posture already used for the s3 component + # below. Selector and topologyKey are unchanged from the subchart default; + # only required -> preferred. + affinity: | + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/name: {{ template "seaweedfs.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + app.kubernetes.io/component: master + topologyKey: kubernetes.io/hostname volume: replicas: 2 resizeHook: