Восстановление кластера ETCD - с примером: различия между версиями
Материал из support.qbpro.ru
Vix (обсуждение | вклад) (Новая страница: «==ВВЕДЕНИЕ== * Предполагаем несколько аварийных ситуаций где используется ETCD + Patroni + PostgreSQL/PRO * В данной статье рассматривается решение проблем конкретно ETCD, а Patroni + PostgreSQL/PRO - являются сопутствующим ПО. * Данные которые хранит ETCD - используются дальше в Patroni...») |
Vix (обсуждение | вклад) |
||
| (не показаны 2 промежуточные версии этого же участника) | |||
| Строка 9: | Строка 9: | ||
==РАБОТА С ПРОБЛЕМАМИ== | ==РАБОТА С ПРОБЛЕМАМИ== | ||
1. '''Пример:''' Потеря одного участника в кластере, база данных etcd испорчена, бакапа - нет.<br> | 1. '''Пример:''' Потеря одного участника в кластере, база данных '''etcd''' испорчена, '''бакапа''' - нет.<br> | ||
* На арбитре делаем запрос состояния кластера: | * На арбитре делаем запрос состояния кластера: | ||
ETCDCTL_API=2 etcdctl cluster-health | ETCDCTL_API=2 etcdctl cluster-health | ||
| Строка 18: | Строка 18: | ||
* Пояснение: | * Пояснение: | ||
ptrcs1 - арбитр | '''ptrcs1''' - арбитр | ||
ptrpg1 - нода1 | '''ptrpg1''' - нода1 | ||
ptrpg2 - нода2 | '''ptrpg2''' - нода2 | ||
* Посмотреть историю обмена ключами: | * Посмотреть историю обмена ключами: | ||
<nowiki>ETCDCTL_API=2 etcdctl get /data/cspgpro/history|sed 's/\,/\n/g'|sed 's/\[//;s/\[//;s/\]]//;s/\]//'</nowiki> | <nowiki>ETCDCTL_API=2 etcdctl get /data/cspgpro/history|sed 's/\,/\n/g'|sed 's/\[//;s/\[//;s/\]]//;s/\]//'</nowiki> | ||
| Строка 65: | Строка 65: | ||
<nowiki>edbaafd55c6a0b67: name=ptrpg2 peerURLs=http://ptrpg2.local.int:2380 clientURLs=http://ptrpg2.local.int:2379 isLeader=false</nowiki> | <nowiki>edbaafd55c6a0b67: name=ptrpg2 peerURLs=http://ptrpg2.local.int:2380 clientURLs=http://ptrpg2.local.int:2379 isLeader=false</nowiki> | ||
* ВЫВОД: Исходное состояние кластера - в рабочем состоянии, все участники присутствуют и идет обмен ключами. | * '''ВЫВОД''': Исходное состояние кластера - в рабочем состоянии, все участники присутствуют и идет обмен ключами. | ||
* Теперь создаем прецедент - вторая нода ptrpg2 - теряется из кластера etcd, архива базы нет: | * Теперь создаем прецедент - вторая нода '''ptrpg2''' - теряется из кластера '''etcd''', архива базы нет: | ||
** на ноде ptrpg2 останавливаем patroni, etcd и удаляем базу etcd (/var/lib/etcd/default/member) | ** на ноде '''ptrpg2''' останавливаем '''patroni''', '''etcd''' и удаляем базу '''etcd''' (/var/lib/etcd/default/member) | ||
systemctl stop patroni | systemctl stop patroni | ||
systemctl stop etcd | systemctl stop etcd | ||
rm -r /var/lib/etcd/default/member/* | rm -r /var/lib/etcd/default/member/* | ||
* На арбитре ptrcs1 смотрим состояние кластера: | * На арбитре '''ptrcs1''' смотрим состояние кластера: | ||
ETCDCTL_API=2 etcdctl cluster-health | ETCDCTL_API=2 etcdctl cluster-health | ||
** Результат: | ** Результат: | ||
| Строка 80: | Строка 80: | ||
<nowiki>http://ptrpg2.local.int:2379] are all unreachable</nowiki> | <nowiki>http://ptrpg2.local.int:2379] are all unreachable</nowiki> | ||
... | ... | ||
** Видно, что нода2 (ptrpg2) - стала недоступна... | ** Видно, что '''нода2''' ('''ptrpg2''') - стала недоступна... | ||
Запуск etcd на ptrpg2 - ни чего не даст, кроме ошибок..<br> | Запуск '''etcd''' на '''ptrpg2''' - ни чего не даст, кроме ошибок..<br> | ||
Поэтому для корректного восстановления нужно на арбитре, который сейчас является Leader - удалить ключ ptrpg2,<br> | Поэтому для корректного восстановления нужно на арбитре, который сейчас является '''Leader''' - удалить ключ '''ptrpg2''',<br> | ||
или попросту убрать ноду из кластера и после этого снова ее добавить, не трогая при этом patroni! | или попросту убрать ноду из кластера и после этого снова ее добавить, не трогая при этом '''patroni'''! | ||
* На арбитре (который сейчас Leader) ptrcs1 - удаляем ноду: | * На арбитре (который сейчас '''Leader''') '''ptrcs1''' - удаляем ноду: | ||
ETCDCTL_API=3 etcdctl --user="root" member remove '''edbaafd55c6a0b67''' | ETCDCTL_API=3 etcdctl --user="root" member remove '''edbaafd55c6a0b67''' | ||
** Команда выполняется с авторизацией и потребует сообщить пароль пользователя root (etcd) | ** Команда выполняется с авторизацией и потребует сообщить пароль пользователя '''root''' (etcd) | ||
* Проверяем состояние кластера: | * Проверяем состояние кластера: | ||
ETCDCTL_API=2 etcdctl cluster-health | ETCDCTL_API=2 etcdctl cluster-health | ||
| Строка 95: | Строка 95: | ||
... | ... | ||
** Видно что в списке нет '''ptrpg2'''! | ** Видно что в списке нет '''ptrpg2'''! | ||
* Теперь нужно заново добавить ptrpg2 в кластер, перед выполнением добавления, на ptrpg2 - etcd должен быть выключен! | * Теперь нужно заново добавить '''ptrpg2''' в кластер, перед выполнением добавления, на '''ptrpg2''' - '''etcd''' должен быть выключен! | ||
** На ptrcs1 выполняем команду добавления: | ** На '''ptrcs1''' выполняем команду добавления: | ||
ETCDCTL_API=3 etcdctl --user="root" --endpoints=ptrcs1.local.int:2379,ptrpg1.local.int:2379 member add ptrpg2 --peer-<nowiki>urls=http://ptrpg2.local.int:2380</nowiki> | ETCDCTL_API=3 etcdctl --user="root" --endpoints=ptrcs1.local.int:2379,ptrpg1.local.int:2379 member add ptrpg2 --peer-<nowiki>urls=http://ptrpg2.local.int:2380</nowiki> | ||
** Результат: | ** Результат: | ||
| Строка 106: | Строка 106: | ||
ETCD_INITIAL_CLUSTER_STATE="existing" | ETCD_INITIAL_CLUSTER_STATE="existing" | ||
... | ... | ||
** После этой команды, на ptrcs1 (который сейчас Leader) - etcd ждет подключения хоста ptrpg2 | ** После этой команды, на '''ptrcs1''' (который сейчас '''Leader''') - '''etcd''' ждет подключения хоста '''ptrpg2''' | ||
* Запускаем третьего участника заново в кластер сначала в etcd: | * Запускаем третьего участника заново в кластер сначала в '''etcd''' - на '''ptrpg2''': | ||
systemctl start etcd | systemctl start etcd | ||
** Проверяем что он в кластере, на ptrcs1 выполняем: | ** Проверяем что он в кластере, на '''ptrcs1''' выполняем: | ||
ETCDCTL_API=2 etcdctl cluster-health | ETCDCTL_API=2 etcdctl cluster-health | ||
** Результат: | ** Результат: | ||
| Строка 118: | Строка 118: | ||
... | ... | ||
** Как видно все участники в кластере. | ** Как видно все участники в кластере. | ||
* Теперь на ptrpg2 - запускаем patroni: | * Теперь на '''ptrpg2''' - запускаем '''patroni''': | ||
systemctl start patroni | systemctl start patroni | ||
** Проверяем | ** Проверяем '''patroni''': | ||
patronictl -c /etc/patroni/patronictl.yml list | patronictl -c /etc/patroni/patronictl.yml list | ||
** Результат: | ** Результат: | ||
| Строка 126: | Строка 126: | ||
| Member | Host | Role | State | TL | Lag in MB | | | Member | Host | Role | State | TL | Lag in MB | | ||
+---------+-------------------+---------+---------+----+-----------+ | +---------+-------------------+---------+---------+----+-----------+ | ||
| ptrpg1 | ptrpg1.local.int | Leader | running | 11 | | | | ptrpg1 | ptrpg1.local.int | Leader | running | 11 | | | ||
| ptrpg2 | ptrpg2.local.int | Replica | running | 11 | 0 | | | ptrpg2 | ptrpg2.local.int | Replica | running | 11 | 0 | | ||
+---------+-------------------+---------+---------+----+-----------+ | +---------+-------------------+---------+---------+----+-----------+ | ||
... | ... | ||
** Как видно кластер работает и идет синхронизация без ошибок. | ** Как видно кластер работает и идет синхронизация без ошибок. | ||
<br> | <br> | ||
==ДОПОЛНИТЕЛЬНО== | ==ДОПОЛНИТЕЛЬНО== | ||
Текущая версия от 16:40, 9 октября 2025
ВВЕДЕНИЕ
- Предполагаем несколько аварийных ситуаций где используется ETCD + Patroni + PostgreSQL/PRO
- В данной статье рассматривается решение проблем конкретно ETCD, а Patroni + PostgreSQL/PRO - являются сопутствующим ПО.
- Данные которые хранит ETCD - используются дальше в Patroni + PostgreSQL/PRO для обмена и взаимодействия между участниками кластера.
- Схема стенда кластера:
РАБОТА С ПРОБЛЕМАМИ
1. Пример: Потеря одного участника в кластере, база данных etcd испорчена, бакапа - нет.
- На арбитре делаем запрос состояния кластера:
ETCDCTL_API=2 etcdctl cluster-health
- Результат:
member c410a7d6456910ab is healthy: got healthy result from http://ptrcs1.local.int:2379 member e59a90ef17ed6871 is healthy: got healthy result from http://ptrpg1.local.int:2379 member '''edbaafd55c6a0b67''' is healthy: got healthy result from http://ptrpg2.local.int:2379
- Пояснение:
ptrcs1 - арбитр ptrpg1 - нода1 ptrpg2 - нода2
- Посмотреть историю обмена ключами:
ETCDCTL_API=2 etcdctl get /data/cspgpro/history|sed 's/\,/\n/g'|sed 's/\[//;s/\[//;s/\]]//;s/\]//'
- Результат:
... 1 21133688 "no recovery target specified" "2025-09-24T02:43:00.783823+03:00" "ptrpg2" 2 50333648 "no recovery target specified" "2025-09-24T03:03:11.812345+03:00" "ptrpg1" 3 50333984 "no recovery target specified" "2025-09-24T19:37:33.206983+03:00" "ptrpg2" ...
- Посмотреть все ключи кластера:
ETCDCTL_API=2 etcdctl ls --recursive
- Результат:
... /data /data/cspgpro /data/cspgpro/config /data/cspgpro/failover /data/cspgpro/failsafe /data/cspgpro/history /data/cspgpro/initialize /data/cspgpro/leader /data/cspgpro/members /data/cspgpro/members/ptrpg2 /data/cspgpro/members/ptrpg1 /data/cspgpro/status ...
- Смотрим кто сейчас является Leader, так как любое внесение изменений делается от него:
ETCDCTL_API=2 etcdctl member list
- Результат:
c410a7d6456910ab: name=ptrcs1 peerURLs=http://ptrcs1.local.int:2380 clientURLs=http://ptrcs1.local.int:2379 isLeader=true' e59a90ef17ed6871: name=ptrpg1 peerURLs=http://ptrpg1.local.int:2380 clientURLs=http://ptrpg1.local.int:2379 isLeader=false edbaafd55c6a0b67: name=ptrpg2 peerURLs=http://ptrpg2.local.int:2380 clientURLs=http://ptrpg2.local.int:2379 isLeader=false
- ВЫВОД: Исходное состояние кластера - в рабочем состоянии, все участники присутствуют и идет обмен ключами.
- Теперь создаем прецедент - вторая нода ptrpg2 - теряется из кластера etcd, архива базы нет:
- на ноде ptrpg2 останавливаем patroni, etcd и удаляем базу etcd (/var/lib/etcd/default/member)
systemctl stop patroni systemctl stop etcd rm -r /var/lib/etcd/default/member/*
- На арбитре ptrcs1 смотрим состояние кластера:
ETCDCTL_API=2 etcdctl cluster-health
- Результат:
member c410a7d6456910ab is healthy: got healthy result from http://ptrcs1.local.int:2379 member e59a90ef17ed6871 is healthy: got healthy result from http://ptrpg1.local.int:2379 failed to check the health of member edbaafd55c6a0b67 on http://ptrpg2.local.int:2379: Get "http://ptrpg2.local.int:2379/health": dial tcp 10.9.9.175:2379: i/o timeout member edbaafd55c6a0b67 is unreachable: http://ptrpg2.local.int:2379] are all unreachable ...
- Видно, что нода2 (ptrpg2) - стала недоступна...
Запуск etcd на ptrpg2 - ни чего не даст, кроме ошибок..
Поэтому для корректного восстановления нужно на арбитре, который сейчас является Leader - удалить ключ ptrpg2,
или попросту убрать ноду из кластера и после этого снова ее добавить, не трогая при этом patroni!
- На арбитре (который сейчас Leader) ptrcs1 - удаляем ноду:
ETCDCTL_API=3 etcdctl --user="root" member remove edbaafd55c6a0b67
- Команда выполняется с авторизацией и потребует сообщить пароль пользователя root (etcd)
- Проверяем состояние кластера:
ETCDCTL_API=2 etcdctl cluster-health
- Результат:
... member c410a7d6456910ab is healthy: got healthy result from http://ptrcs1.local.int:2379 member e59a90ef17ed6871 is healthy: got healthy result from http://ptrpg1.local.int:2379 ...
- Видно что в списке нет ptrpg2!
- Теперь нужно заново добавить ptrpg2 в кластер, перед выполнением добавления, на ptrpg2 - etcd должен быть выключен!
- На ptrcs1 выполняем команду добавления:
ETCDCTL_API=3 etcdctl --user="root" --endpoints=ptrcs1.local.int:2379,ptrpg1.local.int:2379 member add ptrpg2 --peer-urls=http://ptrpg2.local.int:2380
- Результат:
Member b10724c2f8e66abd added to cluster 85466bb104b9e4e5 ETCD_NAME="ptrpg2" ETCD_INITIAL_CLUSTER="ptrpg2=http://ptrpg2.local.int:2380,ptrcs1=http://ptrcs1.local.int:2380,ptrpg1=http://ptrpg1.local.int:2380" ETCD_INITIAL_ADVERTISE_PEER_URLS="http://ptrpg2.local.int:2380" ETCD_INITIAL_CLUSTER_STATE="existing" ...
- После этой команды, на ptrcs1 (который сейчас Leader) - etcd ждет подключения хоста ptrpg2
- Запускаем третьего участника заново в кластер сначала в etcd - на ptrpg2:
systemctl start etcd
- Проверяем что он в кластере, на ptrcs1 выполняем:
ETCDCTL_API=2 etcdctl cluster-health
- Результат:
member b10724c2f8e66abd is healthy: got healthy result from http://ptrpg2.local.int:2379 member c410a7d6456910ab is healthy: got healthy result from http://ptrcs1.local.int:2379 member e59a90ef17ed6871 is healthy: got healthy result from http://ptrpg1.local.int:2379 cluster is healthy ...
- Как видно все участники в кластере.
- Теперь на ptrpg2 - запускаем patroni:
systemctl start patroni
- Проверяем patroni:
patronictl -c /etc/patroni/patronictl.yml list
- Результат:
+ Cluster: cspgpro -----------+---------+---------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +---------+-------------------+---------+---------+----+-----------+ | ptrpg1 | ptrpg1.local.int | Leader | running | 11 | | | ptrpg2 | ptrpg2.local.int | Replica | running | 11 | 0 | +---------+-------------------+---------+---------+----+-----------+ ...
- Как видно кластер работает и идет синхронизация без ошибок.

