HA PostgreSQL with Patroni, Haproxy, Keepalived
https://habr.com/ru/articles/322036/
Привет, Хабр! Встала передо мной недавно задача: настроить максимально надежный кластер серверов PostgreSQL версии 9.6.
По задумке, хотелось получить кластер, который переживает выпадение любого сервера, или даже нескольких серверов, и умеет автоматически вводить в строй сервера после аварий.
Планируя кластер я проштудировал много статей, как из основной документации к PostgreSQL, так и различных howto, в том числе с Хабра, и пробовал настроить стандартный кластер с RepMgr, эксперементировал с pgpool.
В целом оно заработало, но у меня периодически всплывали проблемы с переключениями, требовалось ручное вмешательство для восстановления после аварий, и т.д. В общем я решил поискать еще варианты.
В итоге где-то (уже не вспомню точно где) нашел ссылку на прекрасный проект Zalando Patroni, и все заверте…
Введение
Patroni — это демон на python, позволяющий автоматически обслуживать кластеры PostgreSQL с различными типами репликации, и автоматическим переключением ролей.
Его особенная красота, на мой взгляд в том, что для поддержания актуальности кластера и выборов мастера используются распределенные DCS хранилища (поддерживаются Zookeeper, etcd, Consul).
Таким образом кластер легко интегрируется практически в любую систему, всегда можно выяснить кто в данный момент мастер, и статус всех серверов запросами в DCS, или напрямую к Patroni через http.
Ну и просто это красиво :)
Я потестировал работу Patroni, пробовал ронять мастера и другие сервера, пробовал наливать разные базы (~25 Гб база автоматически поднимается с нуля на 10Гб сети за несколько минут), и в целом мне проект Patroni очень понравился. После полной реализации описанной ниже схемы я проводил тестирование простым бенчером, который ходил в базу по единому адресу, и переживал падения всех элементов кластера (мастер сервера, haproxy, keepalived).
Задержка при передаче роли новому мастеру составляла пару секунд. При возвращении бывшего мастера в кластер, или добавлении нового сервера, смены ролей не происходит.
Для автоматизации разворачивания кластера и добавления новых серверов, решено было использовать привычный Ansible (я дам ссылки на получившиеся роли в конце статьи). В качестве DCS выступает уже применяемый у нас Consul.
У статьи две основные цели: показать пользователям PostgreSQL что есть такая прекрасная штука как Patroni (упоминаний в рунете вообще и на Хабре в частности, практически нет), и заодно немного поделиться опытом использования Ansible на простом примере, тем кто только начинает с ним работать.
Я постараюсь разъяснить все действо сразу на примере разбора Ansible ролей и плейбуков. Те, кто не использует Ansible, смогут перенести все действия в любимое средство автоматизированного управления серверами, либо выполнить их же вручную.
Поскольку большая часть yaml скриптов будет длинной, я буду заворачивать их в спойлер.
Рассказ будет разделен на две части — подготовка серверов и разворачивание непосредственно кластера.
Тем кто хорошо знаком с Ansible первая часть интересна не будет, поэтому рекомендую перейти сразу ко второй.
Часть I
Для этого примера я использую виртуальные машины на базе Centos 7. Виртуалки разворачиваются из шаблона который периодически обновляется (ядро, системные пакеты), но эта тема выходит за рамки данной статьи.
Отмечу только, что никакого прикладного или серверного софта на виртуалках заранее не установлено. Также вполне подойдут любые облачные ресурсы, например с AWS, DO, vScale, и т.п. Для них есть скрипты динамического инвентаря и интеграции с Ansible, либо можно прикрутить Terraform, так что весь процесс создания и удаления серверов c нуля может быть автоматизирован.
Для начала нужно создать инвентарь используемых ресурсов для Ansible. Ansible у меня (и по умолчанию) расположен в /etc/ansible. Создаем инвентарь в файле /etc/ansible/hosts:
У нас используется внутренняя доменная зона .local, поэтому у серверов такие имена.
Далее нужно подготовить каждый сервер к установке всех необходимых компонентов, и рабочих инструментов.
Для этой цели создаем плейбук в /etc/ansible/tasks:
/etc/ansible/tasks/essentialsoftware.yml
Набор пакетов Essential служит для создания на любом сервере привычного рабочего окружения.
Группа пакетов Development tools, некоторые библиотеки -devel и python нужны pip-у для сборки Python модулей к PostgreSQL.
Мы используем виртуальные машины на базе VmWare ESXi, и для удобства администрирования в них нужно запускать агент vmware.
Для этого мы запустим открытый агент vmtoolsd, и опишем его установку в отдельном плейбуке (поскольку не все сервера у нас виртуальные, и возможно для каких-то из них этот таск не понадобится):
/etc/ansible/tasks/open-vm-tools.yml
Для того чтобы завершить подготовку сервера к установке основной части софта, в нашем случае, понадобятся следующие шаги:
настроить синхронизацию времени с помощью ntp
установить и запустить zabbix агент для мониторинга
накатить требуемые ssh ключи и authorized_keys.
Чтобы не слишком раздувать статью деталям не относящимися к собственно кластеру, я кратко процитирую ansible плейбуки, выполняющие эти задачи:
NTP:
/etc/ansible/tasks/ntpd.yml
Вначале проверяется, не выставлена ли для сервера персональная таймзона, и если нет, то выставляется Московская (таких серверов у нас большинство).
Мы не используем ntpd из-за проблем с уплыванием времени на виртуалках ESXi, после которого ntpd отказывается синхронизировать время. (И tinker panic 0 не помогает). Поэтому просто запускаем кроном ntp клиент раз 5 минут.
Zabbix-agent:
/etc/ansible/tasks/zabbix.yml
При установке Zabbix конфиг агента накатывается из шаблона, нужно поменять только адрес сервера.
Сервера расположенные в пределах нашей сети ходят на 192.168.х.98, а сервера не имеющие в нее доступа, на реальный адрес этого же сервера.
Перенос ssh ключей и настройка ssh вынесена в отдельную роль, которую можно найти, например, на ansible-galaxy.
Вариантов там много, а суть изменений достаточно тривиальна, поэтому цитировать весь ее контент здесь я смысла не вижу.
Настала пора накатить на сервера созданную конфигурацию. Вообще я выполняю установку всех компонентов и самого кластера в один шаг, уже при наличии полного конфига, но мне кажется что для целей данного туториала будет лучше разделить это на два шага, соответственно по главам.
Создаем плейбук для группы серверов:
/etc/ansible/cluster-pgsql.yml
Запускаем обработку всех серверов:
Если вы полностью скачали мой пример из гитхаб репозитория, то у вас будет также в наличии и роль Patroni, которую нам пока отрабатывать не нужно.
Аргумент --skip-tags заставляет Ansible пропустить шаги помеченные этим тегом, поэтому роль ansible-role-patroni выполняться сейчас не будет.
Если же ее на диске нет, то ничего страшного и не произойдет, Anisble просто проигнорирует этот ключ.
Ansible у меня заходит на сервера сразу пользователем root, а если вам потребуется пускать ansible под непревилегированного пользователя, стоит дополнительно добавить в шаги требующие рутовых прав специальный флаг «become: true», который побудит ansible использовать вызовы sudo для этих шагов.
Подготовка закончена.
Часть II
Приступаем к разворачиванию непосредственно кластера.
Поскольку для настройки кластера требуется много работы (установить PostgreSQL и все компоненты, залить для них индивидуальные конфиги), я выделил весь этот процесс в отдельную роль.
Роли в Ansible позволяют сгруппировать наборы смежных тасков, и тем упрощают написание скриптов и поддержку их в рабочем состоянии.
Шаблон роли для установки Patroni я взял тут: https://github.com/gitinsky/ansible-role-patroni, за что спасибо его автору.
Для своих целей я переработал имеющийся и добавил свои плейбуки haproxy и keepalived.
Роли у меня лежат в каталоге /etc/ansible/roles. Создаем каталог для новой роли, и подкаталоги для ее компонентов:
Помимо PostgreSQL наш кластер будет состоять из следующих компонентов:
haproxy для отслеживания состояния серверов и перенаправления запросов на мастер сервер.
keepalived для обеспечения наличия единой точки входа в кластер — виртуального IP.
Все плейбуки выполняемые данной ролью перечисляем в файле, запускаемом ansible по умолчанию:
/etc/ansible/roles/ansible-role-patroni/tasks/main.yml
Далее начинаем описывать отдельные таски.
Первый плейбук устанавливает PostgreSQL 9.6 из родного репозитория, и дополнительные пакеты требуемые Patroni, а затем скачивает с GitHub саму Patroni:
/etc/ansible/roles/ansible-role-patroni/tasks/postgres.yml
Кроме установки ПО данный плейбук также заливает конфигурацию для текущего сервера Patroni, и systemd юнит для запуска демона в системе, после чего запускает демон Patroni. Шаблоны конфигов и systemd юнит должны лежать в каталоге templates внутри роли.
Шаблон конфига Patroni:
/etc/ansible/roles/ansible-role-patroni/templates/postgres.yml.j2
Поскольку для каждого сервера кластера требуется индивидуальная конфигурация Patroni, его конфиг лежит в виде шаблона jinja2 (файл postgres0.yml.j2), и шаг template заставляет ansible транслировать этот шаблон с заменой переменных, значения из которых берутся из отдельного описания для каждого сервера.
Переменные, общие для всего кластера укажем в прямо в инвентаре, который примет теперь следующий вид:
/etc/ansible/hosts
Расшифрую для чего нужны некоторые переменные:
patroni_scope — название кластера при регистрации в Consul
patroni_node_name — название сервера при регистрации в Consul
patroni_rest_password — пароль для http интерфейса Patroni (требуется для отправки команд на изменение кластера)
patroni_postgres_password: пароль для юзера postgres. Он устанавливается в случае создания patroni новой базы.
patroni_replicator_password — пароль для юзера replicator. От его имени осуществляется репликация на слейвы.
Также в этом файле перечислены некоторые другие переменные, используемые в других плейбуках или ролях, в частности тот может быть настройка ssh (ключи, пользователи), таймзона для сервера, приоритет сервера в кластере keepalived, и.т.п.
Конфигурация для остальных серверов аналогична, соответственно меняется имя сервер и приоритет (например 99-100-101 для трех серверов).
Установка и настройка haproxy:
/etc/ansible/roles/ansible-role-patroni/tasks/haproxy.yml
Haproxy устаналивается на каждом хосте, и содержит в своем конфиге ссылки на все сервера PostgreSQL, проверяет какой сервер сейчас является мастером, и отправляет запросы на него.
Для этой проверки используется прекрасная фича Patroni — REST интерфейс.
При обращении на урл server:8008 (8008 это порт по умолчанию) Patroni возвращает отчет по состоянию кластера в json, а также отражает кодом ответа http является ли данный сервер мастером. Если является — будет ответ с кодом 200. Если же нет, ответ с кодом 503.
Очень советую обратится в документацию на Patroni, http интерфейс там достаточно интересный, позволяется также принудительно переключать роли, и управлять кластером.
Аналогично, это можно делать при помощи консольной утилиты patronyctl.py, из поставки Patroni.
Конфигурация haproxy достаточно простая:
/etc/ansible/roles/ansible-role-patroni/templates/haproxy.cfg
В соответствии с этой конфигурацией haproxy слушает порт 5000, и отправляет трафик с него на мастер сервер.
Проверка статуса происходит с интервалом в 1 секунду, для перевода сервера в даун требуется 3 неудачных ответа (код 500), для переключения сервера назад — 2 удачных ответа (с кодом 200).
В любой момент времени можно обратиться непосредственно на любой haproxy, и он корректно запроксирует трафик на мастер сервер.
Также в комплекте с Patroni есть шаблон для настройки демона confd, и пример его интеграции с etcd, что позволяет динамически менять конфиг haproxy при удалении или добавлении новых серверов.
Я же пока делаю достаточно статичный кластер, лишняя автоматизация в данной ситуации, имхо, может привести к непредвиденным проблемам.
Нам хотелось, чтобы на клиентах особые изменения логики, отслеживание серверов на живости и т.д. не требовались, поэтому мы делаем единую точку входа в кластер с помощью keepalived.
Демон keepalived работает по протоколу vrrp со своими соседями, и в результате выборов одного из демонов как главного (приоритет указан в конфиге, и шаблонизирован в переменную keepalived_priority в host_vars для каждого сервера), он поднимает у себя виртуальный ip адрес.
Остальные демоны терпеливо ждут. Если текущий основной сервер keepalived по какой-то причине умрет либо просигналит соседям аварию, произойдут перевыборы, и следуюший по приоритету сервер заберет себе виртуальный ip адрес.
Для защиты от падения haproxy демоны keepalived выполняют проверку, запуская раз в секунду команду «killall -0 haproxy». Она возвращает код 0 если процесс haproxy есть, и 1 если его нет.
Если haproxy исчезнет, демон keepalived просигналит аварию по vrrp, и снимет виртуальный ip.
Виртуальный IP сразу же подхватит следующий по приоритету сервер, с живым haproxy.
Установка и настройка keepalived:
/etc/ansible/roles/ansible-role-patroni/tasks/keepalived.yml
Кроме установки keepalived, этот плейбук также копирует простой скрипт для отправки алертов через телеграм. Скрипт принимает сообщение в виде переменной, и просто дергает curl-ом API телеграма.
В этом скрипте только нужно указать свои токен и ID группы telegram для отсылки оповещений.
Конфигурация keepalived описана в виде jinja2 шаблона:
/etc/ansible/roles/ansible-role-patroni/templates/keepalived.conf.j2
В переменные patroni_node_name, cluster_virtual_ip и keepalived_priority транслируются соответствующие данные из host_vars.
Также в конфиге keepalived указан скрипт для отправки сообщений о смене статуса в telegram канал.
Накатываем полную конфигурацию кластера на сервера:
Поскольку Ansible идемпотентен, т.е. выполняет шаги только если они не были выполнены ранее, можно запустить плейбук без дополнительных параметров.
Если же не хочется дольше ждать, или вы уверены что сервера полностью готовы, можно запустить ansible-playbook с ключом -t patroni.
Тогда будут выполнены только шаги из роли Patroni.
Отмечу что я не указываю отдельно роли серверов — мастер или слейв. Данная конфигурация создаст пустую базу, и мастером просто станет первый сконфигурированный сервер.
При добавлении новых серверов Patroni увидит через DCS что мастер кластера уже есть, автоматически скопирует с текущего мастера базу, и подключит к нему слейв.
В случае запуска слейва отставшего на какое-то время от мастера, Patroni автоматически вольет изменения при помощи pg_rewind.
Убеждаемся что все сервера запустились и выбрали себе роли:
Сообщения со слейва (сервер cluster-pgsql-01):
Сообщения с мастера (в данном случае это сервер cluster-pgsql-02):
По логам ясно видно что каждый сервер постоянно мониторит свой статус и статус мастера.
Попробуем остановить мастер:
А вот что в этот момент произошло на слейве:
Этот сервер перехватил роль мастера на себя.
А теперь вернем сервер 2 обратно в кластер:
Patroni обнаружила что подключается к кластеру с имеющимся мастером, и обновив базу до текущего состояния, корректно приняла на себя роль слейва.
Попробуем создать ошибку на другом слое кластера, остановив haproxy на основном сервере keepalived.
По приоритету, эту роль у меня принимает второй сервер:
[root@cluster-pgsql-02 ~]# ip a 2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000 link/ether 00:50:56:a9:b8:7b brd ff:ff:ff:ff:ff:ff inet 192.xx.xx.121/24 brd 192.168.142.255 scope global ens160 valid_lft forever preferred_lft forever inet 192.xx.xx.125/32 scope global ens160 <---- виртуальный адрес кластера valid_lft forever preferred_lft forever inet6 fe80::xxx::4895:6d90/64 scope link valid_lft forever preferred_lft forever
Остановим haproxy:
Feb 18 00:18:54 cluster-pgsql-02.local Keepalived_vrrp[25018]: VRRP_Script(chk_haproxy) failed Feb 18 00:18:56 cluster-pgsql-02.local Keepalived_vrrp[25018]: VRRP_Instance(cluster_pgsql_02) Received higher prio advert Feb 18 00:18:56 cluster-pgsql-02.local Keepalived_vrrp[25018]: VRRP_Instance(cluster_pgsql_02) Entering BACKUP STATE Feb 18 00:18:56 cluster-pgsql-02.local Keepalived_vrrp[25018]: VRRP_Instance(cluster_pgsql_02) removing protocol VIPs. Feb 18 00:18:56 cluster-pgsql-02.local Keepalived_vrrp[25018]: Opening script file /usr/bin/sh Feb 18 00:18:56 cluster-pgsql-02.local Keepalived_healthcheckers[25017]: Netlink reflector reports IP 192.xx.xx.125 removed
Keepalived отловил проблему, и убрал с себя виртуальный адрес, а также просигналил об этом соседям.
Смотрим что произошло на втором сервере:
Feb 18 00:18:56 cluster-pgsql-01.local Keepalived_vrrp[41190]: VRRP_Instance(cluster_pgsql_01) forcing a new MASTER election Feb 18 00:18:56 cluster-pgsql-01.local Keepalived_vrrp[41190]: VRRP_Instance(cluster_pgsql_01) forcing a new MASTER election Feb 18 00:18:56 cluster-pgsql-01.local Keepalived_vrrp[41190]: VRRP_Instance(cluster_pgsql_01) forcing a new MASTER election Feb 18 00:18:56 cluster-pgsql-01.local Keepalived_vrrp[41190]: VRRP_Instance(cluster_pgsql_01) forcing a new MASTER election Feb 18 00:18:57 cluster-pgsql-01.local Keepalived_vrrp[41190]: VRRP_Instance(cluster_pgsql_01) Transition to MASTER STATE Feb 18 00:18:58 cluster-pgsql-01.local Keepalived_vrrp[41190]: VRRP_Instance(cluster_pgsql_01) Entering MASTER STATE Feb 18 00:18:58 cluster-pgsql-01.local Keepalived_vrrp[41190]: VRRP_Instance(cluster_pgsql_01) setting protocol VIPs. Feb 18 00:18:58 cluster-pgsql-01.local Keepalived_vrrp[41190]: VRRP_Instance(cluster_pgsql_01) Sending gratuitous ARPs on ens160 for 192.xx.xx.125 Feb 18 00:18:58 cluster-pgsql-01.local Keepalived_vrrp[41190]: Opening script file /usr/bin/sh Feb 18 00:18:58 cluster-pgsql-01.local Keepalived_vrrp[41190]: VRRP_Instance(cluster_pgsql_01) Received lower prio advert, forcing new election Feb 18 00:18:58 cluster-pgsql-01.local Keepalived_vrrp[41190]: VRRP_Instance(cluster_pgsql_01) Sending gratuitous ARPs on ens160 for 192.xx.xx.125 Feb 18 00:18:58 cluster-pgsql-01.local Keepalived_healthcheckers[41189]: Netlink reflector reports IP 192.xx.xx.125 added Feb 18 00:18:58 cluster-pgsql-01.local Keepalived_vrrp[41190]: VRRP_Instance(cluster_pgsql_01) Received lower prio advert, forcing new election Feb 18 00:18:58 cluster-pgsql-01.local Keepalived_vrrp[41190]: VRRP_Instance(cluster_pgsql_01) Sending gratuitous ARPs on ens160 for 192.xx.xx.125 Feb 18 00:19:03 cluster-pgsql-01.local Keepalived_vrrp[41190]: VRRP_Instance(cluster_pgsql_01) Sending gratuitous ARPs on ens160 for 192.xx.xx.125
Дважды произошли перевыборы (потому что третий сервер кластера успел отправить свой анонс до первых выборов), сервер 1 принял на себя роль ведущего, и выставил виртуальный IP.
Убеждаемся в этом:
[root@cluster-pgsql-01 log]# ip a 2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000 link/ether 00:50:56:a9:f0:90 brd ff:ff:ff:ff:ff:ff inet 192.xx.xx.120/24 brd 192.xx.xx.255 scope global ens160 valid_lft forever preferred_lft forever inet 192.xx.xx.125/32 scope global ens160 <---- виртуальный адрес кластера присутствует! valid_lft forever preferred_lft forever inet6 fe80::1d75:40f6:a14e:5e27/64 scope link valid_lft forever preferred_lft forever
Теперь виртуальный IP присутствует на сервере, не являющимся мастером репликации. Однако это не имеет значения, поскольку в базу мы обращаемся через haproxy, а она мониторит состояние кластера независимо, и отправляет запросы всегда на мастер.
При возврате в строй haproxy на втором сервере снова происходят перевыборы (keepalived с бОльшим приоритетом встает в строй), и виртуальный IP возвращается на свое место.
В редких случаях бывает что слейв не может догнаться до мастера (например он упал очень давно и wal журнал успел частично удалиться). В таком случае можно полностью очистить директорию с базой на слейве:
«rm -rf /var/lib/pgsql/9.6/data», и перезапустить Patroni. Она сольет базу с мастера целиком.(Осторожно с очисткой «ненужных» баз, внимательно смотрите на каком сервере вы выполняете команду!!!)
В таком случае нужно воспользоваться утилитой patronictl. Команда reinit позволяет безопасно очистить конкретный узел кластера, на мастере она выполняться не будет.
Спасибо за дополнение CyberDemon.
Сама утилита patronictl позволяет увидеть текущую ситуацию с кластером через командную строку, без обращений в DCS, и управлять кластером.
Пример отчета о состоянии кластера:
/opt/patroni/patronictl.py -c /etc/patroni/postgres.yml list cluster-pgsql:
+---------------+------------------+-----------------+--------------+------------------+-----------+ | Cluster | Member | Host | Role | State | Lag in MB | +---------------+------------------+-----------------+--------------+------------------+-----------+ | cluster-pgsql | cluster_pgsql_01 | 192.xxx.xxx.120 | Leader | running | 0.0 | | cluster-pgsql | cluster_pgsql_02 | 192.xxx.xxx.121 | Sync standby | running | 0.0 | | cluster-pgsql | cluster_pgsql_03 | 192.xxx.xxx.122 | | creating replica | 33712.0 | +---------------+------------------+-----------------+--------------+------------------+-----------+
В данном случае наливается третья нода, ее отставание от мастера составляет 33 Гб.
После завершения этого процесса она также переходит в состояние Running с нулевым лагом.
Также можно обратить внимание что поле State у нее пустое. Это потому, что кластер в моем случае работает в синхронном режиме. Для уменьшения лага синхронной репликации, один слейв работает в синхронном режиме, а другой в обычном асинхронном. В случае пропадания мастера роли сместятся, и второй слейв перейдет в синхронный режим к ставшему мастером, первому слейву.
Послесловие
Единственное чего этому кластеру, на мой взгляд, не хватает для счастья — это пулинг коннектов и проксирование запросов на чтение на все слейвы для повышения производительности чтения, а запросов на вставки и обновления только на мастер.
В конфигурации с асинхронной репликацией, раскладывание нагрузки на чтение может привести к непредвиденным ответам, если слейв отстанет от мастера, это нужно учитывать.
Стриминговая (асинхронная) репликация не обеспечивает консистентности кластера в любой момент времени, и для этого нужна синхронная репликация.
В этом режиме мастер сервер будет ждать получения подтверждений о копировании и применении транзакций на слейвы, что замедлит работу базы. Однако если потери транзакций недопустимы (например какие-то финансовые приложения), синхронная репликация это ваш выбор.
Patroni поддерживает все варианты, и если синхронная репликация вам подойдет больше, вам всего лишь понадобится изменить значение нескольких полей в конфигах Patroni.
Вопросы разных методов репликации прекрасно разобраны в документации к Patroni.
Кто-то наверное предложит использовать pgpool который сам, по сути, покрывает весь функционал этой системы. Он может и мониторить базы, и проксировать запросы, и выставлять виртуальный IP, а также осуществляет пулинг коннектов клиентов.
Да, он все это может. Но на мой взгляд схема с Patroni гораздо прозрачнее (конечно это только мое мнение), и во время экспериментов с pgpool я ловил странное поведение с его вочдогом и виртуальными адресами, которое не стал пока слишком глубоко дебажить, решив поискать другое решение.
Конечно возможно, что проблема тут только моих в руках, и позже я к тестированию pgpool планирую вернуться.
Однако, в любом случае, pgpool не сможет полностью автоматически управлять кластером, вводом новых и (особенно) возвратом сбойных серверов, работать с DCS. На мой взгляд это самый интересный функционал Patroni.
Спасибо за внимание, буду рад увидеть предложения по дальнейшему улучшению этого решения, и ответить на вопросы в комментариях.
Огромное спасибо Zalando за Patroni, и авторам исходного проекта Governor, который послужил основой для Patroni, а также Алексу Чистякову за шаблон роли для Ansible.
Полный код плейбуков и шаблонов Ansible, описанных в статье лежит тут. Буду благодарен за доработки от гуру Ansible и PostgreSQL. :)
Основные использованные статьи и источники:
Несколько вариантов кластеров PgSQL:
→ https://habrahabr.ru/post/301370/
→ https://habrahabr.ru/post/213409/
→ https://habrahabr.ru/company/etagi/blog/314000/
→ Пост о Patroni в блоге Zalando
→ ansible-role-patroni Алекса Чистякова
→ Governor — к сожалению разработка давно заморожена.
→ Книга Ansble for Devops — прекрасный учебник с кучей примеров применения Ansible.
Last updated