如何用Docker创建实时同步的PostgreSQL只读副本容器?
用Docker搭建PostgreSQL主从实时同步并配置只读副本
你的原配置问题在于共享同一个数据卷,这不是PostgreSQL的合法主从同步方式——PostgreSQL运行时会锁定数据文件,两个容器同时访问同一目录不仅无法实现实时同步,还可能导致数据损坏。正确的做法是使用PostgreSQL原生的流复制(Streaming Replication),这是官方支持的异步实时同步方案,同时可以轻松配置只读副本。
一、完整Docker Compose配置
下面是实现主从同步+只读副本的配置,每个容器使用独立的数据卷,通过PostgreSQL原生复制机制同步:
services: db-primary: image: postgres:15 ports: - '5432:5432' environment: - POSTGRES_PASSWORD=postgres - POSTGRES_USER=postgres volumes: - primary_data:/var/lib/postgresql/data/ - ./init-primary.sh:/docker-entrypoint-initdb.d/init-primary.sh command: > postgres -c wal_level=replica -c max_wal_senders=5 -c wal_keep_size=64 -c max_replication_slots=5 db-read-replica: image: postgres:15 ports: - '5433:5432' environment: - POSTGRES_PASSWORD=postgres - POSTGRES_USER=postgres volumes: - replica_data:/var/lib/postgresql/data/ - ./init-replica.sh:/docker-entrypoint-initdb.d/init-replica.sh command: > postgres -c hot_standby=on -c max_connections=100 depends_on: - db-primary volumes: primary_data: replica_data:
二、初始化脚本编写
需要两个初始化脚本,分别配置主库的复制用户和副本的同步参数:
1. 主库初始化脚本 init-primary.sh
#!/bin/bash set -e # 创建复制用户 psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'replpassword'; EOSQL
2. 副本初始化脚本 init-replica.sh
#!/bin/bash set -e # 停止临时PostgreSQL服务,准备从主库拉取备份 pg_ctl stop -D /var/lib/postgresql/data # 清空副本数据目录,从主库拉取基础备份 rm -rf /var/lib/postgresql/data/* pg_basebackup -h db-primary -U replicator -D /var/lib/postgresql/data -P -Xs -R # 启动PostgreSQL服务 pg_ctl start -D /var/lib/postgresql/data
给脚本添加执行权限:
chmod +x init-primary.sh init-replica.sh
三、启动和验证步骤
- 启动容器
docker-compose up -d
- 验证主从同步
- 主库插入测试数据:
docker exec -it db-primary psql -U postgres -c "CREATE TABLE test(id SERIAL PRIMARY KEY, name TEXT); INSERT INTO test(name) VALUES('test data');"
- 副本查询数据,确认同步:
docker exec -it db-read-replica psql -U postgres -c "SELECT * FROM test;"
- 验证只读限制
尝试在副本执行写入操作,会收到权限错误:
docker exec -it db-read-replica psql -U postgres -c "INSERT INTO test(name) VALUES('write attempt');" # 预期报错:ERROR: cannot execute INSERT in a read-only transaction
关键配置说明
- 主库参数:
wal_level=replica:开启复制所需的WAL日志级别max_wal_senders=5:允许的最大复制连接数wal_keep_size=64:保留足够的WAL日志,防止副本跟不上同步max_replication_slots=5:为副本预留复制槽,避免WAL被过早清理
- 副本参数:
hot_standby=on:允许副本在同步过程中提供只读查询服务pg_basebackup:从主库拉取初始数据备份,-R参数自动生成同步配置文件,无需手动编辑postgresql.conf
内容的提问来源于stack exchange,提问作者Johnny Metz
相关产品推荐
相关产品推荐

