Skip to content

Использование Patroni для создания кластера высокой доступности Postgres — Часть 1: etcd

Автор: Shaun Thomas, Using Patroni to Build a Highly Available Postgres Cluster—Part 1: etcd


Статьи серии:



Предыдущая статья из цикла PG Phriday была посвящена архитектуре кластера Patroni — как и почему он устроен именно так. На этот раз речь пойдёт о непосредственном построении такого кластера. Я часто слышал, что эксплуатация Postgres может пугать, а Patroni находится на уровень выше. Что ж, со вторым я спорить не буду, но я могу хотя бы попытаться облегчить некоторые трудности.


Чтобы избежать ошеломляющего потока информации из двадцати страниц инструкций, я разбил эту статью на серию из трёх частей по следующему принципу:



  • Etcd

  • Postgres и Patroni

  • HAProxy


Это позволит описать каждый из трёх уровней, представляющих полный стек Patroni, и создаст удобный справочный материал для каждого из них.


С этим разобрались, давайте приступим!


Почему etcd?


Предыдущая статья должна была предельно ясно дать понять, что DCS является центром коммуникации и состояния для всего кластера. Следовательно, важно установить его в первую очередь и удостовериться в его работоспособности. Etcd является решением по умолчанию и наиболее часто используемым примером в кластерах Patroni. Это также система хранения ключей и значений, которую Kubernetes использует по умолчанию, так что она должна быть достаточно надёжной для наших нужд.


Не забудьте держать в браузере вкладку с документацией etcd под рукой.



Что вам понадобится


Если вы хотите следовать этой демонстрации, вам потребуется:



  • Возможность создать три виртуальные машины. Будь то экземпляры Amazon EC2, Microsoft Hyper-V, Xen, QEMU, Proxmox, Oracle VirtualBox или даже VMWare Fusion, убедитесь, что у вас есть гипервизор и вы знаете, как им пользоваться.

  • Три виртуальные машины под управлением Debian Stable версии 13. На момент написания это должен быть релиз Trixie.

  • SSH-доступ как пользователь с правами root на каждой ВМ.

  • Подключение к интернету. Если у вас есть первые три пункта, скорее всего, он у вас тоже есть.


Как ни странно, этого должно быть достаточно. Хотя эти инструкции по возможности ориентированы на пакеты Debian, не стесняйтесь заменять их аналогами для RedHat, если вы предпочитаете быть более предприимчивым. Большинство этих инструкций должны работать в любой Linux-системе, если вы знакомы с выбранной вами платформой и знаете, как импровизировать.


Если вы хотите облегчить себе жизнь, добавьте несколько строк в /etc/hosts на виртуальных машинах, чтобы дать им имена. IP-адреса — это здорово, но они не так удобны, как "pg1". Вот пример:


192.168.6.10 pg1
192.168.6.11 pg2
192.168.6.12 pg3

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



Подготовка каждой ВМ


Перед установкой etcd давайте создадим пользователя с именем "etcd", который будет владельцем службы и связанных данных, с помощью быстрой команды useradd:


sudo useradd --system --create-home -s /bin/bash -d /var/lib/etcd etcd

Важно создать пользователя как "системного", так как Systemd часто обрабатывает их иначе.



Установка etcd


Первый урок заключается в том, что большинство этих инструментов не имеют "правильных" пакетов. Под этим я подразумеваю, что не существует официальных пакетов .deb или .rpm, которые можно было бы считать свежими. Сопровождающие ПО etcd не предоставляют ничего, кроме Zip-архивов, tar-архивов или исходного кода. Это означает, что первый шаг — посетить страницу релизов etcd на GitHub и найти URL для последней версии.


Используя этот URL, установите следующими командами:


export DL_FILE=etcd-v3.6.7-linux-amd64.tar.gz
wget https://github.com/etcd-io/etcd/releases/download/v3.6.7/${DL_FILE}
sudo tar -xf ${DL_FILE} -C /usr/local
sudo chown -R root:root /usr/local/etcd-v3.6.7-linux-amd64
sudo ln -s etcd-v3.6.7-linux-amd64 /usr/local/etcd

Затем мы хотим задействовать систему альтернатив Debian, чтобы упростить использование бинарных файлов:


sudo update-alternatives \
--install /usr/sbin/etcd etcd /usr/local/etcd/etcd 100
sudo update-alternatives \
--install /usr/bin/etcdctl etcdctl /usr/local/etcd/etcdctl 100

Наконец, создайте файл службы systemd для управления сервисом etcd:


cat<<EOF|sudo tee /etc/systemd/system/etcd.service
[Unit]
Description=etcd key-value store
Documentation=https://github.com/etcd-io/etcd
After=network.target

[Service]
User=etcd
Type=notify
Environment=ETCD_DATA_DIR=/var/lib/etcd
Environment=ETCD_NAME=%m
ExecStart=/usr/sbin/etcd --config-file /etc/etcd/etcd.yaml
Restart=always
RestartSec=10s
LimitNOFILE=40000

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload

Не запускайте службу; мы её ещё не настроили.



Настройка etcd


Для etcd "сложная" часть — правильно настроить конфигурацию. Обратите внимание на все выделенные жирным шрифтом параметры, включая name, advertise-client-urls, initial-advertise-peer-urls, listen-client-urls и listen-peer-urls в следующем блоке. Все они должны отражать имя или IP-адрес настраиваемого сервера! Самый простой способ сделать это — использовать переменные окружения, как показано в примере.


