Привет, Habr! На связи эксперты команды сервиса WatchDog — Дмитрий Коновалов и Геннадий Переломов.

В ВТБ, у нашего основного заказчика, мы развиваем сервисы автоматизации сопровождения баз данных. Одной из ключевых СУБД в инфраструктуре является PostgreSQL. Поддержка её в актуальном состоянии требует периодических мажорных обновлений, которые остаются одной из самых трудоёмких задач для DBA, особенно в ночные или выходные технологические окна.

В этой статье мы расскажем, как разработали внутренний сервис, позволяющий администраторам прикладных систем запускать мажорное обновление PostgreSQL в один клик и без участия DBA.

Зачем автоматизировать мажорные обновления PostgreSQL

Жизненный цикл мажорной версии PostgreSQL — 5 лет. Чтобы оставаться в зоне официальной поддержки, получать новые возможности и улучшения, и при этом соответствовать внутренним нормативным документам (ВНД), необходимо регулярно обновлять инсталляции. На момент старта проекта в ВТБ было несколько тысяч экземпляров PostgreSQL, и ручное обновление каждого из них было бы затратным и рискованным.

Постановка задачи

В мае 2023 года перед нами поставили задачу:

Создать сервис (условно — «кнопку»), который позволит администраторам АБС выполнять мажорное обновление PostgreSQL без участия DBA.

Требования:

  • Поддержка standalone и cluster конфигураций.

  • Надёжность — на входе и выходе должен быть рабочий экземпляр PostgreSQL.

  • Минимизация человеческого фактора.

  • Поддержка расширений pg_stat_statements и pgaudit.

  • Обязательное выполнение резервного копирования.

  • Полное соответствие корпоративным чеклистам.

Анализ и подготовка

Мы изучили:

  • статистику используемых версий PostgreSQL (от 11 до начинающейся 15),

  • типовые расширения и модули,

  • текущие процессы обновления,

  • особенности конфигураций (Patroni, standalone),

  • ограничения по времени обновлений (ночное окно).

В результате мы сузили фокус:

  • поддержка обновлений до версий 14 и 15,

  • анализ расширений и автоматическая проверка их наличия,

  • обязательные предварительные проверки, чтобы гарантировать запуск PostgreSQL после обновления.

Реализация: архитектура «кнопки»

Сценарий был разбит на две части:

  • Frontend: веб-интерфейс с выбором сервера и мажорной версии;

  • Backend: масштабный Ansible Playbook (более 3000 строк и ~100 шагов).

Форма пользователя:

  • Выбор сервера из доступных.

  • Выбор версии обновления (14 или 15).

  • Отображение ограничений сценария.

  • Чекбокс «Я понимаю, что делаю» — без него запуск невозможен.

Структура playbook

Шесть основных блоков + блоки отката:

1.     Предварительные проверки:

  • Доступность экземпляра,

  • Конфигурация,

  • Наличие расширений,

  • Соответствие чеклисту.

2.     Установка новой версии PostgreSQL.

3.     Подготовка к pg_upgrade:

  • Dump-проверка,

  • Тестовое выполнение pg_upgrade.

4.     Запуск pg_upgrade.

5.     Бэкап:

  • Для cluster — бэкапом является сама реплика, которую сценарий не трогает пока успешно не обновим лидер,

  • Для standalone — до выполнения pg_upgrade.

6.     Финальные проверки и правки конфигурации.

Механизмы отката

Механизмы отката предусмотрены для всех этапов до и после неуспешного выполнения pg_upgrade. В случае ошибки сценарий восстанавливает PostgreSQL в изначальное рабочее состояние.

Дополнительно:

  • Обновление Patroni до целевой версии (если требуется).

  • Асинхронное выполнение ресурсоёмких операций: pg_upgrade, vacuumdb, pg_dump, бэкап.

Тестирование

Мы провели тестирование по всем возможным сценариям:

  • Все поддерживаемые мажорные версии;

  • Разные объёмы $PGDATA, LO, количество таблиц;

  • Все комбинации включённых расширений;

  • Все блоки отката.

Результаты показали надежную работу сценария.

Результаты эксплуатации

На момент публикации сценарий находится в боевой эксплуатации более полутора лет, за это время проведено свыше 1000 успешных обновлений PostgreSQL, а также добавлена поддержка обновления до версии 16.

Статистика работы сценария в ПРОД среде:

config

pg_ver

pgdata_size

count_unlogged_tables

count_all_tables

count_all_lo

duration

cluster

14 -> 15

849 GB

0

25348

0

03:22:16

cluster

14 -> 15

1840 GB

0

6140

0

03:00:36

cluster

14 -> 15

898 GB

