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}"
}
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" {
metadata {
name = "actualbudget-${var.name}"
@ -81,7 +103,7 @@ resource "kubernetes_deployment" "actualbudget" {
volume {
name = "data"
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"
}
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" {
source = "../../modules/kubernetes/nfs_volume"
name = "ebooks-abs-metadata"
@ -589,7 +611,7 @@ resource "kubernetes_deployment" "audiobookshelf" {
volume {
name = "config"
persistent_volume_claim {
claim_name = module.nfs_audiobookshelf_config.claim_name
claim_name = kubernetes_persistent_volume_claim.abs_config_proxmox.metadata[0].name
}
}
volume {

View file

@ -28,6 +28,28 @@ module "nfs_data" {
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" {
metadata {
name = "forgejo"
@ -40,7 +62,7 @@ resource "kubernetes_deployment" "forgejo" {
spec {
replicas = 1
strategy {
type = "RollingUpdate" # DB is external so we can roll
type = "Recreate"
}
selector {
match_labels = {
@ -110,7 +132,7 @@ resource "kubernetes_deployment" "forgejo" {
volume {
name = "data"
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"
}
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" {
source = "../../modules/kubernetes/nfs_volume"
name = "freshrss-extensions"
@ -144,7 +166,7 @@ resource "kubernetes_deployment" "freshrss" {
volume {
name = "data"
persistent_volume_claim {
claim_name = module.nfs_data.claim_name
claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
}
}
volume {

View file

@ -44,6 +44,28 @@ module "nfs_data" {
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" {
metadata {
name = "headscale"
@ -164,7 +186,7 @@ resource "kubernetes_deployment" "headscale" {
volume {
name = "nfs-config"
persistent_volume_claim {
claim_name = module.nfs_data.claim_name
claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
}
}
# container {
@ -414,7 +436,7 @@ resource "kubernetes_cron_job_v1" "headscale_backup" {
volume {
name = "nfs-data"
persistent_volume_claim {
claim_name = module.nfs_data.claim_name
claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
}
}
restart_policy = "OnFailure"

View file

@ -49,6 +49,28 @@ module "nfs_data" {
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" {
metadata {
name = "insta2spotify"
@ -63,6 +85,9 @@ resource "kubernetes_deployment" "insta2spotify" {
}
spec {
replicas = 1
strategy {
type = "Recreate"
}
selector {
match_labels = {
app = "insta2spotify"
@ -174,7 +199,7 @@ resource "kubernetes_deployment" "insta2spotify" {
volume {
name = "data"
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"
}
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" {
source = "../../modules/kubernetes/nfs_volume"
name = "navidrome-music"
@ -82,6 +104,14 @@ module "nfs_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" {
metadata {
name = "navidrome"
@ -125,6 +155,15 @@ resource "kubernetes_deployment" "navidrome" {
mount_path = "/lidarr"
read_only = true
}
volume_mount {
name = "freedify"
mount_path = "/freedify-music"
read_only = true
}
env {
name = "ND_SCANSCHEDULE"
value = "0"
}
port {
name = "http"
container_port = 4533
@ -143,7 +182,7 @@ resource "kubernetes_deployment" "navidrome" {
volume {
name = "data"
persistent_volume_claim {
claim_name = module.nfs_data.claim_name
claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
}
}
volume {
@ -158,6 +197,12 @@ resource "kubernetes_deployment" "navidrome" {
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"
}
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" {
metadata {
name = "ntfy"
@ -43,7 +65,7 @@ resource "kubernetes_deployment" "ntfy" {
spec {
replicas = 1
strategy {
type = "RollingUpdate"
type = "Recreate"
}
selector {
match_labels = {
@ -131,7 +153,7 @@ resource "kubernetes_deployment" "ntfy" {
volume {
name = "data"
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"
}
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" {
metadata {
name = "uptime-kuma"
@ -106,7 +128,7 @@ resource "kubernetes_deployment" "uptime-kuma" {
volume {
name = "data"
persistent_volume_claim {
claim_name = module.nfs_data.claim_name
claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
}
}
dns_config {

View file

@ -60,6 +60,28 @@ module "nfs_data" {
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" {
lifecycle {
ignore_changes = [spec[0].template[0].spec[0].dns_config]
@ -77,6 +99,9 @@ resource "kubernetes_deployment" "wealthfolio" {
}
spec {
replicas = 1
strategy {
type = "Recreate"
}
selector {
match_labels = {
app = "wealthfolio"
@ -141,7 +166,7 @@ resource "kubernetes_deployment" "wealthfolio" {
volume {
name = "data"
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 {
name = "data"
persistent_volume_claim {
claim_name = module.nfs_data.claim_name
claim_name = kubernetes_persistent_volume_claim.data_proxmox.metadata[0].name
}
}
}