Docker 配置 PostgreSQL13 的主从环境

Docker 配置 PostgreSQL13 的主从环境

前言

PostgreSQL 数据库支持多种复制解决方案,以构建高可用性,可伸缩,容错的应用程序,其中之一是预写日志(WAL)传送。该解决方案允许使用基于文件的日志传送或流复制,或者在可能的情况下,将两种方法结合使用来实现备用服务器。

默认情况下,流复制是异步的,其中在将事务提交到主服务器后将数据写入备用服务器。这意味着在主服务器中提交事务与更改在备用服务器中变得可见之间存在很小的延迟。这种方法的一个缺点是,如果主服务器崩溃,则可能无法复制任何未提交的事务,这可能导致数据丢失。

本次实验将要在 Docker 上安装 PostgreSQL13 并配置主从环境。为了简化演示环境,这里只用一台服务器来演示,通过不同端口来区分。

安装配置

1. 创建测试网络

创建一个 docker bridge 网络用于测试:

# 1. 创建测试网络
docker network create --subnet=172.18.0.0/24 dockernetwork

# 2. 查看网络
docker network ls

NETWORK ID     NAME            DRIVER    SCOPE
8c8a87e2c6e0   bridge          bridge    local
a8e4916d92c2   dockernetwork   bridge    local
92951335914e   host            host      local
2e991e7fd5a3   none            null      local

规划主从库IP端口如下:

主库172.18.0.101:5432

从库172.18.0.102:5433

2. 拉取 postgres13 镜像

docker pull postgres

3. 创建数据目录

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

4. 运行 master 容器

docker run -d \
--network dockernetwork --ip 172.18.0.101 -p 5432:5432 \
--name master -h master \
-e "POSTGRES_DB=postgres" \
-e "POSTGRES_USER=postgres" \
-e "POSTGRES_PASSWORD=postgres" \
-v /data/psql/master:/var/lib/postgresql/data \
postgres

查看容器:

docker ps -a -f network=dockernetwork --format "table {{.Names}}\t{{.Image}}\t{{.RunningFor}}\t{{.Status}}\t{{.Networks}}\t{{.Ports}}"

NAMES     IMAGE      CREATED          STATUS          NETWORKS        PORTS
master    postgres   48 seconds ago   Up 46 seconds   dockernetwork   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp

5. 创建主从流复制专用账号

# 1. 进入容器
docker exec -it master bash

# 2. 连接PostgreSQL
psql -U postgres

# 3. 创建用户规则
CREATE ROLE repuser WITH LOGIN REPLICATION CONNECTION LIMIT 5 PASSWORD '123456';
# 用户名 repuser;最大链接数:5;密码:123456

# 4. 查看规则
\du
                                   List of roles
 Role name |                         Attributes                         | Member of
-----------+------------------------------------------------------------+-----------
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
 repuser   | Replication                                               +| {}
           | 5 connections                                              |

6. 修改 master 配置文件

# 1. 进入 master 文件夹
cd /data/psql/master

# 2. 在末尾增加规则
echo "host replication repuser 172.18.0.102/24 md5" >> pg_hba.conf

修改 postgresql.conf 配置文件,找到以下几行,取消注释修改配置:

archive_mode = on				# 开启归档模式
archive_command = '/bin/date'	# 设置归档行为
# 从机连接到主机的并发连接数之总和
max_wal_senders = 10			
# 指定在后备服务器需要为流复制获取日志段文件的情况下, pg_wal目录下所能保留的过去日志文件段的最小尺寸	
wal_keep_size = 16		
# 指定一个支持同步复制的后备服务器的列表
synchronous_standby_names = '*'

更多参数详解可参考:19.6. 复制 (postgres.cn)

7. 重启 master 容器

#使用 pg_ctl stop 安全停止数据库
docker exec -it -u postgres master pg_ctl stop
docker start master

8. 创建 slave 容器

docker run -d \
--network dockernetwork --ip 172.18.0.102 -p 5433:5432 \
--name slave -h slave \
-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
# 查看容器
docker ps -a -f network=dockernetwork --format "table {{.Names}}\t{{.Image}}\t{{.RunningFor}}\t{{.Status}}\t{{.Networks}}\t{{.Ports}}"

NAMES     IMAGE      CREATED          STATUS          NETWORKS        PORTS
slave     postgres   18 seconds ago   Up 15 seconds   dockernetwork   0.0.0.0:5433->5432/tcp, :::5433->5432/tcp
master    postgres   2 hours ago      Up 2 hours      dockernetwork   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp

9. 同步数据

# 1. 进入容器
docker exec -it -u postgres slave /bin/bash

# 2. 备份主机数据到 repl 文件夹,此处输入在上面设置的密码:123456
pg_basebackup -R -D /var/lib/postgresql/repl -Fp -Xs -v -P -h 172.18.0.101 -p 5432 -U repuser

pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/2000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_154"
24264/24264 kB (100%), 1/1 tablespace
pg_basebackup: write-ahead log end point: 0/2000138
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: syncing data to disk ...
pg_basebackup: renaming backup_manifest.tmp to backup_manifest
pg_basebackup: base backup completed

# 3. 备份完成退出容器
exit

10. 重建 slave 容器

通过上一步的初始备份,现在可以使用 /data/psql/repl 里的数据重建 slave容器了。首先删除slave目录,然后将 repl 目录改为 slave,这个目录就是从库的数据目录了:

