Sunday, August 16, 2026

Docker Administration

Docker has become increasingly useful for database administrators for development, testing, proof-of-concept environments, automation, and database tooling. This guide covers practical Docker administration commands with a DBA focus, particularly for PostgreSQL containers.

Throughout this guide, CONTAINER_ID stands for your actual container ID or container name. Substitute it in every command.

Important: Docker containers are not a replacement for database backup, high availability, or disaster recovery. For production databases, persistent storage, backup, recovery, security, monitoring and HA architecture must be designed separately.

1. Basic concepts

Docker objectDescription
ImageRead-only template used to create containers
ContainerRunning or stopped instance created from an image
VolumePersistent storage managed by Docker
NetworkCommunication between containers and the outside
DockerfileFile used to build an image
ComposeTool to define and manage multiple containers
RegistryRepository where images are stored

For a DBA the chain that matters is:

PostgreSQL container
    |
    +-- PostgreSQL process
    |
    +-- /var/lib/postgresql/data
    |       |
    |       +-- Docker volume
    |
    +-- Port 5432
    |
    +-- Container logs

2. Verify Docker version

docker version

Shorter output:

docker --version

Engine and host details:

docker info

Use docker info when investigating the storage driver, Docker root directory, container runtime, logging configuration, and available CPU and memory.

3. List containers

Running containers:

docker ps

Sample output:

CONTAINER ID   IMAGE         COMMAND                  STATUS
efca1e07d460   postgres:13   "docker-entrypoint..."   Up 2 hours

All containers including stopped ones:

docker ps -a

This is one of the most useful DBA commands, because a database container may have stopped due to startup failure, configuration errors, permission problems, disk space, out-of-memory conditions, wrong environment variables, or failed initialization.

Container IDs only:

docker ps -aq

4. Verify container status

Filter for one container:

docker ps -a --filter id=CONTAINER_ID

Example:

docker ps -a --filter id=efca1e07d460

Full detail:

docker inspect CONTAINER_ID

docker inspect returns container state, IP address, port mappings, mounted volumes, environment variables, restart policy, network configuration, startup command and resource limits.

Just the IP address:

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' CONTAINER_ID

5. Container logs

Logs are the first place to look when a database container misbehaves.

docker logs CONTAINER_ID

Example:

docker logs efca1e07d460

For a PostgreSQL container you may see:

database system is ready to accept connections

or:

FATAL:  role "root" does not exist

The second message does not mean PostgreSQL is down. It means something tried to connect using the OS user root, and no PostgreSQL role called root exists. Connect as the correct database user instead:

docker exec -it CONTAINER_ID psql -U postgres

6. Recent log lines

docker logs --tail 100 CONTAINER_ID

Example:

docker logs --tail 200 efca1e07d460

Useful for recent startup failures, connection or authentication errors, crash and restart events, and extension failures.

7. Follow logs in real time

docker logs --follow CONTAINER_ID

or:

docker logs -f CONTAINER_ID

Useful while restarting the database, testing application connections, reproducing a problem, or watching initialization scripts run.

Press Ctrl+C to stop following. This stops the log display only — it does not stop the container.

8. Log timestamps

docker logs -t CONTAINER_ID

or:

docker logs --timestamps CONTAINER_ID

Timestamps let you correlate Docker events with PostgreSQL logs, application logs, monitoring alerts and OS events. Combine with --tail:

docker logs --timestamps --tail 100 CONTAINER_ID

9. Logs from a specific time

Last hour:

docker logs --since 1h CONTAINER_ID

Last 30 minutes:

docker logs --since 30m CONTAINER_ID

After a specific timestamp:

docker logs --since "2026-08-16T10:00:00" CONTAINER_ID

Combined with follow:

docker logs --since 10m -f CONTAINER_ID

During an incident this avoids scanning the entire log history.

10. Check container processes

docker top CONTAINER_ID

For a PostgreSQL container you should see the expected background processes:

postgres
postgres: checkpointer
postgres: background writer
postgres: walwriter
postgres: autovacuum launcher
postgres: logical replication launcher

If these are absent, the container is up but the database is not.

11. Execute a command inside a container

docker exec CONTAINER_ID COMMAND

Example:

docker exec efca1e07d460 ps -ef

Interactive shell:

docker exec -it CONTAINER_ID bash

If bash is not present in the image:

docker exec -it CONTAINER_ID sh

