Docker Environment Management: Images, Logs, and Cleanup (2026 Guide)
Why This Matters
After running a few containers, your Docker host starts accumulating stuff — images, stopped containers, unused volumes, build caches.
I learned this the hard way. A few months into using Docker, I ran df -h and discovered my home directory was 90% full. Docker had quietly consumed gigabytes of images, orphaned volumes, and build layers.
That's when I learned the prune commands.
This guide covers the essential skills for managing your Docker environment:
- Listing and removing images
- Viewing container logs
- Using environment variables (critical for databases)
- Setting restart policies
- Cleaning up disk space safely
Prerequisites
- Docker installed (rootless mode recommended)
- Basic Docker familiarity (run, stop, rm commands)
- 5 minutes to work through the examples
Managing Images
Every time you run a container from an image you haven't used before, Docker downloads it and stores it locally. Over time, these images consume significant disk space.
List All Images
$ docker images
You'll see something like:
IMAGE ID DISK USAGE CONTENT SIZE nginx:latest dec7a90bd097 240MB 65.8MB redis:latest 315270d16608 204MB 55.3MB ghcr.io/jqlang/jq:latest 4f34c6d23f4b 3.33MB 1.03MB hello-world:latest 85404b3c5395 25.9kB 9.52kB
The DISK USAGE column shows the compressed size on disk. Just four images from following this series and you're already at ~450MB. Multiply that across months of pulling images and you can see why knowing how to manage them matters.
Remove an Image
To remove an image you no longer need:
$ docker rmi hello-world:latest
Note: If a container is still using the image (even a stopped one), Docker will refuse to remove it. Stop and remove the container first, or use the -f flag to force removal.
To remove all unused images at once, see the Cleaning Up Disk Space section below.
Viewing Container Logs
When a container fails to start or behaves unexpectedly, the first thing to check is its logs. Docker captures everything a container writes to standard output and standard error.
View Logs
$ docker logs dtnginx
You should see the nginx startup messages:
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh /docker-entrypoint.sh: Configuration complete; ready for start up 2026/03/23 10:08:54 [notice] 1#1: using the "epoll" event method 2026/03/23 10:08:54 [notice] 1#1: nginx/1.29.6 2026/03/23 10:08:54 [notice] 1#1: built by gcc 14.2.0 (Debian 14.2.0-19) 2026/03/23 10:08:54 [notice] 1#1: OS: Linux 6.8.0-100-generic 2026/03/23 10:08:54 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576 2026/03/23 10:08:54 [notice] 1#1: start worker processes 2026/03/23 10:08:54 [notice] 1#1: start worker process 29
The key line to look for is Configuration complete; ready for start up — that confirms nginx started successfully. Everything after that is the worker process startup.
Follow Logs in Real Time
To watch logs as they're written (like tail -f):
$ docker logs -f dtnginx
Press Ctrl+C to stop following.
Show Last N Lines
To see only the last 10 lines:
$ docker logs --tail 10 dtnginx
Combine flags for real-time tailing:
$ docker logs -f --tail 20 dtnginx
Environment Variables
Many Docker images are configured through environment variables rather than configuration files. This makes containers flexible — the same image can behave differently depending on the variables you pass at runtime.
Setting Environment Variables
Use the -e flag to set environment variables when running a container:
$ docker container run -d --name dtpostgres \
-e POSTGRES_PASSWORD=docker \
-e POSTGRES_DB=testdb \
postgres
This starts PostgreSQL with:
- Root password set to
docker - A database called
testdbautomatically created
Important: Without POSTGRES_PASSWORD, the PostgreSQL container will refuse to start. It's a security requirement.
Verify Environment Variables
You can verify the variables inside a running container:
$ docker exec dtpostgres env
You should see:
POSTGRES_PASSWORD=docker POSTGRES_DB=testdb ...
Connect and Use the Database
Once the container is running, connect using the PostgreSQL client inside the container:
$ docker exec -it dtpostgres psql -U postgres -d testdb
You're now inside the PostgreSQL shell. Create a table and insert some data:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(50)
);
INSERT INTO users (name) VALUES ('Alice');
INSERT INTO users (name) VALUES ('Bob');
SELECT * FROM users;
You should see:
id | name ----+------- 1 | Alice 2 | Bob (2 rows)
Exit the PostgreSQL shell:
\q
This confirms that environment variables aren't just startup flags — they configure a working database that you can immediately connect to and use.
Common Environment Variables
Pro tip: Each image documents its supported environment variables on its Docker Hub page. Always check before running.
Cleanup
$ docker stop dtpostgres $ docker rm dtpostgres
Restart Policies
By default, a container stays stopped if it crashes or if the Docker host reboots. Restart policies tell Docker to automatically restart containers.
Available Restart Policies
Run Container with Restart Policy
$ docker run -d --restart unless-stopped --name dtnginx nginx
If you reboot your Docker host, this container will start automatically. If you manually run docker stop dtnginx, it will stay stopped until you explicitly start it again.
Update Restart Policy of Existing Container
$ docker update --restart unless-stopped dtnginx
Cleanup
$ docker stop dtnginx $ docker rm dtnginx
Cleaning Up Disk Space
After working with Docker for a while, your host will have accumulated:
- Stopped containers
- Unused images
- Dangling build layers
- Orphaned volumes
Docker provides prune commands to reclaim this space.
Check Disk Usage
See how much disk space Docker is using:
$ docker system df
You'll see something like:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 5 2 1.2GB 800MB (66%) Containers 3 1 50MB 40MB (80%) Local Volumes 2 1 200MB 100MB (50%) Build Cache 10 0 300MB 300MB (100%)
The RECLAIMABLE column shows how much space you can free up.
Remove Stopped Containers
$ docker container prune
Remove Unused Images
$ docker image prune -a
Clean Up Everything at Once
To clean up stopped containers, unused images, networks, and build cache:
$ docker system prune -a
Docker will ask for confirmation before proceeding. This is a safe way to reclaim disk space, but make sure you don't need any of the stopped containers or unused images before running it.
Exercise
This exercise demonstrates something important — and sets up exactly why you'll need Docker volumes in the next post.
Your Tasks
- Start a MySQL container named
dtmysqlwithMYSQL_ROOT_PASSWORD=dockerandMYSQL_DATABASE=testdb - Verify the environment variables are set inside the running container
- Connect to MySQL and create a
userstable, insert a row with the nameAlice, then query it back - Stop and delete the container
- Start a fresh
dtmysqlcontainer with the same environment variables and try to query theuserstable again - Clean up
Try it yourself before reading the solution below.
Solution
1. Start MySQL:
$ docker run -d --name dtmysql \
-e MYSQL_ROOT_PASSWORD=docker \
-e MYSQL_DATABASE=testdb \
mysql
2. Verify env vars:
$ docker exec dtmysql env | grep MYSQL
3. Connect and insert data:
$ docker exec -it dtmysql mysql -u root -pdocker testdb
Inside the MySQL shell:
CREATE TABLE users (name VARCHAR(50));
INSERT INTO users VALUES ('Alice');
SELECT * FROM users;
You should see:
+-------+ | name | +-------+ | Alice | +-------+
exit
4. Stop and delete the container:
$ docker stop dtmysql $ docker rm dtmysql
5. Start a fresh container and query:
$ docker run -d --name dtmysql \
-e MYSQL_ROOT_PASSWORD=docker \
-e MYSQL_DATABASE=testdb \
mysql
Wait a few seconds for MySQL to initialise, then:
$ docker exec -it dtmysql mysql -u root -pdocker testdb -e "SELECT * FROM users;"
ERROR 1146 (42S02): Table 'testdb.users' doesn't exist
Alice is gone. The container was deleted, and everything inside it went with it.
This is the fundamental problem with containers: they're ephemeral by design. For stateless apps like nginx, that's fine. For databases, it's a disaster.
Coming up next: Docker volumes — the solution to exactly this problem.
6. Clean up:
$ docker stop dtmysql && docker rm dtmysql
What's Next
Now you can manage your Docker environment effectively:
- Keep images organized — remove what you don't need
- Debug with logs — find issues quickly
- Configure with env vars — run databases and other configurable images
- Auto-restart containers — survive reboots
- Reclaim disk space — prune safely
Coming up: Docker persistent volumes — keep your data safe across container restarts and removals.
Want More?
This guide covers the basics from Chapter 4: Managing Docker Environment in my book, "Levelling Up with Docker" — 14 chapters of practical, hands-on Docker guides.
📚 Grab the book: "Levelling Up with Docker" on Amazon
Found this helpful?
- LinkedIn: Share with your network
- Twitter: Tweet about it
- Questions? Drop a comment below or reach out on LinkedIn
Comments
Post a Comment