I spent my morning fighting with a Docker container, and I think I lost. Well, I eventually won, but it took a lot longer than I’d like to admit.
I was trying to do something simple: inspect the raw data files inside a Postgres Docker volume. I just wanted to see what the base and global folders looked like on disk.
I ran a quick Ubuntu container to peek inside the volume:
docker run -it --rm -v postgres-data:/app ubuntu /bin/bash
I went into /app, ran ls, and saw… nothing. Empty.
That sent me down a rabbit hole of debugging that taught me two things: I was using the wrong path, and Postgres 18 has changed the rules.
Mistake 1: The Host Path Trap
My first issue was a classic copy-paste error. I was trying to mount the volume using the host path on my machine instead of the internal path the container expects.
I was doing this:
-v postgres-data:/var/lib/docker/volumes/...
When I should have been doing this:
-v postgres-data:/var/lib/postgresql/data
Docker containers are like magic boxes. They don’t know about your host file system. You have to tell them exactly where to put the “backpack” (the volume) inside the box. Once I fixed that, I thought I was home free.
Mistake 2: The Postgres 18 Surprise
I restarted my container using postgres:latest. Since it is 2026, “latest” now means Postgres 18.
Suddenly, the container refused to start. I got a massive error message about pg_ctlcluster and “major-version-specific directory names.”
It turns out the Postgres Docker maintainers changed how volumes work in version 18+.
The Old Way (Pre-v18):
We used to mount our volume directly to the data folder:
/var/lib/postgresql/data
The New Way (v18+):
Now, they want us to mount to the parent directory:
/var/lib/postgresql
Why? Because this allows Postgres to create a versioned subfolder (like /18/main or /data) inside the volume. This makes future upgrades (like v18 to v19) much cleaner because the new version won’t accidentally overwrite the old version’s files.
The Fix
If you are running into this, you have two options.
Option A: Stick to what you know
Don’t use latest. Pin your version to postgres:16 or 17. The old mount paths still work there.
Option B: Embrace the new standard
If you want to use Postgres 18, update your docker run or Compose file to remove /data from the end of the volume path:
docker run --name postgres-db \
-e POSTGRES_PASSWORD=root \
-v postgres-data:/var/lib/postgresql \
-d postgres
Inspecting the data again
Once I fixed the mount path, I ran my Ubuntu inspector again.
docker run -it --rm -v postgres-data:/app ubuntu /bin/bash
This time, /app wasn’t empty. But it also didn’t have the raw files immediately. Instead, I found a subfolder.
root@container:/app# ls
18
root@container:/root@container:/app# ls
18
root@container:/app# cd 18/docker
root@container:/app/18/docker# ls
base global pg_wal PG_VERSION
There they were.
Lesson learned: latest tags are dangerous, and sometimes reading the giant error message actually helps.
If you’re using Postgres in Docker, double-check your volume mounts and be aware of version changes. It can save you hours of frustration!
Happy New Year and happy debugging! 🎉🚀