18-pgcluster — кластер PostgreSQL со стриминговой репликацией

☐ Опциональный. Превращает узел в участника кластера PostgreSQL (роль primary или replica) со стриминговой репликацией, эндпоинтом роли и watchdog-самовосстановлением на каждом узле.

Зачем нужен

Обычная установка PostgreSQL (модуль 12-postgresql) — это один сервер. Если он выйдет из строя (упало питание, kernel panic, оборвалась сеть, отказал диск), база данных недоступна целиком: приложения не могут ни читать, ни писать, пока сервер не поднимут вручную.

Отказоустойчивость базы данных простыми словами — это когда данные существуют больше чем на одном сервере, и когда главный сервер умирает, его место автоматически занимает запасной, а приложения этого почти не замечают. Достигается это тремя вещами, которые и настраивает этот модуль:

  1. Репликация — копия всех данных постоянно течёт с главного сервера на запасные.
  2. Автоматический failover — сторож (watchdog) на каждом узле замечает смерть главного и повышает одну из копий в главные.
  3. Единая точка входа — приложение всегда обращается по одному адресу, даже если за ним стоит уже другой сервер (это делает модуль 19-pgvip или команда mitdev pg proxy).

Термины, которые встретятся ниже (объясняем сразу):

Чем это НЕ является. Это не шардинг (данные не разрезаются по серверам — на каждом узле лежит полная копия базы). Это не балансировка записи (писать можно только в один узел — primary; реплики принимают только чтение). И это не защита от логических ошибок: DROP TABLE или кривая миграция мгновенно повторятся на всех репликах — от этого спасают только бэкапы.

Картина целиком

                    приложения (пишут и читают)
                              │
                    одна строка подключения
              VIP 10.0.0.100:5432  ИЛИ  127.0.0.1:5432 (HAProxy)
                              │
        ┌─────────────────────┼─────────────────────┐
        ▼                     ▼                     ▼
   ┌─────────┐          ┌─────────┐          ┌─────────┐
   │ srv-1   │          │ srv-2   │          │ srv-3   │
   │ PRIMARY │══ WAL ══▶│ replica │          │ replica │
   │         │══════ WAL ═════════════════▶ │         │
   │ :5432 RW│          │ :5432 RO│          │ :5432 RO│
   │ :8008 → │  200     │ :8008 → │  503     │ :8008 → │  503
   │ watchdog│          │ watchdog│          │ watchdog│
   └─────────┘          └─────────┘          └─────────┘
        └──── приватная сеть 10.0.0.0/24 (WireGuard mesh) ────┘

Когда включать и когда не нужен

Включайте, если:

Не нужен, если:

Важно про число узлов. Кластер из трёх узлов переживает отказ одного. Из пяти — двух. Два узла — это не отказоустойчивость: при разрыве сети ни один не может понять, умер сосед или просто пропала связь, и повышать себя опасно (получите два primary — split-brain).

Зависимости и требования

Что именно делает — роль primary

При установке с PG_CLUSTER_ROLE=primary (_pg_setup_primary):

  1. Создаёт роль репликации PG_REPLICATION_USER (по умолчанию replicator) с правами REPLICATION LOGIN и сгенерированным паролем. Пароль сохраняется в CREDENTIALS_FILE (/root/.mitdev-credentials) и в ~postgres/.mitdev-repl-pass (для watchdog). Шаг идемпотентный: если роль уже есть — не трогает.
  2. Пишет параметры репликации в drop-in conf.d/99-mitdev-replication.conf:
    listen_addresses = '*'          # слушать по сети, не только localhost
    ssl = on
    wal_level = replica             # писать в WAL достаточно данных для реплик
    max_wal_senders = 10            # сколько реплик может стримить одновременно
    max_replication_slots = 10
    wal_keep_size = '512MB'         # запас WAL, чтобы реплика догнала после паузы
    hot_standby = on                # разрешить чтение на репликах
    wal_log_hints = on              # включает pg_rewind (нужно для fencing)
    
  3. Открывает доступ реплик поимённо. Для каждого IP из PG_REPLICA_IPS добавляет в pg_hba.conf запись hostssl replication replicator <ip>/32 scram-sha-256 и правило UFW 5432/tcp только с этого IP. Порт 5432 не открывается «всему миру».
  4. Выдаёт GRANT'ы для pg_rewind роли replicator (функции pg_ls_dir, pg_stat_file, pg_read_binary_file) и добавляет hba-записи hostssl postgres replicator <ip>/32 — чтобы понижённый бывший primary мог автоматически вернуться репликой (см. fencing ниже).
  5. Перезапускает PostgreSQL и проверяет, что wal_level стал replica.
  6. Ставит watchdog (на primary — в режиме fencing, авто-повышение выключено) и эндпоинт роли.

