Skip to main content
RunBook Academy

PostgreSQLXVIII · Platforms, Corruption and Production ArchitecturePlatforms

PostgreSQL in containers: what a container does not solve

Intermediate⏱ ~30 mindocker

What you'll learn

  • Identify what containerisation changes and what it does not
  • Read memory limits correctly from inside a container
  • Handle data persistence and signals deliberately
  • Avoid the container-specific traps met in this course

Prerequisites

Verified against PostgreSQL 18.x · PostgreSQL (comparison targets) 17.11, 16.15 · PostgreSQL (support calendar) 18, 17, 16, 15, 14 supported · pgBackRest 2.59.1 · PgBouncer 1.25.2 · Patroni 4.1.5 · Ubuntu (host baseline) 26.04 LTS · 2026-08-27

Not yet marked complete on this device.

Every measurement in this course was taken in a container. That is a reasonable way to run PostgreSQL, and it introduces a specific set of traps — most of which this course walked into while producing its own evidence.

What a container changes

Packaging. One image, the same everywhere, with the version pinned.

Isolation. Resource limits, network namespace, filesystem namespace.

Lifecycle. Start, stop and restart become orchestration events rather than service-manager events.

What it does not change

Everything in Parts VI to XVII. Storage, MVCC, vacuum, locks, the planner, memory, WAL, backups, replication, upgrades — a container is still running the same PostgreSQL, and every measurement in those parts was taken inside one.

Signals and PID 1

PostgreSQL’s shutdown modes from lesson XII-07 map onto signals: SIGTERM is smart, SIGINT is fast, SIGQUIT is immediate.

A container runtime sends SIGTERM on stop, waits, then SIGKILL. SIGTERM is the smart shutdown — which lesson XII-07 measured failing after 10 seconds while sessions remained connected, with pg_ctl: server does not shut down.

Data persistence

Never keep data in the container’s writable layer. It is destroyed with the container.

This course met the consequence directly. A docker commit of a PostgreSQL container captured no data at all, because the image declares /var/lib/postgresql as a volume and commit does not include volume contents:

Read-only / Safewhat a commit of a PostgreSQL container contains
$ docker commit rbpg-prim rbpg-prim-snap && docker run ... rbpg-prim-snap pg_controldata $PGDATA
pg_controldata: error: could not open file
"/var/lib/postgresql/18/docker/global/pg_control" for reading:
No such file or directory

The fix was to mount the original volume into the new container by name. The general rule: the volume is the database; the container is disposable.

Configuration precedence

The official image is started with -c setting=value command-line arguments. Lesson XIII-05 measured the consequence:

Read-only / SafeALTER SYSTEM writing the file, reporting success, and changing nothing
$ SELECT name, setting, source FROM pg_settings WHERE name = 'archive_command';
      name       |                  setting                   |    source
-----------------+--------------------------------------------+--------------
archive_command | test ! -f /archive/%f && cp %p /archive/%f | command line

ALTER SYSTEM wrote postgresql.auto.conf and reported success. The setting did not change, because command-line arguments outrank it.

Always confirm with pg_settings.source, not with the file contents. This is a container-specific hazard precisely because the official image uses command-line arguments as its configuration mechanism.

What still needs solving

A container gives you none of:

  • Backups. Part XIII.
  • Replication and failover. Parts XIV and XV.
  • Monitoring. Part XVI.
  • Storage durability — an image says nothing about whether the volume’s fsync is honest. Lesson VI-01.
  • Connection pooling. Lesson IV-06.

What to take from this

  • A container changes packaging, isolation and lifecycle. It changes nothing about PostgreSQL’s behaviour.
  • free reports the host’s memory. Read /sys/fs/cgroup/memory.max and size from that.
  • SIGTERM is the smart shutdown, which can fail to complete. Set STOPSIGNAL SIGINT and a generous stop timeout, or every stop is a crash.
  • The volume is the database. docker commit captures no volume data — measured.
  • The official image configures via command-line arguments, which outrank ALTER SYSTEM. Check pg_settings.source.
  • Containers give you no backups, replication, monitoring, durable storage or pooling.

Cross-course references

  • Docker & Containers — Part VIII (Storage) covers volume lifetime against container lifetime, Part VI (Container lifecycle) covers the stop-then-kill sequence that makes crash recovery routine, and Part XV (Resource controls) covers the memory limit the OOM killer uses.
  • Linux for Production Sysadmins — Part LXXVIII (Containers from the Linux perspective) covers what a container actually is, which is what makes the “it does not solve durability” argument concrete.

Quiz

Knowledge check · 6 questions

  1. Q1. A monitoring agent inside a container reports 40 GB of memory free, and the container is then OOM-killed. Why?

  2. Q2. A containerised PostgreSQL performs crash recovery on every start, even though every stop was a normal orchestrated stop. What is the cause?

  3. Q3. Why did docker commit of a PostgreSQL container produce an image with no database in it?

  4. Q4. Which container ecosystem defaults fit a database badly? Select all that apply.

  5. Q5. On the official PostgreSQL image, ALTER SYSTEM reliably changes any setting because it writes postgresql.auto.conf.

  6. Q6. What does containerising PostgreSQL solve, and what does it leave entirely unsolved?

Passing score: 75%. Answers are checked in this browser.