infra/stacks/speedtest/main.tf
Viktor Barzin c670cb7118
Some checks failed
ci/woodpecker/push/default Pipeline failed
eso: Phase 2 — migrate all 104 ExternalSecrets + 2 ClusterSecretStores to v1
The API rewrite half of the ESO 0.12->2.6 migration (last k8s-1.35 compat-gate
blocker). Done on chart 0.16.2, which serves BOTH external-secrets.io/v1beta1
and v1, so this is the safe window — MUST land before 0.17 removes v1beta1
(there is no conversion webhook). Pure apiVersion bump, schema is byte-identical:
106 occurrences (104 ExternalSecrets + 2 ClusterSecretStores vault-kv/vault-database)
across 73 .tf files, v1beta1 -> v1, no other field changes.

Validated live first on tandoor (single, non-coupled, synced ES): the
kubernetes_manifest apiVersion bump forces a REPLACE; the target Secret is
cascade-GC'd for ONE ~0.3s poll then ESO recreates it (identical value re-synced
from Vault, new UID) and the ES returns SecretSynced=True on v1. Running pods
keep their mounted copy through the sub-second blip. All 110 target Secrets were
snapshotted to /tmp first as a backstop.

CI applies the changed stacks serially (staged rollout); watching aggregate ES
sync back to 108 synced (2 pre-existing dead: instagram-poster, payslip-ingest).
Next: Phase 3 climb 0.16.2 -> 2.6.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 19:13:04 +00:00

253 lines
6.8 KiB
HCL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

variable "tls_secret_name" {
type = string
sensitive = true
}
variable "nfs_server" { type = string }
variable "mysql_host" { type = string }
resource "kubernetes_namespace" "speedtest" {
metadata {
name = "speedtest"
labels = {
tier = local.tiers.aux
"keel.sh/enrolled" = "true"
}
}
lifecycle {
# KYVERNO_LIFECYCLE_V1: goldilocks-vpa-auto-mode ClusterPolicy stamps this label on every namespace
ignore_changes = [metadata[0].labels["goldilocks.fairwinds.com/vpa-update-mode"]]
}
}
resource "kubernetes_manifest" "external_secret" {
manifest = {
apiVersion = "external-secrets.io/v1"
kind = "ExternalSecret"
metadata = {
name = "speedtest-secrets"
namespace = "speedtest"
}
spec = {
refreshInterval = "15m"
secretStoreRef = {
name = "vault-database"
kind = "ClusterSecretStore"
}
target = {
name = "speedtest-secrets"
}
data = [{
secretKey = "db_password"
remoteRef = {
key = "static-creds/mysql-speedtest"
property = "password"
}
}]
}
}
depends_on = [kubernetes_namespace.speedtest]
}
module "tls_secret" {
source = "../../modules/kubernetes/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
}
# Config on NFS. Migrated off proxmox-lvm 2026-06-05 for LUN-cap relief —
# speedtest-tracker is MySQL-backed (config dir = logs + Laravel config, no
# embedded DB), NFS-safe. See docs/plans/2026-06-05-block-storage-harden-nfs-design.md
module "nfs_speedtest" {
source = "../../modules/kubernetes/nfs_volume"
name = "speedtest-config-nfs"
namespace = kubernetes_namespace.speedtest.metadata[0].name
nfs_server = var.nfs_server
nfs_path = "/srv/nfs/speedtest"
storage = "5Gi"
}
resource "kubernetes_deployment" "speedtest" {
metadata {
name = "speedtest"
namespace = kubernetes_namespace.speedtest.metadata[0].name
labels = {
app = "speedtest"
tier = local.tiers.aux
}
annotations = {
"reloader.stakater.com/auto" = "true"
}
}
spec {
replicas = 1
strategy {
type = "Recreate"
}
selector {
match_labels = {
app = "speedtest"
}
}
template {
metadata {
labels = {
app = "speedtest"
}
annotations = {
"diun.enable" = "true"
"diun.include_tags" = "^\\d+\\.\\d+\\.\\d+$"
"dependency.kyverno.io/wait-for" = "mysql.dbaas:3306"
}
}
spec {
container {
image = "lscr.io/linuxserver/speedtest-tracker:0.24.1"
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 = var.mysql_host
}
env {
name = "DB_DATABASE"
value = "speedtest"
}
env {
name = "DB_USERNAME"
value = "speedtest"
}
env {
name = "DB_PASSWORD"
value_from {
secret_key_ref {
name = "speedtest-secrets"
key = "db_password"
}
}
}
env {
name = "DB_PORT"
value = "3306"
}
env {
name = "APP_TIMEZONE"
value = "Europe/Sofia"
}
resources {
requests = {
cpu = "25m"
memory = "128Mi"
}
limits = {
memory = "512Mi"
}
}
volume_mount {
name = "config"
mount_path = "/config"
}
}
volume {
name = "config"
persistent_volume_claim {
claim_name = module.nfs_speedtest.claim_name
}
}
}
}
}
lifecycle {
ignore_changes = [
spec[0].template[0].spec[0].dns_config, # KYVERNO_LIFECYCLE_V1
metadata[0].annotations["keel.sh/policy"],
metadata[0].annotations["keel.sh/trigger"],
metadata[0].annotations["keel.sh/pollSchedule"], # KYVERNO_LIFECYCLE_V2
metadata[0].annotations["keel.sh/match-tag"],
spec[0].template[0].spec[0].container[0].image, # KEEL_IGNORE_IMAGE — Keel manages tag updates
metadata[0].annotations["kubernetes.io/change-cause"],
metadata[0].annotations["deployment.kubernetes.io/revision"],
spec[0].template[0].metadata[0].annotations["keel.sh/update-time"], # KEEL_LIFECYCLE_V1
]
}
}
resource "kubernetes_service" "speedtest" {
metadata {
name = "speedtest"
namespace = kubernetes_namespace.speedtest.metadata[0].name
labels = {
"app" = "speedtest"
}
annotations = {
"prometheus.io/scrape" = "false"
}
}
spec {
selector = {
app = "speedtest"
}
port {
name = "http"
port = 80
target_port = 80
}
}
}
module "ingress" {
source = "../../modules/kubernetes/ingress_factory"
dns_type = "proxied"
namespace = kubernetes_namespace.speedtest.metadata[0].name
name = "speedtest"
tls_secret_name = var.tls_secret_name
auth = "required"
extra_annotations = {
"gethomepage.dev/enabled" = "true"
"gethomepage.dev/name" = "Speedtest"
"gethomepage.dev/description" = "Internet speed tracker"
"gethomepage.dev/icon" = "speedtest-tracker.png"
"gethomepage.dev/group" = "Infrastructure"
"gethomepage.dev/widget.type" = "speedtest"
"gethomepage.dev/widget.url" = "http://speedtest.speedtest.svc.cluster.local"
"gethomepage.dev/pod-selector" = ""
}
}
# CI retrigger 2026-05-16T13:42:57+00:00 — bulk enrollment apply (pipeline #689 killed)
# CI retrigger v2 2026-05-16T13:46:35+00:00