Сложилось так исторически, что мы долго не обновляли PostgreSQL и застряли на версии 12. Но пришло время обновлять зависимости проекта и оказалось, что Django 5.1 версию 12 PostgreSQL уже не поддерживает и это мотивировало меня провести обновление до новейшей 16 версии.
На момент написания у нас всё организовано достаточно просто — все необходимые компоненты запускаются в Docker-контейнерах через Docker Compose.
У меня было два варианта, как произвести миграцию:
Сделать полный дамп, загрузить новый образ
postgres:16
и накатить дампИспользовать утилиту
pg_upgrade
, которая позволяет мигрировать данные между версиями PostgreSQL
Поскольку первый метод требует больше времени на восстановление данных, я решил воспользоваться вторым вариантом — pg_upgrade
. Плюс, этот вариант давал возможность попробовать что-то новое.
Сначала было непонятно как применить pg_upgrade
в docker, но после непродолжительного гуглежа я нашёл решение: https://github.com/tianon/docker-postgres-upgrade
По ходу изучения того, как работать с docker-postgres-upgrade
был составлен такой план:
остановить сервисы, зависимые от БД
сделать бэкап БД
остановить БД
произвести миграцию
запустить и проверить БД на новой версии PostgreSQL
запустить сервисы
обновить docker-compose.yml
Примечание: хотя pg_upgrade
и позволяет произвести миграцию на горячую, но я решил не рисковать и сделать это на холодную
Ниже я кратко опишу процесс миграции.
Для начала нужно понять какой volume используется нашим PostgreSQL
% cat docker-compose.yml
services:
...
postgres:
image: postgres:12
container_name: postgres
command: postgres -c "config_file=/etc/postgresql/postgresql.conf"
environment:
POSTGRES_PASSWORD: xxxxxx
volumes:
- ./postgresql/postgresql.conf:/etc/postgresql/postgresql.conf
- postgres:/var/lib/postgresql/data
ports:
- "5432:5432"
...
volumes:
postgres:
% docker volume ls
DRIVER VOLUME NAME
local 1b7ffcbd614f280ab577370912c625135ef84fe8cf721953206ba0142bed8cad
local 6b82aa6ecc19fbea9eb91b8d68af0d6a18d04911717953935cff006a4220e123
local 7c2b74aa668a47d2fe15615b8f4a614ebcf3065ab101cdaf487da6b5e1c95ffd
local 16ea96ec68eeb0134f0eebd27ec983143e9bdd43d527d3c6e1d3f1cd2bacc516
local 180aeeeadba249e991c22bb77c53c9b2a50612a3d181598a8014b667d920762d
local 625ebc83103e8c223395fb7b5e7e31a714110400f6f70f499bee13f3d9b86bce
local 803c056ecb2c83b31e5d0dbb089689ae1b44996fb84aee1e12c8d224b583f8e7
local a1ccdb17c4cc50333ec2c417cf24553e89e4f5aa1e402c1985a8fec2f52c00dd
local a40c9d1b958169dda6db47e7493dacf7c05e6e0acd678954ea87f7ac3ffb8a16
local backend_media
local backend_postgres
local backend_postgres-14
local backend_postgres-16
local backend_static
local c73a013579341af8a05646a501f4b4a9595a3e2b1167543889d1c26a21e4fda3
local cebd974e3e2f2a5bd0b2cf16a4ef293696e30d547ccfd59bad44d155541da16b
local d393b6d74083d4ac5a679a7ed62cf364663a66fa41f113e1b60395ec369e26bb
local dev_badger
local dev_media
local dev_postgres
local dev_static
local edb6be7221e82a9f9c4ba47ac1cae104765bc8d4d29020fef1397aa4d22e9472
local minikube
local minikube-m02
local postgres
local postgres16
local qa-automation_badger
local qa-automation_media
local qa-automation_postgres
local qa-automation_static
Нам нужен volume backend_postgres
, потому что Docker Compose по умолчанию именует volumes в формате "имя проекта + имя volume". Поскольку проект называется backend
(по-умолчанию имя каталога, где запускается Docker Compose, если не задано другое ключом -p
), наш целевой volume будет называться backend_postgres
. Для новой версии PostgreSQL volume будет называться backend_postgres16
.
миграция
% docker run --platform linux/amd64 --rm -v backend_postgres:/var/lib/postgresql/12/data -v backend_postgres16:/var/lib/postgresql/16/data tianon/postgres-upgrade:12-to-16
На MacOS с архитектурой Apple Silicon (M1/M2/M3) возникла необходимость добавить флаг --platform linux/amd64
, так как образ tianon/postgres-upgrade
по умолчанию не поддерживает ARM-архитектуру. Это позволяет принудительно использовать x86_64-образ для успешного запуска.
После завершения процедуры миграции делаем пробный запуск:
% docker run -dit --name postgres16 -p 5432:5432 -e POSTGRESS_PASSWORD=postgres -v backend_postgres16:/var/lib/postgresql/data -v ./postgresql/postgresql.conf:/var/lib/postgresql/data/postgresql.conf -v ./postgresql/pg_hba.conf:/var/lib/postgresql/data/pg_hba.conf postgres:16
У меня кастомные postgresql.conf и pg_hba.conf поэтому прокидываем их внутрь контейнера.
И проверяем по логам, что всё хорошо
% docker logs -f postgres16
Нужно проверить логи на наличие ошибок или предупреждений. Особое внимание стоит уделить сообщениям о несовместимости версий или проблемах с доступом к данным.
Если тестовый запуск прошёл успешно, можно закрепить изменения в основном файле docker-compose.yml
, заменив старую версию PostgreSQL на новую. Важно убедиться, что все зависимости обновлены и настроены правильно перед запуском в продакшн.
Новый docker-compose.yml
services:
...
postgres:
image: postgres:16
container_name: postgres
environment:
POSTGRES_PASSWORD: xxxxxx
volumes:
- ./postgresql/postgresql.conf:/var/lib/postgresql/data/postgresql.conf
- ./postgresql/pg_hba.conf:/var/lib/postgresql/data/pg_hba.conf
- postgres16:/var/lib/postgresql/data
ports:
- "5432:5432"
...
volumes:
postgres16:
Заключение
Благодаря docker-postgres-upgrade
процесс миграции на новую версию PostgreSQL прошёл быстро и гладко. Это отличное решение для тех, кто ищет простой и надёжный способ обновления PostgreSQL в Docker-среде. Рекомендую!