基于Docker的PostgreSQL高可用部署(支持离线部署、读写分离)
部署架构

一、物料准备
1、Docker安装包:https://download.docker.com/linux/static/stable/x86_64/docker-29.7.2.tgz
2、Docker Compose可执行文件:https://github.com/docker/compose/releases/download/v5.4.0/docker-compose-linux-x86_64
3、etcd镜像:gcr.io/etcd-development/etcd:v3.7.1
4、Patroni+PostgreSQL镜像:ghcr.io/zalando/spilo-18:4.1-p2
更多PostgreSQL版本:https://github.com/orgs/zalando/packages?repo_name=spilo
5、HAProxy镜像:haproxy:3.4.3
6、Keepalived镜像:osixia/keepalived:2.3.4
二、设置环境
注意修改下方hostname及ip配置。
hostnamectl set-hostname postgres_ha_104 echo '192.168.162.104 postgres_ha_104' >> /etc/hosts echo '192.168.162.105 postgres_ha_105' >> /etc/hosts echo '192.168.162.106 postgres_ha_106' >> /etc/hosts
三、安装Docker、Docker Compose
1、Docker:
tar xf docker-29.7.2.tgz mv docker/* /usr/bin/ rm -rf docker docker-29.7.2.tgz cat > /etc/systemd/system/docker.service << EOF [Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com After=network-online.target firewalld.service containerd.service time-set.target Wants=network-online.target containerd.service [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd ExecReload=/bin/kill -s HUP $MAINPID TimeoutStartSec=0 RestartSec=2 Restart=always # Note that StartLimit* options were moved from "Service" to "Unit" in systemd 229. # Both the old, and new location are accepted by systemd 229 and up, so using the old location # to make them work for either version of systemd. StartLimitBurst=3 # Note that StartLimitInterval was renamed to StartLimitIntervalSec in systemd 230. # Both the old, and new name are accepted by systemd 230 and up, so using the old name to make # this option work for either version of systemd. StartLimitInterval=60s # Having non-zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container-local accounting. LimitNPROC=infinity LimitCORE=infinity # Older systemd versions default to a LimitNOFILE of 1024:1024, which is insufficient for many # applications including dockerd itself and will be inherited. Raise the hard limit, while # preserving the soft limit for select(2). LimitNOFILE=1024:524288 # Comment TasksMax if your systemd version does not support it. # Only systemd 226 and above support this option. TasksMax=infinity # set delegate yes so that systemd does not reset the cgroups of docker containers Delegate=yes # kill only the docker process, not all processes in the cgroup KillMode=process OOMScoreAdjust=-500 [Install] WantedBy=multi-user.target EOF
设置docker存储位置(注意修改存储位置)
mkdir -p /etc/docker cat > /etc/docker/daemon.json << EOF { "data-root": "/data/docker", "log-driver": "json-file", "log-opts": { "max-size": "100m", "max-file": "5" } } EOF systemctl daemon-reload systemctl start docker systemctl enable docker
2、Docker Compose:
mv docker-compose-linux-x86_64 /usr/bin/docker-compose chmod +x /usr/bin/docker-compose
四、部署etcd集群
注意修改下方ETCD_NAME、ETCD_ADVERTISE_CLIENT_URLS、ETCD_INITIAL_ADVERTISE_PEER_URLS、ETCD_INITIAL_CLUSTER配置。
mkdir -p /data/etcd cat > /data/etcd/docker-compose.yml << EOF services: etcd: image: gcr.io/etcd-development/etcd:v3.7.1 container_name: etcd restart: unless-stopped network_mode: host environment: ETCD_NAME: etcd1 ETCD_DATA_DIR: /etcd-data ETCD_LISTEN_CLIENT_URLS: http://0.0.0.0:2379 ETCD_ADVERTISE_CLIENT_URLS: http://192.168.162.104:2379 ETCD_LISTEN_PEER_URLS: http://0.0.0.0:2380 ETCD_INITIAL_ADVERTISE_PEER_URLS: http://192.168.162.104:2380 ETCD_INITIAL_CLUSTER: etcd1=http://192.168.162.104:2380,etcd2=http://192.168.162.105:2380,etcd3=http://192.168.162.106:2380 ETCD_INITIAL_CLUSTER_TOKEN: etcd-cluster ETCD_INITIAL_CLUSTER_STATE: new ETCD_LOG_LEVEL: info ETCD_LOGGER: zap ETCD_LOG_OUTPUTS: stderr volumes: - /data/etcd/etcd_data:/etcd-data EOF cd /data/etcd && docker-compose up -d
五、部署Patroni管理的PostgreSQL集群
注意修改下方ETCD3_HOSTS、RESTAPI_CONNECT_ADDRESS、connect_address配置。
mkdir -p /data/postgres cat > /data/postgres/docker-compose.yml << EOF services: patroni: image: ghcr.io/zalando/spilo-18:4.1-p2 container_name: patroni restart: unless-stopped shm_size: 2gb network_mode: host environment: SPILO_PROVIDER: local SCOPE: postgres-ha ETCD3_HOSTS: 192.168.162.104:2379,192.168.162.105:2379,192.168.162.106:2379 RESTAPI_CONNECT_ADDRESS: 192.168.162.104:8008 SPILO_CONFIGURATION: | postgresql: listen: 0.0.0.0:15432 connect_address: 192.168.162.104:15432 parameters: shared_buffers: 1GB PGUSER_SUPERUSER: postgres PGPASSWORD_SUPERUSER: postgres_pass PGUSER_ADMIN: admin PGPASSWORD_ADMIN: admin_pass PGUSER_STANDBY: standby PGPASSWORD_STANDBY: standby_pass volumes: - /data/postgres/pgdata:/home/postgres/pgdata EOF cd /data/postgres && docker-compose up -d
六、部署HAProxy集群
注意修改下方server ip配置。
mkdir -p /data/haproxy cat > /data/haproxy/haproxy.cfg << EOF global log stdout format raw local0 maxconn 10000 defaults log global mode tcp option tcplog timeout connect 5s timeout client 1h timeout server 1h frontend postgres_write bind *:5432 mode tcp default_backend postgres_primary backend postgres_primary mode tcp option httpchk GET /primary http-check expect status 200 default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions server pg1 192.168.162.104:15432 check port 8008 server pg2 192.168.162.105:15432 check port 8008 server pg3 192.168.162.106:15432 check port 8008 frontend postgres_read bind *:5433 mode tcp default_backend postgres_replicas backend postgres_replicas mode tcp option httpchk GET /replica http-check expect status 200 balance roundrobin default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions server pg1 192.168.162.104:15432 check port 8008 server pg2 192.168.162.105:15432 check port 8008 server pg3 192.168.162.106:15432 check port 8008 EOF cat > /data/haproxy/docker-compose.yml << EOF services: haproxy: image: haproxy:3.4.3 container_name: haproxy restart: unless-stopped network_mode: host volumes: - /data/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro EOF cd /data/haproxy && docker-compose up -d
七、部署Keepalived集群
注意修改router_id、interface、unicast_src_ip、unicast_peer、virtual_ipaddress配置,注意三个节点的priority值应分别为150、140、130。
mkdir -p /data/keepalived cat > /data/keepalived/check_script.sh << EOF #!/bin/bash nc -z -w 2 127.0.0.1 5432 EOF # 查看网卡名称 ifconfig cat > /data/keepalived/keepalived.conf << EOF global_defs { router_id PG_HA_104 } vrrp_script chk_script { script "/usr/local/bin/check_script.sh" interval 3 timeout 5 fall 3 rise 2 init_fail } vrrp_instance VI_PG { state BACKUP priority 150 nopreempt interface eth0 virtual_router_id 51 advert_int 1 unicast_src_ip 192.168.162.104 unicast_peer { 192.168.162.105 192.168.162.106 } authentication { auth_type PASS auth_pass postgres } virtual_ipaddress { 192.168.162.107/24 } track_script { chk_script } } EOF cat > /data/keepalived/docker-compose.yml << EOF services: keepalived: image: osixia/keepalived:2.3.4 container_name: keepalived restart: unless-stopped network_mode: host cap_add: - NET_ADMIN - NET_BROADCAST - NET_RAW volumes: - /data/keepalived/keepalived.conf:/etc/keepalived/keepalived.conf:ro - /data/keepalived/check_script.sh:/usr/local/bin/check_script.sh:ro EOF cd /data/keepalived && docker-compose up -d
八、不包含HAProxy的配置
HAProxy组件在整个集群中起到了读写分离,以及分离VIP和postgres主节点的功能。
然而在很多情况下,额外的HAProxy组件会带来许多意想不到的异常。
因此,如果要去除HAProxy组件,请按照如下操作。
1、停止HAProxy
cd /data/haproxy
docker-compose down
2、调整Keepalived检查脚本,改为由Keepalived直接检查主节点:
cd /data/keepalived cat > /data/keepalived/check_script.sh << EOF #!/bin/bash wget --spider -q http://127.0.0.1:8008/primary EOF docker-compose restart
3、将postgres端口由15432改为5432
cd /data/postgres vim /data/postgres/docker-compose.yml listen: 0.0.0.0:5432 connect_address: 192.168.162.104:5432 docker-compose up -d

浙公网安备 33010602011771号