diff --git a/main.tf b/main.tf index 5680b3f2..0f826048 100644 --- a/main.tf +++ b/main.tf @@ -133,7 +133,8 @@ variable "clickhouse_postgres_password" { type = string } variable "wealthfolio_password_hash" { type = string } variable "aiostreams_database_connection_string" { type = string } variable "actualbudget_credentials" { type = map(any) } - +variable "speedtest_db_password" { type = string } +variable "freedify_credentials" { type = map(any) } provider "kubernetes" { config_path = var.prod ? "" : "~/.kube/config" @@ -182,12 +183,13 @@ module "k8s-node-template" { snippet_name = local.k8s_cloud_init_snippet_name # Add mirror registry containerd_config_update_command = <<-EOF - echo '[plugins.\"io.containerd.grpc.v1.cri\".registry.mirrors.\"docker.io\"]' >> /etc/containerd/config.toml && echo ' endpoint = [\"http://10.0.20.10:5000\"]' >> /etc/containerd/config.toml # docker registry vm + # BELOW IS DEPRECATED - replace with config_path version!!!! + echo '[plugins.\"io.containerd.grpc.v1.cri\".registry.mirrors.\"*\"]' >> /etc/containerd/config.toml && echo ' endpoint = [\"http://10.0.20.10:5000\"]' >> /etc/containerd/config.toml # docker registry vm sed -i 's/.*max_concurrent_downloads = 3/max_concurrent_downloads = 20/g' /etc/containerd/config.toml # Enable multiple concurrent downloads sudo sed -i '/serializeImagePulls:/d' /var/lib/kubelet/config.yaml && \ sudo sed -i '/maxParallelImagePulls:/d' /var/lib/kubelet/config.yaml && \ - echo -e 'serializeImagePulls: false\nmaxParallelImagePulls: 50' | sudo tee -a /var/lib/kubelet/config.yaml && \ + echo -e 'serializeImagePulls: false\nmaxParallelImagePulls: 50' | sudo tee -a /var/lib/kubelet/config.yaml EOF k8s_join_command = var.k8s_join_command } @@ -556,6 +558,9 @@ module "kubernetes_cluster" { aiostreams_database_connection_string = var.aiostreams_database_connection_string actualbudget_credentials = var.actualbudget_credentials + + speedtest_db_password = var.speedtest_db_password + freedify_credentials = var.freedify_credentials } diff --git a/modules/kubernetes/actualbudget/main.tf b/modules/kubernetes/actualbudget/main.tf index 0226f1ba..f8aaf52d 100644 --- a/modules/kubernetes/actualbudget/main.tf +++ b/modules/kubernetes/actualbudget/main.tf @@ -48,3 +48,15 @@ module "anca" { budget_encryption_password = lookup(var.credentials["anca"], "password", null) sync_id = lookup(var.credentials["anca"], "sync_id", null) } + +# https://budget-emo.viktorbarzin.me/ +module "emo" { + source = "./factory" + name = "emo" + tag = "edge" + tls_secret_name = var.tls_secret_name + depends_on = [kubernetes_namespace.actualbudget] + tier = var.tier + budget_encryption_password = lookup(var.credentials["emo"], "password", null) + sync_id = lookup(var.credentials["emo"], "sync_id", null) +} diff --git a/modules/kubernetes/authentik/pgbouncer.tf b/modules/kubernetes/authentik/pgbouncer.tf index d6d24a8b..ac027e76 100644 --- a/modules/kubernetes/authentik/pgbouncer.tf +++ b/modules/kubernetes/authentik/pgbouncer.tf @@ -35,7 +35,7 @@ resource "kubernetes_deployment" "pgbouncer" { } spec { - replicas = 1 + replicas = 3 selector { match_labels = { @@ -51,6 +51,20 @@ resource "kubernetes_deployment" "pgbouncer" { } spec { + affinity { + pod_anti_affinity { + required_during_scheduling_ignored_during_execution { + label_selector { + match_expressions { + key = "component" + operator = "In" + values = ["server"] + } + } + topology_key = "kubernetes.io/hostname" + } + } + } container { name = "pgbouncer" image = "edoburu/pgbouncer:latest" diff --git a/modules/kubernetes/freedify/factory/main.tf b/modules/kubernetes/freedify/factory/main.tf new file mode 100755 index 00000000..a25a9272 --- /dev/null +++ b/modules/kubernetes/freedify/factory/main.tf @@ -0,0 +1,149 @@ +variable "tls_secret_name" {} +variable "name" {} +variable "tag" { + default = "latest" +} +variable "tier" { type = string } +variable "protected" { + type = bool + default = false +} +variable "listenbrainz_token" { + type = string + default = null +} +variable "genius_token" { + type = string + default = null +} +variable "dab_visitor_id" { + type = string + default = null +} +variable "dab_session" { + type = string + default = null +} +variable "gemini_api_key" { + type = string + default = null +} +variable "cpu_limit" { + type = string + default = "500m" +} +variable "memory_limit" { + type = string + default = "512Mi" +} +variable "cpu_request" { + type = string + default = "100m" +} +variable "memory_request" { + type = string + default = "256Mi" +} + + +resource "kubernetes_deployment" "freedify" { + metadata { + name = "music-${var.name}" + namespace = "freedify" + labels = { + app = "music-${var.name}" + tier = var.tier + } + } + spec { + replicas = 1 + strategy { + type = "RollingUpdate" + } + selector { + match_labels = { + app = "music-${var.name}" + } + } + template { + metadata { + annotations = { + "diun.enable" = "true" + "diun.include_tags" = "^${var.tag}$" + } + labels = { + app = "music-${var.name}" + } + } + spec { + container { + image = "viktorbarzin/freedify:${var.tag}" + name = "freedify" + + port { + container_port = 8000 + } + env { + name = "LISTENBRAINZ_TOKEN" + value = var.listenbrainz_token + } + env { + name = "GENIUS_ACCESS_TOKEN" + value = var.genius_token + } + env { + name = "DAB_SESSION" + value = var.dab_session + } + env { + name = "DAB_VISITOR_ID" + value = var.dab_visitor_id + } + env { + name = "GEMINI_API_KEY" + value = var.gemini_api_key + } + resources { + limits = { + cpu = var.cpu_limit + memory = var.memory_limit + } + requests = { + cpu = var.cpu_request + memory = var.memory_request + } + } + } + } + } + } +} + +resource "kubernetes_service" "freedify" { + metadata { + name = "music-${var.name}" + namespace = "freedify" + labels = { + app = "music-${var.name}" + } + } + + spec { + selector = { + app = "music-${var.name}" + } + port { + name = "http" + port = 80 + target_port = 8000 + } + } +} + +module "ingress" { + source = "../../ingress_factory" + namespace = "freedify" + name = "music-${var.name}" + tls_secret_name = var.tls_secret_name + protected = var.protected +} diff --git a/modules/kubernetes/freedify/main.tf b/modules/kubernetes/freedify/main.tf new file mode 100755 index 00000000..ec5bed0f --- /dev/null +++ b/modules/kubernetes/freedify/main.tf @@ -0,0 +1,54 @@ +variable "tls_secret_name" {} +variable "tier" { type = string } +variable "additional_credentials" { type = map(any) } + +# To create a new deployment: +/** + 1. Export a new nfs share with {name} in truenas at /mnt/main/freedify/{name} + 2. Add {name} as proxied cloudflare route (tfvars) + 3. Add module here +*/ + +resource "kubernetes_namespace" "freedify" { + metadata { + name = "freedify" + labels = { + "istio-injection" : "disabled" + } + } +} + +module "tls_secret" { + source = "../setup_tls_secret" + namespace = kubernetes_namespace.freedify.metadata[0].name + tls_secret_name = var.tls_secret_name +} + +# https://music-viktor.viktorbarzin.me/ +module "viktor" { + source = "./factory" + name = "viktor" + tag = "latest" + tls_secret_name = var.tls_secret_name + depends_on = [kubernetes_namespace.freedify] + tier = var.tier + protected = true + listenbrainz_token = lookup(var.additional_credentials["viktor"], "listenbrainz_token", null) + genius_token = lookup(var.additional_credentials["viktor"], "genius_token", null) + dab_session = lookup(var.additional_credentials["viktor"], "dab_session", null) + dab_visitor_id = lookup(var.additional_credentials["viktor"], "dab_visitor_id", null) + gemini_api_key = lookup(var.additional_credentials["viktor"], "gemini_api_key", null) +} + +# https://music-emo.viktorbarzin.me/ +module "emo" { + source = "./factory" + name = "emo" + tag = "latest" + tls_secret_name = var.tls_secret_name + depends_on = [kubernetes_namespace.freedify] + tier = var.tier + protected = true + genius_token = lookup(var.additional_credentials["emo"], "genius_token", null) + gemini_api_key = lookup(var.additional_credentials["emo"], "gemini_api_key", null) +} diff --git a/modules/kubernetes/keyserver/deploy_keyserver.yaml b/modules/kubernetes/keyserver/deploy_keyserver.yaml index 2a5b5291..362c0954 100644 --- a/modules/kubernetes/keyserver/deploy_keyserver.yaml +++ b/modules/kubernetes/keyserver/deploy_keyserver.yaml @@ -7,7 +7,7 @@ server_name: "keyserver.viktorbarzin.me" key_filename: "truenas.key" htpasswd_user: "truenas" - htpasswd_password: "3RgTvqHWeiae7drCUBGyj6XZSIP" # replace with vault + htpasswd_password: "" # replace with vault ssl_cert_path: "/etc/ssl/certs/keyserver.crt" ssl_key_path: "/etc/ssl/private/keyserver.key" local_ssl_cert: "../../../secrets/fullchain.pem" # LOCAL path diff --git a/modules/kubernetes/main.tf b/modules/kubernetes/main.tf index 21105323..1dcbd6a6 100644 --- a/modules/kubernetes/main.tf +++ b/modules/kubernetes/main.tf @@ -112,6 +112,8 @@ variable "clickhouse_postgres_password" { type = string } variable "wealthfolio_password_hash" { type = string } variable "aiostreams_database_connection_string" { type = string } variable "actualbudget_credentials" { type = map(any) } +variable "speedtest_db_password" { type = string } +variable "freedify_credentials" { type = map(any) } variable "defcon_level" { @@ -137,7 +139,7 @@ locals { "url", "excalidraw", "travel_blog", "dashy", "send", "ytdlp", "wealthfolio", "rybbit", "stirling-pdf", "networking-toolbox", "navidrome", "freshrss", "forgejo", "tor-proxy", "real-estate-crawler", "n8n", "changedetection", "linkwarden", "matrix", "homepage", "meshcentral", "diun", "cyberchef", "ntfy", "ollama", - "servarr", "jsoncrack", "paperless-ngx", "frigate", "audiobookshelf", "tandoor", "ebook2audiobook", "netbox" + "servarr", "jsoncrack", "paperless-ngx", "frigate", "audiobookshelf", "tandoor", "ebook2audiobook", "netbox", "speedtest", "resume", "freedify" ], } active_modules = distinct(flatten([ @@ -187,7 +189,7 @@ module "dbaas" { dbaas_root_password = var.dbaas_root_password postgresql_root_password = var.dbaas_postgresql_root_password pgadmin_password = var.dbaas_pgadmin_password - tier = local.tiers.core + tier = local.tiers.cluster } module "descheduler" { @@ -406,7 +408,7 @@ module "wireguard" { wg_0_conf = var.wireguard_wg_0_conf wg_0_key = var.wireguard_wg_0_key firewall_sh = var.wireguard_firewall_sh - tier = local.tiers.cluster + tier = local.tiers.core depends_on = [null_resource.core_services] } @@ -517,7 +519,7 @@ module "redis" { source = "./redis" for_each = contains(local.active_modules, "redis") ? { redis = true } : {} tls_secret_name = var.tls_secret_name - tier = local.tiers.core + tier = local.tiers.cluster } module "ytdlp" { @@ -553,7 +555,7 @@ module "nginx-ingress" { module "crowdsec" { source = "./crowdsec" - tier = local.tiers.core + tier = local.tiers.cluster for_each = contains(local.active_modules, "crowdsec") ? { crowdsec = true } : {} tls_secret_name = var.tls_secret_name homepage_username = var.homepage_credentials["crowdsec"]["username"] @@ -568,6 +570,8 @@ module "crowdsec" { # Seems like it needs S3 even if pg is local... # module "resume" { # source = "./resume" +# tier = local.tiers.aux +# for_each = contains(local.active_modules, "resume") ? { resume = true } : {} # tls_secret_name = var.tls_secret_name # redis_url = var.resume_redis_url # database_url = var.resume_database_url @@ -786,7 +790,7 @@ module "matrix" { module "authentik" { source = "./authentik" - tier = local.tiers.core + tier = local.tiers.cluster for_each = contains(local.active_modules, "authentik") ? { authentik = true } : {} tls_secret_name = var.tls_secret_name secret_key = var.authentik_secret_key @@ -916,7 +920,7 @@ module "xray" { source = "./xray" for_each = contains(local.active_modules, "xray") ? { xray = true } : {} tls_secret_name = var.tls_secret_name - tier = local.tiers.aux + tier = local.tiers.core xray_reality_clients = var.xray_reality_clients xray_reality_private_key = var.xray_reality_private_key @@ -1024,3 +1028,20 @@ module "kyverno" { for_each = contains(local.active_modules, "kyverno") ? { kyverno = true } : {} depends_on = [null_resource.core_services] } + +module "speedtest" { + source = "./speedtest" + tls_secret_name = var.tls_secret_name + tier = local.tiers.aux + for_each = contains(local.active_modules, "speedtest") ? { speedtest = true } : {} + depends_on = [null_resource.core_services] + db_password = var.speedtest_db_password +} + +module "freedify" { + source = "./freedify" + tls_secret_name = var.tls_secret_name + tier = local.tiers.aux + for_each = contains(local.active_modules, "freedify") ? { freedify = true } : {} + additional_credentials = var.freedify_credentials +} diff --git a/modules/kubernetes/monitoring/grafana_chart_values.yaml b/modules/kubernetes/monitoring/grafana_chart_values.yaml index 812ba4e9..1560bb12 100644 --- a/modules/kubernetes/monitoring/grafana_chart_values.yaml +++ b/modules/kubernetes/monitoring/grafana_chart_values.yaml @@ -1,5 +1,6 @@ deploymentStrategy: - type: Recreate + type: RollingUpdate +replicas: 3 persistence: enabled: false # using external mysql existingClaim: "grafana-pvc" diff --git a/modules/kubernetes/nextcloud/chart_values.yaml b/modules/kubernetes/nextcloud/chart_values.yaml index 46f2b1bc..861eaf1a 100644 --- a/modules/kubernetes/nextcloud/chart_values.yaml +++ b/modules/kubernetes/nextcloud/chart_values.yaml @@ -23,10 +23,18 @@ nextcloud: # - name: loglevel # value: "0" -externalDatabase: +# internalDatabase: +# enabled: false + +externalRedis: enabled: true + host: redis.redis.svc.cluster.local + +# Currently not in use; we use the nextcloud.db sqlite3 +externalDatabase: + enabled: false type: mysql - host: mysql.dbaas + host: mysql.dbaas.svc.cluster.local user: nextcloud password: ${db_password} databse: nextcloud diff --git a/modules/kubernetes/nextcloud/main.tf b/modules/kubernetes/nextcloud/main.tf index b76bb7bd..f86319bb 100644 --- a/modules/kubernetes/nextcloud/main.tf +++ b/modules/kubernetes/nextcloud/main.tf @@ -25,7 +25,7 @@ resource "helm_release" "nextcloud" { repository = "https://nextcloud.github.io/helm/" chart = "nextcloud" atomic = true - version = "8.0.2" + version = "8.8.1" values = [templatefile("${path.module}/chart_values.yaml", { tls_secret_name = var.tls_secret_name, db_password = var.db_password })] timeout = 6000 diff --git a/modules/kubernetes/ollama/main.tf b/modules/kubernetes/ollama/main.tf index 0ecf6063..7d5bd73a 100644 --- a/modules/kubernetes/ollama/main.tf +++ b/modules/kubernetes/ollama/main.tf @@ -184,7 +184,7 @@ resource "kubernetes_deployment" "ollama-ui" { spec { container { # image = "ghcr.io/open-webui/open-webui:main" - image = "ghcr.io/open-webui/open-webui:v0.6.43" + image = "ghcr.io/open-webui/open-webui:v0.7.2" name = "ollama-ui" env { name = "OLLAMA_BASE_URL" diff --git a/modules/kubernetes/speedtest/main.tf b/modules/kubernetes/speedtest/main.tf new file mode 100644 index 00000000..104ac17e --- /dev/null +++ b/modules/kubernetes/speedtest/main.tf @@ -0,0 +1,149 @@ +variable "tls_secret_name" {} +variable "tier" { type = string } +variable "db_password" { type = string } + + +resource "kubernetes_namespace" "speedtest" { + metadata { + name = "speedtest" + } +} + +module "tls_secret" { + source = "../setup_tls_secret" + namespace = kubernetes_namespace.speedtest.metadata[0].name + tls_secret_name = var.tls_secret_name +} + +resource "random_id" "secret_key" { + byte_length = 32 # 32 bytes × 2 hex chars = 64 hex characters +} + +resource "kubernetes_deployment" "speedtest" { + metadata { + name = "speedtest" + namespace = kubernetes_namespace.speedtest.metadata[0].name + labels = { + app = "speedtest" + tier = var.tier + } + } + spec { + replicas = 1 + selector { + match_labels = { + app = "speedtest" + } + } + template { + metadata { + labels = { + app = "speedtest" + } + } + spec { + container { + image = "lscr.io/linuxserver/speedtest-tracker:latest" + name = "speedtest" + port { + container_port = 80 + } + env { + name = "PUID" + value = 1000 + } + env { + name = "PGID" + value = 1000 + } + env { + name = "APP_KEY" + value = "base64:${random_id.secret_key.b64_std}" + } + env { + name = "SPEEDTEST_SCHEDULE" + value = "0 * * * *" + } + # env { + # name = "SPEEDTEST_SERVERS" + # # Sofia speedtest servers - https://c.speedtest.net/speedtest-servers-static.php + # value = "7617,17787,11348,37980,54640,27843,57118,10754,20191,29617" + # } + env { + name = "APP_URL" + value = "https://speedtest.viktorbarzin.me" + } + env { + name = "DB_CONNECTION" + value = "mysql" + } + env { + name = "DB_HOST" + value = "mysql.dbaas.svc.cluster.local" + } + env { + name = "DB_DATABASE" + value = "speedtest" + } + env { + name = "DB_USERNAME" + value = "speedtest" + } + env { + name = "DB_PASSWORD" + value = var.db_password + } + env { + name = "APP_TIMEZONE" + value = "Europe/Sofia" + } + volume_mount { + name = "config" + mount_path = "/config" + } + } + volume { + name = "config" + nfs { + server = "10.0.10.15" + path = "/mnt/main/speedtest" + } + } + } + } + } +} + +resource "kubernetes_service" "speedtest" { + metadata { + name = "speedtest" + namespace = kubernetes_namespace.speedtest.metadata[0].name + labels = { + "app" = "speedtest" + } + annotations = { + "prometheus.io/scrape" = "true" + "prometheus.io/path" = "/prometheus" + "prometheus.io/port" = "80" + } + } + + spec { + selector = { + app = "speedtest" + } + port { + name = "http" + port = 80 + target_port = 80 + } + } +} + +module "ingress" { + source = "../ingress_factory" + namespace = kubernetes_namespace.speedtest.metadata[0].name + name = "speedtest" + tls_secret_name = var.tls_secret_name + protected = true +} diff --git a/modules/kubernetes/vaultwarden/main.tf b/modules/kubernetes/vaultwarden/main.tf index 11cfb4bd..f478611a 100644 --- a/modules/kubernetes/vaultwarden/main.tf +++ b/modules/kubernetes/vaultwarden/main.tf @@ -48,7 +48,7 @@ resource "kubernetes_deployment" "vaultwarden" { } spec { container { - image = "vaultwarden/server:1.34.3" + image = "vaultwarden/server:1.35.2" name = "vaultwarden" env { name = "DOMAIN" diff --git a/secrets/fullchain.pem b/secrets/fullchain.pem index 9c130cfd..69f11a8d 100644 Binary files a/secrets/fullchain.pem and b/secrets/fullchain.pem differ diff --git a/secrets/privkey.pem b/secrets/privkey.pem index 181d9698..594a018a 100644 Binary files a/secrets/privkey.pem and b/secrets/privkey.pem differ diff --git a/terraform.tfstate b/terraform.tfstate index 80c55a29..24946bc1 100644 Binary files a/terraform.tfstate and b/terraform.tfstate differ diff --git a/terraform.tfvars b/terraform.tfvars index 30ea3bbc..ffaa6945 100644 Binary files a/terraform.tfvars and b/terraform.tfvars differ