Once inside, the usual checks apply:

ps -ef
df -h
free -m
ls -ltr /var/lib/postgresql/data

12. Connect to PostgreSQL inside the container

docker exec -it CONTAINER_ID psql -U postgres

Specific database:

docker exec -it CONTAINER_ID psql -U postgres -d postgres

Single query without an interactive session:

docker exec -it CONTAINER_ID psql -U postgres -d postgres -c "SELECT version();"

Example:

docker exec -it efca1e07d460 psql -U postgres -c "SELECT version();"

13. Check database readiness

docker exec CONTAINER_ID pg_isready

Expected output:

/var/run/postgresql:5432 - accepting connections

With explicit host and port:

docker exec CONTAINER_ID pg_isready -h localhost -p 5432

This is the simplest health check for a PostgreSQL container.

14. Check database version

docker exec CONTAINER_ID psql -U postgres -c "SELECT version();"

or:

docker exec CONTAINER_ID psql -U postgres -c "SHOW server_version;"

Worth confirming after deployment, image upgrade, patch testing, migration, restore, or an environment refresh.

15. Start a stopped container

docker start CONTAINER_ID

Start and attach to output:

docker start -a CONTAINER_ID

A useful sequence after starting a database container:

docker start CONTAINER_ID
docker ps
docker logs --tail 100 CONTAINER_ID

16. Stop a running container

docker stop CONTAINER_ID

Docker sends a termination signal to the main process and waits for the configured timeout before forcing termination. Prefer docker stop over docker kill for databases — graceful shutdown lets the database complete its normal shutdown processing.

17. Restart a database container

docker restart CONTAINER_ID

Then validate, in order:

docker ps
docker logs --tail 100 CONTAINER_ID
docker exec CONTAINER_ID pg_isready
docker exec CONTAINER_ID psql -U postgres -c "SELECT now();"

18. Force stop a container

docker kill CONTAINER_ID

This terminates the container process immediately. Avoid it for databases unless the container is completely unresponsive, graceful shutdown has already failed, or emergency recovery requires it.

19. Container resource usage

docker stats

For one container:

docker stats CONTAINER_ID

Shows CPU percentage, memory usage against limit, network I/O, block I/O and process count. Useful when investigating high database CPU, memory pressure, OOM-related restarts, or heavy disk I/O.

For a single non-streaming sample:

docker stats --no-stream CONTAINER_ID

20. Container storage usage

docker system df

More detail:

docker system df -v

Identifies unused images, stopped containers, unused volumes and reclaimable storage.

Be careful cleaning Docker storage on database hosts: never remove a volume because it appears unused without first confirming it holds no database data.

21. Verify database volumes

docker volume ls

Inspect one:

docker volume inspect postgres_data

A PostgreSQL volume is typically mounted at /var/lib/postgresql/data.

The principle to hold on to:
Container = disposable. Database data = persistent.

If PostgreSQL data exists only in the writable container layer, removing the container destroys the database.

22. Verify container mounts

docker inspect -f '{{json .Mounts}}' CONTAINER_ID

Confirm that /var/lib/postgresql/data is backed by persistent storage before running docker rm or docker system prune.

23. Check network configuration

docker network ls

Inspect a network:

docker network inspect NETWORK_NAME

For database troubleshooting, verify the container IP, network name, port mappings, application-to-database connectivity, DNS resolution and network isolation.

24. Check port mapping

docker port CONTAINER_ID

Example output:

5432/tcp -> 0.0.0.0:5432

The host port does not have to match the container port. A mapping of 15432:5432 means:

Docker host port 15432
    |
    v
container port 5432
    |
    v
PostgreSQL

25. Check environment variables

docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' CONTAINER_ID

Common PostgreSQL variables:

POSTGRES_USER
POSTGRES_PASSWORD
POSTGRES_DB
Security note: avoid exposing passwords in screenshots, blog posts, shell history or configuration files. For production, use Docker secrets or an enterprise secret-management solution rather than plain-text environment variables.

26. Container restart policy

docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' CONTAINER_ID

Common policies:

no
always
unless-stopped
on-failure

Change it:

docker update --restart unless-stopped CONTAINER_ID

A restart policy improves availability but is not database HA. Understand why a database container stopped before relying on automatic restart.

27. Identify why a container stopped

