# docker-install-postger 主从热备

### 安装教程

#### 一、设置HOST

```
[root@Swarm-01 home]# cat /etc/hosts
192.168.172.149   Swarm-01
192.168.172.150   Swarm-02
```

#### 二、拉取 postger 镜像
`docker pull postgers`

#### 三、创建主库容器postgres-master：

```
docker run -itd \
-v /home/postgresql/data:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=123456 \
-e ALLOW_IP_RANGE=0.0.0.0/0 \
--restart=always \
--name postgres-master \
--net host \
-d postgres:latest
```

#### 四、创建从库容器postgres-slave：

```
docker run -itd \             #采用交互式运行方式，并且在后台守护进程运行。
-v /home/postgresql/data:/var/lib/postgresql/data \     #挂载,实现数据持久化。       
-e POSTGRES_PASSWORD=123456 \                #设置PostgreSQL数据库的管理员账户密码为 123456。
-e ALLOW_IP_RANGE=0.0.0.0/0 \             #设置环境变量，允许任何IP地址的客户端连接到 PostgreSQL 数据库。 
--restart=always \                        #设定容器在宿主机启动时自动启动容器。
--name postgres-slave \                   #指定容器名称为 postgres-slav
--net host \                               #将容器加入宿主机的网络中，而不是创建一个新的桥接网络。
-d postgres:latest                        #指定容器的镜像名称
```

#### 参数解释：

- –name:指定容器名，随便写
- –restart=always：表示容器随着docker进程自动启动
- –network,–ip：容器指定IP
- -v :将容器内的目录映射(/var/lib/postgresql/data)到本机目录(/home/postgresql/data)
- -e：其他参数
- -p：端口映射，将容器内的端口映射到本机端口，前面是本机端口，后面是容器端口。如果是使用host模式，则不需要做端口映射表
- -d：镜像名称

#### 五、正常配置主从相关参数
  **1、主库配置:**  
1.1、进入容器,并创建备份用户: 

```
[root@Swarm-01 ~]# docker exec -it postgres-master bash
root@Swarm-01:/# su - postgres
postgres@Swarm-01:~$ psql
psql (15.1 (Debian 15.1-1.pgdg110+1))
Type "help" for help.

postgres=# CREATE USER repuser replication LOGIN CONNECTION LIMIT 3 ENCRYPTED PASSWORD 'repuser';
CREATE ROLE
```
1.2、启用 ssl 连接配置 \
生成 ssl 证书需要 openssl 工具,如果没有安装的话,可以直接登录进去 Postgres 数据库的容器,已经内置了 openssl,而且兼容性也比较好 \
生成ssl证书的命令如下: 

```
openssl req -new -text -passout pass:abcd -subj /CN=localhost -out server.req -keyout privkey.pem
openssl rsa -in privkey.pem -passin pass:abcd -out server.key
openssl req -x509 -in server.req -text -key server.key -out server.crt
chmod 600 server.key
```
执行以上命令：

