Files
homelab/k8s/argocd/bootstrap.archived/BOOTSTRAP.md
T
Story Crater Bot f656338a15 feat: complete GitOps migration, storage HA verification, and cluster fixes
Major accomplishments from comprehensive cluster review:

## Storage HA (answering "are volumes replicated?")
- Verified 3-node Longhorn HA: ALL 17 volumes have 3 replicas
- Fixed CLAUDE.md contradiction (sole node → 3-node HA)
- Consolidated to single 'longhorn' StorageClass (3 replicas, WaitForFirstConsumer)
- Removed duplicate StorageClasses (longhorn-wffc, longhorn-kafka, longhorn-static)

## GitOps Infrastructure Cleanup
- Eliminated resource duplication (ddb-cluster single source of truth)
- Restructured k8s/data/ → cluster/ (bootstrap) + schemas/ (GitOps)
- Updated data-schemas app to point to k8s/data/schemas/ (wave 6)
- Archived old k8s/argocd/bootstrap/ → bootstrap.archived/

## Bootstrap Dependencies Fixed
- Added 05-wait-for-databases.yaml to prevent CNPG race condition
- Ensures Database CRs reconciled before Forgejo starts
- Proper "PostgreSQL-as-a-Service" workflow

## Longhorn CSI Plugin Fixed
- Added patch-csi-tolerations-job.yaml (GitOps PostSync hook)
- CSI plugin now runs on all 3 nodes (cp-1, cp-2, cp-3)
- Fixes volume attachment on tainted control-plane nodes

## Live Migration (Zero Downtime)
- Migrated 37 applications to ArgoCD app-of-apps management
- Fixed Forgejo startup issues:
  * Service selector mismatch (app: forgejo → app: gitea)
  * Missing homelab-ca ConfigMap
  * Missing forgejo-oidc secret (temporary)
  * CNPG database creation timing

## Documentation (10 comprehensive files)
- WHATS-NEXT.md - Daily GitOps workflow
- MIGRATION-STATUS.md - Cluster health report
- REVIEW-SUMMARY.md - Session overview
- GITOPS-REBUILD-PLAN.md - Architecture reference
- DDB-REVIEW.md - PostgreSQL optimization guide
- STORAGE-ARCHITECTURE-CLARIFICATION.md - Storage HA investigation
- BOOTSTRAP-DEPENDENCY-FIX.md - CNPG race condition fix
- STORAGECLASS-CONSOLIDATION.md - Single StorageClass rationale
- IMPLEMENTATION-CHECKLIST.md - Migration checklist
- bootstrap.sh - Automated bootstrap script

## Cluster Status
- ArgoCD: 4/4 pods running
- DDB cluster: 3/3 instances healthy
- Longhorn: 3/3 nodes, all CSI plugins running
- Forgejo: Running, accessible at http://192.168.1.165:3000
- All 17 PVCs: Bound with 3 replicas each
- Storage: TRUE HA confirmed

All future changes via git push only (100% GitOps).
2026-08-18 15:08:03 -07:00