docker ps -a
docker inspect -f '{{.State.Status}}' CONTAINER_ID
docker inspect -f '{{.State.ExitCode}}' CONTAINER_ID
docker inspect -f '{{.State.Error}}' CONTAINER_ID

An exit code of 1 indicates the process terminated with an error. Always correlate the exit code with docker logs — the code alone rarely explains the root cause.

28. Troubleshooting flow for an unavailable database

Step 1 — Is the container running?

docker ps -a

Step 2 — What do recent logs show?

docker logs --tail 200 CONTAINER_ID

Step 3 — What is the container state?

docker inspect -f '{{.State.Status}} {{.State.ExitCode}} {{.State.Error}}' CONTAINER_ID

Step 4 — Resource consumption?

docker stats --no-stream CONTAINER_ID

Step 5 — Storage?

docker exec CONTAINER_ID df -h

Step 6 — Is the database process running?

docker top CONTAINER_ID

Step 7 — Is PostgreSQL ready?

docker exec CONTAINER_ID pg_isready

Step 8 — Does a query succeed?

docker exec -it CONTAINER_ID psql -U postgres -c "SELECT now();"

This gives a structured path instead of immediately restarting the container.

29. PostgreSQL log examples

Database ready:

database system is ready to accept connections

Role problem:

FATAL:  role "root" does not exist

Check which roles exist:

docker exec -it CONTAINER_ID psql -U postgres -c "\du"

Port already in use — the container fails to start because the host port is taken. Check on the Docker host:

docker ps
ss -lntp

Disk space — check both sides:

docker exec CONTAINER_ID df -h
df -h

A database can fail even when the container looks healthy, if the underlying host filesystem is full.

30. Remove a container

docker rm CONTAINER_ID

Force removal:

docker rm -f CONTAINER_ID

Before removing a database container, verify: where the data is stored, whether it is in a Docker volume, whether a backup exists, whether the container is still needed, and whether another container uses the same volume.

Removing a container and removing its volume are separate operations, but careless cleanup still causes data loss.

31. Remove unused resources

docker system prune

Review what will be removed first:

docker system df

Be especially careful with:

docker volume prune

Docker volumes may contain database data. On production database hosts, avoid blanket cleanup commands unless they are part of an approved procedure.

32. Backup PostgreSQL from Docker

Plain SQL dump:

docker exec CONTAINER_ID pg_dump -U postgres -d mydatabase > mydatabase.sql

Custom format:

docker exec CONTAINER_ID pg_dump -U postgres -d mydatabase -Fc > mydatabase.dump

All databases:

docker exec CONTAINER_ID pg_dumpall -U postgres > all_databases.sql

Production backup procedures also need retention, encryption, off-host storage, validation, restore testing, defined RPO and RTO, and monitoring.

A Docker volume is not a backup.

33. Restore PostgreSQL into a container

Plain SQL dump:

cat mydatabase.sql | docker exec -i CONTAINER_ID psql -U postgres -d mydatabase

Custom-format dump:

cat mydatabase.dump | docker exec -i CONTAINER_ID pg_restore -U postgres -d mydatabase

Note the -i flag rather than -it: input is piped, so there is no TTY.

Before a production restore, validate the target database and version, required extensions, available disk space, existing objects, role requirements and backup integrity.

34. Copy files between host and container

Host to container:

docker cp backup.sql CONTAINER_ID:/tmp/backup.sql

Container to host:

docker cp CONTAINER_ID:/tmp/backup.sql ./backup.sql

Example:

docker cp efca1e07d460:/var/log/postgresql/postgresql.log .

Do not manually copy database data files while PostgreSQL is running. Use pg_dump, pg_dumpall or pg_basebackup depending on the recovery requirement.

35. Docker images

docker images
docker image ls

Pull an image:

docker pull postgres:16

Image details:

docker image inspect postgres:16

Remove an image:

docker image rm IMAGE_ID

After a database upgrade, do not immediately delete the previous image — it is useful for rollback planning, reproducing issues and version comparison. Balance retention against security and storage requirements.

36. Container naming

docker run --name postgres-dev \
  -e POSTGRES_PASSWORD='ExamplePassword' \
  -d postgres:16

Commands then become readable:

docker logs postgres-dev
docker exec -it postgres-dev psql -U postgres
docker stats postgres-dev

Meaningful names beat randomly generated container IDs.

37. DBA command cheat sheet

