H.4. pg_cluster#
H.4. pg_cluster #
Этот раздел описывает, как развернуть pg_cluster
с использованием автоматизированных инструментов на базе ansible
. В следующем тексте будут представлены примеры команд, которые необходимо ввести в терминале для подготовки SSH-сессии, проверки правильности настроек ansible и запуска playbook. В качестве пользователя будет использоваться учетная запись admin_user
. При запуске команд в окружении Клиента этот пользователь должен быть изменен на учетную запись, которая имеет доступ по SSH без пароля ко всем серверам (виртуальным машинам), указанным в файле my_inventory
, а также доступ к привилегированному режиму (root). В результате работы playbook на серверах, указанных в файле my_inventory
, будет развернут кластер выбранной СУБД (Tantor SE-1C или PostgreSQL), управляемый через patroni.
H.4.3. Требования #
Плейбук требует установки компонентов следующих версий:
Ansible >= 2.9.10
Python3 (с модулем pip) >= 3.10.0
psycopg2 >= 2.5.1 (рекомендуется устанавливать через pip)
packaging >= 24 (рекомендуется устанавливать через pip)
H.4.4. Подготовка хоста (на основе ОС Astra Linux 1.7) #
Создайте пользователя
admin_user
(выполняется на каждом узле из файлаinventory
):sudo adduser admin_user
Установите git (выполняется на узле, с которого будет запускаться ansible-playbook):
sudo apt install git
Скачайте проект (выполняется на узле, с которого будет запущен ansible-playbook):
git clone https://github.com/TantorLabs/pg_cluster cd pg_cluster
Примечание
Пункты с 4 по 5 являются необязательными для случаев, когда пользователь уже сгенерировал SSH-ключи. Если вы не хотите хранить SSH-ключи в нестандартном месте, пункты 4 и 5 можно заменить следующими командами, выполненными от имени учетной записи admin_user:
ssh-keygen -t rsa -b 4096 ssh-copy-id admin_user@ip_node (repeat the command for each node in the inventory file)
Если вы следовали этому примечанию, пожалуйста, продолжайте с пункта 6 текущей инструкции.
Сгенерируйте SSH-ключи и загрузите их на узлы кластера (выполняется на узле, с которого будет запущен ansible-playbook от имени учетной записи admin_user):
ssh-keygen -t rsa -b 4096 -C "admin_user" -f /home/admin_user/pg_lab_ansible -q -N "" cat /home/admin_user/pg_lab_ansible.pub >> /home/admin_user/.ssh/authorized_keys ssh-copy-id -i /home/admin_user/pg_lab_ansible.pub admin_user@ip_node (repeat the command for each node in the inventory file)
Запишите параметры подключения каждого сервера из
inventory file
для пользователяadmin_user
(выполняется на узле, с которого ansible-playbook будет запущен как учетная запись admin_user):mkdir -p $HOME/.ssh/ cat >> $HOME/.ssh/config << EOL Host xxx.xxx.xxx.xxx Port 22 User admin_user PreferredAuthentications publickey StrictHostKeyChecking no IdentityFile /home/admin_user/pg_lab_ansible EOL
Предоставьте пользователю
admin_user
возможность входить в привилегированный режим (root) без ввода пароля (выполняется на каждом узле из файла инвентаризации).Проверьте
ssh
соединение пользователяadmin_user
(при запуске и подключении в качестве учетной записи admin_user пароль запрашиваться не должен):ssh admin_user@ip_node
H.4.5. Подготовка Ansible #
Подготовка к запуску выполняется на узле, с которого будет запущен ansible-playbook, и включает следующие шаги:
Установить ansible
sudo python3 -m pipX.X install ansible==X.X.X # where X.X(.X) represents the version of pip and Ansible specified in the Requirements block of the current instruction.
В файле
inventory/group_vars/prepare_nodes.yml
измените значение переменныхUSERNAME:PASSWORD
на имя пользователя и пароль для доступа к репозиторию Tantor DB.В файле
inventory/group_vars/keepalived.yml
измените значение переменнойcluster_vip_1
на IP, который будет использоваться keepalived для выделенного виртуального адреса — единой точки входа в кластер СУБД.Заполните файл конфигурации
inventory
/opt/pg_cluster/inventory/my_inventory
, содержащий список хостов и их IP-адресов.
После заполнения файла my_inventory
рекомендуется убедиться, что все серверы доступны для подключения к ним через SSH с помощью нужного пользователем. Для этого выполните следующую команду в терминале:
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
.
H.4.6. Функции запуска #
Плейбук позволяет разделять каталоги
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.4.7. Запуск плейбука #
Одна из задач плейбука выполняется на том же узле, с которого
запускается 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-se-1c-server-16
СУБД с помощью команды ansible-playbook -i inventory/my_inventory -u admin_user -e "postgresql_vendor=tantordb edition=se-1c major_version=16" pg-cluster.yaml -K
, убедитесь, что пакет tantor-se-1c-server-16
доступен в вашем локальном репозитории.
Если плейбук запускается в среде с доступом в интернет, вы
можете использовать самые актуальные компоненты, включенные в
решение. Для этого добавьте флаг
add_nexus_repo=true
и укажите данные для подключения
к репозиториям в файле
inventory/group_vars/prepare_nodes.yml
.
Существует несколько вариантов запуска Ansible, с возможностью установки:
Tantor SE-1C
классического PostgreSQL как СУБД.
Используйте следующую команду для установки Tantor SE-1C:
ansible-playbook -i inventory/my_inventory \ -u admin_user -e "postgresql_vendor=tantordb edition=se-1c major_version=16" pg-cluster.yaml -K
Используйте следующую команду для установки классической СУБД PostgreSQL:
ansible-playbook -i inventory/my_inventory \ -u admin_user -e "postgresql_vendor=classic major_version=11" pg-cluster.yaml -K
В приведенных выше командах замените значение параметра
major_version
на версию СУБД, которую необходимо установить, значение postgresql_vendor
на поставщика СУБД и параметр admin_user
на пользователя, который имеет доступ к серверам без пароля
из файла my_inventory
с возможностью
переключения в привилегированный режим (root) без запроса пароля.
Для Tantor SE-1C также необходимо указать редакцию СУБД.
H.4.8. Запуск с доступом в интернет #
Можно запустить плейбук с внешним доступом в интернет.
ansible-playbook -i inventory/my_inventory \ -u admin_user -e "postgresql_vendor=tantordb edition=se-1c major_version=16 add_nexus_repo=true" pg-cluster.yaml -K
В этом случае убедитесь, что детали подключения указаны в
файле
inventory/group_vars/prepare_nodes.yml
.
H.4.9. Примеры использования #
Ниже вы можете найти некоторые общие команды для работы с
программными продуктами, включенными в решение pg_cluster
.
Обратите внимание, что команды и их результаты могут отличаться
в зависимости от используемых версий программного обеспечения.
H.4.9.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.4.9.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.4.9.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.4.10. Кластерный тест #
После успешного развертывания кластера:
# 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