[ci skip] complete NFS CSI migration: complex stacks + platform modules

Migrate remaining multi-volume stacks and all platform modules from
inline NFS volumes to CSI-backed PV/PVC with nfs-truenas StorageClass
(soft,timeo=30,retrans=3 mount options).

Complex stacks: openclaw (4 vols), immich (8 vols), frigate (2 vols),
nextcloud (2 vols + old PV replaced), rybbit (1 vol)

Remaining stacks: affine, ebook2audiobook, f1-stream, osm_routing,
real-estate-crawler

Platform modules: monitoring (prometheus, loki, alertmanager PVs
converted from native NFS to CSI), redis, dbaas, technitium,
headscale, vaultwarden, uptime-kuma, mailserver, infra-maintenance
This commit is contained in:
Viktor Barzin 2026-03-02 01:24:07 +00:00
parent 11b3d92684
commit 0e324df545
No known key found for this signature in database
GPG key ID: 0EB088298288D958
24 changed files with 411 additions and 179 deletions

View file

@ -234,6 +234,30 @@ resource "kubernetes_service" "mysql" {
depends_on = [helm_release.mysql_cluster]
}
module "nfs_mysql_backup" {
source = "../../../../modules/kubernetes/nfs_volume"
name = "dbaas-mysql-backup"
namespace = kubernetes_namespace.dbaas.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/mnt/main/mysql-backup"
}
module "nfs_pgadmin" {
source = "../../../../modules/kubernetes/nfs_volume"
name = "dbaas-pgadmin"
namespace = kubernetes_namespace.dbaas.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/mnt/main/postgresql/pgadmin"
}
module "nfs_postgresql_backup" {
source = "../../../../modules/kubernetes/nfs_volume"
name = "dbaas-postgresql-backup"
namespace = kubernetes_namespace.dbaas.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/mnt/main/postgresql-backup"
}
resource "kubernetes_cron_job_v1" "mysql-backup" {
metadata {
name = "mysql-backup"
@ -281,9 +305,8 @@ resource "kubernetes_cron_job_v1" "mysql-backup" {
}
volume {
name = "mysql-backup"
nfs {
path = "/mnt/main/mysql-backup"
server = var.nfs_server
persistent_volume_claim {
claim_name = module.nfs_mysql_backup.claim_name
}
}
}
@ -927,9 +950,8 @@ resource "kubernetes_deployment" "pgadmin" {
# config_map {
# name = "pgadmin-config"
# }
nfs {
path = "/mnt/main/postgresql/pgadmin"
server = var.nfs_server
persistent_volume_claim {
claim_name = module.nfs_pgadmin.claim_name
}
}
dns_config {
@ -1017,9 +1039,8 @@ resource "kubernetes_cron_job_v1" "postgresql-backup" {
}
volume {
name = "postgresql-backup"
nfs {
path = "/mnt/main/postgresql-backup"
server = var.nfs_server
persistent_volume_claim {
claim_name = module.nfs_postgresql_backup.claim_name
}
}
}

View file

@ -20,6 +20,14 @@ module "tls_secret" {
tls_secret_name = var.tls_secret_name
}
module "nfs_data" {
source = "../../../../modules/kubernetes/nfs_volume"
name = "headscale-data"
namespace = kubernetes_namespace.headscale.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/mnt/main/headscale"
}
resource "kubernetes_deployment" "headscale" {
metadata {
name = "headscale"
@ -111,9 +119,8 @@ resource "kubernetes_deployment" "headscale" {
volume {
name = "nfs-config"
nfs {
path = "/mnt/main/headscale"
server = var.nfs_server
persistent_volume_claim {
claim_name = module.nfs_data.claim_name
}
}
# container {

View file

@ -66,6 +66,14 @@ variable "nfs_server" { type = string }
# }
# }
module "nfs_etcd_backup" {
source = "../../../../modules/kubernetes/nfs_volume"
name = "infra-etcd-backup"
namespace = "default"
nfs_server = var.nfs_server
nfs_path = "/mnt/main/etcd-backup"
}
# # backup etcd
resource "kubernetes_cron_job_v1" "backup-etcd" {
metadata {
@ -123,9 +131,8 @@ resource "kubernetes_cron_job_v1" "backup-etcd" {
volume {
name = "backup"
nfs {
path = "/mnt/main/etcd-backup"
server = var.nfs_server
persistent_volume_claim {
claim_name = module.nfs_etcd_backup.claim_name
}
}
volume {

View file

@ -154,6 +154,14 @@ resource "kubernetes_secret" "opendkim_key" {
}
module "nfs_data" {
source = "../../../../modules/kubernetes/nfs_volume"
name = "mailserver-data"
namespace = kubernetes_namespace.mailserver.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/mnt/main/mailserver"
}
resource "kubernetes_deployment" "mailserver" {
metadata {
name = "mailserver"
@ -413,9 +421,8 @@ resource "kubernetes_deployment" "mailserver" {
}
volume {
name = "data"
nfs {
path = "/mnt/main/mailserver"
server = var.nfs_server
persistent_volume_claim {
claim_name = module.nfs_data.claim_name
}
# iscsi {
# target_portal = "iscsi.viktorbarzin.lan:3260"

View file

@ -1,6 +1,22 @@
variable "roundcube_db_password" { type = string }
variable "mysql_host" { type = string }
module "nfs_roundcube_html" {
source = "../../../../modules/kubernetes/nfs_volume"
name = "roundcubemail-html"
namespace = kubernetes_namespace.mailserver.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/mnt/main/roundcubemail/html"
}
module "nfs_roundcube_enigma" {
source = "../../../../modules/kubernetes/nfs_volume"
name = "roundcubemail-enigma"
namespace = kubernetes_namespace.mailserver.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/mnt/main/roundcubemail/enigma"
}
# If you want to override settings mount this in /var/roundcube/config
# more info in https://github.com/roundcube/roundcubemail-docker?tab=readme-ov-file
# resource "kubernetes_config_map" "roundcubemail_config" {
@ -147,16 +163,14 @@ resource "kubernetes_deployment" "roundcubemail" {
volume {
name = "html"
nfs {
path = "/mnt/main/roundcubemail/html"
server = var.nfs_server
persistent_volume_claim {
claim_name = module.nfs_roundcube_html.claim_name
}
}
volume {
name = "enigma"
nfs {
path = "/mnt/main/roundcubemail/enigma"
server = var.nfs_server
persistent_volume_claim {
claim_name = module.nfs_roundcube_enigma.claim_name
}
}
dns_config {

View file

@ -34,11 +34,16 @@ resource "kubernetes_persistent_volume" "alertmanager_pv" {
}
access_modes = ["ReadWriteOnce"]
persistent_volume_source {
nfs {
path = "/mnt/main/alertmanager"
server = var.nfs_server
csi {
driver = "nfs.csi.k8s.io"
volume_handle = "alertmanager-pv"
volume_attributes = {
server = var.nfs_server
share = "/mnt/main/alertmanager"
}
}
}
storage_class_name = "nfs-truenas"
}
}
# resource "kubernetes_persistent_volume_claim" "grafana_pvc" {

View file

@ -24,11 +24,16 @@ resource "kubernetes_persistent_volume" "loki" {
}
access_modes = ["ReadWriteOnce"]
persistent_volume_source {
nfs {
path = "/mnt/main/loki/loki"
server = var.nfs_server
csi {
driver = "nfs.csi.k8s.io"
volume_handle = "loki"
volume_attributes = {
server = var.nfs_server
share = "/mnt/main/loki/loki"
}
}
}
storage_class_name = "nfs-truenas"
persistent_volume_reclaim_policy = "Retain"
volume_mode = "Filesystem"
}

View file

@ -14,7 +14,8 @@ resource "kubernetes_persistent_volume_claim" "prometheus_server_pvc" {
}
}
# storage_class_name = "standard"
volume_name = "prometheus-iscsi-pv"
storage_class_name = "nfs-truenas"
volume_name = "prometheus-iscsi-pv"
}
}
@ -28,18 +29,16 @@ resource "kubernetes_persistent_volume" "prometheus_server_pvc" {
}
access_modes = ["ReadWriteOnce"]
persistent_volume_source {
nfs {
path = "/mnt/main/prometheus"
server = var.nfs_server
csi {
driver = "nfs.csi.k8s.io"
volume_handle = "prometheus-iscsi-pv"
volume_attributes = {
server = var.nfs_server
share = "/mnt/main/prometheus"
}
}
# iscsi {
# fs_type = "ext4"
# iqn = "iqn.2020-12.lan.viktorbarzin:storage:monitoring:prometheus"
# lun = 0
# target_portal = "iscsi.viktorbarzin.me:3260"
# }
}
storage_class_name = "nfs-truenas"
persistent_volume_reclaim_policy = "Retain"
volume_mode = "Filesystem"
}

View file

@ -139,6 +139,14 @@ resource "kubernetes_service" "redis" {
depends_on = [helm_release.redis]
}
module "nfs_backup" {
source = "../../../../modules/kubernetes/nfs_volume"
name = "redis-backup"
namespace = kubernetes_namespace.redis.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/mnt/main/redis-backup"
}
# Hourly backup: copy RDB snapshot from master to NFS
resource "kubernetes_cron_job_v1" "redis-backup" {
metadata {
@ -179,9 +187,8 @@ resource "kubernetes_cron_job_v1" "redis-backup" {
}
volume {
name = "backup"
nfs {
path = "/mnt/main/redis-backup"
server = var.nfs_server
persistent_volume_claim {
claim_name = module.nfs_backup.claim_name
}
}
}

View file

@ -6,6 +6,14 @@
# Both pods share the `dns-server=true` label so the DNS LoadBalancer
# in main.tf routes queries to whichever pod is healthy.
module "nfs_secondary_config" {
source = "../../../../modules/kubernetes/nfs_volume"
name = "technitium-secondary-config"
namespace = kubernetes_namespace.technitium.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/mnt/main/technitium-secondary"
}
# Primary-only service for zone transfers (AXFR) and API access
resource "kubernetes_service" "technitium_primary" {
metadata {
@ -135,9 +143,8 @@ resource "kubernetes_deployment" "technitium_secondary" {
}
volume {
name = "nfs-config"
nfs {
path = "/mnt/main/technitium-secondary"
server = var.nfs_server
persistent_volume_claim {
claim_name = module.nfs_secondary_config.claim_name
}
}
dns_config {

View file

@ -81,6 +81,14 @@ resource "kubernetes_config_map" "coredns" {
}
}
module "nfs_config" {
source = "../../../../modules/kubernetes/nfs_volume"
name = "technitium-config"
namespace = kubernetes_namespace.technitium.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/mnt/main/technitium"
}
resource "kubernetes_deployment" "technitium" {
# resource "kubernetes_daemonset" "technitium" {
metadata {
@ -196,9 +204,8 @@ resource "kubernetes_deployment" "technitium" {
}
volume {
name = "nfs-config"
nfs {
path = "/mnt/main/technitium"
server = var.nfs_server
persistent_volume_claim {
claim_name = module.nfs_config.claim_name
}
}
volume {

View file

@ -20,6 +20,14 @@ module "tls_secret" {
tls_secret_name = var.tls_secret_name
}
module "nfs_data" {
source = "../../../../modules/kubernetes/nfs_volume"
name = "uptime-kuma-data"
namespace = kubernetes_namespace.uptime-kuma.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/mnt/main/uptime-kuma"
}
resource "kubernetes_deployment" "uptime-kuma" {
metadata {
name = "uptime-kuma"
@ -78,9 +86,8 @@ resource "kubernetes_deployment" "uptime-kuma" {
}
volume {
name = "data"
nfs {
server = var.nfs_server
path = "/mnt/main/uptime-kuma"
persistent_volume_claim {
claim_name = module.nfs_data.claim_name
}
}
dns_config {

View file

@ -20,6 +20,14 @@ module "tls_secret" {
tls_secret_name = var.tls_secret_name
}
module "nfs_data" {
source = "../../../../modules/kubernetes/nfs_volume"
name = "vaultwarden-data"
namespace = kubernetes_namespace.vaultwarden.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/mnt/main/vaultwarden"
}
resource "kubernetes_deployment" "vaultwarden" {
metadata {
name = "vaultwarden"
@ -108,9 +116,8 @@ resource "kubernetes_deployment" "vaultwarden" {
}
volume {
name = "data"
nfs {
path = "/mnt/main/vaultwarden"
server = var.nfs_server
persistent_volume_claim {
claim_name = module.nfs_data.claim_name
}
}
dns_config {