diff --git a/kubernetes/clusters/homelab/infrastructure.yaml b/kubernetes/clusters/homelab/infrastructure.yaml index 5c2601c8..bfb44b30 100644 --- a/kubernetes/clusters/homelab/infrastructure.yaml +++ b/kubernetes/clusters/homelab/infrastructure.yaml @@ -48,6 +48,10 @@ spec: kind: HelmRelease name: cloudnative-pg # DB operator — seed jobs create databases namespace: database + - apiVersion: helm.toolkit.fluxcd.io/v2 + kind: HelmRelease + name: mariadb-operator # the MySQL half — WordPress can't use CNPG + namespace: database # decryption block dropped 2026-07-13: no *.sops.yaml left under this # path — secrets come from OpenBao via ESO (MIGRATION-sops-openbao.md). --- diff --git a/kubernetes/infrastructure/kustomization.yaml b/kubernetes/infrastructure/kustomization.yaml index 3b34a28a..b0a5a735 100644 --- a/kubernetes/infrastructure/kustomization.yaml +++ b/kubernetes/infrastructure/kustomization.yaml @@ -15,6 +15,7 @@ resources: - rook-ceph/ - ceph-csi-drivers/ - cloudnative-pg/ + - mariadb-operator/ - netbird-ingress/ - netbird-backup/ - coredns-config/ diff --git a/kubernetes/infrastructure/mariadb-operator/helmrelease.yaml b/kubernetes/infrastructure/mariadb-operator/helmrelease.yaml new file mode 100644 index 00000000..5299cb91 --- /dev/null +++ b/kubernetes/infrastructure/mariadb-operator/helmrelease.yaml @@ -0,0 +1,81 @@ +# MariaDB operator, for the one workload in this cluster that cannot use +# CloudNativePG: WordPress. WordPress speaks MySQL natively — the PostgreSQL +# route would mean pg4wp, an SQL-rewriting shim whose own README lists +# WordPress 6.5.3 as its newest tested version while renner.uno runs 7.0.4. +# +# The charts are OCI artifacts (ghcr.io), so this follows the OCIRepository +# pattern from infrastructure/spegel rather than the HelmRepository pattern +# used for CNPG. +# +# CRDs ship as a SEPARATE chart that must be installed first — upstream is +# explicit about the ordering, hence the dependsOn below rather than a single +# release with crds: CreateReplace. +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: mariadb-operator-crds + namespace: database +spec: + interval: 24h + url: oci://ghcr.io/mariadb-operator/charts/mariadb-operator-crds + ref: + # Calendar versioning: the major is the year. Upstream ships an upgrade + # guide with each minor (Helm repo deprecations, registry moves), so the + # range is capped at the year boundary instead of the usual open ">=". + semver: ">=26.6.0 <27.0.0" +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: mariadb-operator-crds + namespace: database +spec: + interval: 30m + chartRef: + kind: OCIRepository + name: mariadb-operator-crds + namespace: database + install: + remediation: + retries: 3 + upgrade: + remediation: + retries: 3 +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: mariadb-operator + namespace: database +spec: + interval: 24h + url: oci://ghcr.io/mariadb-operator/charts/mariadb-operator + ref: + semver: ">=26.6.0 <27.0.0" +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: mariadb-operator + namespace: database +spec: + interval: 30m + dependsOn: + - name: mariadb-operator-crds + namespace: database + chartRef: + kind: OCIRepository + name: mariadb-operator + namespace: database + install: + remediation: + retries: 3 + upgrade: + remediation: + retries: 3 + values: + # The operator watches all namespaces; the MariaDB CR itself lives with + # the app in kubernetes/apps/wordpress/, mirroring how CNPG Clusters sit + # in their consumer's namespace (ak-pg in authentik, im-pg in immich). + metrics: + enabled: false diff --git a/kubernetes/infrastructure/mariadb-operator/kustomization.yaml b/kubernetes/infrastructure/mariadb-operator/kustomization.yaml new file mode 100644 index 00000000..4fd939d4 --- /dev/null +++ b/kubernetes/infrastructure/mariadb-operator/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - helmrelease.yaml diff --git a/kubernetes/infrastructure/namespaces/namespaces.yaml b/kubernetes/infrastructure/namespaces/namespaces.yaml index f35185f9..79058429 100644 --- a/kubernetes/infrastructure/namespaces/namespaces.yaml +++ b/kubernetes/infrastructure/namespaces/namespaces.yaml @@ -151,3 +151,12 @@ apiVersion: v1 kind: Namespace metadata: name: trmnl +--- +# WordPress for www.renner.uno, migrated off the Hetzner VM `wordpress-hochzeit`. +# No privileged label needed: the cluster enforces `baseline`, which permits the +# official Apache image's root master process binding :80. It does trip the +# `restricted` audit/warn level — that is expected and not an error. +apiVersion: v1 +kind: Namespace +metadata: + name: wordpress diff --git a/kubernetes/infrastructure/post-crds/openbao-clustersecretstore.yaml b/kubernetes/infrastructure/post-crds/openbao-clustersecretstore.yaml index f2cee8b1..5c8cfb6e 100644 --- a/kubernetes/infrastructure/post-crds/openbao-clustersecretstore.yaml +++ b/kubernetes/infrastructure/post-crds/openbao-clustersecretstore.yaml @@ -30,6 +30,7 @@ spec: - paperless - trmnl - velero + - wordpress provider: vault: # ESO's provider name; speaks OpenBao fine server: http://openbao.openbao.svc.cluster.local:8200 diff --git a/opentofu/object_storage.tf b/opentofu/object_storage.tf index 2e0ac753..99f8443b 100644 --- a/opentofu/object_storage.tf +++ b/opentofu/object_storage.tf @@ -42,6 +42,7 @@ locals { "renner-uno-k8s-velero", # Velero PVC backups (Kopia data mover) "renner-uno-k8s-secrets", # SOPS talosconfig/kubeconfig for cluster bootstrap "renner-uno-tfstate", # OpenTofu remote state (migrated off the nas-1 Garage S3) + "renner-uno-k8s-mariadb", # mariadb-operator logical dumps (wordpress-mariadb) ] } @@ -95,8 +96,9 @@ locals { # precedent in this repo — left uncapped (keep every version) since # storage cost there is negligible. hetzner_buckets_noncurrent_expiry_days = { - "renner-uno-k8s-cnpg" = 30 - "renner-uno-k8s-velero" = 30 + "renner-uno-k8s-cnpg" = 30 + "renner-uno-k8s-velero" = 30 + "renner-uno-k8s-mariadb" = 30 # Backup maxRetention: 720h (kubernetes/apps/wordpress/mariadb.yaml) } }