sudo mkdir /etc/etcd
sudo chown etcd:etcd /etc/etcd

# Убедитесь, что эти переменные установлены для настраиваемого узла
export MY_HOST=pg1
export MY_IP=192.168.6.10

cat<<EOF|sudo tee /etc/etcd/etcd.yaml
name: ${MY_HOST}
advertise-client-urls: http://${MY_HOST}:2379
data-dir: /var/lib/etcd/postgresql
initial-advertise-peer-urls: http://${MY_HOST}:2380
initial-cluster: pg1=http://pg1:2380,pg2=http://pg2:2380,pg3=http://pg3:2380
initial-cluster-state: new
initial-cluster-token: patroni_cluster
listen-client-urls: http://${MY_IP}:2379,http://127.0.0.1:2379
listen-peer-urls: http://${MY_IP}:2380
dial-timeout: 20s
read-timeout: 20s
write-timeout: 20s
EOF

URL-адреса для прослушивания используют IP-адреса, потому что etcd пытается разрешать имена хостов, когда они указаны для этих параметров.


Как только файл конфигурации появится на каждом из серверов, включите и запустите саму службу etcd.


sudo systemctl enable etcd
sudo systemctl start etcd

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



Проверка работоспособности службы


Как только etcd запустится на всех узлах, полезно проверить, что он работает должным образом, прежде чем передавать его Patroni. Начните с запуска инструмента etcdctl для просмотра списка участников кластера, который должен включать все три узла:


etcdctl member list

11be7ea7eac6dbc8, started, pg2, http://pg2:2380, http://pg2:2379, false
2a0c85329dcad4bd, started, pg3, http://pg3:2380, http://pg3:2379, false
608fb0f2dfc0e470, started, pg1, http://pg1:2380, http://pg1:2379, false

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


etcdctl endpoint health --cluster

http://pg1:2379 is healthy: successfully committed proposal: took = 1.69574ms
http://pg2:2379 is healthy: successfully committed proposal: took = 1.774651ms
http://pg3:2379 is healthy: successfully committed proposal: took = 1.80241ms

И вот что мы видим, если узел отключён:


http://pg1:2379 is healthy: successfully committed proposal: took = 1.50183ms
http://pg3:2379 is healthy: successfully committed proposal: took = 3.106761ms
http://pg2:2379 is unhealthy: failed to commit proposal: context deadline exceeded

Наконец, запишите тестовое значение в DCS, получите его с другого узла и удалите с третьего. Это гарантирует, что все узлы могут выполнять запись на основе консенсуса между ними.


# Выполнить на узле 1
etcdctl put testkey "Hello World"

OK

# Выполнить на узле 2
etcdctl get testkey

testkey
Hello World

# Выполнить на узле 3
etcdctl del testkey

1

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



Завершение


К этому моменту у вас должно быть три виртуальные машины, оснащённые службой etcd, и это удобная точка остановки для следующей статьи. Если вы задавались вопросом, почему мы устанавливаем всё на три узла, то это потому, что это минимально жизнеспособный кластер высокой доступности, имеющий реальный смысл.


Хотя можно запустить двухузловой кластер, для гарантии консенсуса кворум требует большинства. Любой узел, который не согласован, просто считается некорректным и должен ресинхронизироваться с большинством. Таким образом, двухузловой кластер должен всегда держать оба узла в сети, иначе ему нельзя доверять. Трёхузловой кластер имеет запасной вариант, так как становится возможным остановить один узел, пока два других поддерживают консенсус.


Как результат, ни один настоящий кластер не имеет менее трёх узлов. Обратите внимание, что это относится только к уровню etcd! Рассмотрим такую конструкцию кластера:


(Изображение: диаграмма кластера с 3 узлами etcd и 2 узлами Postgres/Patroni)
(Изображение: диаграмма кластера с 3 узлами etcd и 2 узлами Postgres/Patroni)


Это та же диаграмма, что и в оригинале, но только с двумя элементами Postgres/Patroni. Это вполне допустимо, потому что уровень DCS сам поддерживает кворум, поэтому нам не нужно применять то же ограничение к Postgres или Patroni. Это означает, что теоретически мы могли бы управлять двумя узлами Postgres в разных регионах, предполагая, что существует внешне управляемый уровень DCS.


Однако в случае этой демонстрации у нас нет такой роскоши. Чтобы отделить Patroni от etcd таким образом, требуется кластер из пяти узлов: три для etcd и два для Patroni и Postgres. На самом деле это превосходный подход для более сложных архитектур, поскольку несколько кластеров Patroni могут использовать один ресурс etcd.


Мы, возможно, исследуем такой продвинутый вариант использования в будущем, а пока экспериментируйте со своим новым кластером etcd, и увидимся на следующей неделе!



Trackbacks

No Trackbacks

Comments

Display comments as Linear | Threaded

No comments

The author does not allow comments to this entry

Add Comment

Enclosing asterisks marks text as bold (*word*), underscore are made via _word_.
Standard emoticons like :-) and ;-) are converted to images.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA

Form options

Submitted comments will be subject to moderation before being displayed.