Патч-релизы обычно проматывают. Этот — не стоит.
В CloudNativePG 1.30.1 (23 сентября 2026) собралась целая гроздь исправлений вокруг failover: семь отдельных сценариев, в которых переключение зависало, тихо откатывалось или повышало не ту реплику. Плюс обход проверки в валидирующем webhook и CVE в gRPC.
Объединяет их неприятное свойство: всё это ломается не в обычной работе, а ровно в момент аварии — когда вы и рассчитываете на автоматику.
Разбор по release notes проекта . Формулировки причин мои, номера PR — из оригинала.
Failover: семь способов не переключиться
Старый primary, который не отвечает, не демотировался
Если PostgreSQL на бывшем primary переставал отвечать, оператор ждал чекпоинта и попыток мягкой остановки — которые уже никогда не завершатся. Узел не выключался и не мог вернуться в кластер репликой нового primary.
Теперь остановка запрашивается, не блокируя реконсиляцию. Оговорка честная: демоушен всё равно может занять минуту и больше, если PostgreSQL продолжает игнорировать сигналы (#11347 ).
Один зафенсенный инстанс блокировал весь кластер
Красивый по своей неочевидности баг. Зафенсенный инстанс продолжал рапортовать о своём здоровье на status-эндпоинте, хотя его под навсегда оставался не Ready.
Из-за этого проверка готовности, выборы primary и переприсоединение подов вставали при аварии в совершенно другом месте кластера — и оставались в ступоре, пока кто-нибудь вручную не снимет фенсинг. Теперь все три механизма распознают и пропускают зафенсенные инстансы (#11274 ).
Failover зависал навсегда или откатывался
Пока переключение было в состоянии «в процессе», реконсилятор мог пропустить проверку готовности его завершить — или принять это состояние за отсутствующий под и сбросить целевой primary обратно на нездоровый узел.
Теперь незавершённый failover продолжает двигаться и завершается, когда WAL-приёмники остановлены, с повторной проверкой кворума прямо перед повышением — на случай, если он изменился за время ожидания (#11336 ).
Ничья по LSN → повышение не той реплики
Сортировка designated primary неверно обрабатывала совпадение LSN. Если под designated primary потом исчезал из списка статусов, оператор мог повысить не тот standby (#11494 ).
Любопытное совпадение: ровно тот же тай-брейк по равным LSN я разбирал в посте про GFM — там его решают детерминированной сортировкой по именам хостов. Задача универсальная для любого HA-механизма, и ошибиться в ней легко.
Окно, в котором primary писал без лизы
Самое серьёзное. Запуск PostgreSQL теперь привязан к фактическому владению лизой primary.
Раньше существовало окно, в котором перезапущенный или переехавший primary успевал начать принимать запись до получения лизы. Получение лизы перенесли в инициализацию инстанса — строго до того, как PostgreSQL разрешено стартовать, а не позже в цикле реконсиляции, когда инстанс уже отрапортовал о готовности (#11356 ).
Что это означает практически: короткое окно расхождения данных, если в этот момент лиза принадлежала другому узлу. Классический split-brain в миниатюре.
Зависший вызов к API server крал лизу
Смежное исправление: вызов Get при перехвате лизы не имел ограничения по времени. При недоступном API server он блокировался бесконечно, а тот же застрявший вызов мог задержать продление собственной лизы primary после кратковременного сбоя — и другой инстанс перехватывал лизу, когда та «истекала» (#11350
).
Теперь вызов ограничен RenewDeadline: быстро падает и повторяется.
stopDelay игнорировался
Запрос на быструю остановку не нёс явного таймаута, поэтому pg_ctl откатывался к своему неявному лимиту в 60 секунд. А менеджер инстанса, будучи PID 1 в контейнере, гасил PostgreSQL посреди остановки независимо от того, какой stopDelay вы настроили (#11263
).
Если у вас база с долгим чекпоинтом и вы заботливо выставили большой stopDelay — он не работал.
Безопасность
Обход валидации webhook. Абсолютный путь расширения со вставленным .. (например, /a/../../../../etc) проходил проверку, потому что проверялся только сырой путь. При разрешении в рантайме такой путь выходил за пределы точки монтирования расширения. Теперь пути разрешаются и отбраковываются согласованно: в admission, в задании мажорного апгрейда и в уже сохранённых спеках (#11210
).
CVE-2026-84304 в gRPC-Go — исчерпание памяти через фрагментацию DATA-фреймов HTTP/2. Зависимость обновлена до v1.83.1 (#11394 ).
Что изменится при обновлении
Три пункта, на которые стоит посмотреть до раскатки:
- Операнд по умолчанию — PostgreSQL 18.6 (
18.6-system-trixie). Если вы не фиксируете образ явно, обновление потянет смену версии PostgreSQL. - Базовый образ оператора переехал с Debian 12 на Debian 13, поскольку bookworm ушёл в режим только-LTS.
- Контрольные суммы данных. В PostgreSQL 18
initdbвключает их по умолчанию, поэтому приdataChecksums: falseоператор теперь явно передаёт--no-data-checksums. Поведение при умолчании изменилось — учитывайте для новых кластеров.
Мелочи, которые пригодятся
Плагин cnpg (разбор всех команд — в отдельной статье):
- у
backupпоявился--dry-run: печатает ресурсBackup, который был бы создан, ничего не создавая; - имя бэкапа по умолчанию теперь в UTC;
cnpg destroyудаляет PVC раньше подов — исчезла гонка, оставлявшая висящие PVC.
PgBouncer:
- метрики переставали быть нулями:
SHOW STATSиSHOW POOLSтеперь разбираются по именам колонок, а не по позициям. Раньше добавление или перестановка колонок в PgBouncer молча обнуляла метрики — идеальный пример «мониторинг зелёный, потому что сломан»; - появился
auth_userвspec.pgbouncer.parameters— можно переопределить пользователя дляauth_query, не выводя его изauthQuerySecret.
Разное:
ssl_ecdh_curveбольше не отвергается webhook’ом;- при восстановлении через плагин
pg_walсимлинкуется на WAL-том, а не проигрывается на том с данными — раньше большой PITR мог его исчерпать; - ошибки
VolumeSnapshotповторяются до дедлайна, а не сдаются сразу (к слову о снапшотах — про их консистентность); - оператор перестал кэшировать секреты Helm-релизов: на кластерах с крупными релизами это раздувало память вплоть до crashloop;
NULLвstats_resetметрикиpg_stat_walбольше не ломает сбор Prometheus на PostgreSQL 18;- метки из
.spec.inheritedMetadataбольше не затираются собственными метками оператора на PVC; PoolerиDatabaseRoleперестали пересоздавать свои ресурсы после пометки на удаление — раньше это вешало внешние финализаторы вроде foreground-удаления в ArgoCD.
Вывод
Обновляться стоит, и вот почему: перечисленные ошибки failover не проявляются в штатном режиме. Кластер выглядит здоровым, метрики зелёные, учения (если вы их проводите) могут пройти успешно — а поймать эти сценарии можно только на конкретном стечении обстоятельств: недоступный узел, забытый фенсинг, моргнувший API server, совпавшие LSN.
Это и есть аргумент в пользу патчей в HA-компонентах: вы не узнаете, что были уязвимы, пока не окажется поздно.
Если только знакомитесь с оператором — серия переводов рецептов лежит в проекте про Postgres в Kubernetes.