Почему PostgreSQL падает в Docker Swarm с ошибкой checkpoint
Развёртывание PostgreSQL в среде Docker Swarm - популярная практика, но иногда она приводит к неожиданным сбоям. Типичная ситуация: база данных объёмом 30 ГБ падает раз в 1-3 месяца с критической ошибкой could not locate a valid checkpoint record. После восстановления (ремонта) БД снова работает стабильно, но цикл повторяется. Рассмотрим, почему это происходит и как избежать проблемы.
Основная причина: некорректное завершение работы контейнера
В Docker Swarm оркестратор может перезапускать или перемещать контейнеры между узлами кластера. Если во время записи checkpoint-записи (контрольной точки) происходит внезапная остановка контейнера (из-за нехватки памяти, перезагрузки узла или ошибки сети), файл контрольной точки повреждается. При следующем запуске PostgreSQL не может найти валидный checkpoint и впадает в PANIC.
Факторы, усугубляющие проблему в Docker Swarm
- Нестабильное сетевое хранилище (NFS, Ceph): если данные БД размещены на сетевом томе, задержки и разрывы соединения приводят к частичной записи WAL или checkpoint.
- Нехватка ресурсов контейнера: ограничение CPU или RAM (cgroups) может вызвать принудительное завершение процесса postgres в критический момент.
- Перемещение сервиса (rescheduling): при сбое узла Swarm запускает контейнер на другом узле. Если том не отмонтирован корректно, данные могут быть повреждены.
- Неверные настройки shared_buffers и wal_buffers: в контейнере с ограниченной памятью эти параметры должны быть рассчитаны с учётом лимитов.
Почему на отдельной VM проблема исчезла
Перенос PostgreSQL на выделенную виртуальную машину решает проблему по нескольким причинам:
- Стабильный доступ к локальному диску (без сетевых задержек).
- Гарантированные ресурсы CPU и RAM (без конкуренции с другими контейнерами).
- Отсутствие перепланирования контейнеров - процесс работает непрерывно.
- Операционная система сама управляет кэшированием и вводом-выводом, что снижает риск частичной записи.
Как предотвратить падение PostgreSQL в Docker Swarm
Если вы не можете отказаться от Docker Swarm, примените следующие меры:
1. Используйте локальные тома или statefulset
Размещайте данные БД на локальном диске узла (bind mount) или используйте драйверы томов с поддержкой консистентности (например, Rook/Ceph с fsync).
2. Настройте ресурсы контейнера
Выделите контейнеру достаточное количество памяти (не менее 2 ГБ на 30 ГБ данных) и CPU (минимум 1 ядро). Укажите limits и reservations в docker-compose.
3. Оптимизируйте параметры PostgreSQL
Увеличьте wal_keep_segments и checkpoint_completion_target, чтобы снизить нагрузку на запись checkpoint. Настройте shared_buffers на 25% от доступной памяти.
4. Включите fsync и full_page_writes
Убедитесь, что fsync = on и full_page_writes = on в postgresql.conf. Это гарантирует целостность страниц даже при сбое.
Диагностика ошибок checkpoint
Чтобы понять, что именно вызывает повреждение, проверьте:
- Логи Docker:
docker service logs- ищите сообщения OOMKilled или exit code 137. - Логи PostgreSQL:
PANIC: could not locate a valid checkpoint record- указывает на битый файл в каталоге pg_wal. - Мониторинг I/O: используйте
iostatилиdstatдля проверки задержек диска на узле Swarm.
В вашем случае перенос на отдельную VM - правильное решение, но описанные настройки помогут и в кластерной среде.