H.2. pg_cluster#
H.2. pg_cluster
Этот раздел описывает, как развернуть pg_cluster
с использованием автоматизированных инструментов на базе ansible
. В следующем тексте будут представлены примеры команд, которые необходимо ввести в терминале для подготовки SSH-сессии, проверки правильности настроек ansible и запуска playbook. В качестве примера пользователя будет использоваться учетная запись admin_user
. При запуске команд в цикле клиента этот пользователь должен быть изменен на учетную запись, которая имеет доступ по SSH без пароля ко всем серверам (виртуальным машинам), указанным в файле my_inventory
, а также доступ в привилегированный режим (root). В результате работы playbook на серверах, указанных в файле my_inventory
, будет развернут кластер Tantor Certified, управляемый через patroni.
H.2.2. Архитектура
Диаграмма H.1. Архитектура

H.2.3. Требования
Плейбук требует установки компонентов следующих версий:
Ansible >= 2.9.10
Python3 (с модулем pip) >= 3.10.0
psycopg2 >= 2.5.1 (рекомендуется устанавливать через pip)
packaging >= 24 (рекомендуется устанавливать через pip)
H.2.4. Использование (на основе ОС Astra Linux 1.7)
Создайте пользователя
admin_user
(выполняется на каждом узле из файлаinventory
):sudo adduser admin_user
Предоставьте пользователю
admin_user
возможность входить в привилегированный режим (root) без ввода пароля (выполняется на каждом узле из файла инвентаризации).cat >> /etc/sudoers <<EOF admin_user ALL=(ALL) NOPASSWD: ALL EOF
Проверьте наличие в системе сертифицированных репозиториев.
Примонтируйте переданный ISO-образ в каталог
/mnt/iso
(выполняется на каждом узле из файла inventory и на узле, с которого будет запущен ansible-playbook).Подключите репозиторий из примонтированного ISO-образа в систему (выполняется на каждом узле из файла inventory и на узле, с которого будет запущен ansible-playbook).
echo 'deb [trusted=yes] file:///mnt/iso/repo 1.8_x86-64 main' | && \ sudo tee /etc/apt/sources.list.d/tantorlabs.list
Установите ansible (выполняется на узле, с которого будет запущен ansible-playbook).
sudo apt install ansible-tantor-all
Скопируйте файлы контрольного примера из примонтированного ISO-образа в каталог
/opt/pg_cluster
(выполняется на узле, с которого будет запущен ansible-playbook):sudo cp -r /mnt/iso/pg_cluster /opt cd /opt/pg_cluster/ sudo chmod +w /opt/pg_cluster/inventory/my_inventory sudo chmod +w /opt/pg_cluster/inventory/group_vars/keepalived.yml
Заполните файл конфигурации
inventory
/opt/pg_cluster/inventory/my_inventory
, содержащий список хостов и их IP-адресов (выполняется на узле, с которого будет запущен ansible-playbook).В файле
inventory/group_vars/keepalived.yml
измените значение переменнойcluster_vip_1
на IP, который будет использоваться keepalived для выделенного виртуального адреса — единой точки входа в кластер СУБД (выполняется на узле, с которого будет запущен ansible-playbook):sed -i \ 's/cluster_vip_1: "xxx\.xxx\.xxx\.xxx"/cluster_vip_1: "<cluster IP address>"/' \ /opt/pg_cluster/inventory/group_vars/keepalived.yml
Сгенерируйте SSH-ключи и загрузите их на узлы кластера из файла конфигурации
inventory
(выполняется на узле, с которого будет запущен ansible-playbook):ssh-keygen -t rsa -b 4096 ssh-copy-id admin_user@<IP address of the first node> ssh-copy-id admin_user@<IP address of the second node> ssh-copy-id admin_user@<IP address of the third node>
Проверьте SSH-соединение от имени
admin_user
(выполняется на узле, с которого будет запущен ansible-playbook):ssh admin_user@<IP address of the first node> ssh admin_user@<IP address of the second node> ssh admin_user@<IP address of the third node>
Убедитесь, что все серверы доступны для подключения по SSH с указанием требуемого пользователя:
/opt/tantor/usr/bin/ansible all -i inventory/my_inventory \ -m ansible.builtin.setup -a "filter=ansible_hostname" -u admin_user
Результатом выполнения вышеуказанной команды будет ответ от каждого из доступных серверов в следующем формате::
<hostname_from_inventory_file> | SUCCESS => { "ansible_facts": { "ansible_hostname": "<device_hostname>", "discovered_interpreter_python": "/usr/bin/<host_python_version>" }, "changed": false }
Этот вывод для каждого сервера, описанного в файле
my_inventory
, означает успешное подключение к нему через SSH. Если в результате ответа с какого-либо сервера сообщение отличается от приведенного выше шаблона - проверьте, возможно ли подключение к нему с использованием ключа от имени пользователя, переданного с использованием флага-u
. Если необходимо подключаться только с вводом пароля (без использования ключей) - необходимо добавить флаги-kK
к запуску команды и ввести пароль для подключения по SSH (флаг-k
) и для перехода пользователя в привилегированный режим (root) (флаг-K
).Обратите внимание на значение переменной
ansible_hostname
в выводе команды. Если значениеlocalhost
илиlocalhost.localdomain
, проверьте файл/etc/hosts
на машинах с некорректным выводом. Убедитесь, что реальное имя хоста устройства установлено перед localhost в строке, содержащей127.0.0.1
.Запустите ansible-playbook для установки базы данных TantorDB (выполняется на узле, с которого будет запущен ansible-playbook):
/opt/tantor/usr/bin/ansible-playbook -i inventory/my_inventory \ -u admin_user -e "postgresql_vendor=tantordb edition=certified major_version=15" pg-cluster.yaml
H.2.5. Функции запуска
Плейбук позволяет разделять каталоги
pg_data
, pg_wal
и
pg_log
. Если необходимо разместить
WAL логи в отдельной папке, необходимо внести изменения в
файл inventory/groupvars/patroni.yml
:
удалите комментарий для переменной
patroni_pg_wal_dir
и укажите каталог для размещения в нем WAL логов;для переменной
patroni_bootstrap_initdb
добавьте параметрwaldir
и проверьте, что он ссылается на переменнуюpatroni_pg_wal_dir
;для выбранного метода создания реплики (по умолчанию
patroni_pg_basebackup
) добавьте параметрwaldir
со значениемbulk_wal_dir
;
В случае необходимости размещения LOGов: удалите комментарий для
переменной patron_pg_pg_log_dir
и укажите в ней
каталог для размещения журналов LOG;
H.2.6. Запуск плейбука
Одна из задач плейбука выполняется на том же узле, с которого
запускается ansible (управляющий сервер). Если пользователь, под которым
запускается ansible, не имеет доступа к режиму root без пароля на
этом сервере, необходимо добавить флаг -K
к
команде запуска и ввести пароль.
По умолчанию плейбук не пытается подключиться к репозиториям Tantor и требует наличия в системе следующих пакетов:
etcd-tantor-all
python3-tantor-all
patroni-tantor-all
pg_configurator-tantor-all
haproxy-тантор-все
keepalived-tantor-all
pgbouncer-tantor-all
wal-g-tantor-all
СУБД tantor
Обратите внимание на последний пункт из приведенного выше списка. Пакет Tantor должен соответствовать среде, используемой во время запуска плейбука. Например, если вы хотите установить tantor-certified-server-15
СУБД с помощью команды ansible-playbook -i inventory/my_inventory -u admin_user -e "postgresql_vendor=tantordb edition=certified major_version=15" pg-cluster.yaml -K
, убедитесь, что пакет tantor-certified-server-15
доступен в вашем локальном репозитории.
H.2.7. Примеры использования
Ниже вы можете найти некоторые общие команды для работы с
программными продуктами, включенными в решение pg_cluster
.
Обратите внимание, что команды и их результаты могут отличаться
в зависимости от используемых версий программного обеспечения.
H.2.7.1. Работа с etcd:
# on NODE_1 e_host=( /opt/tantor/usr/bin/etcdctl --endpoints=https://<HOST_1_IP>:2379,https://<HOST_2_IP>:2379,https://<HOST_N_IP>:2379 --cacert=/opt/tantor/etc/patroni/ca.pem --cert=/opt/tantor/etc/patroni/<NODE1_HOSTNAME>.pem --key=/opt/tantor/etc/patroni/<NODE1_HOSTNAME>-key.pem ) # list etcd members ETCDCTL_API=3 "${e_host[@]}" member list --debug # check version ETCDCTL_API=3 "${e_host[@]}" version # get key value ("main" is "patroni_scope") ETCDCTL_API=3 "${e_host[@]}" get /service/main/config # cleanup patroni cluster configuration ETCDCTL_API=3 "${e_host[@]}" del /service/main --prefix
H.2.7.2. Ручное создание пользователя:
# create user su - postgres -c "psql -A -t -d postgres -c \"CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'repuserpasswd'\"" # check user su - postgres -c "psql -A -t -d postgres -c \"select * from pg_roles where rolname = 'replicator'\""
H.2.7.3. Управление кластером Patroni
Patroni включает команду под названием patronictl
,
которая может использоваться для управления кластером. Давайте проверим статус
кластера:
root@node1:~# patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list + Cluster: main (7351350415269982209) --+---------+-----------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +---------+-----------------+---------+-----------+----+-----------+ | node1 | xxx.xxx.xxx.xxx | Leader | running | 1 | | | node2 | yyy.yyy.yyy.yyy | Replica | streaming | 1 | 0 | | node3 | zzz.zzz.zzz.zzz | Replica | streaming | 1 | 0 | +---------+-----------------+---------+-----------+----+-----------+
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml edit-config
следует использовать только для управления глобальной конфигурацией кластера. Он
не должен содержать никаких настроек, специфичных для узлов, таких как
connect_address
, listen
,
data_dir
и так далее.
Обновить настройки DCS pg_hba
:
cat > pg_hba.conf << EOL host replication replicator 0.0.0.0/0 md5 local all all trust host all all 127.0.0.1/32 trust host all all localhost trust EOL cat pg_hba.conf | jq -R -s 'split("\n") | .[0:-1] | {"postgresql": {"pg_hba": .}}' | \ patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml edit-config --apply - --force main patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml show-config
Изменить настройки postgresql.conf
:
cat > postgresql.conf << EOL "postgresql": { "parameters": { "max_connections" : 101 } } EOL cat postgresql.conf | patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml edit-config --apply - --force main patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml restart main
Сделать переключение switchover
:
root@node1:~# patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml switchover Current cluster topology + Cluster: main (7351350415269982209) --+---------+-----------+----+-----------+ | Member| Host | Role | State | TL | Lag in MB | +-------+-----------------+---------+-----------+----+-----------+ | node1 | xxx.xxx.xxx.xxx | Leader | running | 1 | | | node2 | yyy.yyy.yyy.yyy | Replica | streaming | 1 | 0 | | node3 | zzz.zzz.zzz.zzz | Replica | streaming | 1 | 0 | +-------+-----------------+---------+-----------+----+-----------+ Primary [node1]: Candidate ['node2', 'node3'] []: node2 When should the switchover take place (e.g. 2024-04-02T13:51 ) [now]: Are you sure you want to switchover cluster main, demoting current leader node1? [y/N]: y 2024-04-02 12:51:28.04774 Successfully switched over to "node2" + Cluster: main (7351350415269982209) --+---------+-----------+----+-----------+ | Member| Host | Role | State | TL | Lag in MB | +-------+-----------------+---------+-----------+----+-----------+ | node1 | xxx.xxx.xxx.xxx | Leader | streaming | 2 | | | node2 | yyy.yyy.yyy.yyy | Replica | running | 2 | 0 | | node3 | zzz.zzz.zzz.zzz | Replica | streaming | 2 | 0 | +-------+-----------------+---------+-----------+----+-----------+
Переключиться в асинхронный режим (режим по умолчанию):
cat > postgresql.conf << EOL "postgresql": { "parameters": { "synchronous_commit" : "local" } } "synchronous_mode": false "synchronous_mode_strict": false EOL cat postgresql.conf | patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml edit-config --apply - --force main
Переключиться в синхронный режим:
cat > postgresql.conf << EOL "postgresql": { "parameters": { "synchronous_commit" : "remote_apply" } } "synchronous_mode": true "synchronous_mode_strict": true EOL cat postgresql.conf | patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml edit-config --apply - --force main
Диаграмма H.2. synchronous_commit