Если IP реплик при установке не заданы — не беда, добавите позже командой mitdev pg add-replica <ip>.

Что именно делает — роль replica

При установке с PG_CLUSTER_ROLE=replica (_pg_setup_replica) нужны PG_PRIMARY_HOST и PG_REPLICATION_PASSWORD. Порядок:

  1. Проверка доступности primary (pg_isready -h <primary> -p 5432 -t 10). Это защитный барьер: пока primary недоступен, локальный PostgreSQL НЕ трогается вообще. Если проверка провалилась — модуль печатает, что проверить (mitdev pg add-replica на primary, listen_addresses, файрвол провайдера) и выходит, ничего не сломав.

  2. Идемпотентность. Если узел уже является стримящей репликой (pg_is_in_recovery()=t и статус WAL receiver = streaming) — пересоздание пропускается. Уже работающую реплику модуль не трогает. Исключение — принудительный ресинк (PG_FORCE_RESYNC=yes, его выставляет mitdev pg follow).

  3. Остановка PostgreSQL.

  4. Старый каталог данных откладывается в сторону, а не удаляется. Если в каталоге данных что-то есть, он переименовывается в <datadir>.mitdev-old.<дата-время> (например .../main.mitdev-old.20260710143012). Это и есть ваш откат: если что-то пойдёт не так, старые данные на месте. Также регистрируется автоматический rollback — при сбое установки каталог вернётся на место, и PostgreSQL запустится в исходном виде.

  5. pg_basebackup с primary — полная бинарная копия базы:

    pg_basebackup -d "host=<primary> port=5432 user=replicator password=… sslmode=require" \
      -D <datadir> -R -X stream --checkpoint=fast -C -S mitdev_<hostname>
    
    • -R — записывает standby.signal (файл-признак «я реплика») и primary_conninfo (строку подключения к primary, включая пароль; файл 0600, только для postgres);
    • -X stream — тянет WAL параллельно с копированием, чтобы копия была согласованной;
    • -C -S mitdev_<hostname> — создаёт на primary физический слот репликации с именем mitdev_<короткое-имя-хоста>;
    • sslmode=require — WAL между узлами всегда шифруется.

    При ошибке (не совпал пароль, нет hba-записи, слот уже существует) модуль печатает частые причины и восстанавливает прежние данные из отложенного каталога.

  6. Запуск в режиме standby и проверка до 30 секунд (15 попыток × 2 с), что узел вышел в recovery и WAL receiver в состоянии streaming.

  7. Сохранение данных в credentials (роль, primary_host, имя слота) и установка watchdog + эндпоинта роли. Watchdog ставится независимо от PG_AUTO_FAILOVER: даже реплика, которой запрещено повышаться, обязана уметь автоматически перецепиться на нового primary.

Эндпоинт роли (порт 8008)

Зачем. Когда узлы в разных дата-центрах, VIP не работает (VRRP требует общей L2-сети — см. 19-pg-vip.md). Тогда единую точку входа даёт HAProxy на сервере приложений (mitdev pg proxy), а чтобы HAProxy понимал, кто сейчас primary, каждый узел кластера поднимает эндпоинт роли.

Что это. Персистентный systemd-сервис mitdev-pg-role.service (User=postgres), слушающий PG_ROLE_PORT (по умолчанию 8008) через один постоянный листенер socat (TCP-LISTEN:…,fork), который форкает лёгкий обработчик на каждый коннект внутри одного и того же юнита. На каждое HTTP-подключение он выполняет SELECT pg_is_in_recovery() и отвечает:

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

Почему не socket-activation. Раньше эндпоинт был socket-activated (mitdev-pg-role.socket + [email protected]) — systemd поднимал отдельный юнит на каждое подключение. При частых опросах HAProxy с нескольких app-узлов это упиралось в systemd start-limit: часть коннектов сбрасывалась (RST), HAProxy метил primary как DOWN, и это каскадом валило запись 500/503 у приложений. Поэтому эндпоинт переведён на один персистентный листенер socat — юнит не пересоздаётся на каждый коннект. Модуль ставит зависимость socat на db-узлах автоматически (pkg_install socat) и при обновлении со старой версии сам снимает legacy-юниты mitdev-pg-role.socket/[email protected].

