Files
poimen-memory/tasks/M2.2-memory-db-manifest.md
T

4.1 KiB
Raw Blame History

M2.2 — CNPG memory-db + pgvector

Field Value
Phase M2 — Projections
Size M — 13 days
Status Done
Flags homelab
Spec inlined below
Blocks

Goal

A Postgres with pgvector, provisioned the way everything else in the cluster is: through git, with no manual psql.

Facts (inlined — no spec read needed)

pgvector needs no custom image. Verified on the running cluster:

$ psql -tAc "select name,default_version,installed_version
             from pg_available_extensions where name='vector'"
vector|0.7.0|

on the stock ghcr.io/cloudnative-pg/postgresql:16.2. Available, not yet installed — CREATE EXTENSION is all that is missing.

The operator is CNPG 1.30.0, which supports declarative extensions on the Database CRD (kubectl explain database.spec.extensions resolves). So the extension is git-managed too — no manual step, consistent with the GitOps rule that infrastructure changes flow through version control.

Follow k8s/infra/databases/temporal-db.yaml exactly: 3 instances, imageName pinned, enableSuperuserAccess: false, storageClass: longhorn-cnpg, enablePodMonitor: true, control-plane tolerations, podAntiAffinityType: preferred.

Storage: 10Gi matches the existing clusters. At 768 dims × 4 bytes, a vector is ~3 KB; tens of thousands of nodes is well under a gigabyte, so 10Gi is generous and consistent rather than tight.

Steps

  1. k8s/infra/databases/memory-db.yamlCluster + Database with extensions: [{name: vector, ensure: present}].
  2. Namespace memory, 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.
  4. Commit, push, let ArgoCD sync. No kubectl apply.
  5. Verify the extension installed and the app user can create tables.
  6. Record the connection string convention in the repo README; the password comes from the CNPG-generated secret, never committed.

Acceptance

  • Cluster reaches Cluster in healthy state with 3 instances.
  • select extversion from pg_extension where extname='vector' returns a version.
  • ArgoCD shows the app Synced/Healthy.
  • No manual psql was run to get there.

Verify

Harness: kubectl and psql read-only checks after sync.

Integration testverify/m2.2.sh, output diffed against expected/m2.2.txt:

  1. a1_cluster_healthykubectl get cluster -n memory memory-db reports 3/3 ready.
  2. a2_extension_installedselect extname, extversion from pg_extension where extname='vector' returns one row.
  3. a3_declarative_not_manualkubectl get database -n memory memory-db-vector -o jsonpath='{.spec.extensions}' shows the declaration, proving it came from git.
  4. a4_argocd_synced — the owning app is Synced/Healthy.
  5. a5_app_user_can_ddl — as app, CREATE TABLE t(v vector(768)); DROP TABLE t; succeeds.
  6. a6_hnsw_availableCREATE INDEX ... USING hnsw on that temp table succeeds, proving 0.7.0 has the index type the schema needs.

Command: bash verify/m2.2.sh | diff - expected/m2.2.txt

False pass:

  • Checking pg_available_extensions instead of pg_extension. Available means the files are on disk; installed means CREATE EXTENSION ran. The whole task is the second one.
  • Verifying after a manual CREATE EXTENSION. It passes and proves nothing about the declarative path, which is the actual deliverable. Assertion 3 is the guard.

Traps

  • Forgetting the kustomization resource list. The file sits in git, ArgoCD reports Synced, and the objects never exist — silent, and the failure surfaces later as a connection error.
  • Adding prune: true semantics without thinking about operator-created children. CNPG creates Services, Secrets and PVCs owned by the Cluster; if ArgoCD's tracking label propagates to them, prune fights the operator. The llm-serving app already had to set prune: false for exactly this reason.

Background: DESIGN.md — pgvector · k8s/infra/databases/temporal-db.yaml