Повторная инициализация неудавшегося узла, в случае если вывод
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list
предоставляет информацию о неудачном состоянии узла:
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list >> root@node1:~# patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list + Cluster: main (7351350415269982209) --+------------+-----------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +---------+-----------------+---------+--------------+----+-----------+ | node1 | xxx.xxx.xxx.xxx | Leader | running | 1 | | | node2 | yyy.yyy.yyy.yyy | Replica | streaming | 1 | 0 | | node3 | zzz.zzz.zzz.zzz | Replica | start failed | 1 | 0 | +---------+-----------------+---------+--------------+----+-----------+
Вышедший из строя узел можно перенастроить для присоединения к кластеру с помощью:
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml reinit node3 >> root@node1:~# patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list + Cluster: main (7351350415269982209) --+---------+-----------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +---------+-----------------+---------+-----------+----+-----------+ | node1 | xxx.xxx.xxx.xxx | Leader | running | 1 | | | node2 | yyy.yyy.yyy.yyy | Replica | streaming | 1 | 0 | | node3 | zzz.zzz.zzz.zzz | Replica | streaming | 1 | 0 | +---------+-----------------+---------+-----------+----+-----------+
H.2.8. Кластерный тест
После успешного развертывания кластера:
# on deployment node run test, the test will take about 5 minutes # please use the latest possible version of python3 # please run commands from the pg_cluster folder python3 tools/pg_cluster_backend/pg_cluster_backend.py --operations=10000
Чтобы эмулировать взаимоблокировки, необходимо изменить параметр
test.accounts = 100 -> 10
в
tools/pg_cluster_backend/conf/pg_cluster_backend.conf
.
Одновременно с тестированием вы должны выполнить действия с кластером:
# on NODE_1 patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml restart main shutdown -r now # on NODE_2 patronictl -c /opt/tantor/etc/patroni/<NODE2_HOSTNAME>.yml list patronictl -c /opt/tantor/etc/patroni/<NODE2_HOSTNAME>.yml restart main shutdown -r now # on NODE_3 patronictl -c /opt/tantor/etc/patroni/<NODE3_HOSTNAME>.yml list patronictl -c /opt/tantor/etc/patroni/<NODE3_HOSTNAME>.yml restart main shutdown -r now # on NODE_1 patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml switchover # on primary node su - postgres -c "psql -A -t -d test_db -c \" select pg_terminate_backend(pid) from pg_stat_activity where application_name = 'pg_cluster_backend'\"" # on NODE_1 systemctl stop patroni # on NODE_2 systemctl stop patroni # on NODE_1 systemctl start patroni # on NODE_2 systemctl start patroni # restart all nodes in random order
После выполнения этих действий тестовый сервер должен продолжить работу.
Проверьте, сколько транзакций было потеряно при переключении на асинхронную репликацию:
SELECT sum(balance)::numeric - -- result balance ((select count(1) from public.accounts) * 100 + 10000) -- where "--operations=10000" FROM public.accounts -- positive value means lost transactions -- negative value means successfully committed transactions in which the backend received an exception