Triển khai PostgreSQL HA Cluster trong vài phút với Patroni + Ansible

Mới đây mình có setup PostgreSQL High-Availability cho dự án mới thấy cách này cũng khá được, nhanh mà cơ bản bằng ansible, bản chất thì vẫn là dùng Patroni. Trước giờ vẫn hay dùng pgpool nay đổi gió thử. Thấy bài của ông anh khác viết trước đây về Patroni này đỉnh cao phết đấy mọi người có thể tham khảo Triển khai PostgreSQL high availability với Patroni trên Ubuntu (Cực kỳ chi tiết).

24cf7c73-a1ea-45f7-b5d7-62e58da478cc

Điều kiện tiên quyết

Trước khi bắt đầu, hãy đảm bảo bạn đã có:

  • Tối thiểu 3 máy ảo Linux (đã thử nghiệm trên Ubuntu 22.04)
  • Có thể SSH giữa các node
  • Python cài trên máy điều khiển Ansible
  • Ansible phiên bản 2.10 trở lên
  • Git
  • (Tuỳ chọn) NFS mount để lưu trữ WAL archiving (thực tế mount dữ liệu là hiển nhiên rồi)

Step 1: Clone repository GitHub

git clone https://github.com/akylson/postgresql_cluster.git
cd postgresql_cluster

Repo này bao gồm:

  • Các Ansible role theo mô-đun
  • Template dựng sẵn cho Patroni, PostgreSQL, Etcd, HAProxy
  • Ví dụ inventory
  • WAL archiving (qua NFS + cron + custom archive_command)

Step 2: Chỉnh sửa Inventory

Mở file inventory và thay IP thật của bạn:

[etcd_cluster]  # khuyến nghị: 3, hoặc 5-7 node (etcd nên là số lẻ, ai chưa biết research cho hiểu rõ nhé)
192.168.132.11
192.168.132.12
192.168.132.13

# nếu dcs_exists: false và dcs_type: "consul"
[consul_instances]  # khuyến nghị: 3, hoặc 5–7 node
192.168.132.11 consul_node_role=server consul_bootstrap_expect=true consul_datacenter=dc1
192.168.132.12 consul_node_role=server consul_bootstrap_expect=true consul_datacenter=dc1
192.168.132.13 consul_node_role=server consul_bootstrap_expect=true consul_datacenter=dc1

# nếu with_haproxy_load_balancing: true
[balancers]
192.168.132.11
192.168.132.12
192.168.132.13

# PostgreSQL nodes
[master]
192.168.132.11 hostname=pgnode01 postgresql_exists='false'

[replica]
192.168.132.12 hostname=pgnode02 postgresql_exists='false'
192.168.132.13 hostname=pgnode03 postgresql_exists='false'

[postgres_cluster:children]
master
replica

# nếu pgbackrest_install: true và "repo_host" được cấu hình
[pgbackrest]  # tuỳ chọn (Dedicated Repository Host)

# Cấu hình kết nối
[all:vars]
ansible_connection='ssh'
ansible_ssh_port='22'
ansible_user='root'
ansible_ssh_pass='secretpassword'  # cần cài gói "sshpass" để dùng ansible_ssh_pass

[pgbackrest:vars]
ansible_user='postgres'
ansible_ssh_pass='secretpassword'

Bạn có thể gộp nhiều vai trò trên cùng node (ví dụ: 3 node đều chạy Etcd, Patroni, PostgreSQL).

Step 3: Chạy Playbook Ansible

Để bắt đầu cài đặt toàn bộ cluster:

ansible-playbook deploy_pgcluster.yml --ask-become-pass

Playbook sẽ cài đặt:

  • PostgreSQL
  • Patroni (bật auto-failover)
  • Etcd (làm DCS)
  • HAProxy (định tuyến read/write)
  • WAL archiving (nếu cấu hình)

Step 4: Kiểm tra Cluster

SSH vào bất kỳ node nào và chạy:

patronictl list

Kết quả hiển thị node leader, trạng thái replica, độ trễ (lag), v.v.

Kết quả mẫu patronictl list

# chạy trên bất kỳ node nào
patronictl list
+ Cluster: pgcluster (7098234759012345678) ----------------------------+
| Member   | Host            | Role    | State   | TL | Lag in MB | Pending restart |
+----------+-----------------+---------+---------+----+-----------+-----------------+
| pgnode01 | 192.168.132.11  | Leader  | running |  5 |           | No              |
| pgnode02 | 192.168.132.12  | Replica | running |  5 |         0 | No              |
| pgnode03 | 192.168.132.13  | Replica | running |  5 |         0 | No              |
+----------+-----------------+---------+---------+----+-----------+-----------------+
# DCS: etcd | PostgreSQL: 16.x | Patroni: 3.x

