在单机 Docker 环境下搭建的 PostgreSQL 主从集群虽能满足测试需求,但生产级场景更需要跨主机高可用架构—— 通过多台虚拟机分散风险,避免单点故障导致整个集群不可用。本文将详细讲解如何在三台虚拟机(一主两备)上部署 PostgreSQL 主从集群,并集成 Pgpool 实现负载均衡与自动故障转移,确保数据同步可靠、业务无感知切换。
一、架构设计与环境准备
1.1 集群架构概览
本次部署采用 “1 主 2 备 + 独立 Pgpool” 架构,将数据库节点与负载均衡节点分离部署,各节点职责清晰,架构图如下:
[应用系统] → [Pgpool节点(192.168.1.103)] → 「主库节点(192.168.1.100,写操作)」
→ 「备库1节点(192.168.1.101,读操作)」
→ 「备库2节点(192.168.1.102,读操作)」
1.2 节点规划
| 节点角色 | 虚拟机 IP | 核心功能 | 需开放端口 | 部署软件 |
|---|---|---|---|---|
| PostgreSQL 主库 | 192.168.1.100 | 处理写请求,同步数据到备库 | 5432 | Docker、Docker ***pose |
| PostgreSQL 备库 1 | 192.168.1.101 | 只读节点,同步主库数据,故障时可晋升主库 | 5432 | Docker、Docker ***pose |
| PostgreSQL 备库 2 | 192.168.1.102 | 与备库 1 功能一致,提升读性能与冗余度 | 5432 | Docker、Docker ***pose |
| Pgpool(负载均衡) | 192.168.1.103 | 路由读写请求,自动故障转移,应用唯一入口 | 5432 | Docker、Docker ***pose |
1.3 基础环境准备(所有节点通用)
以CentOS 7/8 或 Ubuntu 20.04+ 为例:为例,所有虚拟机需先完成以下环境配置,确保跨主机通信正常。
步骤 1:安装 Docker 与 Docker ***pose
# 1. 安装依赖包
yum install -y yum-utils device-mapper-persistent-data lvm2
# 2. 添加Docker官方源
yum-config-manager --add-repo https://download.docker.***/linux/centos/docker-ce.repo
# 3. 安装Docker(最新稳定版)
yum install -y docker-ce docker-ce-cli containerd.io
# 4. 启动Docker并设置开机自启
systemctl start docker && systemctl enable docker
# 5. 安装Docker ***pose(v2版本,需替换为最新版链接)
curl -SL https://github.***/docker/***pose/releases/download/v2.27.0/docker-***pose-linux-x86_64 -o /usr/local/bin/docker-***pose
chmod +x /usr/local/bin/docker-***pose
# 验证安装(出现版本号即成功)
docker --version && docker-***pose --version
步骤 2:配置跨主机通信(关键)
跨主机部署的核心前提是 “节点间能互相访问”,需关闭防火墙拦截、禁用 SELinux,并验证网络连通性:
# 1. 临时关闭防火墙(测试环境;生产环境建议开放指定端口,见下文补充)
systemctl stop firewalld && systemctl disable firewalld
# 2. 禁用SELinux(避免权限拦截容器网络)
setenforce 0 # 临时生效
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config # 永久生效
# 3. 验证网络连通性(以主库为例,备库和Pgpool节点需互相ping通)
ping 192.168.1.100 -c 3 # 备库1执行,测试主库可达性
ping 192.168.1.101 -c 3 # 主库执行,测试备库1可达性
二、核心配置文件编写(分节点)
跨主机部署与单机最大的差异是 “用虚拟机 IP 替代容器服务名通信”—— 原单机中通过pg-0这类服务名访问节点,跨主机需改为虚拟机 IP(如192.168.1.100),同时固定数据库端口(5432),确保节点间能精准连接。
2.1 主库节点(192.168.1.100)配置
在主库虚拟机新建目录(如/opt/pg-master),创建docker-***pose.yml文件,核心配置repmgr伙伴节点为 IP 地址:
version: '3.8'
services:
pg-master:
image: docker.io/bitnami/postgresql-repmgr:17 # 含repmgr的PostgreSQL镜像
ports:
- "5432:5432" # 固定宿主机5432端口,备库需通过此端口同步数据
volumes:
- pg_master_data:/bitnami/postgresql # 本地数据卷,持久化主库数据
environment:
# 1. 超级用户配置(postgres,用于权限管理)
- POSTGRESQL_POSTGRES_PASSWORD=adminpassword
# 2. 业务用户配置(应用连接使用,需与备库一致)
- POSTGRESQL_USERNAME=repmgrodoo
- POSTGRESQL_PASSWORD=dwda000409
- POSTGRESQL_DATABASE=customdatabase # 初始业务数据库,自动创建
# 3. repmgr复制配置(核心:跨主机需用IP)
- REPMGR_PASSWORD=repmgrpassword # repmgr工具专用密码
- REPMGR_PRIMARY_HOST=192.168.1.100 # 主库虚拟机IP(自身)
- REPMGR_PRIMARY_PORT=5432
- REPMGR_PARTNER_NODES=192.168.1.100:5432,192.168.1.101:5432,192.168.1.102:5432 # 所有节点IP:端口
- REPMGR_NODE_NAME=pg-master # 节点唯一名称(自定义)
- REPMGR_NODE_***WORK_NAME=192.168.1.100 # 跨主机通信IP
- REPMGR_PORT_NUMBER=5432
- REPMGR_RECONNECT_ATTEMPTS=3 # 断开后重试次数
- REPMGR_RECONNECT_INTERVAL=5 # 重试间隔(秒)
healthcheck:
# 健康检查:确保PostgreSQL服务正常
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
volumes:
pg_master_data:
driver: local # 本地存储(生产环境建议替换为共享存储)
2.2 备库 1 节点(192.168.1.101)配置
在备库 1 虚拟机新建目录(如/opt/pg-standby1),创建docker-***pose.yml,核心是指向主库 IP,确保数据同步:
version: '3.8'
services:
pg-standby1:
image: docker.io/bitnami/postgresql-repmgr:17 # 与主库镜像版本一致
ports:
- "5432:5432" # 固定5432端口,Pgpool需连接
volumes:
- pg_standby1_data:/bitnami/postgresql
environment:
# 1. 超级用户/业务用户配置:与主库完全一致(确保用户同步)
- POSTGRESQL_POSTGRES_PASSWORD=adminpassword
- POSTGRESQL_USERNAME=repmgrodoo
- POSTGRESQL_PASSWORD=dwda000409
- POSTGRESQL_DATABASE=customdatabase
# 2. repmgr复制配置:指向主库IP
- REPMGR_PASSWORD=repmgrpassword
- REPMGR_PRIMARY_HOST=192.168.1.100 # 主库IP(关键,而非服务名)
- REPMGR_PRIMARY_PORT=5432
- REPMGR_PARTNER_NODES=192.168.1.100:5432,192.168.1.101:5432,192.168.1.102:5432
- REPMGR_NODE_NAME=pg-standby1 # 唯一节点名
- REPMGR_NODE_***WORK_NAME=192.168.1.101 # 备库1自身IP
- REPMGR_PORT_NUMBER=5432
- REPMGR_RECONNECT_ATTEMPTS=3
- REPMGR_RECONNECT_INTERVAL=5
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
volumes:
pg_standby1_data:
driver: local
2.3 备库 2 节点(192.168.1.102)配置
与备库 1 配置几乎一致,仅需修改自身 IP 和节点名,在备库 2 虚拟机新建目录(如/opt/pg-standby2),docker-***pose.yml如下:
version: '3.8'
services:
pg-standby2:
image: docker.io/bitnami/postgresql-repmgr:17
ports:
- "5432:5432"
volumes:
- pg_standby2_data:/bitnami/postgresql
environment:
- POSTGRESQL_POSTGRES_PASSWORD=adminpassword
- POSTGRESQL_USERNAME=repmgrodoo
- POSTGRESQL_PASSWORD=dwda000409
- POSTGRESQL_DATABASE=customdatabase
# repmgr配置:仅修改节点名和IP
- REPMGR_PASSWORD=repmgrpassword
- REPMGR_PRIMARY_HOST=192.168.1.100
- REPMGR_PRIMARY_PORT=5432
- REPMGR_PARTNER_NODES=192.168.1.100:5432,192.168.1.101:5432,192.168.1.102:5432
- REPMGR_NODE_NAME=pg-standby2
- REPMGR_NODE_***WORK_NAME=192.168.1.102 # 备库2自身IP
- REPMGR_PORT_NUMBER=5432
- REPMGR_RECONNECT_ATTEMPTS=3
- REPMGR_RECONNECT_INTERVAL=5
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
volumes:
pg_standby2_data:
driver: local
2.4 Pgpool 节点(192.168.1.103)配置
Pgpool 是应用的唯一入口,需配置所有数据库节点的 IP,确保能路由请求。在 Pgpool 虚拟机新建目录(如/opt/pgpool),docker-***pose.yml如下:
version: '3.8'
services:
pgpool:
image: bitnami/pgpool:4 # Pgpool官方镜像,与PostgreSQL兼容
ports:
- "5432:5432" # 固定宿主机5432端口,应用仅需连接此地址
environment:
# 1. 后端数据库节点配置(核心:用虚拟机IP)
- PGPOOL_BACKEND_NODES=0:192.168.1.100:5432,1:192.168.1.101:5432,2:192.168.1.102:5432 # 序号:IP:端口
- PGPOOL_BACKEND_APPLICATION_NAMES=pg-master,pg-standby1,pg-standby2 # 与节点名一一对应
# 2. 主从状态检查配置(用repmgr用户)
- PGPOOL_SR_CHECK_USER=repmgr
- PGPOOL_SR_CHECK_PASSWORD=repmgrpassword
- PGPOOL_ENABLE_LDAP=no # 关闭LDAP,简化配置
# 3. 应用连接配置(与数据库业务用户一致)
- PGPOOL_POSTGRES_USERNAME=repmgrodoo
- PGPOOL_POSTGRES_PASSWORD=dwda000409
# 4. Pgpool管理员配置(用于管理Pgpool自身)
- PGPOOL_ADMIN_USERNAME=pgpool_admin
- PGPOOL_ADMIN_PASSWORD=pgpool_password
# 5. 自动故障转移配置(核心功能)
- PGPOOL_FAILOVER_ON_BACKEND_ERROR=yes # 后端故障时自动触发转移
- PGPOOL_AUTO_FAILBACK=yes # 原主库恢复后自动变为备库
- PGPOOL_NUM_INIT_CHILDREN=32 # 初始子进程数(对应并发连接数)
- PGPOOL_MAX_POOL=4 # 每个后端节点的最大连接池数
healthcheck:
# Pgpool健康检查(用官方脚本)
test: ["CMD", "/opt/bitnami/scripts/pgpool/healthcheck.sh"]
interval: 10s
timeout: 5s
retries: 5
三、集群启动与功能验证
跨主机集群需严格按 “主库 → 备库 1 → 备库 2 → Pgpool” 的顺序启动,避免备库启动时主库未就绪导致同步失败。
3.1 启动主库(192.168.1.100)
# 进入主库配置目录
cd /opt/pg-master
# 后台启动主库(首次启动会初始化数据库和repmgr主节点)
docker-***pose up -d
# 查看主库日志,确认启动成功(关键日志:“repmgr primary register su***essful”)
docker-***pose logs -f pg-master
当日志出现repmgr: su***essfully registered primary node,说明主库初始化完成。
3.2 启动备库 1(192.168.1.101)
# 进入备库1配置目录
cd /opt/pg-standby1
# 启动备库1
docker-***pose up -d
# 查看备库1日志,确认同步成功(关键日志:“repmgr standby register su***essful”)
docker-***pose logs -f pg-standby1
日志出现repmgr: standby registration ***plete,且无connection refused错误,说明备库 1 已成功同步主库数据。
3.3 启动备库 2(192.168.1.102)
操作与备库 1 一致:
cd /opt/pg-standby2
docker-***pose up -d
docker-***pose logs -f pg-standby2
确认日志出现同步成功信息后,再启动 Pgpool。
3.4 启动 Pgpool(192.168.1.103)
# 进入Pgpool配置目录
cd /opt/pgpool
# 启动Pgpool
docker-***pose up -d
# 查看Pgpool日志,确认识别所有节点(关键日志:“backend node 0/1/2 is up”)
docker-***pose logs -f pgpool
当日志出现backend node 0 is up、backend node 1 is up、backend node 2 is up,说明 Pgpool 已成功连接所有数据库节点。
3.5 核心功能验证
验证 1:主从数据同步
-
步骤 1:主库写入数据
在主库虚拟机执行命令,连接主库并插入测试数据:
# 进入主库容器,连接数据库 docker-***pose exec pg-master psql -U repmgrodoo -d customdatabase # 执行SQL:创建表并插入数据 CREATE TABLE test_sync (id INT PRIMARY KEY, content TEXT); INSERT INTO test_sync (id, content) VALUES (1, '跨主机同步测试');