Патч-релизы обычно проматывают. Этот — не стоит.

В 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 ).

Что изменится при обновлении

Три пункта, на которые стоит посмотреть до раскатки:

Мелочи, которые пригодятся

Плагин cnpg (разбор всех команд — в отдельной статье):

PgBouncer:

Разное:

Вывод

Обновляться стоит, и вот почему: перечисленные ошибки failover не проявляются в штатном режиме. Кластер выглядит здоровым, метрики зелёные, учения (если вы их проводите) могут пройти успешно — а поймать эти сценарии можно только на конкретном стечении обстоятельств: недоступный узел, забытый фенсинг, моргнувший API server, совпавшие LSN.

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

Если только знакомитесь с оператором — серия переводов рецептов лежит в проекте про Postgres в Kubernetes.

Авторские права

Автор: Vasiliy Koshkin

Ссылка: https://notes.melancholic.tech/posts/cloudnativepg-1-30-1/

Лицензия: CC BY-NC-SA 4.0

Использование материалов блога разрешается при условии: указания авторства/источника, некоммерческого использования и сохранения лицензии.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
↵
ESC
⌘K Горячая клавиша