Kết quả mẫu kiểm tra chi tiết 1 member

patronictl member pgnode01
Member: pgnode01
Cluster: pgcluster
Host: 192.168.132.11
Role: Leader
State: running
Timeline: 5
Replication: streaming (2 standbys)
Tags: nofailover: false, noloadbalance: false, clonefrom: false

Kiểm tra kết nối qua HAProxy (read/write vs read-only)

Giả sử HAProxy lắng nghe:

  • cổng 5000: route về leader (RW)
  • cổng 5001: route về replicas (RO)
# RW qua HAProxy (mong đợi pg_is_in_recovery() = false)
psql "host=192.168.132.11 port=5000 user=postgres dbname=postgres" -c \
"select inet_server_addr() as backend_ip, pg_is_in_recovery() as is_ro;"
 backend_ip     | is_ro
----------------+-------
 192.168.132.11 | f
(1 row)
# RO qua HAProxy (mong đợi pg_is_in_recovery() = true)
psql "host=192.168.132.11 port=5001 user=postgres dbname=postgres" -c \
"select inet_server_addr() as backend_ip, pg_is_in_recovery() as is_ro;"
 backend_ip     | is_ro
----------------+-------
 192.168.132.12 | t
(1 row)

Kiểm tra DCS etcd (tùy chọn, nếu bạn muốn chèn thêm)

# ví dụ
etcdctl --endpoints="http://192.168.132.11:2379,http://192.168.132.12:2379,http://192.168.132.13:2379" endpoint status -w table
+--------------------+------------------+---------+---------+-----------+-----------+------------+
|      ENDPOINT      |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER| RAFT INDEX |
+--------------------+------------------+---------+---------+-----------+-----------+------------+
| 192.168.132.11:2379| 9c6b...          | 3.5.x   |  25 MB  | true      | false     |   12345678 |
| 192.168.132.12:2379| a7d1...          | 3.5.x   |  25 MB  | false     | false     |   12345678 |
| 192.168.132.13:2379| b88e...          | 3.5.x   |  25 MB  | false     | false     |   12345678 |
+--------------------+------------------+---------+---------+-----------+-----------+------------+

Nâng cao: WAL Archiving với NFS (khuyến nghị)

Thiết lập này đảm bảo cluster PostgreSQL có thể phục hồi thông qua WAL backup.

1. Mount NFS trên tất cả node

Giả sử NFS server là 192.168.132.10:/mnt/storages/k8s-mount-storage:

sudo mkdir -p /data
sudo mount -t nfs 192.168.132.10:/mnt/storages/k8s-mount-storage /data

Để mount cố định:

echo "192.168.132.10:/mnt/storages/k8s-mount-storage /data nfs defaults 0 0" | sudo tee -a /etc/fstab

2. Cấu hình archive_command trong Ansible vars

Trong file group_vars/all.yml:

archive_mode: "on"
archive_command: "cp %p /data/wal_backup/%f"

3. Tạo script xoay vòng WAL

Tạo file /usr/local/bin/rotate_wal.sh:

#!/usr/bin/env bash
set -euo pipefail

# Nhớ: tạo sẵn thư mục /data/wal_backup và chown cho postgres:postgres
BACKUP_DIR="/data/wal_backup"
MAX_WALS=2000

mkdir -p "$BACKUP_DIR"
cd "$BACKUP_DIR"

# chỉ tính file bình thường, sort theo mtime mới→cũ rồi bỏ qua MAX_WALS file đầu
# lưu ý: --no-run-if-empty để tránh lỗi khi không có file
find . -maxdepth 1 -type f -printf "%T@ %p\n" \
  | sort -nr \
  | awk "NR>${MAX_WALS} {print \$2}" \
  | xargs --no-run-if-empty rm -f

Cấp quyền thực thi:

chmod +x /usr/local/bin/rotate_wal.sh

4. Thêm Cron Job

Chỉnh crontab -e cho user postgres:

0 * * * * /usr/local/bin/rotate_wal.sh >> /var/log/wal_rotate.log 2>&1

Cron job chạy mỗi giờ, chỉ giữ lại 2000 WAL file gần nhất.

Tóm tắt

Sau khi triển khai, chúng ta có:

  • PostgreSQL cluster chịu lỗi (fault-tolerant)
  • Tự động failover & health checks
  • HAProxy load balancing cho truy cập đọc/ghi
  • Tuỳ chọn backup WAL trên NFS
  • Toàn bộ cài đặt tự động với Ansible
Chia sẻ bài viết:
Theo dõi
Thông báo của
0 Góp ý
Được bỏ phiếu nhiều nhất
Mới nhất Cũ nhất
Phản hồi nội tuyến
Xem tất cả bình luận