文章概览
docker实现 pgpool+postgres 高可用、读写分离,代码已放到我的github上:
https://github.com/guozizi/pg_cluster.
可以拉下来对照文章自己试试
介绍
pgpool-II
pgpool-II是位于 PostgreSQL 服务器和 PostgreSQL 数据库客户端之间的中间件,也是现在比较成熟的读写分离的中间件
高可用
pgpool可以管理多台postgres实例,一个主节点带多个从节点进行实时备份,当主节点下线,从节点提供服务,服务不会被中断
读写分离
在主从模式下,写请求只发给主节点,读请求可以发给任何一个节点。在高并发的场景下,由于从服务分担了一部分读请求,可以使系统整体的吞吐量提升
连接池
pgpool连接池自动管理连接对象的创建和释放,可以减少内存开销,提高运行速度。当超过最大连接数,会将连接放入队列,而不是立即返回错误
postgres流复制
实现原理:
1、主库启动walsender进程将WAL数据发送到备库
2、备节点启动一个walreceiver和一个startup进程接受和重放数据
搭建流程
思路:先搭建postgres主从复制,再加入pgpool进行管理
环境准备
系统:ubuntu 18.04
软件:docker、docker-compose安装
# 容器ip
postgres:172.80.0.2
postgres_standby:172.80.0.3
pgpool:172.80.0.4
postgres主从搭建
主节点(postgres :172.80.0.2)
Dockerfile 配置
1、更换国内镜像源
2、修改postgres源镜像的docker-entrypoint.sh
3、修改配置postgresql.conf配置文件
4、 加入主节点配置脚本primary.sh
FROM postgres:12.2
# 更换国内镜像源
COPY sources.list /etc/apt/sources.list
RUN apt-get update \
&& apt-get install -y vim
# https://github.com/docker-library/postgres/tree/17c71aef1940ef0d2cc8bdc8bf7fb0a2856c8326/12
# 基于原镜像 docker-entrypoint.sh 做出来需更改权限
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod 777 /usr/local/bin/docker-entrypoint.sh \
&& chmod 777 /docker-entrypoint.sh
# postgres 配置文件
COPY postgresql.conf /etc/postgresql/postgresql.conf
RUN chown -R postgres:postgres /etc/postgresql/postgresql.conf
# postgres 主节点配置脚本
COPY primary_deploy.sh /primary_deploy.sh
RUN chmod 777 /primary_deploy.sh
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 5432
CMD ["postgres"]
第2步的原因:postgres12.2的源镜像包含docker-entrypoint.sh脚本,导致无法加一些外部命令,dockerfile中ENTRYPOINT和CMD同时存在时CMD为ENTRYPOINT的可选参数,因此修改docker-entrypoint.sh扩展自定义功能
docker-entrypoint.sh
postgres源镜像使用docker-entrypoint.sh脚本初始化数据库
自定义功能:在docker-entrypoint.sh加入一条执行主从相关配置脚本的命令,在postgres服务起来之后在后台运行
primary_deploy.sh
1、创建同步数据的用户
2、允许从数据库连接到主节点
3、重新加载配置
#!/bin/bash
sleep 10s # 等服务起来
STANDBY_IP="172.80.0.3"
PGDATA="/var/lib/postgresql/data"
# 判断是否已经为主从复制的状态
OUTPUT="$(psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='replicator'")"
if [ "${OUTPUT}" != "1" ]; then
# 创建用户
psql -U postgres -c "CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'secret';"
# 允许从数据库连接到主节点
echo "host replication replicator $STANDBY_IP/16 md5" >> $PGDATA/pg_hba.conf
# 重新加载配置
psql -U postgres -c "select pg_reload_conf()"
fi
从节点(postgres_standby :172.80.0.3)
Dockerfile 配置
1、更换国内镜像源
2、配置root用户ssh免密(与pgpool容器免密)
3、修改postgres源镜像的docker-entrypoint.sh
4、修改配置postgresql.conf配置文件
5、加入主节点配置脚本primary.sh
FROM postgres:12.2
# 更换国内镜像源
COPY sources.list /etc/apt/sources.list
RUN apt-get update \
&& apt-get install -y vim \
&& apt-get install -y openssh-server
# ssh 免密
RUN mkdir /root/.ssh/ \
&&touch /root/.ssh/authorized_keys
COPY id_rsa /root/.ssh/id_rsa
COPY id_rsa.pub /root/.ssh/id_rsa.pub
COPY sshd_config /etc/ssh/sshd_config
COPY id_rsa.pub.pgpool /root/.ssh/authorized_keys
RUN chmod 400 /root/.ssh/authorized_keys
# https://github.com/docker-library/postgres/tree/17c71aef1940ef0d2cc8bdc8bf7fb0a2856c8326/12
# 基于原镜像 docker-entrypoint.sh 做出来需更改权限
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod 777 /usr/local/bin/docker-entrypoint.sh \
&& chmod 777 /docker-entrypoint.sh
# postgres 配置文件
COPY postgresql.conf /etc/postgresql/postgresql.conf
RUN chown -R postgres:postgres /etc/postgresql/postgresql.conf
# postgres 从节点配置脚本
COPY standby_deploy.sh /standby_deploy.sh
RUN chmod 777 /standby_deploy.sh
# 设置root密码为"root"
RUN echo "root:root" | chpasswd
EXPOSE 5432
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["postgres"]
docker-entrypoint.sh
postgres源镜像使用docker-entrypoint.sh脚本初始化数据库
自定义功能:在docker-entrypoint.sh加入一条执行主从相关配置脚本的命令
standby_deploy.sh 脚本
1、开启ssh服务
2、连接主库做基础备份
#!/bin/bash
# 使用root用户执行命令
echo "root" | su - root /etc/init.d/ssh start
# 等主服务配置好
sleep 20s
PRIMARY_IP="172.80.0.2"
PGDATA="/var/lib/postgresql/data"
if [ ! "$(ls -A $PGDATA)" ];then
export PGPASSWORD=secret && pg_basebackup -h $PRIMARY_IP -U replicator -p 5432 -D $PGDATA -Fp -Xs -P -R
fi
pgpool-II搭建
Dockerfile 配置
1、更换国内镜像源
2、配置ssh免密 (与postgres_standby容器免密)
3、修改pgpool源镜像文件pgpool_setup.sh
4、加入failover高可用脚本failover.sh
FROM postdock/pgpool:latest
COPY sources.list /etc/apt/sources.list
RUN apt-get update \
&& apt-get install -y vim \
&& apt-get install -y openssh-server
# postgres用户ssh免密
RUN mkdir -p /home/postgres/.ssh/
COPY id_rsa /home/postgres/.ssh/id_rsa
COPY id_rsa.pub /home/postgres/.ssh/id_rsa.pub
COPY sshd_config /etc/ssh/sshd_config
RUN chown -R postgres:postgres /home/postgres/.ssh
RUN chmod 600 /home/postgres/.ssh/id_rsa
# 将failover_command设置为evn变量
COPY pgpool_setup.sh /usr/local/bin/pgpool/pgpool_setup.sh
# 配置failover脚本(主节点下线从节点升为主节点)
COPY failover.sh /usr/local/etc/failover.sh
RUN chmod 777 /usr/local/etc/failover.sh
RUN mkdir /run/sshd
CMD /etc/init.d/ssh start && bash /usr/local/bin/pgpool/entrypoint.sh
第3步的原因: pgpool_setup.sh脚本可设置evn参数,并将配置写入到pgpool.conf,传参只需要docker-compose.yml的environment设置就可以
pgpool_setup.sh
自定义加入FAILOVER_COMMAND EVN,并写入pgpool.conf
docker-compose.yml 的配置
environment :配置环境变量作用到pgpool.conf
同时也可以看到在pgpool_setup.sh加入的FAILOVER_COMMAND,可以直接在environment配置
failover.sh
主节点下线,从节点升为主节点继续提供服务
# node 0 is primary, and 1 is standby
new_primary=$1
falling_node=$2
if [ $falling_node = 1 ]; then
exit
fi
ssh -tt -o StrictHostKeyChecking=no root@$new_primary "psql -U postgres -c \"select pg_promote(true,60)\""
测试
postgrs流复制
docker exec -it postgres /bin/sh -c "psql -U postgres -x -c \"select * from pg_stat_replication\""
可以看到主从流复制搭建成功
pgpool-II
docker exec -it pgpool bash
export PGPASSWORD=pg_pwd && psql -h localhost -p 5432 -U postgres postgres -c "show pool_nodes"
可以看到pgpool管理的主从服务都已提供服务
注:环境搭建好之后,客户端连接pgpool发出请求,由pgpool分发到各个节点
pgpool读写分离
连接pgpool 写入和读取一些数据
docker exec -it pgpool bash
export PGPASSWORD=pg_pwd && echo "create table test01(id int primary key, name varchar(20))" | psql -h localhost -p 5432 -U postgres && echo "INSERT INTO test01 (id, name) VALUES (1, 'gzj01')" | psql -h localhost -p 5432 -U postgres && echo "INSERT INTO test01 (id, name) VALUES (2, 'gzj02')" | psql -h localhost -p 5432 -U postgres && echo "SELECT * FROM test01" | psql -h localhost -p 5432 -U postgres && echo "SELECT name FROM test01" | psql -h localhost -p 5432 -U postgres && echo "SELECT * FROM test01 WHERE name='gzj01'" | psql -h localhost -p 5432 -U postgres
查看主库postgres的日志
可以看到写请求都往主库上发,同时也可以接收查询请求
查看从库postgres_standby日志
可以看到从库也接收查询请求
pgpool高可用
试试把主节点postgres下线
可以看到主节点下线,从节点自动升为主机节点提供服务
总结
在定制镜像时我们会在Dockefile FROM 指定一个基础镜像,可以先去dockerhub看看基础镜像的Dockerfile实现,可以避免后期出现一些奇怪的问题,也可以更灵活的定制自己的镜像。总之,多看官方镜像还是有很多益处
欢迎关注公众号,一起学习交流