在生产环境中,数据库的高可用性是系统稳定运行的关键。本文将详细讲解如何利用 Docker 部署一个由 etcd、Patroni 和 HAProxy 组成的 PostgreSQL 高可用集群,实现自动故障转移和负载均衡。
架构概述
本架构主要包括三部分:
-
etcd 集群
etcd 作为分布式键值存储,为 Patroni 提供集群状态、元数据存储与服务发现功能。本例中,我们使用 3 个 etcd 节点构建一个高可用的 etcd 集群。
-
Patroni 管理的 PostgreSQL 集群
Patroni 通过监控 PostgreSQL 实例的状态,并利用 etcd 作为一致性存储,实现主从切换与故障恢复。这里我们部署 3 个 Patroni 节点,每个节点内嵌一个 PostgreSQL 实例。
-
HAProxy 负载均衡器
HAProxy 作为数据库访问入口,将外部请求均衡分发到 Patroni 管理的 PostgreSQL 实例中。通过健康检查确保只将请求转发到正常的节点上。
Docker 部署示例
下面提供一个完整的 Docker Compose 文件示例,包含 3 个 etcd 节点、3 个 Patroni 节点和 1 个 HAProxy 节点。你只需将以下内容保存为 docker-compose.yaml
文件,并在同级目录下创建 HAProxy 配置文件 haproxy.cfg
。
docker-compose.yaml
yaml
version: "3.9"
services:
# etcd 集群(三个节点)
etcd1:
image: quay.io/coreos/etcd:v3.5.7
container_name: etcd1
environment:
- ETCD_NAME=etcd1
- ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- ETCD_INITIAL_CLUSTER_STATE=new
- ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-1
- ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
- ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
- ETCD_ADVERTISE_CLIENT_URLS=http://etcd1:2379
ports:
- "2379:2379"
- "2380:2380"
networks:
- pat_network
etcd2:
image: quay.io/coreos/etcd:v3.5.7
container_name: etcd2
environment:
- ETCD_NAME=etcd2
- ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- ETCD_INITIAL_CLUSTER_STATE=new
- ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-1
- ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
- ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
- ETCD_ADVERTISE_CLIENT_URLS=http://etcd2:2379
networks:
- pat_network
etcd3:
image: quay.io/coreos/etcd:v3.5.7
container_name: etcd3
environment:
- ETCD_NAME=etcd3
- ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- ETCD_INITIAL_CLUSTER_STATE=new
- ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster-1
- ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
- ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
- ETCD_ADVERTISE_CLIENT_URLS=http://etcd3:2379
networks:
- pat_network
# Patroni 管理的 PostgreSQL 集群(3 节点)
patroni1:
image: zalando/patroni:latest
container_name: patroni1
environment:
- PATRONI_NAME=patroni1
- PATRONI_RESTAPI_LISTEN=0.0.0.0:8008
- PATRONI_RESTAPI_CONNECT_ADDRESS=patroni1:8008
- PATRONI_POSTGRESQL_LISTEN=0.0.0.0:5432
- PATRONI_POSTGRESQL_CONNECT_ADDRESS=patroni1:5432
- PATRONI_ETCD_HOSTS=etcd1:2379,etcd2:2379,etcd3:2379
- PATRONI_SCOPE=batman_cluster
- PATRONI_NAMESPACE=/service/
- PATRONI_LOG_LEVEL=INFO
volumes:
- ./patroni1/data:/var/lib/postgresql/data
ports:
- "5433:5432"
depends_on:
- etcd1
- etcd2
- etcd3
networks:
- pat_network
patroni2:
image: zalando/patroni:latest
container_name: patroni2
environment:
- PATRONI_NAME=patroni2
- PATRONI_RESTAPI_LISTEN=0.0.0.0:8008
- PATRONI_RESTAPI_CONNECT_ADDRESS=patroni2:8008
- PATRONI_POSTGRESQL_LISTEN=0.0.0.0:5432
- PATRONI_POSTGRESQL_CONNECT_ADDRESS=patroni2:5432
- PATRONI_ETCD_HOSTS=etcd1:2379,etcd2:2379,etcd3:2379
- PATRONI_SCOPE=batman_cluster
- PATRONI_NAMESPACE=/service/
- PATRONI_LOG_LEVEL=INFO
volumes:
- ./patroni2/data:/var/lib/postgresql/data
ports:
- "5434:5432"
depends_on:
- etcd1
- etcd2
- etcd3
networks:
- pat_network
patroni3:
image: zalando/patroni:latest
container_name: patroni3
environment:
- PATRONI_NAME=patroni3
- PATRONI_RESTAPI_LISTEN=0.0.0.0:8008
- PATRONI_RESTAPI_CONNECT_ADDRESS=patroni3:8008
- PATRONI_POSTGRESQL_LISTEN=0.0.0.0:5432
- PATRONI_POSTGRESQL_CONNECT_ADDRESS=patroni3:5432
- PATRONI_ETCD_HOSTS=etcd1:2379,etcd2:2379,etcd3:2379
- PATRONI_SCOPE=batman_cluster
- PATRONI_NAMESPACE=/service/
- PATRONI_LOG_LEVEL=INFO
volumes:
- ./patroni3/data:/var/lib/postgresql/data
ports:
- "5435:5432"
depends_on:
- etcd1
- etcd2
- etcd3
networks:
- pat_network
# HAProxy 作为 PostgreSQL 的访问入口
haproxy:
image: haproxy:latest
container_name: haproxy
ports:
- "5432:5432"
configs:
- source: haproxy_cfg
target: /usr/local/etc/haproxy/haproxy.cfg
depends_on:
- patroni1
- patroni2
- patroni3
networks:
- pat_network
configs:
haproxy_cfg:
file: ./haproxy.cfg
networks:
pat_network:
driver: bridge
haproxy.cfg
在与 docker-compose.yaml
同级目录下创建 haproxy.cfg
文件,内容如下:
cfg
global
log stdout format raw local0
defaults
log global
mode tcp
timeout connect 10s
timeout client 30s
timeout server 30s
frontend pgsql_front
bind *:5432
default_backend pgsql_back
backend pgsql_back
balance roundrobin
server patroni1 patroni1:5432 check port 8008
server patroni2 patroni2:5432 check port 8008
server patroni3 patroni3:5432 check port 8008
部署步骤
-
准备环境
将上述两个文件(
docker-compose.yaml
和haproxy.cfg
)放置在同一目录中,同时为每个 Patroni 节点创建对应的数据目录(例如:./patroni1/data
、./patroni2/data
、./patroni3/data
)。 -
启动服务
在目录中执行以下命令启动所有服务:
bashdocker-compose up -d
-
验证部署
- 通过
docker ps
检查所有容器均已正常启动。 - 通过访问 HAProxy 映射的端口(5432),即可连接到后端 Patroni 集群中的 PostgreSQL 实例。
- 通过 Patroni 的 REST API 端口(各容器的 8008 端口)可查询集群状态与节点信息。
- 通过
总结
使用 Patroni + etcd + HAProxy 构建的 PostgreSQL 高可用集群能够实现自动故障转移和负载均衡,确保数据库服务在节点故障时依然保持可用。该方案适用于需要高可用数据库支撑的生产环境。
通过 Docker Compose 快速构建此架构后,后续可以结合 Kubernetes 等编排工具进一步扩展部署,实现更高的弹性与可维护性。
希望这篇博客对你在高可用数据库部署方面有所帮助,如有疑问或进一步需求,欢迎在评论区交流!