



























postgres 版本: 17
机器A (192.168.1.10)
├── tailserver (现有容器,保持不变,单机独立)
├── pg-0 (新增:PostgreSQL主库 + repmgr)
└── 端口:5432 (主库)
机器B (192.168.1.20)
├── pg-1 (新增:PostgreSQL从库 + repmgr)
└── 端口:5433 (从库备用)
└── Witness容器 (新增:仅仲裁,不存数据)

本文以测试环境为例:只有一台机器,一个docker 创建三个容器
1) 先拉取 postgres-repmgr 镜像
docker pull docker.io/bitnamilegacy/postgresql-repmgr:17
docker inspect docker.io/bitnamilegacy/postgresql-repmgr:17 | findstr "Architecture"
docker pull postgis/postgis:17-3.6-alpine
2) 创建Dockerfile ,安装 postgis 插件
目录 :D:\武清服务器-路网\images-amd-common\postgis-repmgr
FROM docker.io/bitnamilegacy/postgresql-repmgr:17
USER root
# 安装必要工具(包括 gpg)
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
ca-certificates \
lsb-release \
gnupg2 \
&& rm -rf /var/lib/apt/lists/*
# 添加 PostgreSQL 官方 APT 源
RUN curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg && \
echo "deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
apt-get update
# 安装 PostGIS
RUN apt-get install -y --no-install-recommends \
postgresql-17-postgis-3 \
postgresql-17-postgis-3-scripts \
&& rm -rf /var/lib/apt/lists/*
USER 1001
3) 生成镜像
docker build -t postgis-repmgr:17 .
4) 核验
docker run --rm postgis-repmgr:17 postgres --version

docker run --rm postgis-repmgr:17 repmgr --version

1) 创建映射目录
创建映射文件,这两个文件内容一样
D:\DockerMapping\postgis-repmgr\data-0\conf.d\replication.conf
D:\DockerMapping\postgis-repmgr\data-1\conf.d\replication.conf
wal_level = replica max_wal_senders = 16 max_replication_slots = 16 hot_standby = on wal_log_hints = on listen_addresses = '*' archive_mode = on archive_timeout = 300 archive_command = 'test ! -f /bitnami/postgresql/archive/%f && cp %p /bitnami/postgresql/archive/%f' shared_preload_libraries = 'repmgr,pg_stat_statements' pg_stat_statements.track = all pg_stat_statements.max = 10000 pg_stat_statements.save = on
2) 确认两台机器的 IP 地址
查看代码
# 节点1:主库候选
postgis-node-0:
image: postgis-repmgr:17
container_name: postgis-node-0
hostname: pg-node-0
restart: always
ports:
- "25432:5432"
environment:
- POSTGRESQL_POSTGRES_PASSWORD=Gres*1299
- POSTGRESQL_USERNAME=postgres
- POSTGRESQL_PASSWORD=Gres*1299
- POSTGRESQL_DATABASE=gis_db
- REPMGR_USERNAME=repmgr
- REPMGR_PASSWORD=Gres*1299
- REPMGR_DATABASE=repmgr_db
- REPMGR_NODE_ID=1
- REPMGR_NODE_NAME=pg-node-0
- REPMGR_NODE_NETWORK_NAME=pg-node-0
- REPMGR_PRIMARY_HOST=pg-node-0
- REPMGR_PARTNER_NODES=pg-node-0:5432,pg-node-1:5432,pg-witness-0:5432
- REPMGR_FAILOVER=automatic
- REPMGR_CONNECT_TIMEOUT=5
- REPMGR_RECONNECT_ATTEMPTS=3
- REPMGR_CHILD_NODES_CHECK_INTERVAL=5
- POSTGRESQL_NUM_SYNCHRONOUS_REPLICAS=0
# 关键
- REPMGRD_ENABLED=yes
volumes:
- D:\DockerMapping\postgis-repmgr\data-0:/bitnami/postgresql
- D:\DockerMapping\postgis-repmgr\data-0\conf.d:/opt/bitnami/postgresql/conf/conf.d
- D:\DockerMapping\postgis-repmgr\data-0\archive:/bitnami/postgresql/archive
- D:\DockerMapping\postgis-repmgr\db-back:/db-back
networks:
- pgnet
# 节点2:从库候选
postgis-node-1:
image: postgis-repmgr:17
container_name: postgis-node-1
hostname: pg-node-1
restart: always
ports:
- "35432:5432"
environment:
- POSTGRESQL_POSTGRES_PASSWORD=Gres*1299
- POSTGRESQL_USERNAME=postgres
- POSTGRESQL_PASSWORD=Gres*1299
- POSTGRESQL_DATABASE=gis_db
- REPMGR_USERNAME=repmgr
- REPMGR_PASSWORD=Gres*1299
- REPMGR_DATABASE=repmgr_db
- REPMGR_NODE_ID=2
- REPMGR_NODE_NAME=pg-node-1
- REPMGR_NODE_NETWORK_NAME=pg-node-1
- REPMGR_PRIMARY_HOST=pg-node-0
- REPMGR_PARTNER_NODES=pg-node-0:5432,pg-node-1:5432,pg-witness-0:5432
- REPMGR_FAILOVER=automatic
- REPMGR_CONNECT_TIMEOUT=5
- REPMGR_RECONNECT_ATTEMPTS=3
- REPMGR_CHILD_NODES_CHECK_INTERVAL=5
- POSTGRESQL_NUM_SYNCHRONOUS_REPLICAS=0
# 关键
- REPMGRD_ENABLED=yes
volumes:
- D:\DockerMapping\postgis-repmgr\data-1:/bitnami/postgresql
- D:\DockerMapping\postgis-repmgr\data-1\conf.d:/opt/bitnami/postgresql/conf/conf.d
- D:\DockerMapping\postgis-repmgr\data-1\archive:/bitnami/postgresql/archive
- D:\DockerMapping\postgis-repmgr\db-back:/db-back
networks:
- pgnet
# 节点3:Witness 见证节点
postgis-witness:
image: postgis-repmgr:17
container_name: postgis-witness
hostname: pg-witness-0
restart: always
ports:
- "45433:5432"
environment:
- POSTGRESQL_POSTGRES_PASSWORD=Gres*1299
- POSTGRESQL_USERNAME=repmgr
- POSTGRESQL_PASSWORD=Gres*1299
- POSTGRESQL_DATABASE=repmgr_db
- REPMGR_USERNAME=repmgr
- REPMGR_PASSWORD=Gres*1299
- REPMGR_DATABASE=repmgr_db
- REPMGR_NODE_ID=1002
- REPMGR_NODE_NAME=pg-witness-0
- REPMGR_NODE_NETWORK_NAME=pg-witness-0
- REPMGR_NODE_TYPE=witness
- REPMGR_PRIMARY_HOST=pg-node-0
- REPMGR_PARTNER_NODES=pg-node-0:5432,pg-node-1:5432,pg-witness-0:5432
- REPMGRD_ENABLED=yes
volumes:
- D:\DockerMapping\postgis-repmgr\data-witness:/bitnami/postgresql
networks:
- pgnet
networks:
pgnet:
driver: bridge
4) 启动
在 D:\DockerConfig 目录下,CMD 执行
docker-compose up -d postgis-node-0
docker-compose up -d postgis-node-1
docker-compose up -d postgis-witness
Bitnami 镜像在启动时会自动尝试注册或加入集群。
1) 查看日志:
2) 校验,查看状态
从库是否成功连接到主库
WAL 日志是否在实时传输
数据是否正在同步
docker exec -it postgis-node-0 psql -U postgres -c "SELECT application_name, state, sync_state FROM pg_stat_replication;"输入密码:
Gres*1299
docker exec -it -u postgres postgis-node-0 /opt/bitnami/repmgr/bin/repmgr -f /opt/bitnami/repmgr/conf/repmgr.conf cluster show
- primary:主库
- standby:从库
- witness:仅仲裁
docker exec -it postgis-node-0 bash -c "PGPASSWORD='Gres*1299' psql -U postgres -c 'SELECT pg_is_in_recovery();'"
docker exec -it postgis-node-1 bash -c "PGPASSWORD='Gres*1299' psql -U postgres -c 'SELECT pg_is_in_recovery();'"返回 t 代表从库,f 代表主库
docker exec -it postgis-node-0 bash
psql -U postgres输入密码:
Gres*1299
SHOW wal_level;
SHOW max_wal_senders;
SHOW shared_preload_libraries;
1. postgis-node-0 (主库 primary) 容器关闭
docker stop postgis-node-0
2. postgis-node-1(从库 standby),30秒内自动提升为主库
3. 观查日志或集群视图
docker exec -it -u postgres postgis-node-0 /opt/bitnami/repmgr/bin/repmgr -f /opt/bitnami/repmgr/conf/repmgr.conf cluster show

4. postgis-node-0 容器再次启动
会自动以从库(standby)的角色启动
1) 脑裂问题
如发生脑裂时,即 postgis-node-0 与 postgis-node-1 都认为自已是主库
解决方案:
删除 postgis-node-1 容器
删除 映射的 data-1 文件
重新生成 postgis-node-1 容器
2)docker 重启时
情况:异常断电、宿主机强制关机、docker 容器down,导致 PostgreSQL 未正常关闭
重新启动时会出现这样的问题
[ERROR] PID file "/tmp/repmgrd.pid" exists and seems to contain a valid PID
解决方案:
重新创建容器
docker rm -f postgis-node-0
docker compose up -d postgis-node-0
主库执行后,从库会自动同步
docker exec -it postgis-node-0 bash -c "PGPASSWORD='Gres*1299' psql -U postgres -d gis_db -c 'CREATE EXTENSION IF NOT EXISTS postgis;'"
docker exec -it postgis-node-0 bash -c "PGPASSWORD='Gres*1299' psql -U postgres -d gis_db -c 'SELECT PostGIS_Version();'"
docker exec -it postgis-node-0 bash -c "PGPASSWORD='Gres*1299' psql -U postgres -d gis_db -c \"CREATE EXTENSION IF NOT EXISTS pg_stat_statements;\""

![]()
Sql 文件:docker exec -it postgis-node-0 bash -c "PGPASSWORD='Gres*1299' psql -U postgres -d postgres < /db-back/db_railnet.sql"
Dump 文件: docker exec -it postgis-node-0 bash -c "PGPASSWORD='Gres*1299' pg_restore -U postgres -d postgres /db-back/db_railnet.dump"
结果查看
docker exec -it postgis-node-0 bash -c "PGPASSWORD='Gres*1299' psql -U postgres -d postgres -c '\dt'"
可在镜像中集成 pgBackRest 工具,未实验
测试项目:.net8
安装包:
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"PGRepmgr": "Host=localhost:25432,localhost:35432;Username=postgres;Password=Gres*1299;Database=postgres;Target Session Attributes=read-write;Pooling=true;Minimum Pool Size=2;Maximum Pool Size=20;Connection Idle Lifetime=300;Connection Pruning Interval=60;Timeout=5;Keepalive=30;"
},
"AllowedHosts": "*"
}
| 参数 | 你的值 | 含义 | 作用 |
|---|---|---|---|
Host |
localhost:25432,localhost:35432 |
服务器地址列表 | 按顺序尝试连接,第一个失败自动试下一个 |
Username |
postgres |
登录用户名 | 数据库身份验证 |
Password |
Gres*1299 |
登录密码 | 数据库身份验证 |
Database |
gis_db |
默认数据库名 | 连接后自动切换到该库 |
Target Session Attributes |
read-write |
目标会话属性 | 只连接到可读写的节点(主库) |
Pooling |
true |
启用连接池 | 复用连接,提高性能 |
Minimum Pool Size |
2 |
最小连接池大小 | 池中至少保持2个空闲连接 |
Maximum Pool Size |
20 |
最大连接池大小 | 池中最多20个连接 |
Connection Idle Lifetime |
300 |
空闲连接生命周期 | 空闲300秒(5分钟)后回收 |
Connection Pruning Interval |
60 |
连接修剪间隔 | 每60秒检查一次,清理无效连接 |
Timeout |
5 |
连接超时 | 5秒内连不上就失败,加快故障检测 |
Keepalive |
30 |
心跳间隔 | 每30秒发送心跳,检测连接是否活着 |
Program.cs
#region == EF,Dapper ==
string DbConnectionString_PGRepmgr = configuration.GetSection("ConnectionStrings:PGRepmgr").Value;
Console.WriteLine("Connection PGRepmgr: " + DbConnectionString_PGRepmgr);
builder.Services.AddDbContext<DataBasePGRepmgr>(option => option.UseNpgsql(DbConnectionString_PGRepmgr));
#endregion
在 nuget 包管理器控制台中执行,还原实体类
Scaffold-DbContext -Connection "Host=localhost:25432,localhost:35432;Username=postgres;Password=Gres*1299;Database=postgres;Target Session Attributes=read-write;Pooling=true;Minimum Pool Size=2;Maximum Pool Size=20;" -Provider Npgsql.EntityFrameworkCore.PostgreSQL -Schemas public -OutputDir Models -ContextDir Context -Context DataBasePGRepmgr -Force -UseDatabaseNames -NoOnConfiguring
接口:
using Microsoft.AspNetCore.Mvc;
using NETCORE.PGRepmgr.Models.Context;
namespace NETCORE.PGRepmgr.All.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class LineController : ControllerBase
{
private readonly DataBasePGRepmgr DB;
public LineController(DataBasePGRepmgr db)
{
this.DB = db;
}
[HttpGet]
[Route("Top10")]
public ActionResult Top10()
{
var arr = DB.lines.Take(10).Select(a => new { a.id, a.name }).ToList();
return Ok(arr);
}
}
}
end.
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。