# Docker integration cluster (ParadeDB + pg_replica)
A 3-node **ParadeDB** cluster with **pg_replica** automatic Raft failover, plus
**Dozzle** for log viewing — for integration testing.
## Quick start
```bash
cd docker
cp .env.example .env
docker compose up --build
```
First boot: `node1` seeds (initdb + roles + `CREATE EXTENSION pg_search` + `pg_replica`),
then `node2`/`node3` `pg_basebackup` from it and join the Raft group. Watch it form in
Dozzle (http://localhost:8888) or:
```bash
docker compose exec node1 psql -U postgres -c 'SELECT replica.status();'
```
## Connecting (the app follows the primary, no proxy)
Each node's Postgres is published on the host: node1 `5432`, node2 `5433`, node3 `5434`.
Use a libpq multi-host string with `target_session_attrs=read-write` — it auto-selects
the current primary and, after a failover, reconnects to the new one:
```
postgresql://weido:weido_test_pw@localhost:5432,localhost:5433,localhost:5434/weido?target_session_attrs=read-write
```
(Credentials are the `APP_USER` / `APP_PASSWORD` / `APP_DB` from `.env`
## Watch a failover
```bash
docker compose stop node1 # kill the primary
docker compose exec node2 psql -U postgres -c 'SELECT replica.status();' # node2 or node3 promotes
docker compose start node1 # old primary pg_rewind-rejoins as a standby
```
With `SYNCHRONOUS=on` (default) every acknowledged commit is on a quorum, so failover
is zero committed-transaction loss.
## How the extension is built and installed
`docker/Dockerfile` is multi-stage and **auto-detects ParadeDB's Postgres major version**,
so it always builds against the right PG:
1. **builder** (`FROM paradedb/paradedb:v0.23.1`): installs Rust + `cargo-pgrx 0.18.1` and
the build deps, then
```bash
PGVER=$(pg_config --version | grep -oE '[0-9]+' | head -1) cargo pgrx install --release --no-default-features --features pg${PGVER} \
--pg-config "$(command -v pg_config)"
```
which compiles `pg_replica.so` and installs it into ParadeDB's `pkglibdir` + the
`.control` / `--<ver>.sql` files into its `sharedir/extension`.
2. **runtime** (`FROM paradedb/paradedb:v0.23.1`): copies just those three artifacts onto a
clean image, adds the control-plane helpers (`rejoin.sh`, `watchdog.sh`), and uses
`entrypoint.sh` to seed/replica each node.
`entrypoint.sh` sets `shared_preload_libraries = 'pg_search,pg_replica'` and the per-node
`pg_replica.*` GUCs (node id, raft port, peers, pg_addrs, passfile, synchronous). Auth is
**SCRAM everywhere, no trust** (a chmod-600 `~/.pgpass` holds the replicator + superuser
passwords; `initdb -A scram-sha-256 --pwfile` bootstraps the superuser).