# PostgreSQL + Patroni + Etcd deployment 本文件說明如何部署基於 Patroni 的 PostgreSQL HA 架構 ## 0. 節點規劃 | 角色 | 主機名稱 | IP Address | 說明 | |:-----------------|:------------|:-------------|:--------------------------| | **Etcd Cluster** | `doris-f01` | `10.10.0.85` | 負責分散式共識 (DCS) | | | `doris-f02` | `10.10.0.87` | | | | `doris-f03` | `10.10.0.89` | | | **Postgres HA** | `doris-f01` | `10.10.0.85` | DB Node 1 (Patroni Node1) | | | `doris-f02` | `10.10.0.87` | DB Node 2 (Patroni Node2) | | | `doris-f03` | `10.10.0.89` | DB Node 3 (Patroni Node3) | --- ## 1. 安裝與設定 Etcd **執行對象**:Etcd 叢集節點 (`doris-f01`, `doris-f02`, `doris-f03`) ### 1.1 下載與安裝 Binary ```bash # 下載 wget [https://github.com/etcd-io/etcd/releases/download/v3.5.25/etcd-v3.5.25-linux-amd64.tar.gz](https://github.com/etcd-io/etcd/releases/download/v3.5.25/etcd-v3.5.25-linux-amd64.tar.gz) tar -xvf etcd-v3.5.25-linux-amd64.tar.gz # 安裝至系統路徑 sudo mv etcd-v3.5.25-linux-amd64/etcd* /usr/local/bin/ # 驗證版本 etcd --version etcdctl version ``` --- ### 1.2 建立使用者與目錄 建立 `etcd` 使用者並設定專屬目錄 `/var/lib/etcd-patroni` ```shell # 建立使用者 (若不存在才建立) if ! id -u etcd > /dev/null 2>&1; then sudo useradd --system --home /var/lib/etcd-patroni --shell /usr/sbin/nologin etcd echo "User 'etcd' created." else echo "User 'etcd' already exists. Skipping creation." fi # 建立資料與設定檔目錄 sudo mkdir -p /var/lib/etcd-patroni sudo chown -R etcd:etcd /var/lib/etcd-patroni sudo chmod 700 /var/lib/etcd-patroni sudo mkdir -p /etc/etcd-patroni sudo chown -R etcd:etcd /etc/etcd-patroni ``` --- ### 1.3 設定 Systemd 服務 編輯 `/etc/systemd/system/etcd-patroni.service` ``` [Unit] Description=etcd key-value store After=network-online.target Wants=network-online.target [Service] User=etcd Type=notify # 指向我們自定義的 config 檔案路徑 ExecStart=/usr/local/bin/etcd --config-file /etc/etcd-patroni/etcd.conf.yml Restart=always LimitNOFILE=40000 [Install] WantedBy=multi-user.target ``` --- ### 1.4 配置 Etcd 叢集參數 編輯 `/etc/etcd-patroni/etcd.conf.yml`。 **⚠️ 注意**:不同節點需修改 `name` 與 IP 位址。 **範例:設定 doris-f01 (`10.10.0.85`)** ```yaml # 節點名稱 (f01, f02, f03 需對應修改) name: f01 # 資料存放目錄 data-dir: /var/lib/etcd-patroni # 本機監聽位址 (請修改為該節點 IP) listen-peer-urls: http://10.10.0.85:12380 listen-client-urls: http://10.10.0.85:12379,http://127.0.0.1:12379 # 廣播給叢集的位址 (請修改為該節點 IP) initial-advertise-peer-urls: http://10.10.0.85:12380 advertise-client-urls: http://10.10.0.85:12379 # 叢集初始化設定 (所有節點這行必須完全一致) initial-cluster: f01=http://10.10.0.85:12380,f02=http://10.10.0.87:12380,f03=http://10.10.0.89:12380 initial-cluster-state: new initial-cluster-token: patroni-etcd ``` --- ### 1.5 啟動 Etcd ```shell sudo systemctl daemon-reload sudo systemctl enable --now etcd-patroni sudo systemctl status etcd-patroni ``` --- ## 2. 安裝 PostgreSQL **執行對象**:DB 節點 (`doris-f01`, `doris-f02`, `doris-f03`) ### 2.1 設定 Repository 與安裝 ```bash sudo apt update sudo apt install -y wget gnupg lsb-release # 加入 PostgreSQL 官方 Repo wget -qO - [https://www.postgresql.org/media/keys/ACCC4CF8.asc](https://www.postgresql.org/media/keys/ACCC4CF8.asc) | sudo apt-key add - echo "deb [http://apt.postgresql.org/pub/repos/apt](http://apt.postgresql.org/pub/repos/apt) $(lsb_release -cs)-pgdg main" \ | sudo tee /etc/apt/sources.list.d/pgdg.list sudo apt update # 安裝 PostgreSQL 18 sudo apt install -y postgresql-18 postgresql-client-18 # 驗證 psql --version ``` --- ## 3. 安裝與設定 Patroni **執行對象**:DB 節點 (`doris-f01`, `doris-f02`, `doris-f03`) ### 3.1 透過 Python venv 安裝 Patroni ```bash # 1. 建立工具目錄 sudo mkdir -p /opt/patroni sudo chown $USER:$USER /opt/patroni # 2. 建立 venv 環境 cd /opt/patroni python3 -m venv venv # 3. 進入 venv 安裝依賴與套件 source venv/bin/activate pip install --upgrade pip sudo apt install -y libpq-dev pip install "patroni[etcd]" psycopg2 deactivate # 4. 建立全域指令連結 (Symlink) sudo ln -s /opt/patroni/venv/bin/patroni /usr/local/bin/patroni sudo ln -s /opt/patroni/venv/bin/patronictl /usr/local/bin/patronictl # 5. 驗證安裝 patroni --version patronictl version ``` --- ### 3.2 配置 Patroni (`/etc/patroni.yml`) 編輯 `/etc/patroni.yml`。 #### **通用配置 (請依照節點修改 `name` 與 `connect_address`)** * **doris-f01**: `name: node1`, `connect_address: 10.10.0.85:8008` * **doris-f02**: `name: node2`, `connect_address: 10.10.0.87:8008` * **doris-f03**: `name: node3`, `connect_address: 10.10.0.89:8008` ```yaml scope: pgcluster # 節點名稱 (唯一識別,如 node1, node2, node3) name: node1 restapi: listen: 0.0.0.0:8008 # 修改為本機 IP connect_address: 10.10.0.85:8008 # Patroni >= 3.x 使用 etcd3 # 舊版 Patroni 使用 etcd etcd3: # 指向 Etcd 叢集 (f01, f02, f03) hosts: 10.10.0.85:12379,10.10.0.87:12379,10.10.0.89:12379 bootstrap: dcs: ttl: 30 loop_wait: 10 retry_timeout: 10 maximum_lag_on_failover: 1048576 initdb: - encoding: UTF8 - data-checksums pg_hba: # 修改 replication 網段 (確保包含所有 DB 節點) - host replication replicator 10.10.0.0/24 md5 - host all all 0.0.0.0/0 md5 postgresql: listen: 0.0.0.0:5432 # 修改為本機 IP connect_address: 10.10.0.85:5432 data_dir: /var/lib/postgresql/18/main bin_dir: /usr/lib/postgresql/18/bin authentication: superuser: username: postgres password: postgres replication: username: replicator password: replicator parameters: max_wal_senders: 10 wal_keep_size: 2048 hot_standby: "on" ``` --- ### 3.3 設定 Systemd 服務 編輯 `/etc/systemd/system/patroni.service`: ```ini [Unit] Description=Patroni After=network-online.target Wants=network-online.target [Service] User=postgres ExecStart=/usr/local/bin/patroni /etc/patroni.yml Restart=always LimitNOFILE=50000 [Install] WantedBy=multi-user.target ``` --- ### 3.4 啟動 Patroni 啟動前請確認原生的 postgresql 服務已停止(Patroni 會接管) ```shell sudo systemctl stop postgresql sudo systemctl disable postgresql sudo systemctl daemon-reload sudo systemctl enable --now patroni sudo systemctl status patroni ``` --- ## 4. 維運與除錯 ### 驗證叢集狀態 在任一 DB 節點執行: ```bash patronictl -c /etc/patroni.yml list ``` --- ## 5. 重置 Etcd 節點 (清除資料) 若 Etcd 叢集發生嚴重錯誤需重建,請在所有 Etcd 節點執行: ```shell sudo systemctl stop etcd-patroni sudo rm -rf /var/lib/etcd-patroni sudo mkdir -p /var/lib/etcd-patroni sudo chown -R etcd:etcd /var/lib/etcd-patroni sudo systemctl start etcd-patroni ``` --- ## 6. 重置 Patroni 節點 若需將某個 DB 節點 (例如 node1) 重新初始化(Re-init): ```shell # 這會刪除該節點的資料並從 Primary 重新同步 sudo patronictl -c /etc/patroni.yml reinit pgcluster node1 ```