RequirementCommand
List running containersdocker ps
List all containersdocker ps -a
Inspect containerdocker inspect CONTAINER_ID
View logsdocker logs CONTAINER_ID
Last 100 log linesdocker logs --tail 100 CONTAINER_ID
Follow logsdocker logs -f CONTAINER_ID
Logs with timestampsdocker logs -t CONTAINER_ID
Logs from last hourdocker logs --since 1h CONTAINER_ID
Container processesdocker top CONTAINER_ID
Execute a commanddocker exec CONTAINER_ID COMMAND
Open a shelldocker exec -it CONTAINER_ID bash
Start containerdocker start CONTAINER_ID
Stop containerdocker stop CONTAINER_ID
Restart containerdocker restart CONTAINER_ID
Resource usagedocker stats CONTAINER_ID
List volumesdocker volume ls
Inspect volumedocker volume inspect VOLUME_NAME
List networksdocker network ls
Inspect networkdocker network inspect NETWORK_NAME
Check port mappingdocker port CONTAINER_ID
Docker disk usagedocker system df
Copy filesdocker cp SOURCE DESTINATION
Remove stopped containerdocker rm CONTAINER_ID
List imagesdocker image ls

38. Troubleshooting checklist

When a database inside Docker is reported down, check in order:

  • Is the Docker service running?
  • Is the database container running?
  • Did the container recently restart?
  • What is the container exit code?
  • What do the latest logs show?
  • Is the database process running?
  • Is the database accepting connections?
  • Is the expected port exposed?
  • Is the Docker network working?
  • Is the database volume mounted correctly?
  • Is sufficient disk space available?
  • Is the container hitting its memory limit?
  • Is CPU usage unusually high?
  • Are database credentials correct?
  • Do the required roles exist?
  • Are configuration files present?
  • Is the database version correct?
  • Are backups available and tested?
  • Is the restart policy appropriate?

39. Best practices

  1. Keep database data outside the container layer. Use persistent volumes or external storage.
  2. Never treat a container as a backup. A container can be recreated; the data needs an independent backup strategy.
  3. Monitor the Docker host. CPU, memory, disk latency, disk capacity, network and the storage driver all affect database performance.
  4. Monitor container resources with docker stats, and feed Docker metrics into your monitoring platform.
  5. Avoid plain-text passwords in environment variables. Use approved secret management for production.
  6. Pin image versions. Use postgres:16 rather than postgres:latest, or a more specific tag where the environment requires it.
  7. Test upgrades before production. An image upgrade can also be a database version upgrade — validate application compatibility, extensions, parameters, backup and restore, performance, and the rollback path.
  8. Do not manipulate database files directly from the host or container shell. Use database-native tools.
  9. Separate application and database concerns using Docker networks and clear service boundaries.
  10. Treat production database containers as infrastructure: monitoring, patching, backup, recovery, security, capacity planning, access control, HA, DR and change management all still apply.

40. Quick health check sequence

docker ps
docker inspect -f '{{.State.Status}} {{.State.ExitCode}}' CONTAINER_ID
docker logs --tail 50 CONTAINER_ID
docker stats --no-stream CONTAINER_ID
docker exec CONTAINER_ID df -h
docker exec CONTAINER_ID pg_isready
docker exec CONTAINER_ID psql -U postgres -c "SELECT version();"
docker exec CONTAINER_ID psql -U postgres -c "SELECT now();"

That walks the full stack:

container -> process -> resources -> storage -> PostgreSQL -> connectivity

Conclusion

Docker gives DBAs a lightweight, repeatable way to build database environments for development, testing, automation, migration rehearsal and proof-of-concept work. It does not remove any traditional DBA responsibility.

The commands that matter day to day:

docker ps
docker inspect
docker logs
docker exec
docker stats
docker top
docker start
docker stop
docker restart
docker volume
docker network
docker cp

Combined with PostgreSQL-native tools — psql, pg_isready, pg_dump, pg_dumpall, pg_restore, pg_basebackup — that is a practical foundation for administering PostgreSQL containers.

DBA principle: Docker manages the container lifecycle. The DBA remains responsible for the database lifecycle, data protection, recoverability, security and operational reliability.

Setting Up a PostgreSQL MCP Server in VS Code (AWS RDS, Aurora & On-Prem)

The Model Context Protocol (MCP) lets AI coding assistants talk to external systems — including your databases — through a standard interfac...