Herold
Solutions
Blog
Preview for How to Upgrade Postgres in Docker

How to Upgrade Postgres in Docker

Overcoming Challenges During a Postgres Database Upgrade

October 31, 20245 min read

Postgres is one of my go-to, go-to databases, hands down. But it's also important to keep this database up to date from time to time. I recently wanted to upgrade the Postgres database of my self-hosted Plausible instance from version 14 to version 16. Since this is a step between major versions and not as straightforward as minor versions, I thought I'd document how simple it can be if you have everything set up in Docker with docker compose.

Upgrade Minor/Patch Versions

Upgrading from a minor or patch version is as simple as swapping out the current image for the new version and starting the container again. The other steps will be taken for you automatically, so there's no need for you to take any manual action.

For example just replace you current version:

image: postgres:14.12-alpine

With the new version:

image: postgres:14.13-alpine

Upgrade Major Versions

Upgrading between major versions requires a bit more attention because it could introduce breaking changes. Since it sometimes changes how data is written to the filesystem, it's better to make the migration by exporting the database and importing the data into the new database. This can be done in just a few simple steps.

1. Add a Container for the new Database version

The first thing we'll do is add a new container for the upgrade version to our docker-compose.yml and start the stack.

services:
    plausible_db:
        image: postgres:14-alpine
        container_name: plausible_db_14
        restart: unless-stopped
        volumes:
            - ./postgres-14:/var/lib/postgresql/data
        env_file:
            - stack.env

    # new database version
    plausible_db_15:
        image: postgres:15-alpine
        container_name: plausible_db_15
        restart: unless-stopped
        volumes:
            - ./postgres-15:/var/lib/postgresql/data
        env_file:
            - stack.env

    # other services
    plausible:
        image: ghcr.io/plausible/community-edition:v2.1.4
        container_name: plausible

    # [...]

As you can see in the configuration, we generally use the same setup, but we've added a new volume for the data.

3. Stop the Workload

The goal here is to make sure that no new data is written to our database. In my case, I need to stop the plausible container.

docker stop plausible

4. Create Postgres Backup

We can use pg_dumpall to back up our database.

docker exec -it plausible_db_14 pg_dumpall -U postgres > plausible_upgrade_backup_14.sql

Double-check you're using the right PostgreSQL credentials and take a look at the file to confirm it's in SQL format. If there are any issues with the backup, try to resolve them before moving forward.

5. Import Postgres Backup

Now we can move the backup to the new database.

cat plausible_upgrade_backup_14.sql | docker exec -i plausible_db_15 psql -U postgres

6. Switch Database for your workload

As a final step, we can move our workload to a new database and start the container again.

services:
    # rename so that its no longer in use
    plausible_db_14:
        image: postgres:14-alpine
        container_name: plausible_db_14
        restart: unless-stopped
        volumes:
            - ./postgres-14:/var/lib/postgresql/data
        env_file:
            - stack.env

    # replacement for old database service
    plausible_db:
        image: postgres:15-alpine
        container_name: plausible_db_15
        restart: unless-stopped
        volumes:
            - ./postgres-15:/var/lib/postgresql/data
        env_file:
            - stack.env

    # other services
    plausible:
        image: ghcr.io/plausible/community-edition:v2.1.4
        container_name: plausible

    # [...]

Once we get the workload back up and running, we should be good to go with our service as usual.

docker start plausible

If everything's running fine with our service, we can go and get rid of the old database service plausible_db_14 from our docker-compose.yml and then the database upgrade will be done. But I'd say it's a good idea to check the service first before deleting the old database, because we can always switch back to the old setup if something isn't working right.

Conclusion

As you can see, with a Docker Compose setup, it's pretty simple to upgrade a major Postgres version, but there is a risk of losing all your data. The good news is that we can always switch back to the old version if anything goes wrong.

Selfie of Felix Herold

The article was helpful, or are you feeling a bit unsure about anything?