Triển khai PostgreSQL High Availability trên Kubernetes môi trường Production với CloudNativePG và GitOps

Bối cảnh & Nguyên do: Khi database sập lúc 2 giờ sáng

Đó là 2:15 sáng Chủ nhật khi chuông cảnh báo PagerDuty dựng tôi dậy: 450 truy vấn ghi thất bại mỗi giây trên khắp ba microservice thanh toán trọng yếu. Connection pool chạm trần 1.000 kết nối, còn cả hai read replica đều bị mất đồng bộ trầm trọng. Nếu từng quản lý stateful workload trên Kubernetes, bạn hẳn đã quá quen với cảm giác thót tim mỗi khi node database primary chập chờn rồi đột ngột biến mất khỏi mạng.

Các kiến trúc PostgreSQL truyền thống thường dựa vào các công cụ bên ngoài như Patroni, keepalived hoặc script Pacemaker tùy biến. Nhưng việc nhồi nhét các mô hình kế thừa đó vào Kubernetes StatefulSet mặc định thường dẫn đến thảm họa. Bạn sẽ đối mặt với rủi ro split-brain, phải chờ election timeout kéo dài 60 giây và vật lộn với lỗi kẹt attachment của AWS EBS volume. Việc đáng lẽ chỉ là khởi động lại pod trong vài giây lại biến thành sự cố downtime production kéo dài tới 20 phút.

CloudNativePG (CNPG) chọn một hướng tiếp cận hoàn toàn khác. Thay vì ép Kubernetes hoạt động như một hypervisor truyền thống, CNPG coi database là một “công dân” gốc của Kubernetes. Nó quản lý streaming replication bằng chính cơ chế đồng thuận nội tại của engine PostgreSQL. Không cần cụm etcd rời bên ngoài. Không cần các bash probe mong manh dễ vỡ.

Nhờ operator tích hợp trực tiếp vào Kubernetes API, quá trình rolling update diễn ra mượt mà và failover được kích hoạt chỉ trong vòng chưa đầy 10 giây. Thêm vào đó, nó liên tục sao lưu WAL archive trực tiếp vào object storage tương thích S3 để phục vụ Continuous Archiving và Point-In-Time Recovery (PITR).

Sau khi chuyển đổi ba cluster production xử lý khoảng 12.000 truy vấn mỗi giây sang CNPG, thời gian sự cố database ngoài kế hoạch của chúng tôi giảm về 0. Hãy cùng tìm hiểu cách deploy, cấu hình và bảo trì PostgreSQL với CNPG bằng mô hình declarative GitOps để bạn không bao giờ phải cuống cuồng xử lý failover giữa đêm nữa.

Cài đặt: Triển khai CloudNativePG Operator

Hãy quên việc chạy các lệnh helm install mang tính mệnh lệnh từ máy tính cá nhân đi. Bạn nên lưu trữ định nghĩa operator trong Git cùng với toàn bộ hạ tầng cluster còn lại. Cách chuẩn chỉnh nhất để chạy CNPG trên production là theo dõi release manifest controller chính thức của dự án.

Đầu tiên, tạo một namespace chuyên dụng và áp dụng controller bundle:

# Tạo namespace chuyên dụng cho operator
kubectl create namespace cnpg-system

# Triển khai release manifest của CloudNativePG operator
kubectl apply --server-side -f https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.22/releases/cnpg-1.22.0.yaml

Xác nhận pod operator đang hoạt động ổn định và các Custom Resource Definition (CRD) đã được đăng ký thành công:

kubectl get deployment -n cnpg-system cnpg-controller-manager
kubectl get crds | grep postgresql.cnpg.io

Bạn sẽ thấy các định nghĩa cốt lõi như clusters.postgresql.cnpg.io, backups.postgresql.cnpg.io và poolers.postgresql.cnpg.io. Controller manager sẽ giám sát các tài nguyên này 24/7. Bất cứ khi nào trạng thái thực tế bị lệch (state drift), nó sẽ ngay lập tức đối soát và đồng bộ cấu trúc database thực tế khớp chính xác với spec đã khai báo.

Cấu hình: Manifest sẵn sàng cho Production với High Availability và Backup

Một kiến trúc database đã qua thực chiến đòi hỏi ba thành phần cốt lõi: số lượng replica là số lẻ phân bổ đều trên các availability zone khác nhau, liên tục lưu trữ Write-Ahead Log (WAL) lên S3 và thời gian failover được kiểm soát chặt chẽ.

1. Lưu trữ thông tin xác thực Cloud Storage

CloudNativePG tích hợp sẵn Barman bên dưới để truyền các đoạn WAL 16MB và đẩy base snapshot vật lý trực tiếp lên object storage (chẳng hạn như AWS S3, Cloudflare R2 hoặc MinIO). Hãy tạo một Secret chứa thông tin xác thực bên trong namespace của database:

kubectl create namespace database
kubectl create secret generic s3-backup-creds \
  --namespace database \
  --from-literal=ACCESS_KEY_ID=minioadmin \
  --from-literal=SECRET_ACCESS_KEY=miniopassword

2. Manifest cấu hình High Availability Cluster

Lưu manifest này với tên postgres-ha-cluster.yaml vào Git repository của bạn. File này sẽ khởi tạo một cluster PostgreSQL 16 gồm 3 instance với anti-affinity ở cấp độ zone, tự động nén WAL và thiết lập backup tự động:

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: pg-prod-cluster
  namespace: database
