Upgrading Postgres when running in Docker
Major releases of Postgres require upgrading with migration of system tables to new formats. There are multiple ways to upgrade Postgres including pg_upgrade, logical replication, and dump/restore. In this tutorial you will learn how to perform the dump/restore method.
Preparing for migration
Password Hashing
Newer hub.docker images use SCRAM-SHA-256 by default in pg_hba.conf, this configuration will prevent Roles using md5 hashing from authenticating.
If upgrading from Postgres <= 10 or if the environment is still using the old MD5 passport hashing, you should migrate to using SCRAM-SHA-256. Alternatively set your configuration back to md5 however this is not recommended and has security implications.
To get a list of Roles with md5 hashed passwords that need to be reset you can execute the following SQL query:
SELECT rolname FROM pg_authid
WHERE rolpassword LIKE 'md5%'
AND rolcanlogin;
or
SELECT rolname FROM pg_authid
WHERE rolpassword NOT LIKE 'SCRAM-SHA-256%'
AND rolcanlogin;
Passwords can then be reset with psql using
\password username
for each Role.
There are many online tutorials for this process: https://www.cybertec-postgresql.com/en/from-md5-to-scram-sha-256-in-postgresql/
Volume mapping
The dump/restore method requires that additional disk space equal to the current database size plus a little bit more. A new Docker volume or local disk path should be mapped to the new container. Do not map the old data directory to the new container.
Migration
For all commands below, ${old_pg_container} will refer to our source container we wish to upgrade, ${new_pg_container} will refer to our upgraded container.
- Stop all applications writing to the current database. Leave the ${old_pg_container} container running.
- Start the ${new_pg_container} with the upgraded version with docker run or by creating a new container via docker-composer, mounting a new persistent data volume
- Install any extensions into the new container, but do not install the schema with
CREATE EXTENSION
- Migrate the SCHEMA and data from ${old_pg_container} to ${new_pg_container}
docker exec -i ${old_pg_container} su -c "pg_dumpall --clean" postgres \ | docker exec -i ${new_pg_container} su -c "psql" postgres
- Perform a Vacuum to ensure statistics are gathered
docker exec -i ${new_pg_container} su -c "vacuumdb -a -z" postgres
- Stop ${old_pg_container}
- (Optional) Rename ${new_pg_container} to ${old_pg_container} if you do not wish to modify application configuration
docker rename ${new_pg_container} ${old_pg_container}
or if running via docker-compose, update the configuration of the old container to point to the new docker image and new data volume.
You should now be able ot start your application(s).