unbound was bundled inside apps/pihole/ and invisible in the apps/
listing. Now apps/unbound/ (deployment + service + kustomization); it
stays in the pihole namespace, whose Namespace object remains owned by
apps/pihole. No resource changes — server-side dry-run clean (36
resources).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A fresh node pull of pihole:latest silently upgraded v5->v6 (Core v6.2.2).
v6's default listeningMode=LOCAL drops DNS from non-attached subnets, which
killed all cross-node svclb DNS the moment the pod rescheduled off its old
node. v6 also ignores the WEBPASSWORD env.
- image pinned by digest (Core v6.2.2)
- FTLCONF_dns_listeningMode=ALL
- admin password via FTLCONF_webserver_api_password <- pihole-admin secret
- tcpSocket:53 readiness probe so rollout status waits for FTL
Applied to the cluster via kubectl replace; DNS verified answering on all
four node IPs, admin API auth verified.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- .gitea/workflows/deploy.yaml: PRs run a server-side dry-run; pushes to
main apply the kustomization and wait for all rollouts. Modeled on
socktop-webterm's pipeline; uses the same KUBECONFIG secret convention
and gitea-deployer ServiceAccount.
- rbac/gitea-deployer.yaml: ClusterRole/Binding (admin bootstrap, outside
the root kustomization) — repo resource kinds only, no secrets access,
no delete verbs, no RBAC escalation. Applied to the cluster 2026-07-26.
- One-time env->secretKeyRef migration executed against the cluster;
README updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Captured 2026-07-26 from rpi-master (k3s v1.30.3) and cleaned of runtime
fields. Six apps as per-app kustomizations: vaultwarden, searxng,
home-assistant, nginx, pihole(+unbound), unified-streaming.
Intentional divergences from live state:
- pihole WEBPASSWORD and USP_LICENSE_KEY moved from inline plaintext env
to secretKeyRef (secrets gitignored; templates in secret.example.yaml)
- HA ingress defaultBackend fixed (pointed at nonexistent service)
- unifiedstreaming-svc kept as ClusterIP (LoadBalancer could never bind
port 80 behind svclb-traefik)
Validated against the live cluster with kubectl apply --dry-run=server:
no immutable-field conflicts; one-time kubectl replace procedure for the
two env->secretKeyRef migrations documented in README.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>