128 lines
5.5 KiB
Markdown
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.
# Cluster bootstrap & CD — two scopes
The GitOps repo is hosted on the cluster's own Forgejo, so ArgoCD cannot pull it
until Forgejo exists. There are two distinct workflows — pick the one that
matches your situation.
```
Scope 1 — from scratch cold cluster, nothing running yet → full bootstrap
Scope 2 — iterating CD cluster + Forgejo + ArgoCD are up → just git push
```
---
## Scope 1 — Cluster from scratch (cold bootstrap)
Strict ordering, because each layer depends on the previous one existing.
```
Talos + Cilium CNI Terraform (nodes) — cluster reachable
Substrate cert-manager, ingress-nginx, reloader — Terraform helm_releases
Longhorn, ArgoCD — imperative install
Phase 0 (git-independent) CNPG + ddb-cluster + redis + Forgejo — manual, below
Seed git push repo into Forgejo
Phase 1 app-of-apps root — ArgoCD deploys the rest
```
Run every command from a local checkout with `KUBECONFIG` pointed at the cluster.
### Phase 0 — bootstrap Forgejo and its data plane (git-independent)
```bash
# 1. CNPG operator (public Helm) + its CRDs.
kubectl apply -f k8s/argocd/bootstrap/cnpg-operator.yaml
argocd app sync cnpg-operator
# CNPG ships CRDs in the chart's crds/ folder, which ArgoCD's helm-template does
# NOT install. If the ddb-cluster apply below fails with "no matches for kind
# Cluster", install them once:
# kubectl apply --server-side -f \
# https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.24/releases/cnpg-1.24.1.yaml
# 2. Namespaces first. cicd MUST be labelled privileged (DinD/runner needs it);
# the Forgejo app deliberately does NOT create it.
kubectl create namespace ddb --dry-run=client -o yaml | kubectl apply -f -
kubectl create namespace cicd --dry-run=client -o yaml | kubectl apply -f -
kubectl label namespace cicd pod-security.kubernetes.io/enforce=privileged --overwrite
# 3. Postgres cluster + Forgejo database + Redis (raw manifests, local checkout).
kubectl apply -f k8s/data/ddb-cluster.yaml
kubectl apply -f k8s/data/forgejo-database.yaml
kubectl apply -f k8s/security/ci-cd/forgejo-redis.yaml
# 4. Copy the CNPG-generated app password into cicd (Secrets are ns-scoped).
kubectl get secret ddb-cluster-app -n ddb -o yaml \
| sed 's/namespace: ddb/namespace: cicd/' \
| kubectl apply -n cicd -f -
# 5. Forgejo (public Helm, values inlined — git-independent).
kubectl apply -f k8s/argocd/bootstrap/forgejo.yaml
argocd app sync forgejo
```
### Seed + Phase 1
```bash
# 6. Push this repo to the freshly-created Forgejo so Phase 1 has a source.
git remote add forgejo https://forgejo.riotpiao.com/riotpiao.com/homelab.git
git push forgejo main
# 7. (Optional) Cloudflared tunnel secret — if the SOPS CMP plugin is NOT yet
# wired up: create the cloudflared-token Secret manually before wave 8 syncs.
# Skip this step if the CMP plugin is already live and handling SOPS decryption.
kubectl create namespace cloudflared --dry-run=client -o yaml | kubectl apply -f -
sops -d k8s/applications/cloudflared/cloudflared-secrets.enc.yaml \
| yq '.cloudflared.tunnelToken' \
| kubectl create secret generic cloudflared-token -n cloudflared \
--from-literal=token=- --dry-run=client -o yaml | kubectl apply -f -
# Once the SOPS CMP plugin is deployed (Phase 1 wave 0), migrate this Secret
# into the plugin's script output and remove this manual step.
# 8. Deploy everything else from git — one sync brings up the whole cluster.
kubectl apply -f k8s/argocd/projects/homelab-project.yaml # AppProject
kubectl apply -k k8s/argocd/root # app-of-apps root
argocd app sync homelab-root
```
`homelab-root` renders every Application under `k8s/argocd/apps/` and syncs them
in sync-wave order (networking → storage/observability → logging → security →
data → messaging → applications).
---
## Scope 2 — Iterating CD (day-2, cluster already up)
The app-of-apps and its children already exist and reconcile from Forgejo. To
change anything, you do NOT re-run the bootstrap — you just push:
```bash
# edit manifests under k8s/**
git add -A && git commit -m "..."
git push # to Forgejo main (origin)
# ArgoCD auto-syncs (child apps have syncPolicy.automated); to force it:
argocd app sync homelab-root
```
- Adding a new service = add an Application manifest under `k8s/argocd/apps/`
and its manifests under the path it references, then push. The app-of-apps
picks it up on next sync.
- Changing a Helm value = edit the values file the Application points at
(`$values/...`), push.
- Forgejo itself is Phase-0 / bootstrap (manual sync only) — a bad CI commit
must not be able to break the system CI depends on.
---
## Notes / prerequisites
- **Secrets:** several values files (loki S3, grafana admin, authentik, vault)
expect secrets that helmfile used to inject via `--set`. Under ArgoCD these
come from the `*.enc.yaml` SOPS files via the ArgoCD SOPS plugin — confirm the
plugin is configured before syncing waves 23, or those charts render with
empty secrets.
- **Substrate** (cert-manager, ingress-nginx, reloader) is installed by Terraform
as bootstrap Helm releases, not ArgoCD. Cilium CNI, Longhorn, and ArgoCD
itself are cluster-bootstrap installs.
- **Single storage node:** only `talos-cp-1` runs workloads/storage, so stateful
services are single-instance (`ddb-cluster` = 1). See the repo `USAGE.md` and
root `CLAUDE.md` topology section.