Tools: Docker Environment Management: Images, Logs, and Cleanup (2026 Guide)

Tools: Docker Environment Management: Images, Logs, and Cleanup (2026 Guide)

Docker Environment Management: Images, Logs, and Cleanup (2026 Guide)

Why This Matters

Prerequisites

Managing Images

List All Images

Remove an Image

Viewing Container Logs

View Logs

Follow Logs in Real Time

Show Last N Lines

Environment Variables

Setting Environment Variables

Verify Environment Variables

Connect and Use the Database

Common Environment Variables

Cleanup

Restart Policies

Available Restart Policies

Run Container with Restart Policy

Update Restart Policy of Existing Container

Cleanup

Cleaning Up Disk Space

Check Disk Usage

Remove Stopped Containers

Remove Unused Images

Clean Up Everything at Once

Exercise

Your Tasks

Solution

What's Next

Want More? Quick one-liner: Learn how to manage your Docker environment like a pro — list and remove images, view container logs, use environment variables, and reclaim disk space. 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: 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. You'll see something like: The SIZE 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. To remove an image you no longer need: 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. 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. You should see the nginx startup messages: 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. To watch logs as they're written (like tail -f): Press Ctrl+C to stop following. To see only the last 10 lines: Combine flags for real-time tailing: 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. Use the -e flag to set environment variables when running a container: This starts PostgreSQL with: Important: Without POSTGRES_PASSWORD, the PostgreSQL container will refuse to start. It's a security requirement. You can verify the variables inside a running container: Once the container is running, connect using the PostgreSQL client inside the container: You're now inside the PostgreSQL shell. Create a table and insert some data: Exit the PostgreSQL shell: This confirms that environment variables aren't just startup flags — they configure a working database that you can immediately connect to and use. Pro tip: Each image documents its supported environment variables on its Docker Hub page. Always check before running. By default, a container stays stopped if it crashes or if the Docker host reboots. Restart policies tell Docker to automatically restart containers. 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. After working with Docker for a while, your host will have accumulated: Docker provides prune commands to reclaim this space. See how much disk space Docker is using: You'll see something like: The RECLAIMABLE column shows how much space you can free up. To clean up stopped containers, unused images, networks, and build cache: 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. This exercise demonstrates something important — and sets up exactly why you'll need Docker volumes in the next post. Try it yourself before reading the solution below. 3. Connect and insert data: Inside the MySQL shell: 4. Stop and delete the container: 5. Start a fresh container and query: Wait a few seconds for MySQL to initialise, then: 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. Now you can manage your Docker environment effectively: Coming up: Docker persistent volumes — keep your data safe across container restarts and removals. 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 Published: 23 Mar 2026

Author: David Tio

Word Count: ~1,100 Templates let you quickly answer FAQs or store snippets for re-use. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse

Command

Copy

