diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0ab80d8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,6 @@ +FROM postgres:15 + +COPY docker-entrypoint-initdb.d/* /docker-entrypoint-initdb.d/ + +RUN mkdir /wal_archive +VOLUME /wal_archive diff --git a/README.md b/README.md index 52ca1d2..0c8825c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,85 @@ -# postgres15replicate +# postgres15 + +Implement automatic primary and standby + +## Primary + +Example `compose.yaml` for **primary** instance. + +```yaqml +services: + db: + image: pendragon.zone/docker/postgres15replicate + restart: unless-stopped + shm_size: 128mb + environment: + POSTGRES_PASSWORD: ${DB_ROOT_PASSWORD} + REPLICATOR_PASSWORD: ${REPLICATOR_PASSWORD} + MAX_CONNECTIONS: "400" + + network_mode: bridge + ports: + - 5432:5432 + + volumes: + - data:/var/lib/postgresql/data + - /docker/postgres_wal:/wal_archive + +volumes: + data: +``` + +- Volume `/wal_archive` **must** be mapped to a location available by **all** replication participants. + +- `DB_ROOT_PASSWORD` _required_, must be the same for all replication participants. + +- `REPLICATOR_PASSWORD` _required_, must be the same for all replication participants. + +- `UPSTREAM` **must not** be set for **primary** instance. + +- `WAL_ARCHIVE` _default: `/wal_archive`_ use different location for write-ahead-logs. + +- `TRIGGER_FILE` _default: `i_am_primary`_, name of the file that promotes a standby instance to primary instance, if it exists in directory `/var/lib/postgresql/data`. + +- `WAL_KEEP_SIZE` _default: `1GB`_ + +- `REPLICATOR_NAME` _default: `replicator`_ name of user for replication. + +- `MAX_CONNECTIONS` _optional_, change default value of `max_connections` configuration value. + + +## Standby + +Example `compose.yaml` for **standby** instance. + +```yaqml +services: + db: + image: pendragon.zone/docker/postgres15replicate + restart: unless-stopped + shm_size: 128mb + environment: + POSTGRES_PASSWORD: ${DB_ROOT_PASSWORD} + REPLICATOR_PASSWORD: ${REPLICATOR_PASSWORD} + UPSTREAM: ${UPSTREAM} + + network_mode: bridge + ports: + - 5432:5432 + + volumes: + - data:/var/lib/postgresql/data + - /docker/postgres_wal:/wal_archive + +volumes: + data: +``` + +- Volume `/wal_archive` **must** be mapped to a location available by **all** replication participants. + +- `DB_ROOT_PASSWORD` _required_, must be the same for all replication participants. + +- `REPLICATOR_PASSWORD` _required_, must be the same for all replication participants. + +- `UPSTREAM` _required_, name of the node to replicate from. Can either be **primary** or a different **standby** instance. diff --git a/docker-entrypoint-initdb.d/00-main.sh b/docker-entrypoint-initdb.d/00-main.sh new file mode 100755 index 0000000..b1c990b --- /dev/null +++ b/docker-entrypoint-initdb.d/00-main.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +# the variable UPSTREAM indicates that a standby instance is requested, otherwise this is primary +if [[ -z $UPSTREAM ]]; then + + # ensure required entries in configuration + # shellcheck disable=SC2129 + echo "archive_command = 'cp %p ${WAL_ARCHIVE:-/wal_archive}/%f'" >> /var/lib/postgresql/data/postgresql.conf + echo "archive_mode = on" >> /var/lib/postgresql/data/postgresql.conf + echo "hot_standby = on" >> /var/lib/postgresql/data/postgresql.conf + echo "promote_trigger_file = '/var/lib/postgresql/data/${TRIGGER_FILE:-i_am_primary}'" >> /var/lib/postgresql/data/postgresql.conf + echo "wal_keep_size = ${WAL_KEEP_SIZE:-1GB}" >> /var/lib/postgresql/data/postgresql.conf + echo "wal_level = replica" >> /var/lib/postgresql/data/postgresql.conf + # ensure required entries in hba + echo "host replication ${REPLICATOR_NAME:-replicator} all md5" >> /var/lib/postgresql/data/pg_hba.conf + # create user for replication + psql -c "CREATE USER ${REPLICATOR_NAME:-replicator} WITH REPLICATION ENCRYPTED PASSWORD '${REPLICATOR_PASSWORD}'; GRANT CONNECT ON DATABASE postgres TO ${REPLICATOR_NAME:-replicator}" + + + # process selected tweaks + if [[ -n $MAX_CONNECTIONS ]]; then + echo "max_connections = ${MAX_CONNECTIONS}" >> /var/lib/postgresql/data/postgresql.conf + fi + +else +# this is a standby + source /usr/local/bin/docker-entrypoint.sh + + docker_temp_server_stop + + rm -rf /var/lib/postgresql/data/* + + OLD_PGPASSWORD=$PGPASSWORD + export PGPASSWORD=$REPLICATOR_PASSWORD + pg_basebackup -h "${UPSTREAM}" -U "${REPLICATOR_NAME:-replicator}" -D "${PGDATA}" -Fp -Xs -P -R + export PGPASSWORD=$OLD_PGPASSWORD + +fi