--- # Longhorn — distributed replicated block storage across the 3 nodes (ADR-0003). # Serves R-STATE-01 (state survives destroy/rebuild) and R-STATE-02 (3-way replication). # # Dev-appropriate values. Environment differences enter ONLY via ${...} substitution from # cluster-vars (R-ENV-02); everything else is identical base config for dev and prod. apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: name: longhorn namespace: longhorn-system spec: interval: 30m chart: spec: chart: longhorn version: ">=1.7.0 <1.8.0" # TODO(WS-STORAGE): pin at bring-up; Renovate maintains sourceRef: kind: HelmRepository name: longhorn namespace: longhorn-system install: createNamespace: false # namespace.yaml owns it (GitOps-managed, labelled) remediation: retries: 3 upgrade: remediation: retries: 3 values: # We own the StorageClasses (storageclasses.yaml) so the default 3-replica class and the bulk # tier are explicit and GitOps-managed. Disable the chart's built-in default SC so there is # exactly one default-class annotation in the cluster. persistence: defaultClass: false defaultSettings: # --- data path (R-STATE-02) --- # Dedicated Longhorn data disk (/dev/vdb → ext4) is mounted here by cloud-init on every node # (infra/cloud-init/user-data.yaml.tftpl). Longhorn stores replicas on this disk only. defaultDataPath: "/var/lib/longhorn" # --- replication (R-STATE-02) --- # Global fallback replica count. The `longhorn` StorageClass sets numberOfReplicas explicitly # (authoritative); this keeps any volume created without an explicit count consistent. # Substituted from cluster-vars.longhorn_default_replica_count (=3 in dev). defaultReplicaCount: ${LONGHORN_DEFAULT_REPLICA_COUNT} # --- replica anti-affinity across nodes (R-STATE-02 durability guarantee) --- # HARD anti-affinity: never place two replicas of the same volume on the same node, so a # single node loss cannot take down more than one replica. On a 3-node / 3-replica cluster # this yields exactly one replica per node. replicaSoftAntiAffinity: false # Single zone (3 mini-PCs, no failure zones): allow replicas within the one zone. replicaZoneSoftAntiAffinity: true # When a downed node returns, rebalance replicas back toward one-per-node (best-effort so it # never blocks scheduling). replicaAutoBalance: "best-effort" # --- capacity guardrails (docs/04 "reserve disk headroom") --- # Reserve 20% of the dedicated data disk so a node never fills to 100% (which wedges the # kubelet and Longhorn alike). Dev disks are small, so headroom matters. storageReservedPercentageForDefaultDisk: "20" # Stop scheduling new replicas onto a disk once free space drops below 25%. storageMinimalAvailablePercentage: "25" # Dev: 200% thin over-provisioning — config-only volumes use little actual space, so the small # 39Gi data disks host the full app catalog. Physical fill risk is low (watch monitoring PVCs). # Prod-grade alternative: grow the Longhorn data disks and return to 1:1 (WS-STORAGE). storageOverProvisioningPercentage: "200" # --- misc dev-appropriate defaults --- # Keep replicas spread for durability rather than co-locating with the pod. defaultDataLocality: "disabled" # Reclaim replica space of deleted/failed volumes promptly in dev. orphanAutoDeletion: true # Longhorn's own manager/UI stay in-cluster; UI exposure (if any) is gated behind # oauth2-proxy forward-auth (ADR-0014) by WS-SEC — not exposed here. # TODO(WS-STORAGE, Phase 4): off-cluster backup target (defaultSettings.backupTarget + # backupTargetCredentialSecret) is configured alongside Velero (ADR-0003, R-STATE-03). # Credentials referenced BY NAME only, SOPS-encrypted (WS-SEC) — never inline here.