# Homelab Service — Apps Third bootstrap layer, run after `cluster-bootstrap` and `cluster-platform`. Personal/homelab apps (not cluster infra, not shared platform tooling) — [Ignis](https://github.com/Nystik-gh/ignis) (self-hosted browser-based Obsidian) and `actual-budget-exporter` (Prometheus exporter for a docker-compose-hosted Actual Budget instance). ## Architecture Same app-of-apps pattern as `cluster-platform`: ``` homelab-app.yaml ← root Application, applied once by hand (kubectl apply) apps// application.yaml ArgoCD Application chart/ self-authored Helm chart (no upstream chart to point at) ``` `homelab-app.yaml` watches `apps/*/application.yaml` (recurse) only. **Sync policy differs from `cluster-platform` on purpose:** only the root `homelab` Application is automated (`prune: true`, `selfHeal: true`) — it picks up new/changed `apps/*/application.yaml` files automatically. Each per-service Application (`ignis`, and any future one) has **no** `syncPolicy.automated` — new services or config changes sit `OutOfSync` in ArgoCD until manually synced (UI "Sync" button or `argocd app sync `). These are personal services, not cluster infra — a manual gate before an update actually rolls out is worth it here. ## Bootstrap ```bash kubectl apply -f homelab-app.yaml ``` ## Ignis - Image: `nobbe/ignis:latest` — no official Helm chart, chart here is self-authored from the docker-compose example in the upstream repo. - 3 PVCs on `nfs-delete`: `ignis-vaults` (your actual vault data), `ignis-data` (plugin config/state), `ignis-obsidian-app` (downloaded Obsidian binary, avoids re-download on every restart). - Single replica only — app has an in-process file watcher + write coalescer, not built for multiple instances sharing a vault concurrently. - `ignis-vaults` PVC has `argocd.argoproj.io/sync-options: Delete=false` — the `nfs-delete` StorageClass has `reclaimPolicy: Delete`, so without this annotation an accidental prune (app removed from git, or `helm uninstall`) would delete your vault data on the NAS. The annotation only protects against ArgoCD prune, not `kubectl delete pvc` by hand. - No dedicated health endpoint upstream; probes hit `/api/version` (only documented stable route once the server is up). - **No built-in auth** (upstream docs explicitly warn about this). HTTPRoute is exposed at `ignis.fireflylab.local` with no auth in front — same LAN-only tradeoff already accepted for Vault in `cluster-platform`. Add an Envoy Gateway `SecurityPolicy` (basic auth) later if that's not enough. ### Migrating your existing vault The `ignis-vaults` PVC is backed by `nfs-delete` (NFS subdir provisioner) — data physically lives on the NAS, not on any worker node. After the PVC first binds, a subdir appears under the NAS export (`/ignis--`); mount that export directly (NFS/SMB client) or `kubectl cp` your existing vault folder into the running pod's `/vaults` mount. ### First login / verification ```bash kubectl get pods -n ignis kubectl logs -n ignis deploy/ignis # first boot downloads Obsidian, 1-2 min ``` Visit `http://ignis.fireflylab.local` once the pod is Ready. ## actual-budget-exporter - Image: `docker.io/sakowicz/actual-budget-prometheus-exporter:latest` — Prometheus exporter for [Actual Budget](https://actualbudget.org/), no official Helm chart, chart here is self-authored. - `actual_server` itself is **not** in this cluster — it's a plain docker-compose container on the homelab host (`homelab-docker-compose-prod/actualbudget`), published on the host LAN IP. `values.yaml` points `ACTUAL_SERVER_URL` at that host IP:port, same as `actual-http-api` does in that repo. - No HTTPRoute — this only serves `/metrics`. A `ServiceMonitor` (labeled `release: kube-prometheus-stack` to match that stack's default selector) gets it scraped by the cluster Prometheus instead. - `ACTUAL_PASSWORD` / `ACTUAL_BUDGET_ID_1` are **not** in `values.yaml` — plaintext Actual credentials don't belong in a git-committed file. They come from a Secret you create by hand once, after the Application syncs and the `actualbudget` namespace exists: ```bash kubectl create secret generic actual-budget-exporter-secrets \ -n actualbudget \ --from-literal=ACTUAL_PASSWORD='' \ --from-literal=ACTUAL_BUDGET_ID_1='' ``` Restart the deployment after creating/rotating it: `kubectl rollout restart deployment/actual-budget-exporter -n actualbudget`.