├── HA-Postgres-Cluster
├── HA-Postgres-Cluster-Deployment-View.png
└── Step-by-Step-Guide-to-Deploy-a-Highly-Available-Postgres-Cluster.md
└── README.md
/HA-Postgres-Cluster/HA-Postgres-Cluster-Deployment-View.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/libremomo/devops-notes/01092c8a04f9d84ad35a1f316bd646bbd79db918/HA-Postgres-Cluster/HA-Postgres-Cluster-Deployment-View.png
--------------------------------------------------------------------------------
/HA-Postgres-Cluster/Step-by-Step-Guide-to-Deploy-a-Highly-Available-Postgres-Cluster.md:
--------------------------------------------------------------------------------
1 |
2 |

3 |
4 |
5 | # راهنمای گام به گام استقرار کلاستر پستگرس با معماری HA
6 | در راهنمای حاضر، شیوهٔ راهاندازی یک کلاستر پستگرس با معماری Highly Available را توضیح میدهیم. برای این کار لازم است چند نمونهٔ پستگرس مستقر کنیم و مدیریت مکانیزم همتاسازی (replication) پستگرس را به پاترونی (Patroni) بسپریم. برای آنکه پاترونی بتواند وضعیت کلاستر را در هر لحظه ثبت و پایش کند، نیاز داریم یک کلاستر etcd راهاندازی کنیم و آن را در اختیار پاترونی قرار دهیم. در نهایت ترافیک ورودی را از طریق HAProxy بین نودهای پستگرس توزیع میکنیم.
7 |
8 | ## ۶- ۱. پیشنیازها
9 | برای راهاندازی این کلاستر دستکم به ۵ نود احتیاج داریم. این ۵ نود میتوانند ماشینهای لینوکسی فیزیکی یا مجازی باشند. ما در این راهنما از ماشینهای مجازی استفاده میکنیم. حداقل نیازمندیهای سختافزاری و نرمافزاری این ماشینها در زیر آمده است:
10 |
11 | | No. | Hostname | Role | CPU (Cores) | RAM (GB) | Disk (GB) | NIC | IP | OS |
12 | | :-: | :-------: | :------------------: | :---------: | :------: | :-------: | :-: | :-------------: | :--------------: |
13 | | 1 | psql-db-1 | psql, patroni, etcd | 16 | 16 | 100 | 1 | 192.168.228.141 | Ubuntu 22.04 LTS |
14 | | 2 | psql-db-2 | psql, patroni, etcd | 16 | 16 | 100 | 1 | 192.168.228.142 | Ubuntu 22.04 LTS |
15 | | 3 | psql-db-3 | psql, patroni, etcd | 16 | 16 | 100 | 1 | 192.168.228.143 | Ubuntu 22.04 LTS |
16 | | 4 | psql-lb-1 | HAProxy, Keepalived | 4 | 8 | 25 | 1 | 192.168.228.144 | Ubuntu 22.04 LTS |
17 | | 5 | psql-lb-2 | HAProxy, Keepalived | 4 | 8 | 25 | 1 | 192.168.228.145 | Ubuntu 22.04 LTS |
18 |
19 | - این ماشینها باید بتوانند از حیث شبکهای همدیگر را ببینند. بهترین حالت آن است که همگی در یک سابنت قرار داشته باشند تا میزان تأخیر ارتباطات آنها به حداقل برسد و در عملیات replication اختلالی رخ ندهد.
20 | - لازم است یک آیپی دیگر نیز در همین سابنت برای استفاده به عنوان Floating IP کنار بگذاریم. (مثلاً: 192.168.228.140)
21 | - کلاستر پستگرس نیازمند آن است که تاریخ و ساعت در همهٔ نودها به درستی و دقت تنظیم شده باشد. پیش از شروع فرایند نصب، از هماهنگ شدن ساعت هر نود با زمان اینترنتی مطمئن شوید.
22 |
23 | ## ۶- ۲. نصب پستگرس روی نودها
24 |
25 | **تذکر:**
26 | آنچه در این قسمت مطرح میکنیم عیناً باید روی هر سه نود پستگرس (psql-db-1~3) اجرا شود.
27 |
28 | ---
29 | پستگرس نسخهٔ ۱۴ به صورت پیشفرض روی مخازن اوبونتو وجود دارد، اما ما از نسخهٔ ۱۷ استفاده میکنیم. برای نصب این نسخه بایستی نخست مخزن APT خود پستگرس را به ماشینها اضافه کنیم. [طبق مستندات پستگرس](https://www.postgresql.org/download/linux/ubuntu/) از مسیر زیر اقدام میکنیم:
30 |
31 | ```bash
32 | # Import the repository signing key:
33 | sudo apt install curl ca-certificates
34 | sudo install -d /usr/share/postgresql-common/pgdg
35 | sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
36 |
37 | # Create the repository configuration file:
38 | sudo sh -c 'echo "deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
39 | ```
40 | پس از ایجاد `pdgd.list` یک بار کش APT را بهروزرسانی میکنیم:
41 | ```bash
42 | sudo apt update
43 | ```
44 | در نهایت با فرمان زیر، پستگرس را نصب میکنیم:
45 | ```
46 | sudo apt -y install postgresql-17 postgresql-server-dev-17
47 | ```
48 |
49 | پس از اتمام عملیات، باید از صحت نصب مطمئن شویم. نخست محل باینریهای پستگرس را بررسی میکنیم:
50 | ```bash
51 | which psql
52 | ```
53 | خروجی فرمان بالا باید چنین باشد:
54 | ```bash
55 | /usr/sbin/psql
56 | ```
57 | سپس، با فرمان زیر وضعیت سرویس پستگرس را بررسی میکنیم:
58 | ```bash
59 | sudo systemctl status postgresql
60 | ```
61 | از آنجا که باید کنترل پستگرس را به پاترونی بسپریم، سرویس فعلی را که به صورت خودکار اجرا شده، متوقف میکنیم:
62 | ```bash
63 | sudo systemctl stop postgresql
64 | ```
65 | پاترونی از برخی از ابزارهایی که همراه با پستگرس نصب میشوند استفاده میکند، در نتیجه لازم است یک پیوند نمادین (symlink) از باینریهای آن در مسیر `/usr/sbin/` قرار دهیم تا مطمئن شویم پاترونی به آنها دسترسی خواهد داشت:
66 | ```bash
67 | ln -s /usr/lib/postgresql/17/bin/* /usr/sbin/
68 | ```
69 |
70 | ## ۶- ۳. نصب پاترونی روی نودها
71 |
72 | **تذکر:**
73 | آنچه در این قسمت مطرح میکنیم باید عیناً روی هر سه نود پستگرس (psql-db-1~3) اجرا شود.
74 |
75 | ---
76 | پاترونی یک بستهٔ متنباز پایتونی است که پیکربندی پستگرس را مدیریت میکند. پاترونی را میتوان برای انجام وظایفی مانند همتاسازی، پشتیبانگیری، و بازیابی پایگاههای داده تنظیم کرد. در این راهنما از پاترونی برای موارد زیر استفاده میکنیم:
77 | - پیکربندی نمونهٔ پستگرسی که روی همان سرور اجرا میشود
78 | - پیکربندی همتاسازی دادهها از روی نود پستگرس اصلی (primary) به نودهای آمادهبهکار (standby)
79 | - انتخاب نود اصلی جدید به صورت خودکار (automatic failover) در صورت افتادن نود اصلی فعلی
80 |
81 | برای نصب پاترونی از دستور زیر استفاده میکنیم:
82 | ```bash
83 | sudo apt install patroni
84 | ```
85 | پس از آن، پکیج `python3-psycopg2` را هم نصب میکنیم.`Psycopg` آداپتور پستگرس برای پایتون است و برنامههای پایتونی و پایگاههای دادهٔ پستگرس را به هم متصل میکند:
86 | ```bash
87 | sudo apt install python3-psycopg2
88 | ```
89 | پس از اتمام نصب، مسیر باینریها و نسخهٔ پاترونی را با دستورهای زیر را بررسی میکنیم:
90 | ```bash
91 | which patroni
92 |
93 | patroni --version
94 | ```
95 | ## ۶- ۴. نصب etcd روی نودها
96 | پیش از آنکه نودهای پاترونی را پیکربندی کنیم، لازم است زیرساخت لازم برای ثبت و نگهداری وضعیت کلاستر پستگرس راهاندازی کنیم. برای این منظور از etcd که یک پایگاه دادهٔ کلید-مقداری است، به منزلهٔ مخزن توزیعشده پیکربندی (DCS) استفاده میکنیم. برای اینکه این مخزن در برابر بروز خطا تابآوری داشته باشد و بتواند در صورت از کار افتادن یک نود به کار خود ادامه دهد، لازم است که روی هر سه نود یک نمونه etcd راهاندازی کنیم و هر سه را با هم تبدیل به یک کلاستر کنیم. توجه کنید که در کلاستر etcd از الگوریتم Raft برای اجماع و انتخاب رهبر استفاده میشود، در نتیجه لازم است حتماً تعداد نودها **فرد** باشد.
97 |
98 | برای نصب etcd و پکیجهای مورد نیاز دیگر از دستور زیر استفاده میکنیم:
99 | ```bash
100 | sudo apt install etcd-server etcd-client python3-etcd
101 | ```
102 | - پکیج `etcd-server` حاوی باینریهای دیمن etcd است.
103 | - پکیج `etcd-client` حاوی باینریهای کلاینت etcd است.
104 | - پکیج `python3-etcd` یک کلاینت پایتونی برای تعامل با etcd است که به برنامه های پایتونی اجازه میدهد تا با خوشه های etcd ارتباط برقرار کرده و مدیریت کنند.
105 |
106 | ---
107 | **تذکر:**
108 | عملیات بالا را باید عیناً روی هر سه نود پستگرس (psql-db-1~3) اجرا کرد.
109 |
110 | ---
111 | ## ۶- ۵. پیکربندی نودهای etcd
112 | برای پیکربندی هر نود etcd، لازم است نخست فایلهایی که در شاخهٔ `/var/lib/etcd/` قرار دارد را پاک میکنیم. وجود فایلهای پیشفرض در این مسیر باعث میشود نودهای etcd همگی با یک UUID یکسان ایجاد شوند و به همین خاطر نتوانند یکدیگر را به عنوان اعضای یک کلاستر شناسایی کنند:
113 | ```bash
114 | sudo rm -rf /var/lib/etcd/*
115 | ```
116 | سپس فایلی را که در مسیر `etc/default/etcd/` قرار دارد در ویرایشگر باز میکنیم و خطوط زیر را به آن میافزاییم. تنها لازم است مقدار `etcd-node-name` و `etcd-node-ip` را برای هر نود مطابق جدول زیر در آن جایگذاری کنیم.
117 |
118 | | etcd-node-name | etcd-node-ip |
119 | | ---------------| -------------|
120 | |etcd-1 | 192.168.228.141 |
121 | |etcd-2 | 192.168.228.142 |
122 | |etcd-3 | 192.168.228.143 |
123 |
124 |
125 | ```
126 | ETCD_NAME=""
127 | ETCD_LISTEN_PEER_URLS="http://:2380"
128 | ETCD_LISTEN_CLIENT_URLS="http://localhost:2379,http://:2379"
129 | ETCD_INITIAL_ADVERTISE_PEER_URLS="http://:2380"
130 | ETCD_INITIAL_CLUSTER="etcd-1=http://192.168.228.141:2380,etcd-2=http://192.168.228.142:2380,etcd-3=http://192.168.228.143:2380"
131 | ETCD_ADVERTISE_CLIENT_URLS="http://:2379"
132 | ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
133 | ETCD_INITIAL_CLUSTER_STATE="new"
134 | ```
135 | پس از اتمام ویرایش فایل پیکربندی، سرویس etcd را بازنشانی میکنیم:
136 | ```bash
137 | sudo systemctl restart etcd
138 | ```
139 | پس از بازنشانی، وضعیت سرویس را از طریق فرمانهای زیر چک میکنیم:
140 | ```bash
141 | sudo systemctl is-enabled etcd
142 | sudo systemctl status etcd
143 | ```
144 | خروجی فرمان اول باید `enabled` و خروجی فرمان دوم باید `active (running)` باشد. اکنون میتوانیم با فرمان زیر بررسی کنیم که آیا کلاستر به درستی شکل گرفته است یا نه:
145 | ```bash
146 | etcdctl member list
147 | ```
148 | خروجی این فرمان مشابه این خواهد بود:
149 | ```bash
150 | 38c2f5960a646674: name=etcd-3 peerURLs=http://192.168.228.143:2380 clientURLs=http://192.168.228.143:2379 isLeader=true
151 |
152 | 659f84d35a13cf2f: name=etcd-1 peerURLs=http://192.168.228.141:2380 clientURLs=http://192.168.228.141:2379 isLeader=false
153 |
154 | 731fb9c8c2f57b00: name=etcd-2 peerURLs=http://192.168.228.142:2380 clientURLs=http://192.168.228.142:2379 isLeader=false
155 | ```
156 | **نکته:** اگر پکیج `etcd-client` را نصب نکرده باشید نیز میتوانید از فرمان زیر استفاده کنید:
157 | ```bash
158 | curl http://:2380/members
159 | ```
160 | همانطور مشخص است کلاستر etcd به درستی شکل گرفته است و نودها همدیگر را شناختهاند و یک نود را به عنوان رهبر انتخاب کردهاند. اکنون میتوانیم پیکربندی پاترونی را آغاز کنیم.
161 |
162 | ## ۶- ۶. پیکربندی نودهای پاترونی
163 | پیکربندی پاترونی مهمترین بخش راهاندازی یک کلاستر Highly Available پستگرس است. بنابر این، بخشهای مختلف آن را گام به گام اضافه میکنیم و پارامتر هر بلاک را جداگانه توضیح میدهیم.
164 |
165 | ---
166 | **تذکر:**
167 | - پیکربندی پاترونی باید روی هر نود پستگرس به صورت جداگانه صورت پذیرد.
168 | - نمونهٔ کاملی از فایل پیکربندی پاترونی را میتوان در مخزن [گیتهاب پاترونی](https://github.com/patroni/patroni/blob/master/postgres0.yml) پیدا کرد.
169 |
170 | ---
171 | نخست، فایل `etc/patroni/config.yml/` را در ویرایشگر دلخواهمان باز میکنیم و پیکربندی زیر را به آن میافزاییم. در قسمت `name` باید `hostname` هر نود پستگرس را بنویسیم. مثلاً برای نود ۱، `dc1-psql-db-1` را قرار میدهیم و برای ۲ نود دیگر نیز به همین ترتیب عمل میکنیم:
172 | ```yml
173 | scope: postgres
174 | namespace: /db/
175 | name:
176 | ```
177 | آدرس API پاترونی را تکمیل میکنیم. به جای `` آیپی هر نود را وارد میکنیم:
178 | ```yml
179 | restapi:
180 | listen: :8008
181 | connect_address: :8008
182 | ```
183 | آدرس آیپی و پورت نودهای کلاستر etcd را به پاترونی میدهیم:
184 | ```yml
185 | etcd:
186 | hosts: 192.168.228.141:2379,192.168.228.142:2379,192.168.228.143:2379
187 | ```
188 | سپس پیکربندیهای زیر را به بخش `bootstrap` میافزاییم. در این بخش تعریف میکنیم که نود پستگرس باید در هنگام راهاندازی اولیه از چه مقادیر و تنظیمات پیشفرضی استفاده کند. همچنین نحوهٔ تعامل پاترونی با مخزن توزیعشده پیکربندی (DCS) یا همان etcd را در اینجا تنظیم میکنیم:
189 | ```yml
190 | bootstrap:
191 | dcs:
192 | # Time-to-live for the leader lock, in seconds.
193 | ttl: 30
194 | # Number of seconds to wait between checks on the cluster state.
195 | loop_wait: 10
196 | # Timeout for DCS and PostgreSQL operations, in seconds.
197 | retry_timeout: 10
198 | # Maximum allowed lag in bytes for a follower to be considered as a candidate for promotion.
199 | maximum_lag_on_failover: 1048576
200 | postgresql:
201 | # Enables the use of pg_rewind for faster failover recovery.
202 | use_pg_rewind: true
203 | # Uses replication slots, which ensures that the primary does not remove WAL segments needed by replicas.
204 | use_slots: true
205 | parameters:
206 | # Enables hot standby mode and ensures that enough info is written to the WAL to support a robust HA setup.
207 | wal_level: hot_standby
208 | # Allows read-only queries on standby servers.
209 | hot_standby: "on"
210 | # Maximum number of concurrent connections.
211 | max_connections: 100
212 | # Maximum number of background worker processes.
213 | max_worker_processes: 8
214 | # Minimum number of past log file segments to keep for standby servers.
215 | wal_keep_segments: 8
216 | # Maximum number of concurrent connections for streaming replication.
217 | max_wal_senders: 10
218 | # Maximum number of replication slots.
219 | max_replication_slots: 10
220 | # Maximum number of prepared transactions (0 disables the feature).
221 | max_prepared_transactions: 0
222 | # Maximum number of locks per transaction.
223 | max_locks_per_transaction: 64
224 | # Logs additional information in the WAL to support pg_rewind.
225 | wal_log_hints: "on"
226 | # Disables tracking of commit timestamps.
227 | track_commit_timestamp: "off"
228 | # Enables WAL archiving.
229 | archive_mode: "on"
230 | # Forces a switch to a new WAL file if a new file hasn't been started within 1800 seconds.
231 | archive_timeout: 1800s
232 | # Command to archive WAL files. This command creates a directory named 'wal_archive', checks if the file doesn't already exist, and then copies it
233 | archive_command: mkdir -p ../wal_archive && test ! -f ../wal_archive/%f && cp %p ../wal_archive/%f
234 | recovery_conf:
235 | # Command used to retrieve archived WAL files during recovery. It copies files from the 'wal_archive' directory.
236 | restore_command: cp ../wal_archive/%f %p
237 | initdb:
238 | # Sets the default authentication method
239 | - auth: scram-sha-256
240 | # Sets the default character encoding for the database to UTF-8, which supports a wide range of characters.
241 | - encoding: UTF8
242 | # Enables data checksums on this cluster, which helps detect corruption caused by hardware or I/O subsystem faults.
243 | - data-checksums
244 | ```
245 |
246 | در ادامه نحوهٔ احراز هویت کلاینتهای کلاستر را تعیین میکنیم (`pg_hba.conf`) و به کاربر `replicator` که برای همتاسازی بین نودهای کلاستر از آن استفاده میشود، اجازه میدهیم که با مکانیزم `scram-sha-256` که امنترین شیوه احراز هویت از طریق رمز عبور است، به نودهای کلاستر پستگرس دسترسی پیدا کند. رمز عبور کاربر `admin` را نیز در ادامهٔ همین قسمت تعیین کرده و آن را جایگزین `` میکنیم:
247 | ```yml
248 | # This section configures the pg_hba.conf file, which controls client authentication for PostgreSQL.
249 | pg_hba:
250 | - host replication replicator 127.0.0.1/32 scram-sha-256
251 | - host replication replicator 192.168.228.141/0 scram-sha-256
252 | - host replication replicator 192.168.228.142/0 scram-sha-256
253 | - host replication replicator 192.168.228.143/0 scram-sha-256
254 | - host all all 0.0.0.0/0 scram-sha-256
255 |
256 | # This section defines database users and their properties.
257 | users:
258 | admin:
259 | password:
260 | options:
261 | - createrole
262 | - createdb
263 | ```
264 |
265 | سپس، باقیماندهٔ تنظیمات پستگرس و پاترونی، مانند آدرس پستگرس در هر نود، رمز عبور کاربر `replicator` و `postgres`، و ... را وارد کرده و تغییرات را ذخیره میکنیم.
266 | ```yml
267 | postgresql:
268 | # Specifies the IP address and port on which PostgreSQL should listen for connections.
269 | listen: :5432
270 | # The address and port other nodes should use to connect to this instance.
271 | connect_address: :5432
272 | # The directory where PostgreSQL will store its data files.
273 | data_dir: /var/lib/patroni/
274 | # The location of the .pgpass file, which stores passwords for non-interactive connections.
275 | pgpass: /tmp/pgpass
276 |
277 | # This defines authentication details for different types of connections.
278 | authentication:
279 | replication:
280 | username: replicator
281 | password:
282 | superuser:
283 | username: postgres
284 | password:
285 |
286 | parameters:
287 | # Sets the current directory as the location for Unix-domain sockets.
288 | unix_socket_directories: '.'
289 | password_encryption: 'scram-sha-256'
290 |
291 | # These are Patroni-specific tags that control various behaviors
292 | tags:
293 | # Allows this node to be considered for failover.
294 | nofailover: false
295 | # Allows this node to be considered for load balancing.
296 | noloadbalance: false
297 | # This node will not be used as a preferred source when adding new nodes.
298 | clonefrom: false
299 | # Allows this node to be considered for synchronous replication.
300 | nosync: false
301 | ```
302 |
303 | پس از اتمام ویرایش فایل `config.yml` لازم است مالکیت شاخهای را که برای ذخیرهسازی دادههای پاترونی در نظر گرفتیم (`/var/lib/patroni/`) به کاربر`postgres` انتقال بدهیم و دسترسی خواندن و نوشتن را فقط به مالک شاخه محدود کنیم:
304 | ```bash
305 | mkdir -p /var/lib/patroni
306 |
307 | chown -R postgres:postgres /var/lib/patroni
308 |
309 | chmod 700 /var/lib/patroni
310 | ```
311 |
312 | اکنون میتوانیم سرویس پاترونی را روی هر سه نود راهاندازی کنیم. با این کار، نود اول به عنوان رهبر انتخاب شده و دو نود دیگر از طریق API پاترونی به آن میپیوندند.
313 | ```bash
314 | systemctl start patroni
315 | systemctl status patroni
316 | ```
317 | ---
318 | **تذکر:**
319 | چنانچه پس از راهاندازی اولیه لازم شد در پارامترهای قسمت `bootstrap.dcs` تغییری ایجاد کنیم، باید از دستور `patronictl edit-config` استفاده کنیم.
320 |
321 | ---
322 |
323 | برای بررسی نهایی نودهای پستگرسی که پاترونی مدیریت میکند، فرمان زیر را روی یکی از نودها اجرا کنید:
324 | ```bash
325 | patronictl -c /etc/patroni/config.yml list
326 | ```
327 |
328 | خروجی آن باید چنین چیزی باشد:
329 | ```
330 | + Cluster: postgres (7422247765142374405) --+-----------+----+-----------+
331 | | Member | Host | Role | State | TL | Lag in MB |
332 | +---------------+-----------------+---------+-----------+----+-----------+
333 | | dc1-psql-db-1 | 192.168.228.141 | Leader | running | 1 | |
334 | | dc1-psql-db-2 | 192.168.228.142 | Replica | streaming | 1 | 0 |
335 | | dc1-psql-db-3 | 192.168.228.143 | Replica | streaming | 1 | 0 |
336 | +---------------+-----------------+---------+-----------+----+-----------+
337 | ```
338 |
339 | در نهایت اجرای اتوماتیک سرویس پستگرس را پس از بوت شدن مجدد سیستم غیرفعال میکنیم تا کنترل کلاستر پستگرس در دست پاترونی باقی بماند. اگر اجرای این فرمان موفقیتآمیز باشد، خروجی خاصی نخواهد داشت:
340 | ```bash
341 | sudo systemctl disable --now postgresql
342 | ```
343 | ## ۶- ۷. نصب و پیکربندی HAProxy
344 | پس از استقرار موفقیتآمیز کلاستر پستگرس باید ترافیک کلاینتها را بین نودها توزیع کنیم. برای این منظور لازم است از لودبالانسرهای لایهٔ ۴ مانند HAProxy بالای سر کلاستر استفاده کنیم. در محیطهای تست و توسعه میشود HAProxy را مستقیماً بر روی نودهای پستگرس نصب کرد. اما در محیط پروداکشن به دلایل زیر لازم است نودهای مجزایی برای آن در نظر بگیریم:
345 | - **عملکرد**: پستگرس، بهویژه زمانی که تحت فشار زیادی باشد، منابع زیادی مصرف میکند. از اینرو، اختصاص دادن ماشینهای مجزا به لودبالانسر به ما اطمینان میدهد که عملکرد دیتابیس بابت عملیات توزیع بار تحت تأثیر قرار نمیگیرد.
346 | - **قابلیت نگهداری**: در نظر گرفتن ماشینهای مجزا برای لودبالانسر به ما امکان میدهد که تعمیر، بهروزرسانی و عیبیابی در لایهٔ توزیع بار را بدون درگیر کردن نودهای پستگرس انجام بدهیم.
347 | - **مقیاسپذیری**: به اقتضای مقیاسپذیری ممکن است لازم باشد لایهٔ توزیع بار را به نحو متفاوتی نسبت به لایهٔ دیتابیس گسترش بدهیم. داشتن ماشینهای مجزا این انعطافپذیری را به ما میدهد.
348 | - **امنیت**: با استفاده از نودهای مجزا برای توزیع بار میتوانیم در صورت لزوم معماری شبکهٔ ایمنتری را اجرا کنیم و از یک سو، نودهای دیتابیس را در یک شبکهٔ خصوصی بگذاریم و از سوی دیگر، نودهای HAProxy را در دسترسی لایهٔ اپلیکیشن قرار بدهیم.
349 | ---
350 | **تذکر:**
351 | نصب و پیکربندی HAProxy باید عیناً روی هر کدام از نودهای توزیع بار صورت پذیرد.
352 |
353 | ---
354 | برای نصب HAProxy از فرمان زیر استفاده میکنیم:
355 | ```bash
356 | sudo apt update
357 | sudo apt install haproxy
358 | ```
359 | پس از اتمام نصب، در ابتدا از فایل پیکربندی پیش فرض HAProxy یک پشتیبان درست میکنیم:
360 | ```bash
361 | mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.orig
362 | ```
363 | سپس فایل جدیدی به نام `etc/haproxy/haproxy.cfg/` ایجاد میکنیم و خطوط زیر را به آن اضافه میکنیم:
364 | ```
365 | # Global configuration settings
366 | global
367 | # Maximum connections globally
368 | maxconn 100
369 | # Logging settings
370 | log 127.0.0.1 local2
371 |
372 | # Default settings
373 | defaults
374 | # Global log configuration
375 | log global
376 | # Set mode to TCP
377 | mode tcp
378 | # Number of retries
379 | retries 2
380 | # Client timeout
381 | timeout client 30m
382 | # Connect timeout
383 | timeout connect 4s
384 | # Server timeout
385 | timeout server 30m
386 | # Check timeout
387 | timeout check 5s
388 |
389 | # Stats configuration
390 | listen stats
391 | # Set mode to HTTP
392 | mode http
393 | # Bind to port 8080
394 | bind *:8080
395 | # Enable stats
396 | stats enable
397 | # Stats URI
398 | stats uri /
399 |
400 | # PostgreSQL configuration
401 | listen production
402 | # Bind to port 5000
403 | bind *:5000
404 | # Enable HTTP check
405 | option httpchk OPTIONS/master
406 | # Expect status 200
407 | http-check expect status 200
408 | # Server settings
409 | default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
410 | # Define PostgreSQL servers
411 | server dc1-psql-db-1 192.168.228.141:5432 maxconn 100 check port 8008
412 | server dc1-psql-db-2 192.168.228.142:5432 maxconn 100 check port 8008
413 | server dc1-psql-db-3 192.168.228.143:5432 maxconn 100 check port 8008
414 | listen standby
415 | bind *:5001
416 | option httpchk OPTIONS/replica
417 | http-check expect status 200
418 | default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
419 | server dc1-psql-db-1 192.168.228.141:5432 maxconn 100 check port 8008
420 | server dc1-psql-db-2 192.168.228.142:5432 maxconn 100 check port 8008
421 | server dc1-psql-db-3 192.168.228.143:5432 maxconn 100 check port 8008
422 | ```
423 |
424 | بر اساس پیکربندی فوق هر نود HAProxy روی پورت `5000` منتظر دریافت کانکشنها به نود Primary و روی پورت `5001` منتظر دریافت کانکشنها به نودهای replica است. بنابر این اکنون میتوان درخواستهای write را به نود اصلی فرستاد اما درخواستهای read را به صورت roundrobin میان سه سروری که در انتهای پیکربندی به عنوان بکاند تعریف شدهاند، توزیع کرد.
425 | علاوه بر این، طبق تنظیمات بلاک `listen stats`، داشبورد وضعیت HAProxy روی پورت `8080` قابل دسترس خواهد بود. در تنظیمات هر دو بلاک `listen production` و `listen standby`، در بخش `default-server` نیز پارامترهایی معین شده که رفتار HAProxy را در قبال سرورهای بکاند تعیین میکند:
426 | - فاصلهٔ زمانی بین چکهای سلامتی ۳ ثانیه است (`inter 3s`).
427 | - اگر چک سلامتی ۳ بار پیاپی ناموفق باشد، آن نود به عنوان نود افتاده در نظر گرفته میشود (`fall 3`).
428 | - اگر چک سلامتی ۲ بار پیاپی موفق باشد، آن نود مجدداً برقرار در نظر گرفته میشود (`rise 2`).
429 | - اگر یک سرور به عنوان افتاده در نظر گرفته شود، HAProxy بلافاصله تمامی سشنهای آن سرور را میبندد. این امر کمک میکند که سرورهای معیوب به سرعت کنار بروند و ترافیک به سروهای سالم هدایت شود (`on-marked-down shutdown-sessions`).
430 |
431 | اکنون میتوان سرویس HAProxy را به کار انداخت و صحت آن را بررسی کرد:
432 | ```bash
433 | sudo systemctl restart haproxy
434 | sudo systemctl status haproxy
435 | ```
436 | چنانچه راهاندازی سرویس ناموفق بود، با دستور زیر خطاهای فایل پیکربندی را بررسی کنید:
437 | ```bash
438 | /usr/sbin/haproxy -c -V -f /etc/haproxy/haproxy.cfg
439 | ```
440 | ## ۶- ۸. نصب و پیکربندی Keepalived
441 | برای آنکه نودهای توزیع بار بتوانند در یک حالت Highly Available کار کنند و در صورت بروز عیب در یکی از آنها، نود دیگر بتواند به کار ادامه دهد لازم است یک آیپی شناور بین آنها وجود داشته باشد که در هر لحظه فقط روی یکی از آن دو نود فعال باشد و ترافیک پروداکشن به سمت آن هدایت شود. برای این منظور از Keepalived میکنیم.
442 | برای نصب Keepalived روی نودهای توزیع بار از فرمان زیر استفاده میکنیم:
443 | ```bash
444 | sudo apt install keepalived
445 | ```
446 | پس از نصب، هر کدام از نودها را جداگانه پیکربندی میکنیم. پیکربندی نود اول (`192.168.228.144`) را در مسیر `etc/keepalived/keepalived.conf/` به این صورت انجام میدهیم:
447 | ```
448 | global_defs {
449 | }
450 | vrrp_script chk_haproxy {
451 | script "/usr/bin/killall -0 haproxy"
452 | interval 2
453 | weight 2
454 | }
455 | vrrp_instance VI_1 {
456 | interface ens33
457 | state MASTER
458 | priority 101 # 101 on master, 100 on backup
459 | virtual_router_id 51
460 | advert_int 1
461 | authentication {
462 | auth_type PASS
463 | auth_pass
464 | }
465 | virtual_ipaddress {
466 | 192.168.228.140
467 | }
468 | unicast_src_ip 192.168.228.144 # This haproxy node
469 | unicast_peer {
470 | 192.168.228.145 # Other haproxy nodes
471 | }
472 | track_script {
473 | chk_haproxy
474 | }
475 | }
476 | ```
477 | به طریق مشابه پیکربندی نود دوم (`192.168.228.145`) را در همان مسیر `etc/keepalived/keepalived.conf/` به این صورت انجام میدهیم:
478 | ```
479 | global_defs {
480 | }
481 | vrrp_script chk_haproxy {
482 | script "/usr/bin/killall -0 haproxy"
483 | interval 2
484 | weight 2
485 | }
486 | vrrp_instance VI_1 {
487 | interface ens33
488 | state BACKUP
489 | priority 100
490 | virtual_router_id 51
491 | advert_int 1
492 | authentication {
493 | auth_type PASS
494 | auth_pass
495 | }
496 | virtual_ipaddress {
497 | 192.168.228.140
498 | }
499 | unicast_src_ip 192.168.228.145 # This haproxy node
500 | unicast_peer {
501 | 192.168.228.144 # Other haproxy nodes
502 | }
503 | track_script {
504 | chk_haproxy
505 | }
506 | }
507 | ```
508 | در هر دو پیکربندی بالا باید این نکات توجه کرد:
509 | - در قسمت `interface` نام کارت شبکهٔ هر ماشین را بنویسید.
510 | - مقدار `virtual_router_id` یک عدد انتخابی است اما بین همهٔ نودهای Keepalived باید یکسان باشد.
511 | - رمزی که برای ارتباط دو نود Keepalived به جای `` قرار داده میشود باید در هر دو نود یکسان باشد.
512 | - آیپی شناور (`virtual_ipaddress`) در هر دو پیکربندی یکسان و برابر با `192.168.228.140` است.
513 | - در هر نود، `unicast_src_ip` معادل با آیپی همان نود و `unicast_peer` فهرستی از نودهای دیگر Keepalived است. هر کدام از آیپیهای دیگر را باید در یک خط نوشت.
514 |
515 | پس ذخیره کردن پیکربندی Keepalived در هر دو نود میتوانیم سرویس آن را فعال کنیم:
516 | ```bash
517 | sudo systemctl start keepalived
518 | sudo systemctl enable keepalived
519 | ```
520 | درستی عملکرد Keepalived را نخست با بررسی وضعیت سرویس از طریق فرمان زیر:
521 | ```bash
522 | sudo systemctl status keepalived
523 | ```
524 | و سپس از طریق بررسی آیپیهای کارت شبکه با فرمان `ip a` متوجه میشویم. چنانچه نود ۱ علاوه بر آیپی خودش، آیپی شناور را نیز دریافت کرده باشد یعنی راهاندازی Keepalived به درستی انجام شده و مراحل راهاندازی کلاستر Highly Available پستگرس با ۳ نود دیتابیس و ۲ نود توزیعکنندهٔ بار به موفقیت به پایان رسیده است. هم اکنون میتوانیم از آدرس `192.168.228.140:5000` برای درخواستهای read/write و از `192.168.228.140:5001` برای درخواستهای read-only استفاده کنیم.
525 |
526 | ## ۶- ۹. تست عملکرد
527 | برای تست عملیات failover، داشبورد HAProxy را که روی آدرس `192.168.228.140:8080` در دسترس است، باز میکنیم. دقت کنید که پورت 8080 را قبلاً خودمان در پیکربندی HAProxy تعیین کردهایم و آیپی شناور نیز به همیشه ما را به آن نود HAProxy که ترافیک پروداکشن روی آن جریان دارد هدایت میکند. ذیل جدول `postgres` فهرست نودهای بکاند را مشاهده میکنید. نود اول که اکنون به عنوان primary عمل میکند سبز رنگ و `up` است و دو نود دیگر که در حالت streaming قرار دارند قرمز و `down` نشان داده میشوند.
528 | اکنون با دستور زیر نود ۱ را از مدار خارج میکنیم:
529 | ```bash
530 | sudo systemctl stop patroni
531 | ```
532 | سپس وضعیت پاترونی را با دستور زیر چک میکنیم:
533 | ```bash
534 | patronictl -c /etc/patroni/config.yml list
535 | ```
536 | خروجی باید چنین چیزی باشد:
537 | ```
538 | + Cluster: postgres (7422247765142374405) --+-----------+----+-----------+
539 | | Member | Host | Role | State | TL | Lag in MB |
540 | +---------------+-----------------+---------+-----------+----+-----------+
541 | | dc1-psql-db-1 | 192.168.228.141 | Replica | stopped | | unknown |
542 | | dc1-psql-db-2 | 192.168.228.142 | Replica | running | 1 | 0 |
543 | | dc1-psql-db-3 | 192.168.228.143 | Leader | running | 2 | |
544 | +---------------+-----------------+---------+-----------+----+-----------+
545 | ```
546 |
547 | اکنون اگر به داشبود HAProxy بازگردید، خواهید دید که نود اول `DOWN` شده و به جای آن یکی از دو نود دوم و سوم `UP` شده است. در نهایت، زمانی که نود ۱ را دوباره به کلاستر برگردانید، به عنوان standby با نود primary همگامسازی خواهد شد.
548 |
549 | ## ۶- ۱۰. پیوندها
550 | - [Streaming Replication Protocol - PostgreSQL Documentation](https://www.postgresql.org/docs/current/protocol-replication.html)
551 | - [Patroni GitHub Repo](https://github.com/patroni/patroni/tree/master)
552 | ## ۶- ۱۱. منابع
553 | - [High Availability PostgreSQL with Patroni and HAProxy - ATA Learning ](https://adamtheautomator.com/patroni/)
554 | - [PostgreSQL HA Architecture - Mahmut Can Uçanefe](https://medium.com/@c.ucanefe/patroni-ha-proxy-feed1292d23f)
555 | - [Create a Highly Available PostgreSQL Cluster Using Patroni and HAProxy - Linode Docs](https://www.linode.com/docs/guides/create-a-highly-available-postgresql-cluster-using-patroni-and-haproxy/)
556 | - [Highly Available PostgreSQL Cluster using Patroni and HAProxy - JFrog Community](https://jfrog.com/community/devops/highly-available-postgresql-cluster-using-patroni-and-haproxy/)
557 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # devops-notes
2 | A repository for technical documentation, deployment guides, and system architecture references.
3 |
--------------------------------------------------------------------------------