readinessProbe/livenessProbe hit /metrics on top of Prometheus's own scrapes; exporter re-logs into actual_server on every call (no session reuse), tripped actual_server's login rate limit (too-many-requests). Switch probes to tcpSocket and stretch scrape interval to 5m.
Homelab Service — Apps
Third bootstrap layer, run after cluster-bootstrap and cluster-platform.
Personal/homelab apps (not cluster infra, not shared platform tooling) —
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/<service>/
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 <name>).
These are personal services, not cluster infra — a manual gate before an
update actually rolls out is worth it here.
Bootstrap
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-vaultsPVC hasargocd.argoproj.io/sync-options: Delete=false— thenfs-deleteStorageClass hasreclaimPolicy: Delete, so without this annotation an accidental prune (app removed from git, orhelm uninstall) would delete your vault data on the NAS. The annotation only protects against ArgoCD prune, notkubectl delete pvcby 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.localwith no auth in front — same LAN-only tradeoff already accepted for Vault incluster-platform. Add an Envoy GatewaySecurityPolicy(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
(<nfs path>/ignis-<pvc-name>-<uid>); mount that export directly (NFS/SMB
client) or kubectl cp your existing vault folder into the running pod's
/vaults mount.
First login / verification
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, no official Helm chart, chart here is self-authored. -
actual_serveritself 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.yamlpointsACTUAL_SERVER_URLat that host IP:port, same asactual-http-apidoes in that repo. -
No HTTPRoute — this only serves
/metrics. AServiceMonitor(labeledrelease: kube-prometheus-stackto match that stack's default selector) gets it scraped by the cluster Prometheus instead. -
ACTUAL_PASSWORD/ACTUAL_BUDGET_ID_1/ACTUAL_E2E_PASSWORD_1are not invalues.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 theactualbudgetnamespace exists.ACTUAL_E2E_PASSWORD_1is required if the budget has E2E encryption enabled — the exporter fails withFile ... is encrypted. Please provide a password.otherwise; pass an empty string if the budget isn't encrypted:kubectl create secret generic actual-budget-exporter-secrets \ -n actualbudget \ --from-literal=ACTUAL_PASSWORD='<your actual budget password>' \ --from-literal=ACTUAL_BUDGET_ID_1='<sync ID from Settings → Show advanced settings>' \ --from-literal=ACTUAL_E2E_PASSWORD_1='<E2E encryption password, empty string if none>'Restart the deployment after creating/rotating it:
kubectl rollout restart deployment/actual-budget-exporter -n actualbudget.