feat(compose): opt-in external-Postgres override
Adds `docker-compose.external-db.yml` so teams can point the stack at a managed Postgres (RDS, Cloud SQL, etc.) without forking the base compose file. Disables the bundled `db` service via an unreachable `profiles` label and replaces `depends_on` / `DATABASE_URL` on `migrator` and `app` with `!override`-tagged blocks that read `DATABASE_URL` straight from `.env`. Default `docker compose up -d` flow is unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,10 @@ POSTGRES_DB=memory
|
|||||||
# if you point at an external Postgres.
|
# if you point at an external Postgres.
|
||||||
# DATABASE_URL=postgres://memory:...@db:5432/memory
|
# DATABASE_URL=postgres://memory:...@db:5432/memory
|
||||||
|
|
||||||
|
# When using docker-compose.external-db.yml, set DATABASE_URL explicitly.
|
||||||
|
# Example for AWS RDS Postgres with SSL:
|
||||||
|
# DATABASE_URL=postgres://memory:STRONG_PASSWORD@your-rds.region.rds.amazonaws.com:5432/memory?sslmode=require
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Embedder sidecar. Default points at the in-compose service.
|
# Embedder sidecar. Default points at the in-compose service.
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -133,6 +133,77 @@ Mode column: **A** = external proxy (default), **B** = built-in Caddy TLS.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## External Postgres (RDS, Cloud SQL, etc.)
|
||||||
|
|
||||||
|
By default the compose stack runs a bundled `pgvector/pgvector:pg16` container
|
||||||
|
with its data on a Docker volume. For production deployments you may prefer
|
||||||
|
a managed Postgres (AWS RDS, GCP Cloud SQL, Azure Database for PostgreSQL,
|
||||||
|
…). An opt-in override file disables the bundled `db` service and lets the
|
||||||
|
app point at any reachable Postgres.
|
||||||
|
|
||||||
|
### When to use
|
||||||
|
|
||||||
|
- You already have a managed Postgres you trust (point-in-time recovery,
|
||||||
|
automated snapshots, monitoring, IAM, etc.).
|
||||||
|
- You want to scale the database independently of the app host.
|
||||||
|
- Compliance / data-residency rules require the DB to live elsewhere.
|
||||||
|
|
||||||
|
If none of that applies, the bundled `db` is fine — keep using
|
||||||
|
`docker compose up -d` and skip this section.
|
||||||
|
|
||||||
|
### Connection requirements
|
||||||
|
|
||||||
|
- The DB must be reachable from wherever the app runs (security group /
|
||||||
|
firewall / VPC peering / private link as appropriate).
|
||||||
|
- SSL is strongly recommended. For RDS append `?sslmode=require` to the URL.
|
||||||
|
- The DB user needs enough privileges on first boot to install extensions
|
||||||
|
(`pgvector`, `pg_trgm`, `pgcrypto`). The migrator runs
|
||||||
|
`CREATE EXTENSION IF NOT EXISTS` for each — on RDS the user needs the
|
||||||
|
`rds_superuser` role, or have an admin pre-create the extensions and
|
||||||
|
grant the app's user `USAGE` on them.
|
||||||
|
|
||||||
|
### Extension requirements
|
||||||
|
|
||||||
|
- **pgvector** — vector search. RDS Postgres ≥ 15.5 ships pgvector as a
|
||||||
|
trusted extension; 16.x (what this project targets) supports it out of
|
||||||
|
the box. Cloud SQL and Azure Database for PostgreSQL also expose it as
|
||||||
|
a flagged / configurable extension.
|
||||||
|
- **pg_trgm** — trigram index for hybrid lexical search.
|
||||||
|
- **pgcrypto** — `gen_random_uuid()` for ID generation.
|
||||||
|
|
||||||
|
### Compose invocation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.external-db.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Set `DATABASE_URL` in `.env` to your managed-DB connection string before
|
||||||
|
running this — the `POSTGRES_*` variables are no longer consulted in this
|
||||||
|
mode. See `.env.example` for the RDS-style example URL.
|
||||||
|
|
||||||
|
Combine with the built-in TLS profile if you want Caddy as well:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.yml -f docker-compose.external-db.yml --profile tls up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### What about backups?
|
||||||
|
|
||||||
|
You give up the `db_data` volume (which you'd back up with whatever volume
|
||||||
|
backup story you already use) and inherit your managed provider's backup
|
||||||
|
story instead — RDS automated snapshots + point-in-time recovery, Cloud SQL
|
||||||
|
automated backups, Azure server-level backups, etc. In practice this is the
|
||||||
|
main reason to switch: pushing backup-and-restore to a managed service that
|
||||||
|
already does it well.
|
||||||
|
|
||||||
|
### AWS Fargate / managed deploy
|
||||||
|
|
||||||
|
For a fully-managed deployment (Fargate app + RDS DB, no Docker host of
|
||||||
|
your own), see [`terraform/README.md`](terraform/README.md) for an
|
||||||
|
opinionated Terraform module that wires it all up.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## OIDC provider setup
|
## OIDC provider setup
|
||||||
|
|
||||||
You need **two** OAuth2 / OIDC clients on your identity provider:
|
You need **two** OAuth2 / OIDC clients on your identity provider:
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# =============================================================================
|
||||||
|
# shared-memory — external Postgres override.
|
||||||
|
#
|
||||||
|
# Use this override when you want to point the app at a managed Postgres
|
||||||
|
# (AWS RDS, GCP Cloud SQL, Azure Database for PostgreSQL, your own VM, ...)
|
||||||
|
# instead of the bundled `db` container.
|
||||||
|
#
|
||||||
|
# Invocation (always together with the base file):
|
||||||
|
#
|
||||||
|
# docker compose -f docker-compose.yml -f docker-compose.external-db.yml up -d
|
||||||
|
#
|
||||||
|
# The caller MUST set `DATABASE_URL` explicitly in `.env` so that `migrator`
|
||||||
|
# and `app` know where to connect. The `POSTGRES_*` variables are not used
|
||||||
|
# in this mode (the bundled `db` service is disabled below). Example:
|
||||||
|
#
|
||||||
|
# DATABASE_URL=postgres://memory:STRONG_PASSWORD@your-rds.region.rds.amazonaws.com:5432/memory?sslmode=require
|
||||||
|
#
|
||||||
|
# The DB user needs privileges to `CREATE EXTENSION` for pgvector, pg_trgm,
|
||||||
|
# and pgcrypto on first run — on RDS that means the `rds_superuser` role, or
|
||||||
|
# pre-create the extensions yourself. See README "External Postgres".
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
# Park the bundled DB on a profile that nothing ever enables. Compose
|
||||||
|
# only starts services whose profile list is empty OR matches a
|
||||||
|
# `--profile` flag on the command line. "never" is not a magic name —
|
||||||
|
# it's just a label we promise not to pass, so the service stays down.
|
||||||
|
profiles: ["never"]
|
||||||
|
|
||||||
|
migrator:
|
||||||
|
# Docker compose merges `depends_on` by key — listing `embedder` here
|
||||||
|
# alone would keep the base file's `db` entry and break with
|
||||||
|
# "depends on undefined service db". The `!override` tag (compose 2.24+)
|
||||||
|
# replaces the whole block instead of merging.
|
||||||
|
depends_on: !override
|
||||||
|
embedder:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
# The base file hardcodes DATABASE_URL to point at the bundled `db`
|
||||||
|
# service. Override it to pass through whatever the operator set in
|
||||||
|
# `.env` (e.g. an RDS endpoint with sslmode=require).
|
||||||
|
DATABASE_URL: ${DATABASE_URL:?DATABASE_URL not set in .env (required with external-db override)}
|
||||||
|
|
||||||
|
app:
|
||||||
|
# Same merge caveat as above — fully replace the block, keep embedder
|
||||||
|
# and migrator deps.
|
||||||
|
depends_on: !override
|
||||||
|
embedder:
|
||||||
|
condition: service_healthy
|
||||||
|
migrator:
|
||||||
|
condition: service_completed_successfully
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: ${DATABASE_URL:?DATABASE_URL not set in .env (required with external-db override)}
|
||||||
Reference in New Issue
Block a user