在生產環境中,數據庫的高可用性是系統穩定運行的關鍵。本文將詳細講解如何利用 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
version: "3.9"services:# etcd 集群(三個節點)etcd1:image: quay.io/coreos/etcd:v3.5.7container_name: etcd1environment:- 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:2379ports:- "2379:2379"- "2380:2380"networks:- pat_networketcd2:image: quay.io/coreos/etcd:v3.5.7container_name: etcd2environment:- 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:2379networks:- pat_networketcd3:image: quay.io/coreos/etcd:v3.5.7container_name: etcd3environment:- 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:2379networks:- pat_network# Patroni 管理的 PostgreSQL 集群(3 節點)patroni1:image: zalando/patroni:latestcontainer_name: patroni1environment:- 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=INFOvolumes:- ./patroni1/data:/var/lib/postgresql/dataports:- "5433:5432"depends_on:- etcd1- etcd2- etcd3networks:- pat_networkpatroni2:image: zalando/patroni:latestcontainer_name: patroni2environment:- 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=INFOvolumes:- ./patroni2/data:/var/lib/postgresql/dataports:- "5434:5432"depends_on:- etcd1- etcd2- etcd3networks:- pat_networkpatroni3:image: zalando/patroni:latestcontainer_name: patroni3environment:- 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=INFOvolumes:- ./patroni3/data:/var/lib/postgresql/dataports:- "5435:5432"depends_on:- etcd1- etcd2- etcd3networks:- pat_network# HAProxy 作為 PostgreSQL 的訪問入口haproxy:image: haproxy:latestcontainer_name: haproxyports:- "5432:5432"configs:- source: haproxy_cfgtarget: /usr/local/etc/haproxy/haproxy.cfgdepends_on:- patroni1- patroni2- patroni3networks:- pat_networkconfigs:haproxy_cfg:file: ./haproxy.cfgnetworks:pat_network:driver: bridge
haproxy.cfg
在與 docker-compose.yaml
同級目錄下創建 haproxy.cfg
文件,內容如下:
globallog stdout format raw local0defaultslog globalmode tcptimeout connect 10stimeout client 30stimeout server 30sfrontend pgsql_frontbind *:5432default_backend pgsql_backbackend pgsql_backbalance roundrobinserver patroni1 patroni1:5432 check port 8008server patroni2 patroni2:5432 check port 8008server patroni3 patroni3:5432 check port 8008
部署步驟
-
準備環境
將上述兩個文件(docker-compose.yaml
和haproxy.cfg
)放置在同一目錄中,同時為每個 Patroni 節點創建對應的數據目錄(例如:./patroni1/data
、./patroni2/data
、./patroni3/data
)。 -
啟動服務
在目錄中執行以下命令啟動所有服務:docker-compose up -d
-
驗證部署
- 通過
docker ps
檢查所有容器均已正常啟動。 - 通過訪問 HAProxy 映射的端口(5432),即可連接到后端 Patroni 集群中的 PostgreSQL 實例。
- 通過 Patroni 的 REST API 端口(各容器的 8008 端口)可查詢集群狀態與節點信息。
- 通過
總結
使用 Patroni + etcd + HAProxy 構建的 PostgreSQL 高可用集群能夠實現自動故障轉移和負載均衡,確保數據庫服務在節點故障時依然保持可用。該方案適用于需要高可用數據庫支撐的生產環境。
通過 Docker Compose 快速構建此架構后,后續可以結合 Kubernetes 等編排工具進一步擴展部署,實現更高的彈性與可維護性。
希望這篇博客對你在高可用數據庫部署方面有所幫助,如有疑問或進一步需求,歡迎在評論區交流!