How to Debug Docker Containers Like a PRO: Essential CLI Tools and Techniques
Master Docker container debugging with proven CLI commands and techniques used by experienced DevOps engineers and homelab operators.
Master Docker container debugging with proven CLI commands and techniques used by experienced DevOps engineers and homelab operators.
Docker containers are the backbone of modern self-hosting and homelab infrastructure. They package applications cleanly, but when something goes wrong, debugging a container can feel like working in the dark. Whether you are dealing with a crashed service, a misconfigured environment variable, or a container that refuses to start, knowing the right debugging commands makes all the difference.
This guide covers the essential Docker CLI tools and techniques that experienced operators use to debug containers in production and homelab environments. All commands referenced here are drawn from official Docker documentation and widely accepted best practices.
Before diving into debugging, ensure you have the following in place:
docker command-line interfaceVerifying that Docker is responsive is your first sanity check. Run:
docker versionIf this returns version information for both the client and server, your Docker daemon is running and reachable.
A structured debugging workflow saves time and reduces guesswork. Follow these steps in order:
Start by identifying the state of all containers on your host. A container may have exited without you noticing.
docker container ls --allThis command shows every container on the system, including stopped and exited ones. The STATUS column tells you whether a container is running, how long it has been up, or why it exited. Pay close attention to exit codes and time stamps.
The first place to look when a container behaves unexpectedly is its logs. Docker captures standard output and standard error from the container's main process.
docker logs container-nameTo stream logs in real time, add the --follow flag:
docker logs -f --tail 100 container-nameThis command shows the last 100 log lines and continues streaming new output. You can also filter logs by time:
docker logs --since 30m container-nameThis shows only logs generated in the last 30 minutes, which is useful when investigating recent failures.
Note: Thedocker logscommand batch-retrieves logs present at the time of execution. Use--followto keep the stream open for real-time monitoring.
Sometimes the issue is not in the application code but in the container's configuration. The docker inspect command provides detailed metadata about a container in JSON format.
docker inspect container-nameThis outputs a wealth of information including:
To extract a specific value, use the --format flag. For example, to check the exit code of a stopped container:
docker inspect --format '{{.State.ExitCode}}' container-nameCommon exit codes to watch for:
0 — Success1 — Application error125 — Docker daemon error126 — Command cannot be invoked127 — Command not found137 — Container killed (OOM or SIGKILL)139 — Segmentation fault143 — Graceful termination (SIGTERM)To check the health status of a container (if a health check is defined):
docker inspect --format='{{.State.Health.Status}}' container-nameWhen logs and configuration inspection are not enough, you need to go inside the container. The docker exec command runs a process inside an already running container.
docker exec -it container-name bashIf the container does not have bash installed, try sh instead:
docker exec -it container-name shOnce inside, you can inspect the filesystem, check running processes, test network connectivity, and verify environment variables. For environments with limited tools, you can often install debugging utilities temporarily using the container's package manager.
If the container is not running, you cannot use docker exec. In that case, you have two options:
docker run --rm -it --name debug-container IMAGE bashPerformance issues often masquerade as application bugs. Use docker stats to view real-time CPU, memory, network I/O, and block I/O for one or more containers.
docker stats container-nameTo see all running containers at once:
docker statsFor a single snapshot without continuous streaming:
docker stats --no-streamHigh memory usage or CPU spikes can indicate memory leaks, inefficient code, or insufficient resource limits.
If a container has been running for a while and you suspect files have been modified outside of the intended application behavior, use docker diff to compare the container's filesystem against the original image.
docker diff container-nameThis outputs a list of files that have been added (A), changed (C), or deleted (D) since the container was created.
To see the processes running inside a container from the host side:
docker top container-nameThis shows the processes, their PIDs, and the commands that started them, which helps identify runaway processes or unexpected child processes.
Docker Desktop includes a docker debug CLI plugin that provides a debug shell into any container or image, even if they do not contain a shell. According to the official Docker documentation, with docker debug you can:
Example usage:
docker debug container-nameThis command spawns a debug shell using a dedicated debug image that includes common troubleshooting tools. It is especially useful for distroless or minimal images that lack a shell entirely.
Note: As of the latest updates, docker debug is a closed-source CLI plugin available with Docker Desktop. It is not available for standalone Docker Engine installations without Docker Desktop.If you run containers using Docker Compose, you can adapt the same commands by referencing service names.
List all services in your Compose project:
docker compose psView logs for a specific service:
docker compose logs service-nameStream logs from all services:
docker compose logs -fInspect the Compose configuration that Docker is actually using:
docker compose configThis resolves all variables and shows the effective configuration, which is invaluable when environment variables are not being interpolated as expected.
Sometimes the issue is not inside the container but on the host. Check:
docker system df shows disk usage by images, containers, volumes, and build cachedocker events streams real-time events from the Docker daemondocker system prune with caution to clean up unused resourcesWhen a container exits immediately, run the image interactively in the foreground to see the error directly:
docker run -it IMAGEThis bypasses any restart policies and lets you see the startup error in real time.
If you need to examine configuration files or logs that are not streamed to stdout, use docker cp:
docker cp container-name:/path/to/file /host/destinationThis copies files from the container's filesystem to the host.
1. Run docker container ls --all and note the exit code
2. Check logs with docker logs container-name
3. Run the image interactively: docker run -it IMAGE
4. Verify environment variables with docker inspect container-name
1. Check port mappings with docker port container-name
2. Inspect network settings: docker inspect container-name | grep IPAddress
3. Verify the container is bound to the correct network: docker network ls
4. Test connectivity from inside the container using docker exec -it container-name curl localhost:PORT
1. Run docker stats container-name to confirm high usage
2. Check logs for error loops that may indicate a memory leak
3. Review the container's memory limits with docker inspect container-name
4. Consider adding memory limits in your docker run command or Compose file
--name so you do not have to reference random IDsalways, unless-stopped) for production containerscurl, ping, bash) in development imagesdocker system pruneDebugging Docker containers does not have to be a guessing game. By following a structured workflow — list containers, check logs, inspect configuration, exec into the container, monitor resources, and use specialized debug tools — you can quickly identify and resolve issues in your homelab or production environment.
Master these commands and you will debug Docker containers like a PRO, reducing downtime and keeping your self-hosted services running smoothly.
# Quick reference: Essential debug commands
docker container ls --all
docker logs -f --tail 100 container-name
docker inspect container-name
docker exec -it container-name bash
docker stats --no-stream
docker diff container-name
docker top container-name
docker system df