talos-platform/main.tf

158 lines
4 KiB
Terraform
Raw Normal View History

2026-11-08 01:25:56 +00:00
# talos-platform – gemeinsame Cluster-Dienste für Produktion (Talos)
# Hier liegt alles, was ALLE Apps brauchen. Apps (boday_tf, ...) bringen nur ihr eigenes Chart mit.
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.26"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.12"
}
}
backend "consul" {
address = "consul:8500"
path = "terraform/states/talos_platform"
}
}
variable "kubeconfig_path" {
type = string
default = "./talos_kubeconfig"
}
# Version des Traefik-Helm-Charts (traefik/traefik). Bewusst pinnen, damit Updates geplant passieren.
variable "traefik_chart_version" {
type = string
}
provider "kubernetes" {
config_path = var.kubeconfig_path
}
provider "helm" {
kubernetes {
config_path = var.kubeconfig_path
}
}
# Feste IP für Traefik aus dem MetalLB-Pool. Auf diese IP zeigt das OPNsense-Portforwarding (80/443).
variable "traefik_lb_ip" {
type = string
}
2026-11-08 02:08:54 +00:00
# Hostname des Longhorn-Dashboards (internes DNS, z.B. Unbound-Override in OPNsense)
variable "longhorn_host" {
type = string
default = "longhorn.boday.lan"
}
# BasicAuth für Longhorn als htpasswd-Zeile, z.B.: htpasswd -nbB admin 'geheim'
variable "longhorn_basic_auth" {
type = string
sensitive = true
}
2026-11-08 01:25:56 +00:00
# Kein hostPort mehr -> der Talos-Standard (PSA "baseline") reicht
resource "kubernetes_namespace" "traefik" {
metadata {
name = "traefik"
}
}
# Traefik hinter einem MetalLB-LoadBalancer: VIP wandert bei Node-Ausfall auf den anderen Node
resource "helm_release" "traefik" {
name = "traefik"
repository = "https://traefik.github.io/charts"
chart = "traefik"
version = var.traefik_chart_version
namespace = kubernetes_namespace.traefik.metadata[0].name
values = [yamlencode({
deployment = { replicas = 2 }
# Je ein Pod pro Node
topologySpreadConstraints = [{
maxSkew = 1
topologyKey = "kubernetes.io/hostname"
whenUnsatisfiable = "DoNotSchedule"
labelSelector = {
matchLabels = {
"app.kubernetes.io/name" = "traefik"
"app.kubernetes.io/instance" = "traefik-traefik"
}
}
}]
service = {
type = "LoadBalancer"
annotations = {
"metallb.io/loadBalancerIPs" = var.traefik_lb_ip
}
spec = {
# Echte Client-IP bleibt erhalten (Django-Logs, CrowdSec)
externalTrafficPolicy = "Local"
}
}
ingressClass = {
enabled = true
isDefaultClass = true
name = "traefik"
}
providers = {
kubernetesIngress = { enabled = true }
kubernetesCRD = { enabled = true }
}
2026-11-08 02:08:54 +00:00
# Gemeinsame Routen der Plattform: Longhorn-Dashboard mit Login hinter Traefik
extraObjects = [
{
apiVersion = "v1"
kind = "Secret"
metadata = { name = "longhorn-basic-auth", namespace = "longhorn-system" }
type = "Opaque"
stringData = { users = var.longhorn_basic_auth }
},
{
apiVersion = "traefik.io/v1alpha1"
kind = "Middleware"
metadata = { name = "longhorn-auth", namespace = "longhorn-system" }
spec = { basicAuth = { secret = "longhorn-basic-auth" } }
},
{
apiVersion = "networking.k8s.io/v1"
kind = "Ingress"
metadata = {
name = "longhorn"
namespace = "longhorn-system"
annotations = {
"traefik.ingress.kubernetes.io/router.middlewares" = "longhorn-system-longhorn-auth@kubernetescrd"
}
}
spec = {
ingressClassName = "traefik"
rules = [{
host = var.longhorn_host
http = {
paths = [{
path = "/"
pathType = "Prefix"
backend = { service = { name = "longhorn-frontend", port = { number = 80 } } }
}]
}
}]
}
},
]
2026-11-08 01:25:56 +00:00
})]
}
output "traefik_lb_ip" {
value = var.traefik_lb_ip
}