Диагностика. sudo systemctl status mitdev-pg-role.service, логи — journalctl -u mitdev-pg-role.service.

Безопасность. Порт 8008 закрыт в UFW и открывается точечно только серверам приложений командой mitdev pg allow <ip> (она открывает и 5432, и 8008 для указанного IP).

TLS между узлами

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

PostgreSQL использует самоподписанный сертификат, который Debian/Ubuntu генерируют при установке. sslmode=require шифрует канал, но не проверяет имя сертификата — этого достаточно против пассивного перехвата; строгая проверка (verify-full) потребовала бы собственного CA и здесь не настраивается.

Watchdog самовосстановления v3

Это ключевая часть, делающая конструкцию отказоустойчивой, а не просто реплицированной. Скрипт — lib/pg-watchdog.sh, ставится в /usr/local/lib/mitdev/pg-watchdog.sh.

Где и как работает:

Кворум — почему реплика не всегда повышается

Само по себе «я не вижу primary» не означает, что primary умер. Может быть, это вас отрезали от сети, а primary жив и продолжает принимать запись от приложений. Если такая реплика повысится, в кластере окажется два primary, а когда связь восстановится, pg_rewind молча откатит всё, что настоящий primary успел записать.

Поэтому реплика повышается, только пока видит большинство узлов кластера (себя + достижимые пиры ≥ N/2+1). Симметрично: primary, оказавшийся в меньшинстве, переводит свой эндпоинт роли в 503 — HAProxy и VIP уводят от него запись, хотя PostgreSQL продолжает работать и обслуживать чтение. Это «мягкий self-fence»: узел не останавливается, но перестаёт быть точкой записи.

Кластер из двух узлов — особый случай. Большинство там недостижимо: после потери одного узла второй видит 1 из 2. Правила асимметричны:

Ситуация Без PG_WITNESS_HOSTS С witness
Реплика не видит primary не повышается (primary может быть жив) повышается, если видит witness
Primary не видит реплику продолжает работать (иначе отказ реплики убил бы запись) уходит в 503, если witness недоступен

Witness — это любой хост вне обоих узлов БД, достижимость которого доказывает, что вы на связной стороне сети: сервер приложений, шлюз. Задаётся PG_WITNESS_HOSTS="10.0.0.9". Для кластера из трёх и более узлов witness не нужен — там работает обычное большинство.

Возврат упавшего primary: почему он сначала «невидим»

Когда упавший primary включается обратно, PostgreSQL поднимает его как обычный primary — он ещё не знает, что за время его отсутствия повысили реплику. Раньше в это окно HAProxy и VIP успевали направить в него записи, которые затем уничтожал pg_rewind.

Теперь watchdog при старте в роли primary создаёт ~postgres/.mitdev-pg-unverified. Пока файл существует, эндпоинт роли отвечает 503 unverified, а pg-vip-check не отдаёт узлу VIP — то есть запись в него не попадает. Файл снимается после первой же проверки пиров, когда выясняется, что никто узел не превзошёл. Если watchdog остановлен, файл удаляется автоматически (ExecStopPost), чтобы узел не выпал из кластера навсегда.

На реплике: авто-failover и авто-перецепление

Каждые CHECK_INTERVAL (5 с) реплика дважды проверяет primary: pg_isready и сырой TCP-коннект на 5432. Отказ засчитывается, только если оба способа провалились — это отсекает ложные срабатывания при кратковременной загрузке БД.

После FAIL_THRESHOLD (6) неудач подряд и паузы PROMOTE_DELAY:

Если AUTO_PROMOTE=no и нового primary среди пиров нет — реплика просто ждёт (она заведомо не должна становиться главной, например слабее по железу), но перецепиться к чужому повышению всё равно сможет.

На primary: fencing (защита от split-brain)

