chore(phase4): stub helmfile — all releases managed by Terraform + ArgoCD
This commit is contained in:
+26
-306
@@ -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 <pending>. 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 <app-name> # Check what ArgoCD would change
|
||||
# terraform plan # Check what Terraform would change
|
||||
|
||||
Reference in New Issue
Block a user