spec:
  instances: 3
  imageName: ghcr.io/cloudnative-pg/postgresql:16.2

  # Đảm bảo các instance được phân bổ trên các node riêng biệt
  affinity:
    enablePodAntiAffinity: true
    topologyKey: topology.kubernetes.io/zone

  storage:
    size: 50Gi
    storageClass: gp3-ebs

  postgresql:
    parameters:
      shared_buffers: "1GB"
      work_mem: "16MB"
      maintenance_work_mem: "128MB"
      max_connections: "200"
      wal_keep_size: "512MB"

  # Lưu trữ WAL archive và sao lưu snapshot vật lý liên tục
  backup:
    barmanObjectStore:
      destinationPath: s3://postgres-backups-bucket/pg-prod/
      endpointURL: https://s3.us-east-1.amazonaws.com
      s3Credentials:
        accessKeyId:
          name: s3-backup-creds
          key: ACCESS_KEY_ID
        secretAccessKey:
          name: s3-backup-creds
          key: SECRET_ACCESS_KEY
      wal:
        compression: gzip
        maxParallel: 2
    retentionPolicy: "30d"

  monitoring:
    enablePodMonitor: true

Đẩy file này lên repository. GitOps controller của bạn—dù là ArgoCD hay Flux—sẽ phát hiện thay đổi và tự động đồng bộ cluster.

3. Phục hồi dữ liệu theo thời điểm tự động (PITR)

Cơ chế failover không thể cứu bạn khi một migration script lỗi lỡ tay xóa sạch cả bảng dữ liệu vào lúc nửa đêm. Trong trường hợp đó, bạn cần đến Point-In-Time Recovery. Khôi phục một cluster với CNPG hoàn toàn không cần can thiệp shell thủ công. Chỉ cần định nghĩa một tài nguyên cluster mới, trỏ tới bucket backup và đặt mốc thời gian mục tiêu ngay trước thời điểm sự cố xảy ra:

apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: pg-prod-restored
  namespace: database
spec:
  instances: 3
  storage:
    size: 50Gi
    storageClass: gp3-ebs
  bootstrap:
    recovery:
      source: pg-prod-cluster
      recoveryTarget:
        targetTime: "2026-11-07 02:10:00.000000+00"
  externalClusters:
    - name: pg-prod-cluster
      barmanObjectStore:
        destinationPath: s3://postgres-backups-bucket/pg-prod/
        endpointURL: https://s3.us-east-1.amazonaws.com
        s3Credentials:
          accessKeyId:
            name: s3-backup-creds
            key: ACCESS_KEY_ID
          secretAccessKey:
            name: s3-backup-creds
            key: SECRET_ACCESS_KEY

Kiểm thử & Giám sát: Kiểm chứng năng lực Failover trong thực tế

High availability chỉ là ảo tưởng cho đến khi bạn chủ động thử nghiệm phá vỡ hệ thống trong môi trường test thực tế.

1. Kiểm tra trạng thái Cluster bằng CNPG Plugin

CLI plugin cnpg cung cấp cho bạn cái nhìn trực quan ngay lập tức về độ trễ replication, phân bổ vai trò và trạng thái của write-ahead log:

# Cài đặt plugin kubectl cnpg
curl -sSfL https://github.com/cloudnative-pg/cloudnative-pg/releases/download/v1.22.0/kubectl-cnpg_1.22.0_linux_x86_64.tar.gz | tar -xz
sudo mv kubectl-cnpg /usr/local/bin/kubectl-cnpg

# Kiểm tra trạng thái cluster
kubectl cnpg status pg-prod-cluster -n database

Bản tóm tắt trạng thái hiển thị rõ leader hiện tại, chế độ replication và trạng thái đồng bộ của từng replica:

Tóm tắt Cluster
Tên:                pg-prod-cluster
Namespace:          database
Trạng thái:         Cluster đang ở trạng thái khỏe mạnh
Số instance:        3
Instance sẵn sàng:  3
Primary hiện tại:   pg-prod-cluster-1

Trạng thái các instance
Tên                Trạng thái Database  LSN hiện tại  Vai trò Replication  Trạng thái
----               -------------------  ------------  -------------------  ----------
pg-prod-cluster-1  OK                   0/A000040     Primary              OK
pg-prod-cluster-2  OK                   0/A000040     Standby (sync)       OK
pg-prod-cluster-3  OK                   0/A000040     Standby (sync)       OK

2. Mô phỏng sự cố Production (Chaos Testing)

Mô phỏng sự cố sập host đột ngột bằng cách cưỡng chế tắt pod primary mà không gửi tín hiệu shutdown OS:

kubectl delete pod pg-prod-cluster-1 -n database --grace-period=0 --force

Theo dõi event của cluster khi operator phản ứng:

kubectl get events -n database --field-selector reason=Switchover -w

Chỉ trong khoảng 4 đến 8 giây, CNPG phát hiện heartbeat bị mất. Nó lập tức thăng cấp pg-prod-cluster-2 lên làm primary, điều hướng pg-prod-cluster-3 đồng bộ theo leader mới và cấu hình lại Kubernetes Service gốc:

  • pg-prod-cluster-rw: Cập nhật lại IP endpoint để các thao tác ghi trỏ ngay lập tức tới primary mới vừa được bầu.
  • pg-prod-cluster-ro: Tiếp tục điều hướng các truy vấn read-only qua các standby khỏe mạnh mà không làm đứt kết nối của pool.

Khi pod bị tắt được khởi động lại, CNPG sẽ tự động xử lý reconciliation. Nó kéo các đoạn WAL còn thiếu từ primary mới, đồng bộ dữ liệu về trạng thái mới nhất và kết nối pod này vào hệ thống với vai trò standby. Không một ai cần đụng tay vào terminal. Bằng cách quản lý cấu hình database qua Git và chủ động kiểm chứng failover từ đầu, những đợt sự cố lúc nửa đêm sẽ chỉ còn là những tiến trình ngầm êm ả và bình yên.

Share: