Files
poimen-memory/tasks/M6.1-agent-manager-db-manifest.md

5.0 KiB
Raw Permalink Blame History

M6.1 — CNPG agent-manager-db manifest

Field Value
Phase M6 — agent-manager migration
Size M — 13 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

  1. k8s/infra/databases/agent-manager-db.yamlCluster + Database, namespace agent-manager, no extensions (plain relational, no pgvector).
  2. Namespace agent-manager, created by the ArgoCD app that owns it.
  3. 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).
  4. Commit, push to both Forgejo origin and the GitHub mirror — verify which repoURL the eventual ArgoCD Application for this app actually watches before assuming either push is the one that matters (kong app, for example, tracks the GitHub mirror specifically, not Forgejo).
  5. Let ArgoCD sync. No kubectl apply.
  6. 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

  • Cluster reaches Cluster in healthy state.
  • ArgoCD shows the app Synced/Healthy.
  • No manual psql was 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 testverify/m6.1.sh, output diffed against expected/m6.1.txt:

  1. a1_cluster_healthykubectl get cluster -n agent-manager agent-manager-db reports all instances ready.
  2. a2_clusterip_onlykubectl get svc -n agent-manager -o jsonpath='{.items[*].spec.type}' contains no LoadBalancer or NodePort.
  3. a3_argocd_synced — the owning app is Synced/Healthy.
  4. a4_app_user_can_ddl — as app, CREATE TABLE t(id text); DROP TABLE t; succeeds.
  5. 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 Cluster can be healthy and Synced while someone fat-fingered a LoadBalancer type 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: true without accounting for CNPG-operator-created children (Services, Secrets, PVCs). M2.2's Traps section already hit this on llm-serving; same fix applies here (prune: false).

Background: k8s/infra/databases/temporal-db.yaml · M2.2 (same pattern, different app)