129 lines
3.9 KiB
Markdown
129 lines
3.9 KiB
Markdown
# Homelab Bootstrap — Single-Cluster, GitOps-Ready
|
|
|
|
**Run once manually, GitOps forever after.**
|
|
|
|
This bootstrap breaks the ArgoCD ↔ Forgejo circular dependency by:
|
|
1. Installing infrastructure in correct dependency order
|
|
2. Pointing ArgoCD at a GitHub mirror initially
|
|
3. Cutting over to Forgejo once healthy
|
|
4. Using Helm for reproducible installs
|
|
5. Ensuring ArgoCD adopts (not duplicates) bootstrap resources
|
|
|
|
## Prerequisites
|
|
|
|
- Talos cluster running (terraform applied)
|
|
- kubectl configured (`KUBECONFIG` points at cluster)
|
|
- Helm 3 installed
|
|
- SOPS age key at `~/.sops/homelab-age.key`
|
|
- GitHub mirror of this repo (for initial ArgoCD source)
|
|
|
|
## Directory Structure
|
|
|
|
```
|
|
bootstrap/
|
|
├── phase1-storage/ # Longhorn via Helm
|
|
├── phase2-cnpg/ # CNPG operator via Helm
|
|
├── phase3-forgejo/ # Forgejo DB + Forgejo via Helm
|
|
├── phase4-argocd/ # ArgoCD via Helm → GitHub initially
|
|
└── phase5-cutover/ # Switch ArgoCD source to Forgejo
|
|
```
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
# From repo root:
|
|
./bootstrap.sh
|
|
|
|
# Or step-by-step:
|
|
./bootstrap.sh phase1 # Storage
|
|
./bootstrap.sh phase2 # CNPG
|
|
./bootstrap.sh phase3 # Forgejo
|
|
./bootstrap.sh phase4 # ArgoCD (GitHub mirror)
|
|
./bootstrap.sh phase5 # Cut over to Forgejo
|
|
```
|
|
|
|
## Design Principles
|
|
|
|
1. **DRY**: Helm values used by both bootstrap and ArgoCD
|
|
2. **Single Source of Truth**: Manifests match what ArgoCD will manage
|
|
3. **Idempotent**: Can re-run phases safely
|
|
4. **Adoption Ready**: Resources have `argocd.argoproj.io/sync-options: Prune=false`
|
|
5. **Dependency Ordered**: Each phase waits for previous to be Ready
|
|
|
|
## Phase Details
|
|
|
|
### Phase 1: Storage (Longhorn)
|
|
|
|
Installs Longhorn with:
|
|
- 3-node HA configuration
|
|
- Unified `longhorn` StorageClass (default)
|
|
- Special `longhorn-cnpg` StorageClass with postgres UID/GID mount options
|
|
- CSI plugin tolerations for control-plane nodes
|
|
|
|
**Source of Truth**: `phase1-storage/longhorn-values.yaml`
|
|
|
|
### Phase 2: CNPG Operator
|
|
|
|
Installs CloudNativePG operator with:
|
|
- CRD registration (blocks until CRD available)
|
|
- Webhook configuration
|
|
- Monitoring enabled
|
|
|
|
**Source of Truth**: `phase2-cnpg/cnpg-values.yaml`
|
|
|
|
### Phase 3: Forgejo Database + Forgejo
|
|
|
|
1. Creates `forgejo-db` CNPG Cluster
|
|
2. Waits for cluster Ready (PostgreSQL accepting connections)
|
|
3. Installs Forgejo via Helm pointing at `forgejo-db-rw` service
|
|
4. Waits for Forgejo healthy
|
|
|
|
**Source of Truth**:
|
|
- `phase3-forgejo/forgejo-db.yaml` (CNPG Cluster CR)
|
|
- `phase3-forgejo/forgejo-values.yaml` (Helm values)
|
|
|
|
### Phase 4: ArgoCD (GitHub Mirror)
|
|
|
|
Installs ArgoCD via Helm, then applies root app-of-apps pointing at **GitHub mirror**.
|
|
|
|
This is the circle-breaker: ArgoCD syncs from GitHub (not Forgejo) initially.
|
|
|
|
**Source of Truth**:
|
|
- `phase4-argocd/argocd-values.yaml`
|
|
- `phase4-argocd/root-app-github.yaml` (repoURL = GitHub)
|
|
|
|
ArgoCD **adopts** Phases 1-3 resources (no duplication) because manifests match.
|
|
|
|
### Phase 5: Cut Over to Forgejo
|
|
|
|
1. Push repo to Forgejo
|
|
2. Update root app `repoURL` from GitHub → Forgejo
|
|
3. ArgoCD re-syncs from Forgejo
|
|
|
|
**The circle is broken. GitHub mirror is now disaster recovery only.**
|
|
|
|
## Post-Bootstrap
|
|
|
|
All changes via Git:
|
|
```bash
|
|
git commit -m "feat(app): add new service"
|
|
git push forgejo main
|
|
# ArgoCD auto-syncs
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
- **Phase stuck?** Check `kubectl get events -n <namespace> --sort-by='.lastTimestamp'`
|
|
- **ArgoCD duplicating?** Verify manifests match exactly (Helm values ↔ ArgoCD Application)
|
|
- **Forgejo won't start?** Check CNPG cluster Ready: `kubectl get cluster forgejo-db -n forgejo`
|
|
- **Can't push to Forgejo?** Verify ingress-nginx healthy, DNS resolves `forgejo.riotpiao.com`
|
|
|
|
## Migration from Old Bootstrap
|
|
|
|
If you have existing `k8s/bootstrap-local/`:
|
|
|
|
1. **DO NOT delete** existing resources (Longhorn data!)
|
|
2. Run refined bootstrap in "adoption mode" (no delete, just apply)
|
|
3. Verify ArgoCD shows "Synced" for all apps
|
|
4. Archive old bootstrap: `git mv k8s/bootstrap-local k8s/archive/bootstrap-local-v1`
|