惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Troy Hunt's Blog
P
Proofpoint News Feed
V
Vulnerabilities – Threatpost
C
Cybersecurity and Infrastructure Security Agency CISA
K
Kaspersky official blog
Cyberwarzone
Cyberwarzone
T
Tor Project blog
Cisco Talos Blog
Cisco Talos Blog
S
Securelist
L
Lohrmann on Cybersecurity
Security Latest
Security Latest
T
Threatpost
H
Heimdal Security Blog
W
WeLiveSecurity
A
Arctic Wolf
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
G
GRAHAM CLULEY
IT之家
IT之家
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
TaoSecurity Blog
TaoSecurity Blog
A
About on SuperTechFans
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
Last Week in AI
Last Week in AI
T
The Blog of Author Tim Ferriss
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Microsoft Azure Blog
Microsoft Azure Blog
Hugging Face - Blog
Hugging Face - Blog
Google DeepMind News
Google DeepMind News
量子位
Stack Overflow Blog
Stack Overflow Blog
Know Your Adversary
Know Your Adversary
B
Blog RSS Feed
阮一峰的网络日志
阮一峰的网络日志
WordPress大学
WordPress大学
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
AI
AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
GbyAI
GbyAI
Vercel News
Vercel News
C
Cyber Attacks, Cyber Crime and Cyber Security
Latest news
Latest news
D
Darknet – Hacking Tools, Hacker News & Cyber Security
大猫的无限游戏
大猫的无限游戏
Forbes - Security
Forbes - Security

博客园 - 无心々菜

高并发 - 配置2 高并发 - 配置 地图 - QGIS加载geojson,并导入Postgis数据库 VUE2 - Geoserver打印矢量PDF地图 - 在VUE2中的应用 地图 - Geoserver打印矢量PDF地图 Docker - 离线+无root环境安装 docker-rootless 运维 - 哪吒监控 Postgres 数据库在docker环境下分布式部署(arm64框架) Https - 配置方案 OpenObserver - 系统接口监控 VUE3 - Docker部署 + traefik反代 VUE2 - Docker部署 + traefik反代 高斯DB 数据库的安装 NETCORE - 使用 EFCORE 调用 高斯DB数据库 JMeter - 压力测试 NETCORE - IdentityServer4 多节点部署 NETCORE - IdentityServer4 相关文档 .NET框架 - NETCORE + API + EF(DBFirst) + PostgresSql Docker 部署 APISIX + etcd Docker部署martin 矢量切片服务器 Postgres 数据库的安装 NETCORE - 调用 RUSTFS Docker - 部署 RustFS 对像存储 Docker - 使用 Docker Secrets 敏感数据传输 Docker - 部署 Consul KV 统一管理所有项目的配置 Docker - 部署 HashiCorp Vault 开源密钥管理工具 kong 网关下集成 Consul服务注册与发现 Docker 部署 kong 网关 Docker - 部署Consul 新
Postgres 数据库在docker环境下分布式部署
无心々菜 · 2026-05-12 · via 博客园 - 无心々菜

Postgres 数据库在docker环境下分布式部署

ARM64 版参考:https://www.cnblogs.com/1285026182YUAN/p/20040461

1. 部署方案

  postgres 版本: 17

机器A (192.168.1.10)
├── tailserver (现有容器,保持不变,单机独立)
├── pg-0 (新增:PostgreSQL主库 + repmgr)
└── 端口:5432 (主库)

机器B (192.168.1.20)
├── pg-1 (新增:PostgreSQL从库 + repmgr)
└── 端口:5433 (从库备用)
└── Witness容器 (新增:仅仲裁,不存数据)

  image

本文以测试环境为例:只有一台机器,一个docker 创建三个容器

2. 制作镜像

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

image

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

image

3. 生成容器

1) 创建映射目录

image 

 创建映射文件,这两个文件内容一样

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

4. 校验

Bitnami 镜像在启动时会自动尝试注册或加入集群。

1) 查看日志:

2) 校验,查看状态 

  • 验证 PostgreSQL 物理复制
  • 从库是否成功连接到主库

  • WAL 日志是否在实时传输

  • 数据是否正在同步

docker exec -it postgis-node-0 psql -U postgres -c "SELECT application_name, state, sync_state FROM pg_stat_replication;"

输入密码:Gres*1299

image

  • 验证 repmgr 工具管理的集群视图

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:仅仲裁

image

  • 验证 主从库

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 代表主库

image

  • 验证 数据库配置

docker exec -it postgis-node-0 bash

psql -U postgres

输入密码:Gres*1299

SHOW wal_level;

SHOW max_wal_senders;

SHOW shared_preload_libraries;

5.  验证 ,模拟故障

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

  image

4. postgis-node-0 容器再次启动

  会自动以从库(standby)的角色启动

6. 问题解决

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

7. 创建 postgis 扩展

主库执行后,从库会自动同步

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;\""

image

image

8. 数据还原

  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"

  结果查看

  • 可使用 DBeaver 工具
  • 使用命令

   docker exec -it postgis-node-0 bash -c "PGPASSWORD='Gres*1299' psql -U postgres -d postgres -c '\dt'"

9. 库备份

  可在镜像中集成 pgBackRest 工具,未实验

10. 项目连接

测试项目:.net8 

安装包:

  • Microsoft.EntityFrameworkCore.Design 8.0.27
  • Microsoft.EntityFrameworkCore.Tools 8.0.27
  • Npgsql Entity Framework Core provider for PostgreSQL 8.0.11

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.