[ci skip] Move Terraform modules into stack directories

Move all 88 service modules (66 individual + 22 platform) from
modules/kubernetes/<service>/ into their corresponding stack directories:

- Service stacks: stacks/<service>/module/
- Platform stack: stacks/platform/modules/<service>/

This collocates module source code with its Terragrunt definition.
Only shared utility modules remain in modules/kubernetes/:
ingress_factory, setup_tls_secret, dockerhub_secret, oauth-proxy.

All cross-references to shared modules updated to use correct
relative paths. Verified with terragrunt run --all -- plan:
0 adds, 0 destroys across all 68 stacks.
This commit is contained in:
Viktor Barzin 2026-02-22 14:38:14 +00:00
parent 73cb696f12
commit e225e81ebf
No known key found for this signature in database
GPG key ID: 0EB088298288D958
614 changed files with 12075 additions and 352 deletions

View file

@ -0,0 +1,103 @@
variable "tls_secret_name" {}
variable "tier" { type = string }
variable "aiostreams_database_connection_string" { type = string }
resource "kubernetes_namespace" "aiostreams" {
metadata {
name = "aiostreams"
labels = {
"istio-injection" : "disabled"
}
}
}
resource "random_id" "secret_key" {
byte_length = 32 # 32 bytes × 2 hex chars = 64 hex characters
}
resource "kubernetes_deployment" "aiostreams" {
metadata {
name = "aiostreams"
namespace = kubernetes_namespace.aiostreams.metadata[0].name
labels = {
app = "aiostreams"
tier = var.tier
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "aiostreams"
}
}
template {
metadata {
labels = {
app = "aiostreams"
}
}
spec {
container {
image = "viren070/aiostreams:nightly"
name = "aiostreams"
port {
container_port = 3000
}
env {
name = "BASE_URL"
value = "https://aiostreams.viktorbarzin.me"
}
env {
name = "SECRET_KEY"
value = random_id.secret_key.hex
}
env {
name = "DATABASE_URI"
value = var.aiostreams_database_connection_string
}
volume_mount {
name = "data"
mount_path = "/app/data"
}
}
volume {
name = "data"
nfs {
server = "10.0.10.15"
path = "/mnt/main/servarr/aiostreams"
}
}
}
}
}
}
resource "kubernetes_service" "aiostreams" {
metadata {
name = "aiostreams"
namespace = kubernetes_namespace.aiostreams.metadata[0].name
labels = {
"app" = "aiostreams"
}
}
spec {
selector = {
app = "aiostreams"
}
port {
name = "http"
port = 80
target_port = 3000
}
}
}
module "ingress" {
source = "../../../../modules/kubernetes/ingress_factory"
namespace = kubernetes_namespace.aiostreams.metadata[0].name
name = "aiostreams"
tls_secret_name = var.tls_secret_name
# protected = true
}

View file

@ -0,0 +1,74 @@
variable "tls_secret_name" {}
variable "tier" { type = string }
resource "kubernetes_deployment" "flaresolverr" {
metadata {
name = "flaresolverr"
namespace = "servarr"
labels = {
app = "flaresolverr"
tier = var.tier
}
annotations = {
"reloader.stakater.com/search" = "true"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "flaresolverr"
}
}
template {
metadata {
labels = {
app = "flaresolverr"
}
}
spec {
container {
image = "ghcr.io/flaresolverr/flaresolverr:latest"
name = "flaresolverr"
port {
container_port = 8191
}
}
}
}
}
}
resource "kubernetes_service" "flaresolverr" {
metadata {
name = "flaresolverr"
namespace = "servarr"
labels = {
app = "flaresolverr"
}
}
spec {
selector = {
app = "flaresolverr"
}
port {
name = "http"
target_port = 8191
port = 80
}
}
}
module "ingress" {
source = "../../../../modules/kubernetes/ingress_factory"
namespace = "servarr"
name = "flaresolverr"
tls_secret_name = var.tls_secret_name
protected = true
# extra_annotations = {
# "nginx.ingress.kubernetes.io/proxy-body-size" : "1G" // allow uploading .torrent files
# }
}

View file

