Введение
В данном howto я опишу свой опыт обновления СУБД PosgreSQL 9.5, работающей в Docker, до версии 12.2.
Необходимость обновления давно имела место быть, т.к. 9.5 уже откровенно старая версия и приложение, использующее PostgreSQL, уже было готово для работы с новой версией 12.2. Мне же нужно было только обновиться. Немного сложности добавляет то, что PostgreSQL запущен в docker-контейнере, но в целом инструкция подойдет и для классической установки.
Мне не приходилось обновляться напрямую, минуя несколько мажорных версий, т.к. в процессе может быть очень много нюансов, как для разработчиков, так и для системных администраторов, о чём подробно было написано в данной статье. Но практика показала, что возможность прямого и беспроблемного обновления есть.
Как будет проходить обновление
pg_upgrade может принести много сюрпризов при обновлении с такой старой версии, минуя несколько мажорных релизов. Поэтому при небольшом объеме базы допустимо обновиться напрямую через pg_dumpall — данная утилита поочередно выполнит pg_dump для всех существующих БД и выгрузку глобальных ролей и прочих объектов (чего не делает pg_dump) в один SQL-файл. Но для этого нужен уже временно запущенный PostgreSQL 12 версии, т.к. дамп от pg_dump версии 9.5 не подходит к 12 версии.
Выполнение обновления
Подразумевается, что новый docker-образ 12.2 уже загружен на сервер и запущен контейнер со старой PostgreSQL 9.5 на порту 5432. Далее порядок действий следующий:
- Сделать бэкап
- Запустить временный контейнер с PostgreSQL 12.2 на порту 15432:
OLD_CONTAINER_NAME="postgresql-9.5"
NEW_CONTAINER_NAME="postgresql-12.2"
docker run -d --name=${NEW_CONTAINER_NAME} \
-h ${NEW_CONTAINER_NAME} \
--restart=on-failure:1 \
-p 15432:5432 \
-e "POSTGRES_HOST_AUTH_METHOD=trust" \
-v /storage/${NEW_CONTAINER_NAME}/var/lib/postgresql/data:/var/lib/postgresql/data \
postgres:12.2
Директория /storage/${NEW_CONTAINER_NAME}/var/lib/postgresql/data создаётся автоматически
- Из временного контейнера выполнить дамп всех сущностей в базе посредством уже новой версии pg_dumpall:
docker exec -it ${NEW_CONTAINER_NAME} bash
su - postgres
HOST_IP="IP_ADDRESS" # IP адрес хост-машины, на которой располагаются контейнеры
PGPASS="password" # пароль пользователя postgres на $OLD_CONTAINER_NAME
echo "${HOST_IP}:*:*:postgres:${PGPASS}" > /var/lib/postgresql/.pgpass
chmod 600 /var/lib/postgresql/.pgpass
pg_dumpall -h ${HOST_IP} -f /var/lib/postgresql/data/dumpall.sql
Удобно иметь файл .pgpass, чтобы каждый раз не вводить пароль, когда будет происходить выгрузка всех БД.
- После получения файла с дампом, его необходимо импортировать в текущем же контейнере — это будет основой для нового контейнера вместо временного:
psql -f /var/lib/postgresql/data/dumpall.sql
- После выхода из контейнера, его можно удалить — далее он будет создан с другими опциями:
docker stop ${NEW_CONTAINER_NAME} && docker rm ${NEW_CONTAINER_NAME}
- Перед запуском нового контейнера, необходимо скопировать старые конфигурационные файлы:
cat /storage/${OLD_CONTAINER_NAME}/var/lib/postgresql/data/pg_hba.conf > /storage/${NEW_CONTAINER_NAME}/var/lib/postgresql/data/pg_hba.conf
cat /storage/${OLD_CONTAINER_NAME}/var/lib/postgresql/data/postgresql.conf > /storage/${NEW_CONTAINER_NAME}/var/lib/postgresql/data/postgresql.conf
Стоит обратить внимание на совместимость директив конфигурационного файла из 9.5 и 12.2 — в моём случае большая часть параметров была по умолчанию и не требовала изменений от версии к версии.
- Необходимо изменить политику перезапуска старого контейнера, чтобы он случайно не запустился, а после выполнить его остановку:
docker update --restart=no ${OLD_CONTAINER_NAME} && docker stop ${OLD_CONTAINER_NAME}
- При наличии slave, его также необходимо остановить.
- И наконец пора запустить новый контейнер уже на дефолтном порту 5432 с указанием директории, где подготовлены все БД и конфигурационные файлы:
docker run -d --name=${NEW_CONTAINER_NAME} \
-h ${NEW_CONTAINER_NAME} \
--restart=unless-stopped \
-p 5432:5432 \
-v /storage/${NEW_CONTAINER_NAME}/var/lib/postgresql/data:/var/lib/postgresql/data \
postgres:12.2
docker logs ${NEW_CONTAINER_NAME}
- Проверить логи: ошибок быть не должно.
Заключение
Таким простым образом получилось выполнить обновление напрямую с PostgreSQL 9.5 на 12.2, минуя предыдущие мажорные релизы. Хочу обратить внимание, что база была крайне маленькая – всего 20 Гб, поэтому pgdumpall был вполне себе допустим и даунтайм приложения был небольшой, примерно 20 минут. Для более крупных и серьезных проектов такой вариант вряд ли будет допустим, поэтому нужно учитывать этот момент и искать другие корректные варианты обновления.