You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

三、启动和验证步骤

  1. 启动容器
docker-compose up -d
  1. 验证主从同步
  • 主库插入测试数据:
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;"
  1. 验证只读限制
    尝试在副本执行写入操作,会收到权限错误:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 14:46:02