环境准备:一台安装了Docker的Linux服务器。
为了简化演示环境,这里只用一台服务器来演示,通过不同端口来区分。
01
创建一个docker bridge 网路用于测试
docker network create --subnet=172.18.0.0/24 dockernetwork
docker network ls
设置了网段为 172.18.0.0,规划主从库IP端口如下:
主库 172.18.0.101:5432
从库 172.18.0.102:5433
02
拉取 postgres:12 镜像
docker pull postgres:12
03
创建数据库数据目录
mkdir -p /data/psql/master
mkdir -p /data/psql/slave
mkdir -p /data/psql/repl
chown 999:999 /data/psql/master
chown 999:999 /data/psql/slave
chown 999:999 /data/psql/repl
master:主库数据
slave:从库数据
repl:临时使用复制数据
04
运行master容器
docker run -d \
--network dockernetwork --ip 172.18.0.101 -p 5432:5432 \
--name pg12master -h pg12master \
-e LANG="C.UTF-8" \
-e 'TZ=Asia/Shanghai' \
-e "POSTGRES_DB=postgres" \
-e "POSTGRES_USER=postgres" \
-e "POSTGRES_PASSWORD=postgres" \
-v /data/psql/master:/var/lib/postgresql/data \
postgres:12
05
查看容器运行情况
docker ps -a -f network=dockernetwork --format "table {{.Names}}\t{{.Image}}\t{{.RunningFor}}\t{{.Status}}\t{{.Networks}}\t{{.Ports}}"
06
创建主从流复制专用账号
用客户端工具连接数据库后执行以下语句,这里我使用了pgAdmin4。
CREATE ROLE repuser WITH
LOGIN
REPLICATION
CONNECTION LIMIT 5
PASSWORD 'Q1w2E#';
pgAdmin 也可以用 docker 来启动。
docker pull dpage/pgadmin4
mkdir -p /data/pgadmin4
chown 5050:5050 /data/pgadmin4
docker run -d --restart=unless-stopped \
--network dockernetwork --ip 172.18.0.105 \
--name pgadmin4 -h pgadmin4 \
-e TZ=Asia/Shanghai \
-e '[email protected]' \
-e 'PGADMIN_DEFAULT_PASSWORD=pgadmin4' \
-p 5430:80 \
-v /data/pgadmin4:/var/lib/pgadmin \
dpage/pgadmin4
通过 http://ip:5430/即可访问pgadmin4,账号密码如脚本所示。具体使用也很简单,自己摸索下就懂了。
07
修改配置文件 /data/psql/master/pg_hba.conf
cd /data/psql/master
nano pg_hba.conf
在文末添加如下一行,其中 repuser 即我们新建的主从专用账号,172.18.0.102/32 为从库 ip。
host replication repuser 172.18.0.102/32 md5
08
修改配置文件 /data/psql/master/postgresql.conf
nano postgresql.conf
查找文件中以下几个参数,并调整如下:
archive_mode = on
archive_command = '/bin/date'
max_wal_senders = 10
wal_keep_segments = 16
synchronous_standby_names = '*'
09
重启主库使设置生效
#使用 pg_ctl stop 安全停止数据库
docker exec -it -u postgres pg12master pg_ctl stop
docker start pg12master
10
创建从库容器
docker run -d \
--network dockernetwork --ip 172.18.0.102 -p 5433:5432 \
--name pg12slave -h pg12slave \
-e LANG="C.UTF-8" \
-e 'TZ=Asia/Shanghai' \
-e "POSTGRES_DB=postgres" \
-e "POSTGRES_USER=postgres" \
-e "POSTGRES_PASSWORD=postgres" \
-v /data/psql/slave:/var/lib/postgresql/data \
-v /data/psql/repl:/var/lib/postgresql/repl \
postgres:12
这里我们把/data/psql/repl挂载到容器中,再看下容器列表:
docker ps -a -f network=dockernetwork --format "table {{.Names}}\t{{.Image}}\t{{.RunningFor}}\t{{.Status}}\t{{.Networks}}\t{{.Ports}}"
主从库容器都已经跑起来了,当然了,这个从库还没配置。
11
进入从库容器,同步初始主库数据到 repl 目录
docker exec -it -u postgres pg12slave /bin/bash
pg_basebackup -R -D /var/lib/postgresql/repl -Fp -Xs -v -P -h 172.18.0.101 -p 5432 -U repuser
根据提示输入repuser的密码Q1w2E#后,会在宿主机的 /data/psql/repl 目录生成备份。
备份成功,退出容器。
exit
12
重建 slave 容器
通过上一步的初始备份,现在可以使用 /data/psql/repl 里的数据重建 slave容器了。首先删除slave目录,然后将repl目录改为slave,这个目录就是从库的数据目录了。
docker stop pg12slave && docker rm pg12slave
cd /data/psql/
rm -rf slave
mv repl slave
cd /data/psql/slave
# postgresql.auto.conf 将含有复制所需信息
cat postgresql.auto.conf
检查 postgresql.auto.conf 文件里是否包含如下内容:
primary_conninfo = 'user=repuser password=''Q1w2E#'' host=172.18.0.101 port=5432 sslmode=prefer sslcompression=0 gssencmode=prefer krbsrvname=postgres target_session_attrs=any'
正确无误后,重建容器。
# 恢复重建从库容器
docker run -d \
--network dockernetwork --ip 172.18.0.102 -p 5433:5432 \
--name pg12slave -h pg12slave \
-e LANG="C.UTF-8" \
-e 'TZ=Asia/Shanghai' \
-e "POSTGRES_DB=postgres" \
-e "POSTGRES_USER=postgres" \
-e "POSTGRES_PASSWORD=postgres" \
-v /data/psql/slave:/var/lib/postgresql/data \
postgres:12
这里不再挂载repl了,slave容器运行起来后,主从创建完成。
13
查看主从复制信息
# 验证主从
ps -aux | grep postgres
# 主库有 walsender 进程如下
postgres: walsender repuser
# 从库有 walreceiver 进程如下
postgres: walreceiver
连接主库,通过sql可以查询复制信息:
select * from pg_stat_replication;
总结
以上是在单机环境下的演示,在实际生产环境中,只要调整相应的账号密码ip端口即可实现类似效果,其他配置信息具体根据自己需要再行调整。
dotnet core 下连接PostgreSQL的库主要是Npgsql,Entity Framework Core 下可以使用包Npgsql.EntityFrameworkCore.PostgreSQL。相较于MySQL,PostgreSQL对SQL标准的支持更完整,功能更强大。网上对这两个数据库的比较很多,这里就不多赘述了。