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

Обновлено Обновлено: Опубликовано Опубликовано:

Используемые термины: PatroniConsul.

Кластер Postgresql, созданный штатными средствами не совсем удобен в эксплуатации — у него сложные механизмы отслеживания проблем с репликацией, нет возможности автоматического переключения с основной ноды на резервную и обратно, сложный процесс восстановления после падения. Приложение Patroni позволяет сделать процесс управления кластером Postgresql проще. Оно хранит данные кластера в базе типа key-value и ориентируется на работоспособность системы с помощью DCS (Distributed Control Service). В качестве таких систем для Patroni могут выступать:

В данной инструкции мы рассмотрим процесс установки и настройки Patroni с Consul.

Предполагается, что у нас уже есть кластер consul, а также серверы с установленным Postgresql (чистыми без полезных данных). На последних также должны быть установлены consul в режиме агента или сервера. Ссылки на необходимые материалы будут приведены в конце данной инструкции.

Предварительная настройка

Прежде чем перейти к настройке patroni и кластера, подготовим наши серверы баз данных.

Настройка брандмауэра

Если на наших серверах используется брандмауэр, то нам нужно открыть порт 5432, по которому работает postgresql, а также порт 8008 для patroni.

Вводим команды:

iptables -I INPUT -p tcp --dport 5432 -j ACCEPT

iptables -I INPUT -p tcp --dport 8008 -j ACCEPT

Для сохранения правил вводим:

apt install iptables-persistent

netfilter-persistent save

Подготовка СУБД

Patroni самостоятельно инициализирует базу и настройки, поэтому наш каталог с данными Postgresql должен быть чист, а сервис postgresql находится в выключенном состоянии.

Если на вашем сервере баз данных есть ценная информация, действия ниже приведут к ее потере. В этом случае стоит развернуть кластер на других серверах и перенести данные.

На наших серверах СУБД смотрим путь до каталога с данными:

su - postgres -c "psql -c 'SHOW data_directory;'"

В моем случае для обоих серверов путь был /var/lib/postgresql/14/main — сохраняем путь. Скоро он нам понадобиться.

Останавливаем сервис postgres и запрещаем его автозапуск:

systemctl disable postgresql --now

Удаляем содержимое каталога с данными, путь до которого нам вернула команда SHOW data_directory:

