5.0 KiB
M6.1 — CNPG agent-manager-db manifest
| Field | Value |
|---|---|
| Phase | M6 — agent-manager migration |
| Size | M — 1–3 days |
| Status | ⬜ Not started |
| Flags | homelab |
| Spec | inlined below |
| Blocks | — |
Goal
A dedicated Postgres for agent-manager's session store, provisioned the way
everything else in the cluster is: through git, with no manual psql. Same
pattern this project already used for memory-db (M2.2), applied to a
different, unrelated app.
Facts (inlined — no spec read needed)
agent-manager is a separate repo, not part of this Rust workspace:
github.com/Riotpiaole/agent-manager (fork of github.com/YoanWai/ agent-manager), local checkout ~/workplace/agent-manager, branch
add-headless-spawn. Its session store is internal/store/store.go — see
M6.2/M6.3 for the schema and query port.
Existing CNPG pattern, verified on the live cluster: 3 Clusters today, one per app, each ClusterIP-only (not LAN-reachable):
| namespace/name | app |
|---|---|
cicd/forgejo-db |
Forgejo |
iam/authentik-db |
Authentik |
temporal/temporal-db |
Temporal |
No shared/multi-tenant DB cluster — every app gets its own dedicated
CNPG Cluster. agent-manager-db follows the same rule; it does not join
memory-db (M2.2's cluster) even though both are new Postgres instances
touched by the same person around the same time. Different app, different
cluster.
Follow k8s/infra/databases/temporal-db.yaml exactly, same as M2.2 did:
imageName pinned, enableSuperuserAccess: false, storageClass: longhorn-cnpg, enablePodMonitor: true, control-plane tolerations,
podAntiAffinityType: preferred.
Instance count — open question, default to convention. Motivation for this whole migration is durability-of-location, not HA (single-machine usage, not a multi-host shared-session requirement). The 3 existing clusters are all 3-instance. Default to 3 instances for consistency with every other app in the cluster rather than special-casing this one to 1; revisit only if resource pressure on the homelab nodes makes it a real tradeoff.
Storage: session rows are tiny (sessions, groups, settings,
review_* — no blobs beyond a snapshot TEXT pane capture per session).
1Gi is generous; no need for memory-db's 10Gi (that one holds
768-dim vectors).
Steps
k8s/infra/databases/agent-manager-db.yaml—Cluster+Database, namespaceagent-manager, no extensions (plain relational, no pgvector).- Namespace
agent-manager, created by the ArgoCD app that owns it. - Add to the owning kustomization's explicit resource list — an unlisted file is silently dropped with no error and no drift shown (the M2.2 task file names this exact trap).
- Commit, push to both Forgejo origin and the GitHub mirror — verify
which
repoURLthe eventual ArgoCDApplicationfor this app actually watches before assuming either push is the one that matters (kongapp, for example, tracks the GitHub mirror specifically, not Forgejo). - Let ArgoCD sync. No
kubectl apply. - Verify the app user can create tables (schema arrives in M6.2, but a
throwaway
CREATE TABLE t(id text); DROP TABLE t;proves connectivity here).
Acceptance
ClusterreachesCluster in healthy state.- ArgoCD shows the app
Synced/Healthy. - No manual
psqlwas run to get there. - Service is ClusterIP-only — not reachable from the LAN directly (M6.4's nginx route is the only path in).
Verify
Harness: kubectl and psql read-only checks after sync.
Integration test — verify/m6.1.sh, output diffed against
expected/m6.1.txt:
a1_cluster_healthy—kubectl get cluster -n agent-manager agent-manager-dbreports all instances ready.a2_clusterip_only—kubectl get svc -n agent-manager -o jsonpath='{.items[*].spec.type}'contains noLoadBalancerorNodePort.a3_argocd_synced— the owning app isSynced/Healthy.a4_app_user_can_ddl— asapp,CREATE TABLE t(id text); DROP TABLE t;succeeds.a5_no_lan_route_yet— connection attempt from outside the cluster network fails at this point in the plan (M6.4 hasn't landed).
Command: bash verify/m6.1.sh | diff - expected/m6.1.txt
False pass:
- Confirming sync without checking service type. A
Clustercan be healthy andSyncedwhile someone fat-fingered aLoadBalancertype into the manifest, silently violating the "dedicated ingress, not raw LAN IP" network-path decision this whole migration made. Assertion 2 is the guard.
Traps
- Forgetting the kustomization resource list (same trap M2.2 already named) — file sits in git, ArgoCD reports Synced, objects never exist.
- Adding
prune: truewithout accounting for CNPG-operator-created children (Services, Secrets, PVCs). M2.2's Traps section already hit this onllm-serving; same fix applies here (prune: false).
Background: k8s/infra/databases/temporal-db.yaml · M2.2 (same pattern, different app)