FrankWiles.com

Installing a specific version of PostgreSQL in your Dockerfile

It happened to me again today, pg_dump: error: aborting because of server version mismatch. It is an error I know well. I know the reason and I know the remedy, but the specific steps aren’t something that sticks in my memory so I’m writing this for future me to consume as much as anything.

I run into this mostly with Python based projects, typically using the official Python Docker images which are Debian based.

The reason

The reason is that you have installed say version 15 or 17 of PostgreSQL in your Docker container, but are communicating with a server that is running 16.x.

The psql tool is more forgiving and can often operate just fine with several major versions of drift, but pg_dump is another story.

The remedy

The remedy is simple enough, install the right version in your Docker container. Easy, right?

Well sort of. It’s possible to do for sure, but the steps are a little more complicated than your average issue.

To be clear, we’re not trying to run PostgreSQL as a server process here. If you’re wanting to do that you should run the official PostgreSQL docker image for the version you want.

What we are trying to do is install specific versions of the PostgreSQL client tools that are compatible with PostgreSQL running somewhere remotely.

The fix

The steps to do this are pretty straight forward.

  1. Install some tools we need such as curl, gnupg2, lsb-release, etc.
  2. Create a new apt repository in /etc/apt/sources.list.d/ specific to the PGDG (PostgreSQL Development Group)
  3. Download and trust the PostgreSQL team’s GPG key
  4. apt install the version you want.

Here are the details:

FROM python:3.12-slim

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt \
    apt update && \
    apt install --no-install-recommends -y libpq-dev curl gnupg2 lsb-release apt-transport-https ca-certificates

# Add the PGDG apt repo
RUN echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list

# Trust the PGDG gpg key
RUN curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc| gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked,id=apt \
    apt update \
    && apt -y install postgresql-16 \
    && rm -rf /var/lib/apt/lists/*

Two things that might be confusing to you are the use of --mount-type=cache which is just a fancy way to cache apt package downloads so rebuilding locally is faster and the use of lsb_release -cs.

The output for lsb_release -cs in this python 3.12 image is bookworm which makes the second command add the text:

deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main

to the file. You could chose to hard code this instead and skip using lsb_release but I find this easier and more portable across Python versions which often use different Debian versions.

Headshot of Frank Wiles

Frank Wiles

Founder of REVSYS and former President of the Django Software Foundation . Expert in building, scaling and maintaining complex web applications. Want to reach out? Contact me here or use the social links below.