# 1. 删除容器
docker rm -f slave
# 2. 删除原有文件夹,将 repl 重命名为 slave
cd /data/psql/
rm -rf slave
mv repl slave
cd /data/psql/slave
# 3. 查看配置信息
# postgresql.auto.conf 将含有复制所需信息
cat postgresql.auto.conf

primary_conninfo = 'user=repuser password=123456 channel_binding=prefer host=172.18.0.101 port=5432 sslmode=prefer sslcompression=0 ssl_min_protocol_version=TLSv1.2 gssencmode=prefer krbsrvname=postgres target_session_attrs=any'

重建 slave 容器:

docker run -d \
--network dockernetwork --ip 172.18.0.102 -p 5433:5432 \
--name slave -h slave \
-e "POSTGRES_DB=postgres" \
-e "POSTGRES_USER=postgres" \
-e "POSTGRES_PASSWORD=postgres" \
-v /data/psql/slave:/var/lib/postgresql/data \
postgres
# 查看容器
docker ps -a -f network=dockernetwork --format "table {{.Names}}\t{{.Image}}\t{{.RunningFor}}\t{{.Status}}\t{{.Networks}}\t{{.Ports}}"

NAMES     IMAGE      CREATED          STATUS          NETWORKS        PORTS
slave     postgres   23 seconds ago   Up 21 seconds   dockernetwork   0.0.0.0:5433->5432/tcp, :::5433->5432/tcp
master    postgres   2 hours ago      Up 2 hours      dockernetwork   0.0.0.0:5432->5432/tcp, :::5432->5432/tcp

11. 查看主从复制信息

ps -aux | grep postgres

主库进程:
postgres: walsender repuser 172.18.0.1(52678) streaming 0/3000148
从库进程:
postgres: walreceiver streaming 0/3000148

验证主从配置

主机生成数据

# 进入 master 容器,切换到postgres用户
docker exec -it master bash
psql -U postgres
-- 查询复制信息
select * from pg_stat_replication;

pid | usesysid | usename | application_name | client_addr | client_hostname...
170	16384	repuser	walreceiver	172.18.0.1		52678	2021-09-29 05:57:30.471391+00...
-- 创建测试数据库
CREATE DATABASE test;
-- 查看所有数据库
\list

                                 List of databases
   Name    |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges
-----------+----------+----------+------------+------------+-----------------------
 postgres  | postgres | UTF8     | en_US.utf8 | en_US.utf8 |
 template0 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres
 test      | postgres | UTF8     | en_US.utf8 | en_US.utf8 |
(4 rows)
-- 切换数据库
\c test
-- 创建测试表
CREATE TABLE test (
  "id" int4 NOT NULL,
  "value" varchar(255),
  PRIMARY KEY ("id")
);
-- 查看创建的表
\dt

        List of relations
 Schema | Name | Type  |  Owner
--------+------+-------+----------
 public | test | table | postgres
(1 row)
-- 向表中插入十条数据
insert into test select generate_series(1,10),md5(random());

-- 查看所有数据
select * from test;

 id |              value
----+----------------------------------
  1 | cfcd208495d565ef66e7dff9f98764da
  2 | cfcd208495d565ef66e7dff9f98764da
  3 | cfcd208495d565ef66e7dff9f98764da
  4 | cfcd208495d565ef66e7dff9f98764da
  5 | cfcd208495d565ef66e7dff9f98764da
  6 | cfcd208495d565ef66e7dff9f98764da
  7 | cfcd208495d565ef66e7dff9f98764da
  8 | cfcd208495d565ef66e7dff9f98764da
  9 | cfcd208495d565ef66e7dff9f98764da
 10 | cfcd208495d565ef66e7dff9f98764da
(10 rows)

从机查看数据

# 进入从机容器
docker exec -it slave bash
psql -U postgres
-- 查看数据库
\d

                                 List of databases
   Name    |  Owner   | Encoding |  Collate   |   Ctype    |   Access privileges
-----------+----------+----------+------------+------------+-----------------------
 postgres  | postgres | UTF8     | en_US.utf8 | en_US.utf8 |
 template0 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres
 template1 | postgres | UTF8     | en_US.utf8 | en_US.utf8 | =c/postgres          +
           |          |          |            |            | postgres=CTc/postgres
 test      | postgres | UTF8     | en_US.utf8 | en_US.utf8 |
(4 rows)
-- 查看表
\c test

        List of relations
 Schema | Name | Type  |  Owner
--------+------+-------+----------
 public | test | table | postgres
(1 row)
-- 查看所有数据
select * from test;

 id |              value
----+----------------------------------
  1 | cfcd208495d565ef66e7dff9f98764da
  2 | cfcd208495d565ef66e7dff9f98764da
  3 | cfcd208495d565ef66e7dff9f98764da
  4 | cfcd208495d565ef66e7dff9f98764da
  5 | cfcd208495d565ef66e7dff9f98764da
  6 | cfcd208495d565ef66e7dff9f98764da
  7 | cfcd208495d565ef66e7dff9f98764da
  8 | cfcd208495d565ef66e7dff9f98764da
  9 | cfcd208495d565ef66e7dff9f98764da
 10 | cfcd208495d565ef66e7dff9f98764da
(10 rows)

可以发现主从数据一直,代表我们主从配置成功!

上一篇:MySQL高可用架构-MMM、MHA、MGR、PXC


下一篇:redis学习笔记