@ -0,0 +1,163 @@
variable "tls_secret_name" {}
variable "tier" { type = string }
resource "kubernetes_deployment" "lidarr" {
metadata {
name = "lidarr"
namespace = "servarr"
labels = {
app = "lidarr"
tier = var.tier
}
annotations = {
"reloader.stakater.com/search" = "true"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "lidarr"
}
}
template {
metadata {
labels = {
app = "lidarr"
}
}
spec {
container {
image = "lscr.io/linuxserver/lidarr:latest"
# image = "youegraillot/lidarr-on-steroids"
name = "lidarr"
port {
name = "lidarr"
container_port = 8686
}
port {
name = "deemix"
container_port = 6595
}
env {
name = "PUID"
value = 1000
}
env {
name = "PGID"
value = 1000
}
env {
name = "TZ"
value = "Etc/UTC"
}
volume_mount {
name = "data"
mount_path = "/config"
}
volume_mount {
name = "downloads"
mount_path = "/downloads"
}
volume_mount {
name = "data"
mount_path = "/music"
sub_path = "music"
}
volume_mount {
name = "deemix-config"
mount_path = "/config_deemix"
sub_path = "deemix"
}
}
volume {
name = "data"
nfs {
path = "/mnt/main/servarr/lidarr"
server = "10.0.10.15"
}
}
volume {
name = "downloads"
nfs {
path = "/mnt/main/servarr/downloads"
server = "10.0.10.15"
}
}
volume {
name = "deemix-config"
nfs {
path = "/mnt/main/servarr/lidarr"
server = "10.0.10.15"
}
}
}
}
}
}
resource "kubernetes_service" "lidarr" {
metadata {
name = "lidarr"
namespace = "servarr"
labels = {
app = "lidarr"
}
}
spec {
selector = {
app = "lidarr"
}
port {
name = "http"
port = 80
target_port = 8686
}
}
}
resource "kubernetes_service" "deemix" {
metadata {
name = "deemix"
namespace = "servarr"
labels = {
app = "deemix"
}
}
spec {
selector = {
app = "lidarr"
}
port {
name = "deemix"
port = 80
target_port = 6595
}
}
}
module "ingress" {
source = "../../../../modules/kubernetes/ingress_factory"
namespace = "servarr"
name = "lidarr"
tls_secret_name = var.tls_secret_name
protected = true
# extra_annotations = {
# "nginx.ingress.kubernetes.io/proxy-body-size" : "1G" // allow uploading .torrent files
# }
}
module "ingress-deemix" {
source = "../../../../modules/kubernetes/ingress_factory"
namespace = "servarr"
name = "deemix"
tls_secret_name = var.tls_secret_name
protected = true
}

View file

@ -0,0 +1,90 @@
variable "tls_secret_name" {}
variable "tier" { type = string }
resource "kubernetes_deployment" "listenarr" {
metadata {
name = "listenarr"
namespace = "servarr"
labels = {
app = "listenarr"
tier = var.tier
}
annotations = {
"reloader.stakater.com/search" = "true"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "listenarr"
}
}
template {
metadata {
labels = {
app = "listenarr"
}
}
spec {
container {
image = "ghcr.io/therobbiedavis/listenarr:canary"
name = "listenarr"
port {
container_port = 5000
}
volume_mount {
name = "data"
mount_path = "/app/config"
}
}
volume {
name = "data"
nfs {
path = "/mnt/main/servarr/listenarr"
server = "10.0.10.15"
}
}
volume {
name = "downloads"
nfs {
path = "/mnt/main/servarr/downloads"
server = "10.0.10.15"
}
}
}
}
}
}
resource "kubernetes_service" "listenarr" {
metadata {
name = "listenarr"
namespace = "servarr"
labels = {
app = "listenarr"
}
}
spec {
selector = {
app = "listenarr"
}
port {
name = "http"
port = 80
target_port = 5000
}
}
}
module "ingress" {
source = "../../../../modules/kubernetes/ingress_factory"
namespace = "servarr"
name = "listenarr"
tls_secret_name = var.tls_secret_name
protected = true
}

View file