rm -rf /var/lib/postgresql/14/main/*

Готово. Можно переходить к установке и настройке Patroni.

Установка и настройка Patroni

Данное приложение разработано на Python и требует установки как последнего, так и некоторых его компонентов. 

Выполняем команду:

apt install python3 python3-pip python3-psycopg2

* в нашем примере мы будем работать с python версии 3. Также нам нужна библиотека для работы с postgresql python3-psycopg2.

Теперь ставим сам patroni, как приложение python:

pip3 install patroni[consul]

Установка завершена. Переходим к настройке.

Создадим каталог для хранения конфигурации:

mkdir /etc/patroni

И сам конфигурационный файл:

vi /etc/patroni/patroni.yml

name: postgres01.dmosk.local
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.0.11: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 all trust
  - host replication replicator 192.168.0.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/.pgpass
  listen: 0.0.0.0:5432
  connect_address: "192.168.0.11:5432"
  data_dir: /var/lib/postgresql/14/main/
  bin_dir: /usr/lib/postgresql/14/bin/
  pg_rewind:
    username: postgres
    password: password
  pg_hba:
    - local all all trust
    - host replication replicator 192.168.0.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. Желательно, чтобы это выл домашний каталог пользователя postgres — eval echo ~postgres.
  • postgresql - connect_address — адрес и порт, которые будут использоваться для подключения к СУДБ.
  • postgresql - data_dir — путь до файлов с данными базы.
  • postgresql - bin_dir — путь до бинарников postgresql.
  • pg_rewind, replication, superuser — логины и пароли, которые будут созданы для базы.

Создадим юнит в systemd для patroni:

vi /lib/systemd/system/patroni.service

[Unit]
Description=Patroni service
After=syslog.target network.target

[Service]
Type=simple
User=postgres
Group=postgres
ExecStart=/usr/local/bin/patroni /etc/patroni/patroni.yml
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=process
TimeoutSec=30
Restart=no

[Install]
WantedBy=multi-user.target

* обратите внимание, что в официальной документации предлагается не перезапускать автоматически службу (Restart=no). Это дает возможность разобраться в причине падения базы.

Перечитываем конфигурацию systemd:

systemctl daemon-reload

Разрешаем автозапуск и стартуем сервис:

systemctl enable patroni --now

Проверяем статусы сервиса на обоих серверах:

systemctl status patroni

Посмотреть список нод

patronictl -c /etc/patroni/patroni.yml list pgdb

* где pgdb — имя нашей базы (указана с использованием директивы scope в конфигурационном файле patroni).

Мы должны увидеть что-то на подобие:

+------------------------+--------------+---------+---------+----+-----------+
| Member                 | Host         | Role    | State   | TL | Lag in MB |
+ Cluster: pgdb (7126124696482454785) --+---------+---------+----+-----------+
| postgres01.dmosk.local | 192.168.0.11 | Leader  | running |  1 |           |
| postgres02.dmosk.local | 192.168.0.12 | 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/patroni.yml

...
consul:
  ...
  token: 5adb466f-b6ee-9048-6458-e8edbffc42a3

Установка patroni в своем окружении

Мы можем захотеть установить приложение patroni в отдельном окружении python. Для этого выполняем команду, чтобы создать его:

python3 -m venv --copies /opt/patroni

* в данном примере будет создано окружение в каталоге /opt/patroni.

Запустим виртуальное окружение:

source /opt/patroni/bin/activate

Установим необходимые модули python внутри созданного окружения:

pip3 install patroni[consul] psycopg[binary,pool]

* в процессе установки модулей мы можем получить ошибки выполнения команды. Как правило, они связаны с отсутствием необходимых пакетов в системе. Следуйте подсказкам в сообщениях, чтобы решить проблему самостоятельно.

Создадим конфигурационный файл по пути, где находится окружение:

mkdir /opt/patroni/etc

vi /opt/patroni/etc/patroni.yml

Само содержимое файла рассмотрено выше.

Файл для systemd немного отличается от того, что мы разбирали ранее:

vi /lib/systemd/system/patroni.service

[Unit]
Description=Patroni service
After=syslog.target network.target

[Service]
Type=simple
User=postgres
Group=postgres
ExecStart=/bin/bash -c "source /opt/patroni/bin/activate && patroni /opt/patroni/etc/patroni.yml"
WorkingDirectory=/opt/patroni
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=process
TimeoutSec=30
Restart=no

[Install]
WantedBy=multi-user.target

* в данном примере мы сначала активируем окружение, в котором установлен patroni, после запускаем его. Также обратите внимание на опцию WorkingDirectory, в которой указан рабочий каталог (созданное окружение).

Остальные дейсвия по запуску описаны выше.

Примеры некоторых команд patronictl

Рассмотрим несколько полезных команд для работы с 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

Или если мы не выполнили рекомендации пункта 1:

patronictl -c /etc/patroni/config.yml list

Если у нас несколько кластеров, то можно указать конкретный, чтобы получить список узлов только для него, например:

patronictl list pgdb

3. Смена лидера.

Может быть выполнена командой patronictl с аргументом failover. Например:

patronictl failover pgdb

* где pgdb — имя кластера патрони.

Система покажет список узлов, на которые можно передать функцию лидера — указываем его:

Candidate ['postgresql2'] []: postgresql2

И подтверждаем наш выбор:

Are you sure you want to failover cluster pgdb, demoting current master postgresql2? [y/N]: y

В нашем примере, роли лидера переедет на сервер postgresql2.

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

Возможные ошибки

Рассмотрим некоторые ошибки, с которым пришлось столкнуться автору.

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 на Ubuntu.

2. Установка и настройка кластера Consul Hashicorp на Linux Ubuntu.

3. Установка агента Consul и примеры регистрации сервисов.

4. Настройка потоковой репликации PostgreSQL.

5. Мониторинг репликации PostgreSQL в Zabbix.

# Ubuntu # Базы данных # Серверы
Дмитрий Моск — частный мастер
Была ли полезна вам эта инструкция?

Да            Нет