duynguyen 26526ecc50 fix: add ACTUAL_E2E_PASSWORD_1 to actual-budget-exporter
Budget is E2E-encrypted; exporter fails with 'File ... is encrypted' without
this. Sourced from the same hand-created Secret as the other credentials.
2026-09-03 15:44:19 +07:00

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-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 (<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_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 / ACTUAL_E2E_PASSWORD_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. ACTUAL_E2E_PASSWORD_1 is required if the budget has E2E encryption enabled — the exporter fails with File ... 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.

S
Description
No description provided
Readme
54 KiB