feat(storage): migrate 12 SQLite NFS PVCs to proxmox-lvm (Wave 1)

Add proxmox-lvm PVCs with pvc-autoresizer annotations for all
SQLite-backed services. Deployments updated to use new block storage
PVCs. Old NFS modules retained for 1-week rollback.

Services: ntfy, freshrss, insta2spotify, actualbudget (x3),
wealthfolio, navidrome (DB only), audiobookshelf config,
headscale, forgejo, uptime-kuma.

Also: set Recreate strategy on ntfy, forgejo, insta2spotify,
wealthfolio (required for RWO volumes).
This commit is contained in:
Viktor Barzin 2026-04-04 16:26:59 +03:00
parent 792da5c066
commit ee39dd2fc9
10 changed files with 263 additions and 14 deletions

View file

@ -27,6 +27,28 @@ module "nfs_data" {
nfs_path = "/mnt/main/actualbudget/${var.name}" nfs_path = "/mnt/main/actualbudget/${var.name}"
} }
resource "kubernetes_persistent_volume_claim" "data_proxmox" {
wait_until_bound = false
metadata {
name = "actualbudget-${var.name}-data-proxmox"
namespace = "actualbudget"
annotations = {
"resize.topolvm.io/threshold" = "80%"
"resize.topolvm.io/increase" = "100%"
"resize.topolvm.io/storage_limit" = "5Gi"
}
}
spec {
access_modes = ["ReadWriteOnce"]
storage_class_name = "proxmox-lvm"
resources {
requests = {
storage = "1Gi"
}
}
}
}
resource "kubernetes_deployment" "actualbudget" { resource "kubernetes_deployment" "actualbudget" {
metadata { metadata {
name = "actualbudget-${var.name}" name = "actualbudget-${var.name}"
@ -81,7 +103,7 @@ resource "kubernetes_deployment" "actualbudget" {
volume { volume {
name = "data" name = "data"
persistent_volume_claim { persistent_volume_claim {
claim_name = module.nfs_data.claim_name claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
} }
} }
} }

View file

@ -203,6 +203,28 @@ module "nfs_audiobookshelf_config" {
nfs_path = "/mnt/main/audiobookshelf/config" nfs_path = "/mnt/main/audiobookshelf/config"
} }
resource "kubernetes_persistent_volume_claim" "abs_config_proxmox" {
wait_until_bound = false
metadata {
name = "ebooks-abs-config-proxmox"
namespace = kubernetes_namespace.ebooks.metadata[0].name
annotations = {
"resize.topolvm.io/threshold" = "80%"
"resize.topolvm.io/increase" = "100%"
"resize.topolvm.io/storage_limit" = "5Gi"
}
}
spec {
access_modes = ["ReadWriteOnce"]
storage_class_name = "proxmox-lvm"
resources {
requests = {
storage = "1Gi"
}
}
}
}
module "nfs_audiobookshelf_metadata" { module "nfs_audiobookshelf_metadata" {
source = "../../modules/kubernetes/nfs_volume" source = "../../modules/kubernetes/nfs_volume"
name = "ebooks-abs-metadata" name = "ebooks-abs-metadata"
@ -589,7 +611,7 @@ resource "kubernetes_deployment" "audiobookshelf" {
volume { volume {
name = "config" name = "config"
persistent_volume_claim { persistent_volume_claim {
claim_name = module.nfs_audiobookshelf_config.claim_name claim_name = kubernetes_persistent_volume_claim.abs_config_proxmox.metadata[0].name
} }
} }
volume { volume {

View file

@ -28,6 +28,28 @@ module "nfs_data" {
nfs_path = "/mnt/main/forgejo" nfs_path = "/mnt/main/forgejo"
} }
resource "kubernetes_persistent_volume_claim" "data_proxmox" {
wait_until_bound = false
metadata {
name = "forgejo-data-proxmox"
namespace = kubernetes_namespace.forgejo.metadata[0].name
annotations = {
"resize.topolvm.io/threshold" = "80%"
"resize.topolvm.io/increase" = "50%"
"resize.topolvm.io/storage_limit" = "20Gi"
}
}
spec {
access_modes = ["ReadWriteOnce"]
storage_class_name = "proxmox-lvm"
resources {
requests = {
storage = "5Gi"
}
}
}
}
resource "kubernetes_deployment" "forgejo" { resource "kubernetes_deployment" "forgejo" {
metadata { metadata {
name = "forgejo" name = "forgejo"
@ -40,7 +62,7 @@ resource "kubernetes_deployment" "forgejo" {
spec { spec {
replicas = 1 replicas = 1
strategy { strategy {
type = "RollingUpdate" # DB is external so we can roll type = "Recreate"
} }
selector { selector {
match_labels = { match_labels = {
@ -110,7 +132,7 @@ resource "kubernetes_deployment" "forgejo" {
volume { volume {
name = "data" name = "data"
persistent_volume_claim { persistent_volume_claim {
claim_name = module.nfs_data.claim_name claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
} }
} }
} }

View file

@ -65,6 +65,28 @@ module "nfs_data" {
nfs_path = "/mnt/main/freshrss/data" nfs_path = "/mnt/main/freshrss/data"
} }
resource "kubernetes_persistent_volume_claim" "data_proxmox" {
wait_until_bound = false
metadata {
name = "freshrss-data-proxmox"
namespace = kubernetes_namespace.immich.metadata[0].name
annotations = {
"resize.topolvm.io/threshold" = "80%"
"resize.topolvm.io/increase" = "100%"
"resize.topolvm.io/storage_limit" = "5Gi"
}
}
spec {
access_modes = ["ReadWriteOnce"]
storage_class_name = "proxmox-lvm"
resources {
requests = {
storage = "1Gi"
}
}
}
}
module "nfs_extensions" { module "nfs_extensions" {
source = "../../modules/kubernetes/nfs_volume" source = "../../modules/kubernetes/nfs_volume"
name = "freshrss-extensions" name = "freshrss-extensions"
@ -144,7 +166,7 @@ resource "kubernetes_deployment" "freshrss" {
volume { volume {
name = "data" name = "data"
persistent_volume_claim { persistent_volume_claim {
claim_name = module.nfs_data.claim_name claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
} }
} }
volume { volume {

View file

@ -44,6 +44,28 @@ module "nfs_data" {
nfs_path = "/mnt/main/headscale" nfs_path = "/mnt/main/headscale"
} }
resource "kubernetes_persistent_volume_claim" "data_proxmox" {
wait_until_bound = false
metadata {
name = "headscale-data-proxmox"
namespace = kubernetes_namespace.headscale.metadata[0].name
annotations = {
"resize.topolvm.io/threshold" = "80%"
"resize.topolvm.io/increase" = "100%"
"resize.topolvm.io/storage_limit" = "5Gi"
}
}
spec {
access_modes = ["ReadWriteOnce"]
storage_class_name = "proxmox-lvm"
resources {
requests = {
storage = "1Gi"
}
}
}
}
resource "kubernetes_deployment" "headscale" { resource "kubernetes_deployment" "headscale" {
metadata { metadata {
name = "headscale" name = "headscale"
@ -164,7 +186,7 @@ resource "kubernetes_deployment" "headscale" {
volume { volume {
name = "nfs-config" name = "nfs-config"
persistent_volume_claim { persistent_volume_claim {
claim_name = module.nfs_data.claim_name claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
} }
} }
# container { # container {
@ -414,7 +436,7 @@ resource "kubernetes_cron_job_v1" "headscale_backup" {
volume { volume {
name = "nfs-data" name = "nfs-data"
persistent_volume_claim { persistent_volume_claim {
claim_name = module.nfs_data.claim_name claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
} }
} }
restart_policy = "OnFailure" restart_policy = "OnFailure"

View file

@ -49,6 +49,28 @@ module "nfs_data" {
nfs_path = "/mnt/main/insta2spotify" nfs_path = "/mnt/main/insta2spotify"
} }
resource "kubernetes_persistent_volume_claim" "data_proxmox" {
wait_until_bound = false
metadata {
name = "insta2spotify-data-proxmox"
namespace = kubernetes_namespace.insta2spotify.metadata[0].name
annotations = {
"resize.topolvm.io/threshold" = "80%"
"resize.topolvm.io/increase" = "100%"
"resize.topolvm.io/storage_limit" = "5Gi"
}
}
spec {
access_modes = ["ReadWriteOnce"]
storage_class_name = "proxmox-lvm"
resources {
requests = {
storage = "1Gi"
}
}
}
}
resource "kubernetes_deployment" "insta2spotify" { resource "kubernetes_deployment" "insta2spotify" {
metadata { metadata {
name = "insta2spotify" name = "insta2spotify"
@ -63,6 +85,9 @@ resource "kubernetes_deployment" "insta2spotify" {
} }
spec { spec {
replicas = 1 replicas = 1
strategy {
type = "Recreate"
}
selector { selector {
match_labels = { match_labels = {
app = "insta2spotify" app = "insta2spotify"
@ -174,7 +199,7 @@ resource "kubernetes_deployment" "insta2spotify" {
volume { volume {
name = "data" name = "data"
persistent_volume_claim { persistent_volume_claim {
claim_name = module.nfs_data.claim_name claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
} }
} }
} }

View file

@ -66,6 +66,28 @@ module "nfs_data" {
nfs_path = "/mnt/main/navidrome" nfs_path = "/mnt/main/navidrome"
} }
resource "kubernetes_persistent_volume_claim" "data_proxmox" {
wait_until_bound = false
metadata {
name = "navidrome-data-proxmox"
namespace = kubernetes_namespace.navidrome.metadata[0].name
annotations = {
"resize.topolvm.io/threshold" = "80%"
"resize.topolvm.io/increase" = "100%"
"resize.topolvm.io/storage_limit" = "5Gi"
}
}
spec {
access_modes = ["ReadWriteOnce"]
storage_class_name = "proxmox-lvm"
resources {
requests = {
storage = "1Gi"
}
}
}
}
module "nfs_music" { module "nfs_music" {
source = "../../modules/kubernetes/nfs_volume" source = "../../modules/kubernetes/nfs_volume"
name = "navidrome-music" name = "navidrome-music"
@ -82,6 +104,14 @@ module "nfs_lidarr" {
nfs_path = "/mnt/main/servarr/lidarr" nfs_path = "/mnt/main/servarr/lidarr"
} }
module "nfs_freedify" {
source = "../../modules/kubernetes/nfs_volume"
name = "navidrome-freedify"
namespace = kubernetes_namespace.navidrome.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/mnt/main/freedify-music"
}
resource "kubernetes_deployment" "navidrome" { resource "kubernetes_deployment" "navidrome" {
metadata { metadata {
name = "navidrome" name = "navidrome"
@ -125,6 +155,15 @@ resource "kubernetes_deployment" "navidrome" {
mount_path = "/lidarr" mount_path = "/lidarr"
read_only = true read_only = true
} }
volume_mount {
name = "freedify"
mount_path = "/freedify-music"
read_only = true
}
env {
name = "ND_SCANSCHEDULE"
value = "0"
}
port { port {
name = "http" name = "http"
container_port = 4533 container_port = 4533
@ -143,7 +182,7 @@ resource "kubernetes_deployment" "navidrome" {
volume { volume {
name = "data" name = "data"
persistent_volume_claim { persistent_volume_claim {
claim_name = module.nfs_data.claim_name claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
} }
} }
volume { volume {
@ -158,6 +197,12 @@ resource "kubernetes_deployment" "navidrome" {
claim_name = module.nfs_lidarr.claim_name claim_name = module.nfs_lidarr.claim_name
} }
} }
volume {
name = "freedify"
persistent_volume_claim {
claim_name = module.nfs_freedify.claim_name
}
}
} }
} }
} }

View file

@ -28,6 +28,28 @@ module "nfs_data" {
nfs_path = "/mnt/main/ntfy" nfs_path = "/mnt/main/ntfy"
} }
resource "kubernetes_persistent_volume_claim" "data_proxmox" {
wait_until_bound = false
metadata {
name = "ntfy-data-proxmox"
namespace = kubernetes_namespace.ntfy.metadata[0].name
annotations = {
"resize.topolvm.io/threshold" = "80%"
"resize.topolvm.io/increase" = "100%"
"resize.topolvm.io/storage_limit" = "5Gi"
}
}
spec {
access_modes = ["ReadWriteOnce"]
storage_class_name = "proxmox-lvm"
resources {
requests = {
storage = "1Gi"
}
}
}
}
resource "kubernetes_deployment" "ntfy" { resource "kubernetes_deployment" "ntfy" {
metadata { metadata {
name = "ntfy" name = "ntfy"
@ -43,7 +65,7 @@ resource "kubernetes_deployment" "ntfy" {
spec { spec {
replicas = 1 replicas = 1
strategy { strategy {
type = "RollingUpdate" type = "Recreate"
} }
selector { selector {
match_labels = { match_labels = {
@ -131,7 +153,7 @@ resource "kubernetes_deployment" "ntfy" {
volume { volume {
name = "data" name = "data"
persistent_volume_claim { persistent_volume_claim {
claim_name = module.nfs_data.claim_name claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
} }
} }
} }

View file

@ -28,6 +28,28 @@ module "nfs_data" {
nfs_path = "/mnt/main/uptime-kuma" nfs_path = "/mnt/main/uptime-kuma"
} }
resource "kubernetes_persistent_volume_claim" "data_proxmox" {
wait_until_bound = false
metadata {
name = "uptime-kuma-data-proxmox"
namespace = kubernetes_namespace.uptime-kuma.metadata[0].name
annotations = {
"resize.topolvm.io/threshold" = "80%"
"resize.topolvm.io/increase" = "50%"
"resize.topolvm.io/storage_limit" = "20Gi"
}
}
spec {
access_modes = ["ReadWriteOnce"]
storage_class_name = "proxmox-lvm"
resources {
requests = {
storage = "5Gi"
}
}
}
}
resource "kubernetes_deployment" "uptime-kuma" { resource "kubernetes_deployment" "uptime-kuma" {
metadata { metadata {
name = "uptime-kuma" name = "uptime-kuma"
@ -106,7 +128,7 @@ resource "kubernetes_deployment" "uptime-kuma" {
volume { volume {
name = "data" name = "data"
persistent_volume_claim { persistent_volume_claim {
claim_name = module.nfs_data.claim_name claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
} }
} }
dns_config { dns_config {

View file

@ -60,6 +60,28 @@ module "nfs_data" {
nfs_path = "/mnt/main/wealthfolio" nfs_path = "/mnt/main/wealthfolio"
} }
resource "kubernetes_persistent_volume_claim" "data_proxmox" {
wait_until_bound = false
metadata {
name = "wealthfolio-data-proxmox"
namespace = kubernetes_namespace.wealthfolio.metadata[0].name
annotations = {
"resize.topolvm.io/threshold" = "80%"
"resize.topolvm.io/increase" = "100%"
"resize.topolvm.io/storage_limit" = "5Gi"
}
}
spec {
access_modes = ["ReadWriteOnce"]
storage_class_name = "proxmox-lvm"
resources {
requests = {
storage = "1Gi"
}
}
}
}
resource "kubernetes_deployment" "wealthfolio" { resource "kubernetes_deployment" "wealthfolio" {
lifecycle { lifecycle {
ignore_changes = [spec[0].template[0].spec[0].dns_config] ignore_changes = [spec[0].template[0].spec[0].dns_config]
@ -77,6 +99,9 @@ resource "kubernetes_deployment" "wealthfolio" {
} }
spec { spec {
replicas = 1 replicas = 1
strategy {
type = "Recreate"
}
selector { selector {
match_labels = { match_labels = {
app = "wealthfolio" app = "wealthfolio"
@ -141,7 +166,7 @@ resource "kubernetes_deployment" "wealthfolio" {
volume { volume {
name = "data" name = "data"
persistent_volume_claim { persistent_volume_claim {
claim_name = module.nfs_data.claim_name claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
} }
} }
} }
@ -276,7 +301,7 @@ resource "kubernetes_cron_job_v1" "wealthfolio_sync" {
volume { volume {
name = "data" name = "data"
persistent_volume_claim { persistent_volume_claim {
claim_name = module.nfs_data.claim_name claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
} }
} }
} }