Budget is E2E-encrypted; exporter fails with 'File ... is encrypted' without this. Sourced from the same hand-created Secret as the other credentials.
107 lines
4.9 KiB
Markdown
107 lines
4.9 KiB
Markdown
# 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/<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
|
|
|
|
```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
|
|
(`<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
|
|
|
|
```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` / `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:
|
|
|
|
```bash
|
|
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`.
|