Создание кластера Postgres на Ubuntu с помощью Patroni + Consul


Используемые термины: PostgreSQL, Patroni, Consul, Ubuntu.
Кластер Postgresql, созданный штатными средствами не совсем удобен в эксплуатации — у него сложные механизмы отслеживания проблем с репликацией, нет возможности автоматического переключения с основной ноды на резервную и обратно, сложный процесс восстановления после падения. Приложение Patroni позволяет сделать процесс управления кластером PostgreSQL проще. Оно хранит данные кластера в базе типа key-value и ориентируется на работоспособность системы с помощью DCS (Distributed Control Service). В качестве таких систем для Patroni могут выступать:
В данной инструкции мы рассмотрим процесс установки и настройки Patroni с Consul на операционной системе Ubuntu. Также мы рассмотрим установку consul в режиме агента.
Предполагается, что у нас уже есть кластер consul, а также серверы с установленным PostgreSQL (чистыми без полезных данных). Ссылки на необходимые материалы будут приведены в конце данной инструкции. В целом, инструкция также подойдет для Postgres Pro.
Подготовка системы
Регистрация агента consul
Установка и настройка Patroni
Политика для ACL на consul
Примеры команд для patronictl
Решение возможных проблем
Дополнительная информация
Предварительная настройка
Прежде чем перейти к настройке patroni и кластера, подготовим наши серверы баз данных.
Настройка брандмауэра
Нам нужно открыть следующие порты в брандмауэре:
- 8300,8301,8302,8500 — для работы консул агента.
- 5432 — порт postgresql.
- 8008 — порт для patroni
По умолчанию, в Ubuntu брандмауэр работает в режиме «разрешить все» и нет необходимости его настраивать. Но если в вашей конфигурации он используется, то правила необходимо настроить.
Вводим команды:
iptables -I INPUT -p tcp --match multiport --dport 8300,8500 -j ACCEPT
iptables -I INPUT -p tcp --match multiport --dport 8301,8302 -j ACCEPT
iptables -I INPUT -p udp --match multiport --dport 8301,8302 -j ACCEPT
iptables -I INPUT -p tcp --dport 5432 -j ACCEPT
iptables -I INPUT -p tcp --dport 8008 -j ACCEPT
Для сохранения используем пакет iptables-persistent:
apt install iptables-persistent
netfilter-persistent save
Подготовка СУБД
Patroni самостоятельно инициализирует базу и настройки, поэтому наш каталог с данными Postgresql должен быть чист, а сервис postgresql находиться в выключенном состоянии.
Если на вашем сервере баз данных есть ценная информация, действия ниже приведут к ее потере. В этом случае стоит развернуть кластер на других серверах и перенести данные.
На наших серверах СУБД смотрим путь до каталога с данными:
su - postgres -c "psql -c 'SHOW data_directory;'"
Если мы получим ошибку:
psql: could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?... значит, наш сервер находится в выключенном состоянии. Его можно включить на некоторое время или будем просто использовать свой путь, который укажем в конфигурационном файлей patroni.
В моем случае для обоих серверов путь был /var/lib/pgsql/11/data — сохраняем его.
Останавливаем сервис postgres и запрещаем его автозапуск:
systemctl disable postgresql-11 --now
* имя службы может зависеть от версии. Например, у меня 11-я.
Удаляем содержимое каталога с данными, путь до которого нам вернула команда SHOW data_directory:
rm -rf /var/lib/pgsql/11/data/*
* где /var/lib/pgsql/11/data — путь, который мы получили командой SHOW data_directory.
Наша система готова к дальнейшей настройке.
Установка и регистрация агента Consul
Для начала, установим дополнительные пакеты:
- wget — утилита для загрузки файлов.
- unzip — пакет для распаковки архивов zip.
apt install wget unzip
На странице со списком релизов необходимо посмотреть на все версии и выбрать необходимую. Также мы можем посмотреть версию consul на сервере:
consul -v
... и установить такую же.
Так или иначе, для нашего удобства, создаем переменную с номером версии:
export VER="1.15.1"
И скачиваем архив с бинарным файлом:
wget https://releases.hashicorp.com/consul/${VER}/consul_${VER}_linux_amd64.zip
Распаковываем его в каталог /usr/bin:
unzip consul_${VER}_linux_amd64.zip -d /usr/bin
Проверяем, что команды консул выполняются:
consul -v
Мы должны увидеть версию программы:
Consul v1.10.2
...
Агент установлен.
Создаем конфигурационный файл. Для каждого сервера кластера будет свой конфигурационный файл.
а) на первом сервере:
vi /etc/consul.d/config.json
{
"server": false,
"datacenter": "dc1",
"node_name": "postgresql1",
"data_dir": "/var/lib/consul",
"bind_addr": "192.168.1.10",
"client_addr": "127.0.0.1",
"retry_join": ["consul01", "consul02", "consul03"],
"encrypt": "BE2FFVPwyxGhF/tnlfO4dckMoDoU1UOW/AdJ/7QkTNI=",
"log_level": "warn",
"enable_syslog": true,
"enable_local_script_checks": true,
"enable_script_checks": true,
"leave_on_terminate": true
}
б) на втором сервере:
vi /etc/consul.d/config.json
{
"server": false,
"datacenter": "dc1",
"node_name": "postgresql2",
"data_dir": "/var/lib/consul",
"bind_addr": "192.168.1.20",
"client_addr": "127.0.0.1",
"retry_join": ["consul01", "consul02", "consul03"],
"encrypt": "BE2FFVPwyxGhF/tnlfO4dckMoDoU1UOW/AdJ/7QkTNI=",
"log_level": "warn",
"enable_syslog": true,
"enable_local_script_checks": true,
"enable_script_checks": true,
"leave_on_terminate": true
}
* обратите внимание, что наши конфигурации различаются только директивами node_name (имя, под которым нода зарегистрируется в консуле) и bind_addr (на каком адресе должен слушать агент). Предполагается, что наши серверы работают на адресах 192.168.1.10 и 192.168.1.20.
** также для нас имеют значение следующие настройки:
- datacenter — датацентр, к которому будет присоединяться участник кластера. dc1 — датацентр по умолчанию.
- retry_join — список серверов консула, к которым должен присоединиться агент.
- encrypt — ключ, который был сформирован для серверов консул и используется в качестве значения параметра encrypt (его можно посмотреть в конфигурационном файле на сервере consul).
Подробнее о регистрации агента в консуле читайте в инструкции Установка агента Consul и примеры регистрации сервисов.
Если наш сервер consul настроен на разграничение прав с помощью ACL, необходимо также добавить опцию acl:
...,
"acl": {
"enabled": true,
"tokens": {
"default": "6e57aef4-95e5-47cb-944f-8efa04d6d2fa"
}
}
...* где значение default — токен для acl с правами регистрации в качестве агента. Обратите внимание на запятую в конце строки, после которой мы вставили acl.
Настройка консула закончена. Можно его запускать.
Для разрешения автозапуска и старта сервиса выполним команду на всех серверах кластера PostgreSQL:
systemctl enable consul --now
Проверяем, что наши серверы стали частью кластера:
consul members
Среди всего списка мы должны увидеть:
postgresql1 192.168.1.10:8301 alive client ...
postgresql2 192.168.1.20:8301 alive client ...
* где postgresql1 и postgresql2 — имена нод, под которыми мы их зарегистрировали.
Мы готовы переходить к настройке и настройке patroni.
Установка и настройка Patroni
Нужный нам пакет для установки есть в репозитории PostgreSQL. Скорее всего, он есть в нашей системе, так как мы устанавливали последний, но мы все-равно, приведем пример команды для настройки postgres repo:
echo "deb [arch=amd64] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/postgresql.list
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
Теперь ставим сам patroni:
apt install --no-install-recommends patroni python3-consul
* обратите внимание, что мы ставим пакет patroni-consul (патрони, заточенный для консула).
Установка завершена. Переходим к настройке.
Создадим каталог для хранения конфигурации:
mkdir /etc/patroni
И сам конфигурационный файл:
vi /etc/patroni/config.yml
name: postgresql1
scope: pgdb
watchdog:
mode: off
consul:
host: "localhost:8500"
register_service: true
#token: <consul-acl-token>
restapi:
listen: 0.0.0.0:8008
connect_address: "192.168.1.10:8008"
auth: 'patrest:password'
bootstrap:
dcs:
ttl: 30
loop_wait: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
archive_mode: "on"
wal_level: hot_standby
max_wal_senders: 10
wal_keep_segments: 8
archive_timeout: 1800s
max_replication_slots: 5
hot_standby: "on"
wal_log_hints: "on"
initdb:
- encoding: UTF8
- data-checksums
pg_hba:
- local all postgres peer
- host replication replicator 192.168.1.0/24 md5
- host replication replicator 127.0.0.1/32 trust
- host all all 0.0.0.0/0 md5
postgresql:
pgpass: /var/lib/pgsql/11/.pgpass
listen: 0.0.0.0:5432
connect_address: "192.168.1.10:5432"
data_dir: /var/lib/pgsql/11/data/
bin_dir: /usr/pgsql-11/bin/
pg_rewind:
username: postgres
password: password
pg_hba:
- local all postgres peer
- host replication replicator 192.168.1.0/24 md5
- host replication replicator 127.0.0.1/32 trust
- host all all 0.0.0.0/0 md5
replication:
username: replicator
password: password
superuser:
username: postgres
password: password
* особое внимание стоит уделить данным, которые отмечены желтым.
** данные конфигурационные файлы на разных серверах будут немного различаться. Опишем подробнее опции наиболее критичные для работы кластера:
- name — имя узла, на котором настраивается данный конфиг.
- scope — имя кластера. Его мы будем использовать при обращении к ресурсу, а также под этим именем будет зарегистрирован сервис в consul.
- consul - token — если наш кластер consul использует ACL, необходимо указать токен.
- restapi - connect_address — адрес на настраиваемом сервере, на который будут приходить подключения к patroni.
- restapi - auth — логин и пароль для аутентификации на интерфейсе API.
- pg_hba — блок конфигурации pg_hba для разрешения подключения к СУБД и ее базам. Необходимо обратить внимание на подсеть для строки host replication replicator. Она должна соответствовать той, которая используется в вашей инфраструктуре.
- postgresql - pgpass — путь до файла, который создаст патрони. В нем будет храниться пароль для подключения к postgresql. Он будет зависеть от версии СУБД.
- postgresql - connect_address — адрес и порт, которые будут использоваться для подключения к СУБД.
- postgresql - data_dir — путь до файлов с данными базы.
- postgresql - bin_dir — путь до бинарников postgresql.
- pg_rewind, replication, superuser — логины и пароли, которые будут созданы для базы.
На втором сервере будет такой же конфигурационный файл, за исключением следующих опций:
name: postgresql2
...
connect_address: "192.168.1.20:8008"
...
connect_address: "192.168.1.20:5432"
...
Разрешаем автозапуск и стартуем сервис patroni:
systemctl enable patroni --now
Проверяем статусы сервиса на обоих серверах:
systemctl status patroni
Посмотреть список нод можно командой:
patronictl -c /etc/patroni/config.yml list
Мы должны увидеть что-то на подобие:
+ Cluster: pgdb (7126124696482454785) -+---------+----+-----------+
+-------------+--------------+---------+---------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
| postgresql1 | 192.168.1.10 | Leader | running | 1 | |
| postgresql2 | 192.168.1.20 | Replica | running | 1 | 0 |
+-------------+--------------+---------+---------+----+-----------+
Можно проверить, что сервер консул разрешает имена кластера:
nslookup -port=8600 master.pgdb.service.consul 127.0.0.1
nslookup -port=8600 replica.pgdb.service.consul 127.0.0.1
* где consul — настроенный в consul домен.
Команды нам должны вернуть адреса соответствующих серверов — лидера и реплики.
Наш кластер в рабочем состоянии.
Использование ACL на сервере Consul
Как было сказано выше, если сервер консула использует проверку доступа на основе ACL, необходимо прописать token. Рассмотрим процесс подробнее.
Сначала на сервере консул создаем файл для политики:
cd /var/lib/consul
vi patroni-policy.json
service_prefix "" {
policy = "write"
}
session_prefix "" {
policy = "write"
}
key_prefix "" {
policy = "write"
}
node_prefix "" {
policy = "read"
}
agent_prefix "" {
policy = "read"
}
Для ее применения вводим команду:
consul acl policy create -name "patroni-policy" -rules @patroni-policy.json
Теперь создаем токен с привязкой к созданной политике:
consul acl token create -description "Token for Patroni" -policy-name patroni-policy
Мы должны увидеть что-то на подобие:
...
SecretID: 5adb466f-b6ee-9048-6458-e8edbffc42a3
...
Это и есть токен, который нужно прописать в конфигурационном файле patroni:
vi /etc/patroni/cofig.yml
...
consul:
...
token: 5adb466f-b6ee-9048-6458-e8edbffc42a3
После чего сервис нужно перезапустить:
systemctl restart patroni
Дополнительные команды управления patroni
Рассмотрим несколько полезных команд для работы с patroni при помощью patronictl.
1. Настройка системной переменной.
По умолчанию, для ввода команд patronictl необходимо указывать путь до конфигурационного файла, например, мы вводили команду:
patronictl -c /etc/patroni/config.yml list
Чтобы этого не делать, мы можем указать путь до конфига с помощью системной переменной PATRONICTL_CONFIG_FILE:
export PATRONICTL_CONFIG_FILE=/etc/patroni/config.yml
Если нам нужно, чтобы системная переменная задавалась автоматически при входе пользователя в консоль, то в файл:
vi ~/.bashrc
Добавить:
export PATRONICTL_CONFIG_FILE=/etc/patroni/config.yml
Теперь можно вводить команду patronictl без указания пути до конфигурационного файла.
2. Список кластеров и узлов.
Команда позволяет увидеть кластеры, их узлы со статусами и сводной информацией. Смотрим с помощью аргумента list.
patronictl list
Если у нас несколько кластеров, то можно указать конкретный, чтобы получить список узлов только для него, например:
patronictl list pgdb
3. Смена лидера.
Может быть выполнена командой patronictl с аргументом failover. Например:
patronictl failover pgdb
Система покажет список узлов, на которые можно передать функцию лидера — указываем его:
Candidate ['postgresql2'] []: postgresql2
И подтверждаем наш выбор:
Are you sure you want to failover cluster pgdb, demoting current master postgresql2? [y/N]: y
4. Повторная инициализация узла кластера.
Бывает так, что один из участников кластера подвисает и репликация может работать неправильно. Мы можем увидеть в статусе большое значение для колонки Lag in MB, например:
| Member | Host | Role | State | TL | Lag in MB |
| postgresql1 | 192.168.1.10 | Leader | running | 1 | |
| postgresql2 | 192.168.1.20 | Replica | running | 1 | 1054 |
В этом случае нам может понадобиться повторно инициализировать узел для кластера. Это выполняется с помощью аргумента reinit:
patronictl reinit pgdb
Система задаст вопрос, для какого узла выполнить операцию — вписываем имя узла:
Which member do you want to reinitialize [postgresql1, postgresql2]? []: postgresql1
* в нашем примере мы выполним реинициализацию на сервере postgresql1.
Подтверждаем наше действие:
Are you sure you want to reinitialize members postgresql1? [y/N]: y
Посмотреть результат можно командой:
patronictl list
Возможные ошибки
Увидеть подробный лог работы patroni можно с помощью команды:
journalctl -u patroni -e
Рассмотрим некоторые проблемы, с которыми удалось столкнуться мне.
waiting for leader to bootstrap
Команда:
patronictl -c /etc/patroni/config.yml list
... показывает, что все участники кластера работают в режиме Replica, а лидера нет. В логах мы видим строку:
... waiting for leader to bootstrap
Причина: patroni не может инициализировать кластер и выбрать лидера. Как правило, из-за уже наличия соответствующей настройки в consul, например, если мы ранее уже запускали кластер patroni с таким же названием.
Решение: проблему можно решить двумя способамы. Решение зависит от ситуации.
а) Если в сети работает кластер patroni с таким же именем, то мы должны задать новое имя в файле:
vi /etc/patroni/config.yml
...
scope: pgdb
...
После перезапускаем patroni:
systemctl restart patroni
б) Если имя нашего кластера совпало с ранее использовавшемся кластером, то такую запись можно смело удалить из consul. Это можно сделать в веб-интерфейсе, разделе Key / Values - Service или из командной строки на сервере консула:
consul kv delete -recurse service/pgdb
password authentication failed
При запуске службы на вторичном сервере (slave) не выполняется репликация и мы можем увидеть в логе сообщение:
pg_basebackup: error: FATAL: password authentication failed for user "replicator"
Причина: не создана учетная запись replicator на сервере postgresql.
Решение: переходим на master сервер. Заходим под пользователем postgres:
su - postgres
Создаем учетную запись для репликации:
createuser --replication -P replicator
Система потребует ввести пароль, который будет использоваться для учетной записи. В нашем примере в конфигурационном файле мы используем password, поэтому нужно ввести именно его.
Читайте также
Другие инструкции, имеющие отношение к кластеризации Postgres:
1. Установка и запуск PostgreSQL на CentOS.
2. Установка и настройка кластера Consul Hashicorp на CentOS.
3. Настройка потоковой репликации PostgreSQL.