Primary следит за эндпоинтами ролей пиров. Если он видит другой узел, который сообщает primary со старшим timeline, — значит, этот узел был недоступен, за это время реплику повысили, и он устарел. Тогда он сам себя понижает:

  1. останавливается;
  2. делает pg_rewind от победителя (пароль передаётся через PGPASSWORD, а не в командной строке — чтобы не светился в ps);
  3. если pg_rewind не удался — fallback: откладывает каталог в .mitdev-old.<дата> и делает полный pg_basebackup;
  4. запускается уже репликой нового primary.

Именно поэтому split-brain не случается: узел со старым timeline никогда не остаётся primary. Ожившый после сбоя старый primary возвращается в кластер репликой — без единой ручной команды.

Два primary с одинаковым timeline (обе реплики повысились одновременно) разрешаются автоматически и детерминированно: узел с бóльшим IP-адресом самопонижается через pg_rewind, узел с меньшим остаётся primary. Оба узла выполняют одно и то же сравнение и приходят к противоположным выводам, поэтому понижается ровно один. Сравнение числовое, а не строковое — иначе 23.134.42.10 оказался бы «меньше» 23.134.42.9.

Журнал pg_rewind при самопонижении — /var/log/postgresql/mitdev-pg-rewind.log.

Что делает watchdog возможным

Управление watchdog

mitdev pg watchdog status         # состояние службы, конфиг, последние события
sudo mitdev pg watchdog enable    # включить
sudo mitdev pg watchdog disable   # выключить (тогда повышать — вручную: mitdev pg promote)
sudo mitdev pg watchdog set FAIL_THRESHOLD 12   # поменять порог (служба перезапустится)

События сторожа: journalctl -t mitdev-pg-watchdog.

Настройка

Все переменные можно задать при установке (установщик спрашивает основные) или экспортировать перед install.sh. Значения по умолчанию — из config/defaults.conf.

Переменная Тип По умолчанию Влияние Когда менять
PG_CLUSTER_ROLE primary|replica primary какую роль настроить на узле обязательно на репликах — replica (спрашивает установщик)
PG_REPLICA_IPS список IP пусто IP реплик, которым открыть доступ (только на primary) заполнить на primary; иначе добавлять mitdev pg add-replica
PG_PRIMARY_HOST IP/хост пусто адрес primary (только на реплике) обязательно на реплике (спрашивает установщик)
PG_REPLICATION_PASSWORD строка пусто пароль роли replicator с primary (на реплике) обязательно на реплике (берётся из credentials primary)
PG_REPLICATION_USER строка replicator имя роли репликации почти никогда
PG_CLUSTER_PEERS список IP PG_PRIMARY_HOST пиры для watchdog реплики (кого спрашивать про новый primary) указать все другие узлы кластера
PG_AUTO_FAILOVER yes|no no разрешить этой реплике авто-повышение в primary yes на основной реплике; no на резервной/слабой
PG_MAX_WAL_SENDERS число 10 сколько реплик может стримить одновременно при > ~8 реплик
PG_MAX_REPLICATION_SLOTS число 10 максимум слотов репликации вместе с числом реплик
PG_WAL_KEEP_SIZE размер 512MB запас WAL для отставшей реплики увеличить при частых больших паузах реплик
PG_WATCHDOG_INTERVAL сек 5 период проб primary реже — при «дёрганой» сети
PG_WATCHDOG_THRESHOLD число 6 неудач подряд до реакции больше — консервативнее (см. формулу)
PG_WATCHDOG_PROMOTE_DELAY сек 0 доп. пауза перед повышением разнести приоритет реплик (резервной дать 45 с)
PG_ROLE_PORT порт 8008 порт эндпоинта роли при конфликте порта

Время до повышения = PG_WATCHDOG_INTERVAL × PG_WATCHDOG_THRESHOLD + PG_WATCHDOG_PROMOTE_DELAY. По умолчанию 5 × 6 + 0 = 30 с. Агрессивнее (3 × 4 = 12 с) — стабильная сеть в одной стойке; консервативнее (5 × 12 = 60 с) — разные ДЦ со всплесками задержки.

Основные значения (PG_CLUSTER_ROLE, PG_REPLICA_IPS / PG_PRIMARY_HOST, PG_REPLICATION_PASSWORD, PG_AUTO_FAILOVER, приоритет) собирает интерактивный установщик.

Пошаговое развёртывание кластера из 3 узлов

Предполагаем приватную сеть 10.0.0.0/24: primary 10.0.0.1, реплики 10.0.0.2 и 10.0.0.3. Соберите mesh заранее (см. ../MESH.md).

