diff --git a/helmfile.yaml.gotmpl b/helmfile.yaml.gotmpl index 708a8d8..1680fba 100644 --- a/helmfile.yaml.gotmpl +++ b/helmfile.yaml.gotmpl @@ -1,313 +1,33 @@ -# helmfile.yaml -# Single source of truth for all Helm releases in the homelab cluster. +# helmfile.yaml — DEPRECATED # -# Usage: -# helmfile apply # deploy / reconcile everything -# helmfile apply -l namespace=logging # only logging stack -# helmfile apply -l name=grafana # only grafana -# helmfile diff # preview changes -# helmfile destroy -l name=portainer # tear down one release +# This file is kept for historical reference only. +# All Helm releases have been migrated to: +# 1. Terraform (bootstrap releases: cert-manager, reloader, ingress-nginx) +# 2. ArgoCD Applications (all workload releases) # -# Required env vars (export or place in .env at repo root): -# MINIO_ROOT_USER, MINIO_ROOT_PASSWORD -# GRAFANA_ADMIN_PASSWORD +# Deployment now uses: +# - terraform apply (for core infrastructure) +# - ArgoCD auto-sync (for all workloads) # -# .env is loaded automatically by helmfile if it exists at the repo root. - -repositories: - - name: grafana - url: https://grafana.github.io/helm-charts - - name: minio - url: https://charts.min.io - - name: prometheus-community - url: https://prometheus-community.github.io/helm-charts - - name: portainer - url: https://portainer.github.io/k8s/ - - name: authentik - url: https://charts.goauthentik.io - - name: hashicorp - url: https://helm.releases.hashicorp.com - - name: ingress-nginx - url: https://kubernetes.github.io/ingress-nginx - - name: argo - url: https://argoproj.github.io/argo-helm - - name: gitea-charts - url: https://dl.gitea.com/charts/ - - name: jetstack - url: https://charts.jetstack.io - - name: stakater - url: https://stakater.github.io/stakater-charts - - name: strimzi - url: https://strimzi.io/charts/ - - name: bitnami - url: https://charts.bitnami.com/bitnami - - name: temporal - url: https://go.temporal.io/helm-charts - - name: cnpg - url: https://cloudnative-pg.github.io/charts - -# ── cert-manager ───────────────────────────────────────────────────────────── - -releases: - - name: cert-manager - namespace: cert-manager - createNamespace: true - chart: jetstack/cert-manager - version: "~v1" - values: - - k8s/cert-manager/cert-manager-values.yaml - set: - # CRDs must be installed by the chart — avoids a separate kubectl apply step - - name: crds.enabled - value: true - hooks: - - events: ["postsync"] - command: bash - args: - - -c - - | - # Wait for cert-manager webhooks to be ready before applying CRD instances. - # Without this, ClusterIssuer/Certificate creation races the webhook and fails. - kubectl rollout status deploy/cert-manager -n cert-manager --timeout=120s - kubectl rollout status deploy/cert-manager-webhook -n cert-manager --timeout=120s - - kubectl apply -f - <<'EOF' - # Phase 2a — bootstrap issuer (selfSigned) used only to sign the CA cert. - # Never referenced by ingresses — its sole job is to sign homelab-ca below. - apiVersion: cert-manager.io/v1 - kind: ClusterIssuer - metadata: - name: selfsigned-bootstrap - spec: - selfSigned: {} - --- - # Phase 2b — the cluster CA certificate. - # cert-manager stores the signed cert + key in homelab-ca-secret. - # isCA: true marks it so it can sign other certs. - # 10-year lifetime; renewBefore triggers 30 days early. - apiVersion: cert-manager.io/v1 - kind: Certificate - metadata: - name: homelab-ca - namespace: cert-manager - spec: - isCA: true - commonName: homelab-ca - secretName: homelab-ca-secret - duration: 87600h - renewBefore: 720h - privateKey: - algorithm: ECDSA - size: 256 - issuerRef: - name: selfsigned-bootstrap - kind: ClusterIssuer - group: cert-manager.io - --- - # Phase 2c — the real issuer all ingresses reference. - # Reads the CA cert+key from homelab-ca-secret and signs per-hostname certs. - # Annotate any ingress with: cert-manager.io/cluster-issuer: homelab-ca - apiVersion: cert-manager.io/v1 - kind: ClusterIssuer - metadata: - name: homelab-ca - spec: - ca: - secretName: homelab-ca-secret - EOF - -# ── Stakater Reloader ───────────────────────────────────────────────────────── -# Watches Deployments for secret.reloader.stakater.com/reload and -# configmap.reloader.stakater.com/reload annotations, then triggers a rolling -# restart whenever the named Secret or ConfigMap is updated (e.g. cert-manager -# renewing a TLS cert, or homelab-ca rotating). This replaces the need for -# manual `kubectl rollout restart` on cert renewal. - - - name: reloader - namespace: reloader - createNamespace: true - chart: stakater/reloader - version: "~1" - - # Pod Disruption Budgets applied after reloader (ensures all namespaces exist) - hooks: - - events: ["postsync"] - command: bash - args: - - -c - - kubectl apply -f k8s/base/poddisruptionbudgets.yaml - -# ── Ingress ─────────────────────────────────────────────────────────────────── - - - name: ingress-nginx - namespace: ingress-nginx - createNamespace: true - chart: ingress-nginx/ingress-nginx - values: - - k8s/ingress/nginx-values.yaml - # ServiceMonitor enabled in nginx-values.yaml requires the Prometheus Operator - # CRDs, which the prometheus release installs — must apply after it. - needs: - - monitoring/prometheus - hooks: - - events: ["presync"] - command: bash - args: - - -c - - | - bash k8s/base/namespace-setup.sh ingress-nginx - # LB-IPAM pool must exist before any LoadBalancer service is created, - # otherwise services stay . Apply it here as the first hook. - kubectl apply -f k8s/cilium/lb-ipam-pool.yaml - kubectl apply -f k8s/coredns/coredns-configmap.yaml - kubectl apply -f k8s/coredns/coredns-deployment.yaml - kubectl rollout restart deployment/coredns -n kube-system - kubectl rollout status deployment/coredns -n kube-system --timeout=60s - # Wildcard TLS cert — must exist before nginx starts so it can read the secret. - # cert-manager issues it in the ingress-nginx namespace; wait until Ready. - kubectl apply -f k8s/ingress/wildcard-cert.yaml - kubectl wait certificate homelab-tls -n ingress-nginx \ - --for=condition=Ready --timeout=120s - - events: ["postsync"] - command: kubectl - args: - - apply - - -f - - k8s/ingress/ingress.yaml - -# ── Storage (MinIO with Longhorn replication) ─────────────────────────────── - - - name: minio - namespace: storage - createNamespace: true - chart: minio/minio - values: - - k8s/storage/minio-values.yaml - set: - - name: rootUser - value: {{ env "MINIO_ROOT_USER" }} - - name: rootPassword - value: {{ env "MINIO_ROOT_PASSWORD" }} - hooks: - - events: ["presync"] - command: bash - args: - - -c - - | - bash k8s/base/namespace-setup.sh storage - CA_PEM=$(kubectl get secret homelab-ca-secret -n cert-manager \ - -o jsonpath='{.data.tls\.crt}' | base64 -d) - kubectl create configmap homelab-ca -n storage \ - --from-literal=homelab-ca.crt="$CA_PEM" \ - --dry-run=client -o yaml | kubectl apply -f - - kubectl create secret generic minio-oidc -n storage \ - --from-literal=MINIO_IDENTITY_OPENID_CLIENT_SECRET="{{ env "MINIO_OIDC_CLIENT_SECRET" }}" \ - --dry-run=client -o yaml | kubectl apply -f - - bash k8s/storage/minio-bucket-init.sh storage loki-chunks loki-ruler loki-admin loki-index vault riotpiao-models - -# ── Logging (Loki + Promtail + Grafana — backed by storage/minio) ─── -# Loki uses minio.storage.svc.cluster.local:9000 with Longhorn-replicated storage. -# Buckets (loki-chunks, loki-ruler, loki-admin) created by minio presync hook. - -# ── CI/CD (Argo CD) ────────────────────────────────────────────────────────── -# Forgejo + runner are bootstrapped via kubectl apply (forge/forgejo.yaml, forge/runner.yaml) -# and then handed to Argo CD self-management in Phase 4 (talos_version_control.html). -# Only Argo CD itself lives here — it can't manage its own initial install. +# To view or manage releases: +# kubectl get applications -n argocd # -# Required env vars (none for Argo CD itself — secrets injected post-deploy via Phase 1.5.4): -# AUTHENTIK_ARGOCD_CLIENT_ID, AUTHENTIK_ARGOCD_CLIENT_SECRET (set after Authentik Phase 1.5) +# To modify releases, update k8s/argocd/apps/*.yaml files and commit to git. +# +# This file remains as a marker to prevent accidental `helmfile apply` usage. +# DELETE if no longer needed after full migration verification. - - name: argocd - namespace: cicd - createNamespace: false # cicd namespace already exists - chart: argo/argo-cd - version: "~7" # pin major; check https://github.com/argoproj/argo-helm/releases for current - values: - - k8s/talos-ci-cd/argocd-values.yaml - needs: - - iam/authentik # Authentik must be up before OIDC is wired (Phase 1.5.4) - hooks: - - events: ["presync"] - command: bash - args: - - -c - - | - # oidc-secret holds Authentik client credentials — referenced by argocd-cm via $oidc-secret:key - # Must be labelled part-of: argocd so Argo CD's credential templating can read it - kubectl -n cicd create secret generic oidc-secret \ - --from-literal=client-id="{{ env "AUTHENTIK_ARGOCD_CLIENT_ID" }}" \ - --from-literal=client-secret="{{ env "AUTHENTIK_ARGOCD_CLIENT_SECRET" }}" \ - --dry-run=client -o yaml \ - | kubectl label --local -f - app.kubernetes.io/part-of=argocd -o yaml \ - | kubectl apply -f - +# Historical note: +# - Phases 0-3 migrated: cert-manager, reloader, ingress-nginx, strimzi-operator, +# kmsvc-redis, kafka-cluster, queue-crd, management-service, promtail, portainer, +# cloudnative-pg, loki, grafana, prometheus, forgejo, forgejo-runner, authentik +# - Phase 4 cutover: 2026-07-15 (helmfile stubbed, ArgoCD becomes sole convergence engine) - - events: ["postsync"] - command: bash - args: - - -c - - | - # Inject homelab-ca into argocd-tls-certs-cm so Argo CD can verify Authentik TLS - CA_PEM=$(kubectl get configmap homelab-ca -n iam \ - -o jsonpath='{.data.homelab-ca\.crt}') - AUTHENTIK_HOST="authentik.{{ env "CLUSTER_DOMAIN" }}" - kubectl -n cicd patch configmap argocd-tls-certs-cm --type merge \ - -p "$(jq -n --arg host "$AUTHENTIK_HOST" --arg ca "$CA_PEM" '{data: {($host): $ca}}')" +# ── DO NOT USE ──────────────────────────────────────────────────────────────── +# helmfile apply # FORBIDDEN (use ArgoCD) +# helmfile diff # FORBIDDEN (use argocd app diff) +# helmfile destroy # FORBIDDEN (use kubectl delete) - # Configure OIDC in argocd-cm ConfigMap with rootCA for Authentik TLS verification - CA_PEM=$(kubectl get configmap homelab-ca -n iam -o jsonpath='{.data.homelab-ca\.crt}') - AUTHENTIK_HOST="authentik.{{ env "CLUSTER_DOMAIN" }}" - OIDC_CONFIG="name: Authentik\nissuers: https://${AUTHENTIK_HOST}/application/o/argocd/\nclientID: argocd\nclientSecret: \$oidc-secret:client-secret\nrequestedScopes:\n - openid\n - profile\n - email\nrootCA: |\n$(echo "$CA_PEM" | sed 's/^/ /')" - kubectl -n cicd patch configmap argocd-cm --type merge -p "$(jq -n --arg config "$OIDC_CONFIG" '{data: {"oidc.config": $config}}')" - -# ── Dashboard (Portainer) ───────────────────────────────────────────────────── - -# ── Messaging Queue (SQS-like Kafka) ───────────────────────────────────────── - -# ── Temporal (workflow engine) ───────────────────────────────────────────────── - - - name: temporal - namespace: temporal - createNamespace: true - chart: temporal/temporal - version: "~0.55" - values: - - k8s/temporal/temporal-values.yaml - needs: - - monitoring/prometheus - set: - - name: web.auth.providers[0].clientId - value: {{ env "AUTHENTIK_TEMPORAL_CLIENT_ID" }} - - name: web.auth.providers[0].clientSecret - value: {{ env "AUTHENTIK_TEMPORAL_CLIENT_SECRET" }} - hooks: - - events: ["presync"] - command: bash - args: - - -c - - | - bash k8s/base/namespace-setup.sh temporal - kubectl apply -f k8s/temporal/elasticsearch.yaml - kubectl create secret generic temporal-oidc -n temporal \ - --from-literal=client_id="{{ env "AUTHENTIK_TEMPORAL_CLIENT_ID" }}" \ - --from-literal=client_secret="{{ env "AUTHENTIK_TEMPORAL_CLIENT_SECRET" }}" \ - --dry-run=client -o yaml | kubectl apply -f - - -# ── Claude Terminal (persistent dev environment) ───────────────────────────── - -# ── Global Reloader Configuration ──────────────────────────────────────────── - -hooks: - - events: ["postsync"] - command: bash - args: - - -c - - | - # Enable Reloader on all Secrets and ConfigMaps to auto-restart pods on updates - for ns in cert-manager ingress-nginx monitoring logging storage iam cicd temporal dashboard story-crater-backend llm dev-tools ddb; do - echo "Patching $ns Secrets..." - kubectl patch secret -n $ns --all -p '{"metadata":{"annotations":{"secrets.stakater.com/match":"true"}}}' 2>/dev/null || true - - echo "Patching $ns ConfigMaps..." - kubectl patch configmap -n $ns --all -p '{"metadata":{"annotations":{"configmap.reloader.stakater.com/match":"true"}}}' 2>/dev/null || true - done - echo "✓ Reloader annotations applied to all Secrets and ConfigMaps" +# For drift detection (CI only): +# argocd app diff # Check what ArgoCD would change +# terraform plan # Check what Terraform would change