diff --git a/k8s/applications/portainer/portainer-values.yaml b/k8s/applications/portainer/portainer-values.yaml index 573e113..3711dc1 100644 --- a/k8s/applications/portainer/portainer-values.yaml +++ b/k8s/applications/portainer/portainer-values.yaml @@ -33,7 +33,7 @@ tls: # RWO block volume. 10Gi is generous for config data but cheap on Longhorn. persistence: enabled: true - storageClass: "longhorn" + storageClass: "longhorn-wffc" size: 10Gi resources: @@ -51,3 +51,8 @@ tolerations: - key: node-role.kubernetes.io/control-plane operator: Exists effect: NoSchedule + +# Pin to az-a (talos-cp-1) — sole Longhorn storage node. Its RWO PVC can only +# attach there; without this the pod may land on cp-2/cp-3 and fail to mount. +nodeSelector: + topology.kubernetes.io/zone: az-a diff --git a/k8s/infrastructure/longhorn/kustomization.yaml b/k8s/infrastructure/longhorn/kustomization.yaml index bc9c51b..a587239 100644 --- a/k8s/infrastructure/longhorn/kustomization.yaml +++ b/k8s/infrastructure/longhorn/kustomization.yaml @@ -1,5 +1,8 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization namespace: longhorn-system -resources: [] -# Longhorn deployed via Helm chart (values in parent layer) +resources: + - longhorn-wffc-storageclass.yaml +# Longhorn deployed via Helm chart (values in parent layer). The WFFC +# StorageClass above is the new default; the chart's Immediate `longhorn` SC is +# demoted (default-class annotation removed on the live object at bootstrap). diff --git a/k8s/infrastructure/longhorn/longhorn-wffc-storageclass.yaml b/k8s/infrastructure/longhorn/longhorn-wffc-storageclass.yaml new file mode 100644 index 0000000..7cfd7e6 --- /dev/null +++ b/k8s/infrastructure/longhorn/longhorn-wffc-storageclass.yaml @@ -0,0 +1,29 @@ +# longhorn-wffc — Longhorn StorageClass with WaitForFirstConsumer binding. +# +# The chart's default `longhorn` SC uses Immediate binding: the PV binds before +# the pod is scheduled, so on this single-storage-node topology (only talos-cp-1 +# runs Longhorn) the scheduler often places the pod on cp-2/cp-3 where the volume +# can't attach ("CSINode does not contain driver driver.longhorn.io"). +# +# WaitForFirstConsumer defers binding until the pod is scheduled, so the volume +# is provisioned on the node the pod lands on — and with a single Longhorn node +# that co-locates pod + volume on cp-1 automatically. This is the new default; +# the chart's `longhorn` SC is demoted (see longhorn-values default-class=false). +# +# volumeBindingMode is immutable, so this is a distinct SC (not an edit of the +# chart's). Existing volumes stay on `longhorn`; new PVCs use this. +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: longhorn-wffc + annotations: + storageclass.kubernetes.io/is-default-class: "true" +provisioner: driver.longhorn.io +allowVolumeExpansion: true +reclaimPolicy: Delete +volumeBindingMode: WaitForFirstConsumer +parameters: + numberOfReplicas: "1" + staleReplicaTimeout: "30" + fromBackup: "" + dataLocality: "best-effort" diff --git a/k8s/security/ci-cd/charts/forgejo-runner/templates/deployment.yaml b/k8s/security/ci-cd/charts/forgejo-runner/templates/deployment.yaml index a87a725..49394ce 100644 --- a/k8s/security/ci-cd/charts/forgejo-runner/templates/deployment.yaml +++ b/k8s/security/ci-cd/charts/forgejo-runner/templates/deployment.yaml @@ -19,6 +19,10 @@ spec: spec: tolerations: {{- toYaml .Values.tolerations | nindent 8 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} initContainers: - name: register diff --git a/k8s/security/ci-cd/charts/forgejo-runner/values.yaml b/k8s/security/ci-cd/charts/forgejo-runner/values.yaml index ad57e2f..74c9832 100644 --- a/k8s/security/ci-cd/charts/forgejo-runner/values.yaml +++ b/k8s/security/ci-cd/charts/forgejo-runner/values.yaml @@ -30,13 +30,18 @@ dind: persistence: reg: - storageClass: longhorn + storageClass: longhorn-wffc size: 1Gi # .runner registration file + config — survives pod restarts dind: - storageClass: longhorn + storageClass: longhorn-wffc size: 30Gi # docker layer cache — keeps rebuilds fast across restarts tolerations: - key: node-role.kubernetes.io/control-plane operator: Exists effect: NoSchedule + +# Pin to az-a (talos-cp-1) — sole Longhorn node; RWO PVCs (reg/dind cache) only +# attach there. +nodeSelector: + topology.kubernetes.io/zone: az-a