Шаг 1. Узел A (10.0.0.1) — primary.

curl -fsSL https://ваш-домен/get | sudo bash
# в установщике: компоненты PostgreSQL + «PostgreSQL-кластер»
#   роль: primary
#   IP реплик: 10.0.0.2 10.0.0.3
sudo mitdev net bind postgresql private     # 5432 только в приватной сети

Пароль репликации показан в /root/.mitdev-credentials — он понадобится на репликах.

Шаг 2. (Опционально) Залить существующую базу на A.

sudo mitdev pg import /path/backup.dump mydb   # реплики получат данные сами

Шаг 3. Узел B (10.0.0.2) — основная реплика.

sudo ./install.sh
#   модуль «PostgreSQL-кластер», роль: replica
#   primary: 10.0.0.1
#   пароль репликации: <из credentials узла A>
#   авто-failover: Да,  приоритет: 1 — основная
sudo mitdev net bind postgresql private

Шаг 4. Узел C (10.0.0.3) — резервная реплика.

sudo ./install.sh
#   роль: replica, primary: 10.0.0.1, пароль тот же
#   авто-failover: Да,  приоритет: 2 — резервная (задержка 45 с настроится сама)
sudo mitdev net bind postgresql private

Шаг 5. Единая точка входа.

Шаг 6. Проверка.

sudo mitdev pg status          # A: primary, 2 реплики, лаг ~0
sudo mitdev pg replication     # слоты активны
sudo mitdev pg watchdog status # активен на всех трёх

Повседневная эксплуатация

Все команды — подкоманда mitdev pg:

mitdev pg status               # роль, базы, подключения, wal_level + сводка репликации
mitdev pg replication          # детально: на primary — реплики/слоты/лаг; на реплике — WAL receiver
sudo mitdev pg add-replica 10.0.0.4     # (на primary) разрешить новую реплику: pg_hba + UFW + восстановить listen_addresses
sudo mitdev pg remove-replica 10.0.0.3  # (на primary) убрать одну реплику: слот + pg_hba + UFW
sudo mitdev pg allow 10.0.0.20 mydb deploy   # открыть доступ серверу приложений (5432 + 8008)
sudo mitdev pg promote         # ручное повышение реплики в primary (плановое)
sudo mitdev pg follow 10.0.0.2 # ручное перецепление реплики на другого primary (плановое)
sudo mitdev pg import dump.sql mydb          # (на primary) залить бекап, формат — автоопределение
sudo mitdev pg proxy 10.0.0.1 10.0.0.2 10.0.0.3   # (на сервере приложений) локальный HAProxy
mitdev pg vip                  # состояние VIP (см. модуль 19)
mitdev pg watchdog status      # см. раздел watchdog

Про import: формат определяется сам (pg_dump -Fc → pg_restore; .sql → psql; .sql.gz → gunzip|psql; pg_dumpall → все базы и роли). База создаётся, если её нет (владелец — deploy-пользователь). Выполняется только на primary — на реплике команда честно откажется. Реплики получат данные автоматически.

Про promote/follow: они для плановых операций (обслуживание primary, переезд между ДЦ). При авариях watchdog делает всё сам — не мешайте ему параллельными ручными командами. Перед follow на новом primary выполните mitdev pg add-replica <ip этой реплики>.

Про allow: выполняйте на каждом узле кластера — после failover новый primary тоже должен принимать это приложение.

Проверка, что всё работает

На primary:

sudo -u postgres psql -tAc "SHOW wal_level"                 # replica (или logical)
sudo -u postgres psql -c "SELECT * FROM pg_stat_replication" # строка на каждую подключённую реплику
mitdev pg replication                                       # слоты active=t, лаг маленький
curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8008/   # 200

На реплике:

sudo -u postgres psql -tAc "SELECT pg_is_in_recovery()"     # t
sudo -u postgres psql -tAc "SELECT status FROM pg_stat_wal_receiver"   # streaming
curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8008/   # 503

module_verify считает узел исправным, если служба postgresql активна и: primary — wal_level ∈ {replica, logical}; replica — pg_is_in_recovery()=t.

Сценарии отказа

