123 lines
5.0 KiB
Markdown
123 lines
5.0 KiB
Markdown
# 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
|
||
|
||
1. `k8s/infra/databases/agent-manager-db.yaml` — `Cluster` + `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 test** — `verify/m6.1.sh`, output diffed against
|
||
`expected/m6.1.txt`:
|
||
1. `a1_cluster_healthy` — `kubectl get cluster -n agent-manager
|
||
agent-manager-db` reports all instances ready.
|
||
2. `a2_clusterip_only` — `kubectl 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](M2.2-memory-db-manifest.md) (same pattern, different app)
|