$ -weight: 500;">docker images $ -weight: 500;">docker images $ -weight: 500;">docker images 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 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 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 $ -weight: 500;">docker rmi hello-world:latest $ -weight: 500;">docker rmi hello-world:latest $ -weight: 500;">docker rmi hello-world:latest $ -weight: 500;">docker logs dtnginx $ -weight: 500;">docker logs dtnginx $ -weight: 500;">docker logs dtnginx /-weight: 500;">docker-entrypoint.sh: /-weight: 500;">docker-entrypoint.d/ is not empty, will attempt to perform configuration /-weight: 500;">docker-entrypoint.sh: Looking for shell scripts in /-weight: 500;">docker-entrypoint.d/ /-weight: 500;">docker-entrypoint.sh: Launching /-weight: 500;">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 /-weight: 500;">docker-entrypoint.sh: Sourcing /-weight: 500;">docker-entrypoint.d/15-local-resolvers.envsh /-weight: 500;">docker-entrypoint.sh: Launching /-weight: 500;">docker-entrypoint.d/20-envsubst-on-templates.sh /-weight: 500;">docker-entrypoint.sh: Launching /-weight: 500;">docker-entrypoint.d/30-tune-worker-processes.sh /-weight: 500;">docker-entrypoint.sh: Configuration complete; ready for -weight: 500;">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: -weight: 500;">start worker processes 2026/03/23 10:08:54 [notice] 1#1: -weight: 500;">start worker process 29 /-weight: 500;">docker-entrypoint.sh: /-weight: 500;">docker-entrypoint.d/ is not empty, will attempt to perform configuration /-weight: 500;">docker-entrypoint.sh: Looking for shell scripts in /-weight: 500;">docker-entrypoint.d/ /-weight: 500;">docker-entrypoint.sh: Launching /-weight: 500;">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 /-weight: 500;">docker-entrypoint.sh: Sourcing /-weight: 500;">docker-entrypoint.d/15-local-resolvers.envsh /-weight: 500;">docker-entrypoint.sh: Launching /-weight: 500;">docker-entrypoint.d/20-envsubst-on-templates.sh /-weight: 500;">docker-entrypoint.sh: Launching /-weight: 500;">docker-entrypoint.d/30-tune-worker-processes.sh /-weight: 500;">docker-entrypoint.sh: Configuration complete; ready for -weight: 500;">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: -weight: 500;">start worker processes 2026/03/23 10:08:54 [notice] 1#1: -weight: 500;">start worker process 29 /-weight: 500;">docker-entrypoint.sh: /-weight: 500;">docker-entrypoint.d/ is not empty, will attempt to perform configuration /-weight: 500;">docker-entrypoint.sh: Looking for shell scripts in /-weight: 500;">docker-entrypoint.d/ /-weight: 500;">docker-entrypoint.sh: Launching /-weight: 500;">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 /-weight: 500;">docker-entrypoint.sh: Sourcing /-weight: 500;">docker-entrypoint.d/15-local-resolvers.envsh /-weight: 500;">docker-entrypoint.sh: Launching /-weight: 500;">docker-entrypoint.d/20-envsubst-on-templates.sh /-weight: 500;">docker-entrypoint.sh: Launching /-weight: 500;">docker-entrypoint.d/30-tune-worker-processes.sh /-weight: 500;">docker-entrypoint.sh: Configuration complete; ready for -weight: 500;">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: -weight: 500;">start worker processes 2026/03/23 10:08:54 [notice] 1#1: -weight: 500;">start worker process 29 $ -weight: 500;">docker logs -f dtnginx $ -weight: 500;">docker logs -f dtnginx $ -weight: 500;">docker logs -f dtnginx $ -weight: 500;">docker logs --tail 10 dtnginx $ -weight: 500;">docker logs --tail 10 dtnginx $ -weight: 500;">docker logs --tail 10 dtnginx $ -weight: 500;">docker logs -f --tail 20 dtnginx $ -weight: 500;">docker logs -f --tail 20 dtnginx $ -weight: 500;">docker logs -f --tail 20 dtnginx $ -weight: 500;">docker container run -d --name dtpostgres \ -e POSTGRES_PASSWORD=-weight: 500;">docker \ -e POSTGRES_DB=testdb \ postgres $ -weight: 500;">docker container run -d --name dtpostgres \ -e POSTGRES_PASSWORD=-weight: 500;">docker \ -e POSTGRES_DB=testdb \ postgres $ -weight: 500;">docker container run -d --name dtpostgres \ -e POSTGRES_PASSWORD=-weight: 500;">docker \ -e POSTGRES_DB=testdb \ postgres $ -weight: 500;">docker exec dtpostgres env $ -weight: 500;">docker exec dtpostgres env $ -weight: 500;">docker exec dtpostgres env POSTGRES_PASSWORD=-weight: 500;">docker POSTGRES_DB=testdb ... POSTGRES_PASSWORD=-weight: 500;">docker POSTGRES_DB=testdb ... POSTGRES_PASSWORD=-weight: 500;">docker POSTGRES_DB=testdb ... $ -weight: 500;">docker exec -it dtpostgres psql -U postgres -d testdb $ -weight: 500;">docker exec -it dtpostgres psql -U postgres -d testdb $ -weight: 500;">docker exec -it dtpostgres psql -U postgres -d testdb 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; 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; 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; id | name ----+------- 1 | Alice 2 | Bob (2 rows) id | name ----+------- 1 | Alice 2 | Bob (2 rows) id | name ----+------- 1 | Alice 2 | Bob (2 rows) $ -weight: 500;">docker -weight: 500;">stop dtpostgres $ -weight: 500;">docker rm dtpostgres $ -weight: 500;">docker -weight: 500;">stop dtpostgres $ -weight: 500;">docker rm dtpostgres $ -weight: 500;">docker -weight: 500;">stop dtpostgres $ -weight: 500;">docker rm dtpostgres $ -weight: 500;">docker run -d ---weight: 500;">restart unless-stopped --name dtnginx nginx $ -weight: 500;">docker run -d ---weight: 500;">restart unless-stopped --name dtnginx nginx $ -weight: 500;">docker run -d ---weight: 500;">restart unless-stopped --name dtnginx nginx $ -weight: 500;">docker -weight: 500;">update ---weight: 500;">restart unless-stopped dtnginx $ -weight: 500;">docker -weight: 500;">update ---weight: 500;">restart unless-stopped dtnginx $ -weight: 500;">docker -weight: 500;">update ---weight: 500;">restart unless-stopped dtnginx $ -weight: 500;">docker -weight: 500;">stop dtnginx $ -weight: 500;">docker rm dtnginx $ -weight: 500;">docker -weight: 500;">stop dtnginx $ -weight: 500;">docker rm dtnginx $ -weight: 500;">docker -weight: 500;">stop dtnginx $ -weight: 500;">docker rm dtnginx $ -weight: 500;">docker system df $ -weight: 500;">docker system df $ -weight: 500;">docker system df 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%) 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%) 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%) $ -weight: 500;">docker container prune $ -weight: 500;">docker container prune $ -weight: 500;">docker container prune $ -weight: 500;">docker image prune -a $ -weight: 500;">docker image prune -a $ -weight: 500;">docker image prune -a $ -weight: 500;">docker system prune -a $ -weight: 500;">docker system prune -a $ -weight: 500;">docker system prune -a $ -weight: 500;">docker run -d --name dtmysql \ -e MYSQL_ROOT_PASSWORD=-weight: 500;">docker \ -e MYSQL_DATABASE=testdb \ mysql $ -weight: 500;">docker run -d --name dtmysql \ -e MYSQL_ROOT_PASSWORD=-weight: 500;">docker \ -e MYSQL_DATABASE=testdb \ mysql $ -weight: 500;">docker run -d --name dtmysql \ -e MYSQL_ROOT_PASSWORD=-weight: 500;">docker \ -e MYSQL_DATABASE=testdb \ mysql $ -weight: 500;">docker exec dtmysql env | grep MYSQL $ -weight: 500;">docker exec dtmysql env | grep MYSQL $ -weight: 500;">docker exec dtmysql env | grep MYSQL $ -weight: 500;">docker exec -it dtmysql mysql -u root -pdocker testdb $ -weight: 500;">docker exec -it dtmysql mysql -u root -pdocker testdb $ -weight: 500;">docker exec -it dtmysql mysql -u root -pdocker testdb CREATE TABLE users (name VARCHAR(50)); INSERT INTO users VALUES ('Alice'); SELECT * FROM users; CREATE TABLE users (name VARCHAR(50)); INSERT INTO users VALUES ('Alice'); SELECT * FROM users; CREATE TABLE users (name VARCHAR(50)); INSERT INTO users VALUES ('Alice'); SELECT * FROM users; +-------+ | name | +-------+ | Alice | +-------+ +-------+ | name | +-------+ | Alice | +-------+ +-------+ | name | +-------+ | Alice | +-------+ $ -weight: 500;">docker -weight: 500;">stop dtmysql $ -weight: 500;">docker rm dtmysql $ -weight: 500;">docker -weight: 500;">stop dtmysql $ -weight: 500;">docker rm dtmysql $ -weight: 500;">docker -weight: 500;">stop dtmysql $ -weight: 500;">docker rm dtmysql $ -weight: 500;">docker run -d --name dtmysql \ -e MYSQL_ROOT_PASSWORD=-weight: 500;">docker \ -e MYSQL_DATABASE=testdb \ mysql $ -weight: 500;">docker run -d --name dtmysql \ -e MYSQL_ROOT_PASSWORD=-weight: 500;">docker \ -e MYSQL_DATABASE=testdb \ mysql $ -weight: 500;">docker run -d --name dtmysql \ -e MYSQL_ROOT_PASSWORD=-weight: 500;">docker \ -e MYSQL_DATABASE=testdb \ mysql $ -weight: 500;">docker exec -it dtmysql mysql -u root -pdocker testdb -e "SELECT * FROM users;" $ -weight: 500;">docker exec -it dtmysql mysql -u root -pdocker testdb -e "SELECT * FROM users;" $ -weight: 500;">docker exec -it dtmysql mysql -u root -pdocker testdb -e "SELECT * FROM users;" ERROR 1146 (42S02): Table 'testdb.users' doesn't exist ERROR 1146 (42S02): Table 'testdb.users' doesn't exist ERROR 1146 (42S02): Table 'testdb.users' doesn't exist $ -weight: 500;">docker -weight: 500;">stop dtmysql && -weight: 500;">docker rm dtmysql $ -weight: 500;">docker -weight: 500;">stop dtmysql && -weight: 500;">docker rm dtmysql $ -weight: 500;">docker -weight: 500;">stop dtmysql && -weight: 500;">docker rm dtmysql - Listing and removing images - Viewing container logs - Using environment variables (critical for databases) - Setting -weight: 500;">restart policies - Cleaning up disk space safely - Docker installed (rootless mode recommended) - Basic Docker familiarity (run, -weight: 500;">stop, rm commands) - 5 minutes to work through the examples - Root password set to -weight: 500;">docker - A database called testdb automatically created - Stopped containers - Unused images - Dangling build layers - Orphaned volumes - Start a MySQL container named dtmysql with MYSQL_ROOT_PASSWORD=-weight: 500;">docker and MYSQL_DATABASE=testdb - Verify the environment variables are set inside the running container - Connect to MySQL and create a users table, insert a row with the name Alice, then query it back - Stop and delete the container - Start a fresh dtmysql container with the same environment variables and try to query the users table again - Keep images organized — -weight: 500;">remove what you don't need - Debug with logs — find issues quickly - Configure with env vars — run databases and other configurable images - Auto--weight: 500;">restart containers — survive reboots - Reclaim disk space — prune safely - LinkedIn: Share with your network - Twitter: Tweet about it - Questions? Drop a comment below or reach out on LinkedIn - Title: Docker Environment Management: Images, Logs, and Cleanup (2026 Guide) - Meta Description: Learn how to manage your Docker environment — list and -weight: 500;">remove images, view container logs, use environment variables, and reclaim disk space. Includes a hands-on MySQL exercise that shows exactly why volumes matter. - Target Keywords: -weight: 500;">docker images command, -weight: 500;">docker logs, -weight: 500;">docker environment variables, -weight: 500;">docker system prune, -weight: 500;">docker image prune, -weight: 500;">docker cleanup, -weight: 500;">docker env flag, beginner -weight: 500;">docker tutorial 2026