# ───────────────────────────────────────────────────────────────────────── # postgresql/cutover/test/pgha-dryrun.yaml — DISPOSABLE dry-run stack # # Validates the ADR-0001 cutover mechanics WITHOUT touching production: # - own overlay network (pgha-test_db-backend), own stack name # - throwaway "legacy" postgres:17 seeded with marker data, carrying the # in-network alias "postgresql" (mirrors prod CLONE_HOST) # - same etcd/patroni/haproxy topology, images, and env wiring as the # real staging file — including clone-from-live via pg_basebackup # - reuses the real Docker secrets (read-only mounts; harmless) # - disposable data dirs under /volume1/docker/PostgreSQL/dryrun/ # # Deploy: docker stack deploy -c pgha-test # Teardown: docker stack rm pgha-test && rm -rf /volume1/docker/PostgreSQL/dryrun # ───────────────────────────────────────────────────────────────────────── version: "3.6" services: # Stand-in for the production single-instance postgres (clone source) legacy: image: public.ecr.aws/docker/library/postgres:17 hostname: db command: [postgres] environment: POSTGRES_USER: PGadmin POSTGRES_PASSWORD_FILE: /run/secrets/postgresql_password secrets: - postgresql_password volumes: - /volume1/docker/PostgreSQL/dryrun/legacy:/var/lib/postgresql/data networks: db-backend: aliases: - postgresql - db deploy: placement: constraints: - node.hostname == docker-2 etcd-1: image: quay.io/coreos/etcd:v3.5.9 hostname: etcd-1 command: - etcd - --name=etcd-1 - --data-dir=/etcd-data - --initial-advertise-peer-urls=http://etcd-1:2380 - --listen-peer-urls=http://0.0.0.0:2380 - --listen-client-urls=http://0.0.0.0:2379 - --advertise-client-urls=http://etcd-1:2379 - --initial-cluster=etcd-1=http://etcd-1:2380,etcd-2=http://etcd-2:2380,etcd-3=http://etcd-3:2380 - --initial-cluster-state=new - --initial-cluster-token=pgha-test-etcd volumes: - /volume1/docker/PostgreSQL/dryrun/etcd-1:/etcd-data networks: - db-backend deploy: placement: constraints: - node.hostname == docker-1 etcd-2: image: quay.io/coreos/etcd:v3.5.9 hostname: etcd-2 command: - etcd - --name=etcd-2 - --data-dir=/etcd-data - --initial-advertise-peer-urls=http://etcd-2:2380 - --listen-peer-urls=http://0.0.0.0:2380 - --listen-client-urls=http://0.0.0.0:2379 - --advertise-client-urls=http://etcd-2:2379 - --initial-cluster=etcd-1=http://etcd-1:2380,etcd-2=http://etcd-2:2380,etcd-3=http://etcd-3:2380 - --initial-cluster-state=new - --initial-cluster-token=pgha-test-etcd volumes: - /volume1/docker/PostgreSQL/dryrun/etcd-2:/etcd-data networks: - db-backend deploy: placement: constraints: - node.hostname == docker-2 etcd-3: image: quay.io/coreos/etcd:v3.5.9 hostname: etcd-3 command: - etcd - --name=etcd-3 - --data-dir=/etcd-data - --initial-advertise-peer-urls=http://etcd-3:2380 - --listen-peer-urls=http://0.0.0.0:2380 - --listen-client-urls=http://0.0.0.0:2379 - --advertise-client-urls=http://etcd-3:2379 - --initial-cluster=etcd-1=http://etcd-1:2380,etcd-2=http://etcd-2:2380,etcd-3=http://etcd-3:2380 - --initial-cluster-state=new - --initial-cluster-token=pgha-test-etcd volumes: - /volume1/docker/PostgreSQL/dryrun/etcd-3:/etcd-data networks: - db-backend deploy: placement: constraints: - node.hostname == docker-3 patroni-0: image: ghcr.io/zalando/spilo-17:4.0-p3 hostname: patroni-0 command: - /bin/sh - -c - | export PGPASSWORD_SUPERUSER="$(cat /run/secrets/postgresql_password)" export PGPASSWORD_STANDBY="$(cat /run/secrets/postgresql_replication_password)" export PATRONI_RESTAPI_PASSWORD="$(cat /run/secrets/postgresql_patroni_password)" export CLONE_PASSWORD="$(cat /run/secrets/postgresql_password)" exec /bin/sh /launch.sh init environment: SCOPE: pgha-test PATRONI_NAME: patroni-0 ETCD_HOSTS: '"etcd-1:2379","etcd-2:2379","etcd-3:2379"' PGUSER_SUPERUSER: PGadmin PGUSER_STANDBY: standby PATRONI_RESTAPI_USERNAME: patroni PGROOT: /home/postgres/pgdata/pgroot CLONE_METHOD: CLONE_WITH_BASEBACKUP CLONE_SCOPE: legacy-single CLONE_HOST: postgresql CLONE_PORT: "5432" CLONE_USER: PGadmin secrets: - postgresql_password - postgresql_replication_password - postgresql_patroni_password volumes: - /volume1/docker/PostgreSQL/dryrun/patroni-0:/home/postgres/pgdata networks: - db-backend deploy: placement: constraints: - node.labels.pg-role == primary patroni-1: image: ghcr.io/zalando/spilo-17:4.0-p3 hostname: patroni-1 command: - /bin/sh - -c - | export PGPASSWORD_SUPERUSER="$(cat /run/secrets/postgresql_password)" export PGPASSWORD_STANDBY="$(cat /run/secrets/postgresql_replication_password)" export PATRONI_RESTAPI_PASSWORD="$(cat /run/secrets/postgresql_patroni_password)" export CLONE_PASSWORD="$(cat /run/secrets/postgresql_password)" exec /bin/sh /launch.sh init environment: SCOPE: pgha-test PATRONI_NAME: patroni-1 ETCD_HOSTS: '"etcd-1:2379","etcd-2:2379","etcd-3:2379"' PGUSER_SUPERUSER: PGadmin PGUSER_STANDBY: standby PATRONI_RESTAPI_USERNAME: patroni PGROOT: /home/postgres/pgdata/pgroot CLONE_METHOD: CLONE_WITH_BASEBACKUP CLONE_SCOPE: legacy-single CLONE_HOST: postgresql CLONE_PORT: "5432" CLONE_USER: PGadmin secrets: - postgresql_password - postgresql_replication_password - postgresql_patroni_password volumes: - /volume1/docker/PostgreSQL/dryrun/patroni-1:/home/postgres/pgdata networks: - db-backend deploy: placement: constraints: - node.labels.pg-role == replica haproxy: image: haproxy:2.9-alpine hostname: haproxy volumes: - /volume1/docker/compose-files/postgresql/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro networks: - db-backend deploy: mode: global networks: db-backend: attachable: true driver: overlay secrets: postgresql_password: external: true postgresql_replication_password: external: true postgresql_patroni_password: external: true