@ -0,0 +1,68 @@
variable "tls_secret_name" {}
variable "tier" { type = string }
variable "aiostreams_database_connection_string" { type = string }
resource "kubernetes_namespace" "servarr" {
metadata {
name = "servarr"
labels = {
tier = var.tier
}
}
}
module "tls_secret" {
source = "../../../modules/kubernetes/setup_tls_secret"
namespace = kubernetes_namespace.servarr.metadata[0].name
tls_secret_name = var.tls_secret_name
}
# module "readarr" {
# source = "./readarr"
# tls_secret_name = var.tls_secret_name
# tier = var.tier
# }
module "prowlarr" {
source = "./prowlarr"
tls_secret_name = var.tls_secret_name
tier = var.tier
}
module "qbittorrent" {
source = "./qbittorrent"
tls_secret_name = var.tls_secret_name
tier = var.tier
}
module "flaresolverr" {
source = "./flaresolverr"
tls_secret_name = var.tls_secret_name
tier = var.tier
}
# module "lidarr" {
# source = "./lidarr"
# tls_secret_name = var.tls_secret_name
# tier = var.tier
# }
# module "soulseek" {
# source = "./soulseek"
# tls_secret_name = var.tls_secret_name
# tier = var.tier
# }
module "listenarr" {
source = "./listenarr"
tls_secret_name = var.tls_secret_name
tier = var.tier
}
module "aiostreams" {
source = "./aiostreams"
tls_secret_name = var.tls_secret_name
aiostreams_database_connection_string = var.aiostreams_database_connection_string
tier = var.tier
}

View file

@ -0,0 +1,110 @@
variable "tls_secret_name" {}
variable "tier" { type = string }
resource "kubernetes_deployment" "prowlarr" {
metadata {
name = "prowlarr"
namespace = "servarr"
labels = {
app = "prowlarr"
tier = var.tier
}
annotations = {
"reloader.stakater.com/search" = "true"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "prowlarr"
}
}
template {
metadata {
labels = {
app = "prowlarr"
}
}
spec {
container {
image = "lscr.io/linuxserver/prowlarr:latest"
name = "prowlarr"
port {
container_port = 9696
}
env {
name = "PUID"
value = 1000
}
env {
name = "PGID"
value = 1000
}
env {
name = "TZ"
value = "Etc/UTC"
}
volume_mount {
name = "data"
mount_path = "/config"
}
volume_mount {
name = "data"
mount_path = "/books"
}
volume_mount {
name = "downloads"
mount_path = "/downloads"
}
}
volume {
name = "data"
nfs {
path = "/mnt/main/servarr/prowlarr"
server = "10.0.10.15"
}
}
volume {
name = "downloads"
nfs {
path = "/mnt/main/servarr/downloads"
server = "10.0.10.15"
}
}
}
}
}
}
resource "kubernetes_service" "prowlarr" {
metadata {
name = "prowlarr"
namespace = "servarr"
labels = {
app = "prowlarr"
}
}
spec {
selector = {
app = "prowlarr"
}
port {
name = "http"
port = 80
target_port = 9696
}
}
}
module "ingress" {
source = "../../../../modules/kubernetes/ingress_factory"
namespace = "servarr"
name = "prowlarr"
tls_secret_name = var.tls_secret_name
protected = true
}

View file

@ -0,0 +1,143 @@
variable "tls_secret_name" {}
variable "tier" { type = string }
resource "kubernetes_deployment" "qbittorrent" {
metadata {
name = "qbittorrent"
namespace = "servarr"
labels = {
app = "qbittorrent"
tier = var.tier
}
annotations = {
"reloader.stakater.com/search" = "true"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "qbittorrent"
}
}
template {
metadata {
labels = {
app = "qbittorrent"
}
}
spec {
container {
image = "lscr.io/linuxserver/qbittorrent:latest"
name = "qbittorrent"
port {
container_port = 8787
}
env {
name = "PUID"
value = 1000
}
env {
name = "PGID"
value = 1000
}
env {
name = "WEBUI_PORT"
value = 8080
}
env {
name = "TORRENTING_PORT"
value = 6881
}
volume_mount {
name = "data"
mount_path = "/config"
}
volume_mount {
name = "downloads"
mount_path = "/downloads"
}
}
volume {
name = "data"
nfs {
path = "/mnt/main/servarr/qbittorrent"
server = "10.0.10.15"
}
}
volume {
name = "downloads"
nfs {
path = "/mnt/main/servarr/downloads"
server = "10.0.10.15"
}
}
}
}
}
}
resource "kubernetes_service" "qbittorrent" {
metadata {
name = "qbittorrent"
namespace = "servarr"
labels = {
app = "qbittorrent"
}
}
spec {
selector = {
app = "qbittorrent"
}
port {
name = "http"
port = 80
target_port = 8080
}
}
}
resource "kubernetes_service" "qbittorrent-torrenting" {
metadata {
name = "qbittorrent-torrenting"
namespace = "servarr"
labels = {
app = "qbittorrent-torrenting"
}
annotations = {
"metallb.universe.tf/allow-shared-ip" = "shared"
}
}
spec {
type = "LoadBalancer"
external_traffic_policy = "Cluster"
selector = {
app = "qbittorrent"
}
port {
name = "torrenting"
port = 6881
target_port = 6881
}
port {
name = "torrenting-udp"
port = 6881
protocol = "UDP"
target_port = 6881
}
}
}
module "ingress" {
source = "../../../../modules/kubernetes/ingress_factory"
namespace = "servarr"
name = "qbittorrent"
tls_secret_name = var.tls_secret_name
protected = true
}