Что упало Что делает система сама Что делать вам
Реплика (одна из) ничего; primary продолжает, её слот копит WAL вернуть узел; при долгой смерти — pg remove-replica <ip>, чтобы освободить WAL
Primary (авто-failover on) через ~30 с одна реплика → promote (timeline +1); остальные реплики перецепляются к ней; VIP/HAProxy переключается ничего; позже вернуть старый узел
Ожившый старый primary до подтверждения роли эндпоинт отдаёт 503 (запись в него не идёт); затем fencing по timeline: сам понижается через pg_rewind и возвращается репликой ничего
Отставание реплики так, что WAL стёрт слот удерживает WAL (wal_keep_size); при переполнении реплика отвалится увеличить PG_WAL_KEEP_SIZE; пересобрать реплику mitdev pg follow
Сетевой раздел (реплика отрезана) реплика видит меньшинство → не повышается; primary в большинстве продолжает принимать запись ничего; данные не расходятся
Сетевой раздел (primary отрезан) primary в меньшинстве → эндпоинт роли в 503, HAProxy/VIP уводят запись; большинство повышает реплику ничего; при схождении старый primary сам вернётся репликой
Две реплики повысились одновременно (равный timeline) узел с бóльшим IP самопонижается через pg_rewind, меньший остаётся primary ничего
Отказ 2 из 3 узлов кворум не набран: последний узел НЕ повышается (не отличит «все умерли» от «я изолирован») — БД read-only человеческое решение: pg watchdog disable → убедиться, что узлы мертвы → pg promote → потом enable
Отказ 1 из 2 узлов, PG_WITNESS_HOSTS не задан primary продолжает работать; реплика не повышается задать witness — иначе авто-failover на 2 узлах невозможен в принципе
Split-brain (два primary, равный timeline) watchdog пишет предупреждение, но не «лечит» разобраться вручную, какой узел оставить primary, второй — pg follow

Частые ошибки

Симптом: на реплике pg_basebackup не удался, установка откатилась. Причина: не совпал пароль репликации; на primary нет hba-записи для IP этой реплики; слот уже существует. Решение: взять пароль из /root/.mitdev-credentials узла-primary; на primary sudo mitdev pg add-replica <ip реплики>; при «слот существует» на primary sudo -u postgres psql -c "SELECT pg_drop_replication_slot('mitdev_<hostname>')".

Симптом: реплика не выходит в streaming, primary недоступен. Причина: файрвол провайдера/панели блокирует 5432 между узлами (UFW открыт, но внешний фильтр — нет); listen_addresses не *. Решение: проверить sudo ss -tlnp | grep 5432 и SHOW listen_addresses на primary; открыть 5432 с IP реплики в панели провайдера.

Симптом: mitdev pg status показывает на primary «0 реплик» и растущее число неактивных слотов. Причина: реплика отключилась, но её слот остался и копит WAL — грозит переполнением диска primary. Решение: sudo mitdev pg remove-replica <ip> или удалить слот вручную (pg_drop_replication_slot).

Симптом: приложение получает permission denied при подключении к базе. Причина: доступ этому серверу приложений открыт не на всех узлах — после failover новый primary его не пускает. Решение: sudo mitdev pg allow <ip приложения> на каждом узле кластера.

Симптом: после ручного pg promote при живой сети — два primary. Причина: повысили реплику, не убедившись в смерти старого primary → split-brain. Решение: promote только при реальной аварии; ожившый старый primary с меньшим timeline сам понизится (fencing), но при равном timeline разрешайте вручную.

Безопасность и продакшен

Откат и удаление

Автоматический откат при сбое установки: отложенный каталог данных возвращается на место, удаляются drop-in, hba-записи, правила UFW, watchdog, эндпоинт роли.

Снять кластерный оверлей (PostgreSQL остаётся работать автономно):

sudo mitdev remove pgcluster        # = mitdev pg cluster-remove

Удаляет watchdog, эндпоинт роли, конфиг репликации, mitdev-записи pg_hba, правила файрвола, файл пароля. Данные и сама СУБД не трогаются.

Ролевое удаление с --purge:

sudo mitdev remove pgcluster --purge

Убрать одну реплику из кластера, не трогая остальные (со стороны primary):

sudo mitdev pg remove-replica <ip>   # слот + pg_hba + UFW этого IP

Затем на самом сервере-реплике: mitdev remove pgcluster --purge (стереть её БД) или mitdev remove postgresql --purge (снести PostgreSQL целиком).

См. также