0

4419

0

02:58:19

cluster

14 -> 15

721 GB

0

13846

0

01:39:38

cluster

13 -> 15

150 GB

0

19834

307969

00:56:31

cluster

14 -> 15

829 GB

0

382

0

00:50:25

cluster

14 -> 15

922 GB

0

1454

0

00:43:47

cluster

14 -> 15

390 GB

0

868

0

00:43:30

cluster

14 -> 15

377 GB

0

236

0

00:40:59

cluster

13 -> 15

644 GB

0

138

0

00:40:56

cluster

14 -> 15

750 GB

0

778

0

00:39:47

cluster

14 -> 15

1022 GB

0

45

0

00:35:58

cluster

14 -> 15

224 GB

0

352

0

00:29:39

cluster

14 -> 15

241 GB

0

150

0

00:29:04

cluster

15 -> 16

250 GB

0

93

0

00:28:51

cluster

14 -> 15

436 GB

0

101

0

00:26:50

cluster

14 -> 15

230 GB

0

103

0

00:25:56

cluster

14 -> 15

381 GB

0

257

0

00:25:16

cluster

13 -> 15

61 GB

0

21758

180

00:24:27

cluster

14 -> 15

210 GB

0

129

0

00:22:34

cluster

13 -> 15

218 GB

0

197

0

00:21:33

cluster

14 -> 15

186 GB

0

547

0

00:21:28

cluster

14 -> 15

80 GB

0

397

0

00:21:12

cluster

14 -> 15

184 GB

0

106

0

00:21:06

cluster

13 -> 15

223 GB

0

197

0

00:20:34

cluster

14 -> 15

61 GB

0

449

0

00:15:51

cluster

14 -> 15

163 GB

0

57

0

00:15:00

cluster

14 -> 15

96 GB

0

49

0

00:14:16

cluster

14 -> 15

9718 MB

0

43

0

00:13:39

cluster

14 -> 15

57 GB

0

118

0

00:11:52

cluster

14 -> 15

56 GB

0

34

0

00:11:49

cluster

14 -> 15

9731 MB

0

43

0

00:11:42

cluster

15 -> 16

80 GB

0

81

0

00:11:23

cluster

14 -> 15

16 GB

0

167

0

00:11:13

cluster

14 -> 15

10 GB

0

408

0

00:11:11

cluster

14 -> 15

68 GB

0

598

0

00:11:07

cluster

14 -> 15

14 GB

0

73

0

00:10:41

cluster

15 -> 16

43 GB

0

101

0

00:10:36

cluster

14 -> 15

20 GB

0

129

0

00:09:50

cluster

13 -> 15

8613 MB

0

21

0

00:09:37

cluster

14 -> 15

9005 MB

0

74

0

00:09:30

cluster

14 -> 15

65 GB

0

178

0

00:09:09

cluster

14 -> 15

8787 MB

0

210

0

00:08:56

cluster

14 -> 15

21 GB

0

324

14893

00:08:50

cluster

15 -> 16

8642 MB

0

21

0

00:08:47

cluster

14 -> 15

8749 MB

0

54

0

00:08:44

cluster

14 -> 15

31 GB

0

44

0

00:08:41

cluster

14 -> 15

9434 MB

0

76

0

00:08:33

cluster

14 -> 15

8567 MB

0

21

0

00:08:28

cluster

15 -> 16

22 GB

0

333

0

00:08:19

cluster

14 -> 15

17 GB

0

165

0

00:08:07

cluster

14 -> 15

12 GB

0

275

0

00:08:01

cluster

12 -> 15

8627 MB

0

21

0

00:07:57

cluster

15 -> 16

11 GB

20

1250

0

00:07:36

cluster

14 -> 15

8807 MB

0

26

0

00:07:35

cluster

15 -> 16

9771 MB

0

135

0

00:07:33

cluster

12 -> 15

8628 MB

0

21

0

00:06:58

Заключение

Ключом к успешному внедрению стало соблюдение чеклистов и подготовка экземпляров — спасибо команде сопровождения PostgreSQL и сервису контроля инфраструктуры WatchDog.

Мы продолжаем развивать сценарий, и с нетерпением ждём появления в Банке версии PostgreSQL 17, чтобы добавить её поддержку в нашу «кнопку».

Что дальше

Если у вас есть опыт автоматизации обновлений PostgreSQL — поделитесь в комментариях. Какие подходы вы используете? Как решаете проблему rollback? Насколько глубоко интегрируете с CI/CD?

Мы открыты к диалогу.

Комментарии (1)


  1. mblp
    12.09.2025 12:22

    только я не увидел ссылки на плейбук, без которой это статья полно барахло?