View file

@ -0,0 +1,128 @@
variable "tls_secret_name" {}
variable "tier" { type = string }
resource "kubernetes_namespace" "readarr" {
metadata {
name = "readarr"
# labels = {
# "istio-injection" : "enabled"
# }
}
}
module "tls_secret" {
source = "../../../../modules/kubernetes/setup_tls_secret"
namespace = "readarr"
tls_secret_name = var.tls_secret_name
}
resource "kubernetes_deployment" "readarr" {
metadata {
name = "readarr"
namespace = "readarr"
labels = {
app = "readarr"
tier = var.tier
}
annotations = {
"reloader.stakater.com/search" = "true"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "readarr"
}
}
template {
metadata {
labels = {
app = "readarr"
}
}
spec {
container {
image = "lscr.io/linuxserver/readarr:develop"
name = "readarr"
port {
container_port = 8787
}
env {
name = "PUID"
value = 1000
}
env {
name = "PGID"
value = 1000
}
env {
name = "TZ"
value = "Etc/UTC"
}
volume_mount {
name = "data"
mount_path = "/config"
}
volume_mount {
name = "data"
mount_path = "/books"
}
volume_mount {
name = "data"
mount_path = "/downloads"
}
volume_mount {
name = "qbittorrent"
mount_path = "/mnt"
read_only = true
}
}
volume {
name = "data"
nfs {
path = "/mnt/main/servarr/readarr"
server = "10.0.10.15"
}
}
volume {
name = "qbittorrent"
nfs {
path = "/mnt/main/servarr/qbittorrent"
server = "10.0.10.15"
}
}
}
}
}
}
resource "kubernetes_service" "readarr" {
metadata {
name = "readarr"
namespace = "readarr"
labels = {
app = "readarr"
}
}
spec {
selector = {
app = "readarr"
}
port {
name = "http"
port = 8787
}
}
}
module "ingress" {
source = "../../../../modules/kubernetes/ingress_factory"
namespace = "readarr"
name = "readarr"
port = 8787
tls_secret_name = var.tls_secret_name
protected = true
}

View file

@ -0,0 +1,105 @@
variable "tls_secret_name" {}
variable "tier" { type = string }
resource "kubernetes_deployment" "soulseek" {
metadata {
name = "soulseek"
namespace = "servarr"
labels = {
app = "soulseek"
tier = var.tier
}
annotations = {
"reloader.stakater.com/search" = "true"
}
}
spec {
replicas = 1
selector {
match_labels = {
app = "soulseek"
}
}
template {
metadata {
labels = {
app = "soulseek"
}
}
spec {
container {
image = "realies/soulseek"
name = "soulseek"
port {
name = "soulseek"
container_port = 6080
}
env {
name = "PUID"
value = 1000
}
env {
name = "PGID"
value = 1000
}
volume_mount {
name = "config"
mount_path = "/data/.SoulseekQt"
sub_path = "soulseek/config"
}
volume_mount {
name = "downloads"
mount_path = "/data/Soulseek Downloads"
sub_path = "soulseek/downloads"
}
}
volume {
name = "config"
nfs {
path = "/mnt/main/servarr/lidarr"
server = "10.0.10.15"
}
}
volume {
name = "downloads"
nfs {
path = "/mnt/main/servarr/lidarr"
server = "10.0.10.15"
}
}
}
}
}
}
resource "kubernetes_service" "soulseek" {
metadata {
name = "soulseek"
namespace = "servarr"
labels = {
app = "soulseek"
}
}
spec {
selector = {
app = "soulseek"
}
port {
name = "http"
port = 80
target_port = 6080
}
}
}
module "ingress" {
source = "../../../../modules/kubernetes/ingress_factory"
namespace = "servarr"
name = "soulseek"
tls_secret_name = var.tls_secret_name
protected = true
}