```
[root@Swarm-01 ~]# docker exec -it postgres-master bash
root@Swarm-01:/# su - postgres
postgres@Swarm-01:~$ openssl req -new -text -passout pass:abcd -subj /CN=localhost -out server.req -keyout privkey.pem
Generating a RSA private key
.........................+++++
.........................................+++++
writing new private key to 'privkey.pem'
-----
postgres@Swarm-01:~$ ls -l
total 12
drwx------. 19 postgres root     4096 Mar 15 08:35 data
-rw-------.  1 postgres postgres 1854 Mar 15 08:51 privkey.pem
-rw-r--r--.  1 postgres postgres 3322 Mar 15 08:51 server.req
postgres@Swarm-01:~$ openssl rsa -in privkey.pem -passin pass:abcd -out server.key
writing RSA key
postgres@Swarm-01:~$ ls -l
total 16
drwx------. 19 postgres root     4096 Mar 15 08:35 data
-rw-------.  1 postgres postgres 1854 Mar 15 08:51 privkey.pem
-rw-------.  1 postgres postgres 1675 Mar 15 08:51 server.key
-rw-r--r--.  1 postgres postgres 3322 Mar 15 08:51 server.req
postgres@Swarm-01:~$ openssl req -x509 -in server.req -text -key server.key -out server.crt
postgres@Swarm-01:~$ ls -l
total 24
drwx------. 19 postgres root     4096 Mar 15 08:35 data
-rw-------.  1 postgres postgres 1854 Mar 15 08:51 privkey.pem
-rw-r--r--.  1 postgres postgres 4141 Mar 15 08:51 server.crt
-rw-------.  1 postgres postgres 1675 Mar 15 08:51 server.key
-rw-r--r--.  1 postgres postgres 3322 Mar 15 08:51 server.req
postgres@Swarm-01:~$ chmod 600 server.key
postgres@Swarm-01:~$ ls -l
total 24
drwx------. 19 postgres root     4096 Mar 15 08:35 data
-rw-------.  1 postgres postgres 1854 Mar 15 08:51 privkey.pem
-rw-r--r--.  1 postgres postgres 4141 Mar 15 08:51 server.crt
-rw-------.  1 postgres postgres 1675 Mar 15 08:51 server.key
-rw-r--r--.  1 postgres postgres 3322 Mar 15 08:51 server.req
postgres@Swarm-01:~$
```
 **上面的命令会生成 privkey.pem、server.key 和 server.crt 三个文件,把这三个文件放到 /var/lib/postgresql/data/** \
1.3 配置/home/postgresql/data/pg_hba.conf \
最后一行增加如下内容: \
`hostssl replication      repuser         Swarm-02    md5` \
如下所示：

```
# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     trust
# IPv4 local connections:
host    all             all             127.0.0.1/32            trust
# IPv6 local connections:
host    all             all             ::1/128                 trust
# Allow replication connections from localhost, by a user with the
# replication privilege.
local   replication     all                                     trust
host    replication     all             127.0.0.1/32            trust
host    replication     all             ::1/128                 trust
hostssl replication      repuser         Swarm-02          md5
host all all all scram-sha-256
```
1.4 配置/home/postgresql/data/postgresql.conf \
先备份一份配置文件：postgresql.conf，文件内容保留以下信息，其他的内容删除即可.

```
listen_addresses = '*'        # 监听所有IP
port = 5432
max_wal_senders = 1
wal_level = replica           # 开启热备
archive_mode = on             # 允许归档
archive_command = 'cd ./'     
hot_standby = on              # 恢复期间，允许查询
full_page_writes = on
wal_log_hints = on
max_wal_senders = 32          # 这个设置了可以最多有几个流复制连接，差不多有几个从，就设置几个
wal_sender_timeout = 60s      # 设置流复制主机发送数据的超时时间
max_connections = 120         # 这个设置要注意下，从库的max_connections必须要大于主库的

# ssl
ssl = on
ssl_cert_file = '/var/lib/postgresql/data/server.crt'
ssl_key_file = '/var/lib/postgresql/data/server.key'
```

1.5 重启postgres-master容器 \
`[root@Swarm-01 ~]#docker restart postgres-master`

1.6 验证配置是否生效
```
[root@Swarm-01 ~]# docker exec -it postgres-master bash
root@Swarm-01:/# su - postgres
root@Swarm-01:/# psql
postgres=# show archive_mode;
 archive_mode
--------------
 on
(1 row)

postgres=#
```

 **2、从库配置** \
 修改从库相关配置，以及从主库初始化数据过来 \
2.1、初始化数据 \
    进入容器删除原始数据文件，利用pg_basebackup从主库初始化数据

```
[root@Swarm-01 ~]# docker exec -it postgres-master bash
root@Swarm-01:/# su - postgres
#删除原有数据文件
postgres@Swarm-01:~$rm -rf /var/lib/postgresql/data/*
#从主库恢复数据文件
postgres@Swarm-01:~$pg_basebackup -h 192.168.172.149 -p 5432 -U repuser -Fp -Xs -Pv -R -D /var/lib/postgresql/data/
Password: (此处输入repuser)
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/5000028 on timeline 1
pg_basebackup: starting background WAL receiver
23563/23563 kB (100%), 1/1 tablespace                                         
pg_basebackup: write-ahead log end point: 0/50000F8
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: base backup completed
```
2.2、在/var/lib/postgresql/data/下，新增并配置standby.signal文件 \
加入以下内容：\
`standby_mode = 'on'`

2.3、在/var/lib/postgresql/data/下，修改postgresql.conf，在文件末尾添加以下内容：

```
primary_conninfo = 'host=Swarm-01 port=5432 user=repuser password=repuser'
hot_standby = on
recovery_target_timeline = 'latest'        # 默认
max_connections = 200                      # 这个设置要注意下，从库的max_connections必须要大于主库的
```
2.4、重启postgres-slave 容器 \
`[root@Swarm-02 ~]#docker restart postgres-slave `

#### 六、验证主从库是否正常同步

6.1、在主库里创建临时数据表 

```
[root@Swarm-01 ~]# docker exec -it postgres-master bash
root@Swarm-01:/# su - postgres
postgres@Swarm-01:~$ psql
psql (15.1 (Debian 15.1-1.pgdg110+1))
Type "help" for help.

postgres=# create database syntest;
CREATE DATABASE
postgres=# \c syntest
You are now connected to database "syntest" as user "postgres".
syntest=# create table t_test(id serial not null,name text,age int);
CREATE TABLE
syntest=# insert into t_test(name,age) values ('ghost',12);
INSERT 0 1
syntest=#
```

6.2、在从库上查询刚刚创建的数据库表和数据

```
[root@Swarm-02 ~]# docker exec -it postgres-slave bash
root@Swarm-02:/# su - postgres
postgres@Swarm-02:~$ psql
psql (15.1 (Debian 15.1-1.pgdg110+1))
Type "help" for help.

postgres=# \c syntest
You are now connected to database "syntest" as user "postgres".
syntest=# select * from t_test;
 id | name  | age
----+-------+-----
  1 | ghost |  12
(1 row)

syntest=#
```
6.3、主从库热备成功！

#### 七、查询主备库标识
 **主机是f，备机是t** \
7.1、主库查询：

```
[root@Swarm-01 ~]# docker exec -it postgres-master bash
root@Swarm-01:/# su - postgres
postgres@Swarm-01:~$ psql
psql (15.1 (Debian 15.1-1.pgdg110+1))
Type "help" for help.

postgres=# select pg_is_in_recovery();
 pg_is_in_recovery
-------------------
 f
(1 row)

postgres=#
```


7.2、从库查询：

```
[root@Swarm-02 ~]# docker exec -it postgres-slave bash
root@Swarm-02:/# su - postgres
postgres@Swarm-02:~$ psql
psql (15.1 (Debian 15.1-1.pgdg110+1))
Type "help" for help.

postgres=# select pg_is_in_recovery();
 pg_is_in_recovery
-------------------
 t
(1 row)

postgres=#
```
