Skip to main content
RunBook Academy

Docker & ContainersI Β· FoundationsProduction lens

What production-readiness means here

Foundation⏱ ~22 mindocker

What you'll learn

  • Distinguish the production lens from the developer lens
  • Recognise when a tutorial-grade pattern is unsafe in production
  • Adopt the operational defaults we use throughout the course
  • Audit a running host against those defaults with commands that can fail
  • Explain what a restart policy responds to, and what it ignores

Prerequisites

None β€” start here.

Verified against Docker Engine 29.x Β· Docker Engine 28.x Β· Docker Compose 2.x Β· containerd 2.x Β· runc 1.2.x Β· BuildKit 0.20+ Β· Linux kernel 5.15+ Β· Ubuntu 24.04 LTS Β· Debian 12 (Bookworm) Β· 2026-08-12

Not yet marked complete on this device.

The single most useful question a sysadmin can ask of any Docker content is:

Would this survive at 03:00 with no one awake to debug it?

Most Docker tutorials are written for developers who want their app to run on their laptop. Most production Docker environments are written for operators who need the platform to run unattended for months. The patterns overlap less than you think.

Production vs developer defaults

ConcernDeveloper defaultProduction defaultVerify with
Image baselatestPinned digestdocker inspect --format '{{.Image}}'
Container userrootNon-root via USER directivedocker inspect --format '{{.Config.User}}'
Restart policynoneunless-stoppeddocker inspect --format '{{.HostConfig.RestartPolicy.Name}}'
Health checknoneDefined HEALTHCHECK in imagedocker inspect --format '{{.State.Health.Status}}'
Resource limitsnoneCPU + memory + PIDsdocker inspect --format '{{.HostConfig.Memory}}'
Loggingjson-file unboundedrotated + shipped to central storedocker inspect --format '{{.HostConfig.LogConfig}}'
Storageanonymous volumesnamed volumes with backup plandocker inspect --format '{{json .Mounts}}'
Networkingdefault bridgeuser-defined bridge with segmentationdocker network ls
Secretsenv vars in composeexternal secret managerdocker inspect --format '{{json .Config.Env}}'
Updatesdocker pull && restartstaged rollouts with rollbackchange record

The fourth column is the point. A production default that nobody checks reverts within a quarter, quietly, one deployment at a time.

Auditing a host against the list

Read-only / Safehost audit
docker ps --format '{{.Names}}' | while read -r C; do
docker inspect "$C" --format '{{.Name}}
user={{if .Config.User}}{{.Config.User}}{{else}}ROOT(unset){{end}}
restart={{if .HostConfig.RestartPolicy.Name}}{{.HostConfig.RestartPolicy.Name}}{{else}}none{{end}}
memory={{if .HostConfig.Memory}}{{.HostConfig.Memory}}{{else}}UNLIMITED{{end}}
pids={{if .HostConfig.PidsLimit}}{{.HostConfig.PidsLimit}}{{else}}UNLIMITED{{end}}
health={{if .State.Health}}{{.State.Health.Status}}{{else}}NONE{{end}}
logdriver={{.HostConfig.LogConfig.Type}} opts={{if .HostConfig.LogConfig.Config}}{{.HostConfig.LogConfig.Config}}{{else}}DEFAULTS(unbounded){{end}}'
done
Read-only / Safeaudit output
$ ./docker-audit.sh
/web
user=ROOT(unset)
restart=unless-stopped
memory=UNLIMITED
pids=UNLIMITED
health=healthy
logdriver=json-file opts=DEFAULTS(unbounded)
/postgres
user=999
restart=always
memory=2147483648
pids=512
health=NONE
logdriver=json-file opts=map[max-file:3 max-size:10m]

Illustrative output

Two containers, six findings. None of them is an outage today, and each is a plausible cause of one: an unbounded web can take the host’s memory, an unbounded log can take the host’s disk, and postgres has no health signal at all.

The five questions every production decision must answer

  1. What happens when this fails? Every component will fail. The question is what the failure looks like and how contained it is.
  2. What is the rollback? If a change makes things worse, how do you reverse it? Rollback is part of the change, not a separate concern.
  3. Who gets paged? Every change that affects observability, capacity, or reliability changes the on-call experience.
  4. What is the blast radius? A bug or attack affects a container, a host, a network segment, an entire fleet. The blast radius should be proportional to the value.
  5. Is the change observable? A change that cannot be measured is a change that cannot be reasoned about.

The five things production Docker always does

  • Pins image versions by digest, not tag.
  • Runs containers as non-root with the smallest capability set the workload needs.
  • Defines a HEALTHCHECK for every long-running service.
  • Ships logs out of the host (to journald, syslog, Loki, or a sidecar).
  • Backs up volumes and validates restores β€” quarterly, on a clock, with a clock.

What we will NOT do

This course will not:

  • Pretend docker run -v /:/host is fine because β€œit’s a lab”.
  • Show you how to skip healthchecks to β€œsave time”.
  • Treat latest as a valid production tag.
  • Encourage disabling security features for convenience.
  • Promise that Kubernetes will fix your Compose problems.

It will, instead, give you the operational foundation to run Docker the way it is run in environments that take production seriously.

Knowledge check

Knowledge check Β· 6 questions

  1. Q1. A production Docker default that differs from a developer default is:

  2. Q2. A HEALTHCHECK in the image is optional in production.

  3. Q3. A container is running, reports `unhealthy`, and has `restart: unless-stopped`. What does Docker Engine do?

  4. Q4. You deliberately stop a misbehaving container at 22:00. At 03:00 an unattended upgrade restarts dockerd. Which restart policy brings the container back?

  5. Q5. The filesystem holding /var/lib/docker fills up because of unbounded json-file logs. Which of these are consequences? Select all that apply.

  6. Q6. Log options are fixed at container creation, so adding rotation to daemon.json only affects containers created after the change.

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