DEV Community

Cover image for Day 14: Docker Debugging
Jonas Scholz
Jonas Scholz Subscriber

Posted on • Originally published at adventofdocker.com

Day 14: Docker Debugging

This post is a crosspost from adventofdocker.com

Welcome to Day 14 of Advent of Docker! Today, we'll explore essential Docker debugging tools that will help you troubleshoot container issues. We'll use our Go HTTP server from previous days as an example to demonstrate these tools.

Docker ps - Container Status

The docker ps command is your first stop for debugging. It shows running containers and their basic information:

$ docker ps
CONTAINER ID   IMAGE            COMMAND   CREATED          STATUS          PORTS                    NAMES
abc123def456   hello-world-go   "./main"  20 minutes ago   Up 20 minutes   0.0.0.0:8080->8080/tcp   myapp
Enter fullscreen mode Exit fullscreen mode

Some useful flags:

  • -a: Show all containers (including stopped ones)
  • -q: Only display container IDs (useful for scripting)
  • -f status=exited: Filter containers by status

Docker Logs - Container Output

When your container isn't behaving as expected, checking its logs is crucial:

$ docker logs myapp
Listening on port 8080
Enter fullscreen mode Exit fullscreen mode

Useful flags:

  • -f: Follow log output (like tail -f)
  • --tail 100: Show last 100 lines
  • --since 5m: Show logs from last 5 minutes

For our Go server, we can watch incoming requests in real-time:

$ docker logs -f myapp
Listening on port 8080
New visit recorded at 2024-12-14T10:00:00Z
New visit recorded at 2024-12-14T10:01:00Z
Enter fullscreen mode Exit fullscreen mode

Docker Inspect - Deep Dive

docker inspect provides detailed information about a container:

$ docker inspect myapp
[
    {
        "Id": "f915b41c43f7cadb2be97e30b6d7eac9ec0f04beed3ffd1d47b62d7c4f6d649a",
        "Created": "2024-12-14T18:07:45.903730046Z",
        "Path": "./main",
        "Args": [],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 1564,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2024-12-14T18:07:46.19197188Z",
            "FinishedAt": "0001-01-01T00:00:00Z"
        },
        "Image": "sha256:6209fff2e82261192905db51004792b13e688c44729e457299daa5230b2f8c31",
        "ResolvConfPath": "/var/lib/docker/containers/f915b41c43f7cadb2be97e30b6d7eac9ec0f04beed3ffd1d47b62d7c4f6d649a/resolv.conf",
        "HostnamePath": "/var/lib/docker/containers/f915b41c43f7cadb2be97e30b6d7eac9ec0f04beed3ffd1d47b62d7c4f6d649a/hostname",
        "HostsPath": "/var/lib/docker/containers/f915b41c43f7cadb2be97e30b6d7eac9ec0f04beed3ffd1d47b62d7c4f6d649a/hosts",
        "LogPath": "/var/lib/docker/containers/f915b41c43f7cadb2be97e30b6d7eac9ec0f04beed3ffd1d47b62d7c4f6d649a/f915b41c43f7cadb2be97e30b6d7eac9ec0f04beed3ffd1d47b62d7c4f6d649a-json.log",
        "Name": "/relaxed_mayer",
        "RestartCount": 0,
        "Driver": "overlay2",
        "Platform": "linux",
        "MountLabel": "",
        "ProcessLabel": "",
        "AppArmorProfile": "",
        "ExecIDs": null,
        "HostConfig": {
            "Binds": null,
            "ContainerIDFile": "",
            "LogConfig": {
                "Type": "json-file",
                "Config": {}
            },
            "NetworkMode": "default",
            "PortBindings": {},
            "RestartPolicy": {
                "Name": "no",
                "MaximumRetryCount": 0
            },
            "AutoRemove": false,
            "VolumeDriver": "",
            "VolumesFrom": null,
            "ConsoleSize": [
                22,
                97
            ],
            "CapAdd": null,
            "CapDrop": null,
            "CgroupnsMode": "private",
            "Dns": [],
            "DnsOptions": [],
            "DnsSearch": [],
            "ExtraHosts": null,
            "GroupAdd": null,
            "IpcMode": "private",
            "Cgroup": "",
            "Links": null,
            "OomScoreAdj": 0,
            "PidMode": "",
            "Privileged": false,
            "PublishAllPorts": false,
            "ReadonlyRootfs": false,
            "SecurityOpt": null,
            "UTSMode": "",
            "UsernsMode": "",
            "ShmSize": 67108864,
            "Runtime": "runc",
            "Isolation": "",
            "CpuShares": 0,
            "Memory": 0,
            "NanoCpus": 0,
            "CgroupParent": "",
            "BlkioWeight": 0,
            "BlkioWeightDevice": [],
            "BlkioDeviceReadBps": [],
            "BlkioDeviceWriteBps": [],
            "BlkioDeviceReadIOps": [],
            "BlkioDeviceWriteIOps": [],
            "CpuPeriod": 0,
            "CpuQuota": 0,
            "CpuRealtimePeriod": 0,
            "CpuRealtimeRuntime": 0,
            "CpusetCpus": "",
            "CpusetMems": "",
            "Devices": [],
            "DeviceCgroupRules": null,
            "DeviceRequests": null,
            "MemoryReservation": 0,
            "MemorySwap": 0,
            "MemorySwappiness": null,
            "OomKillDisable": null,
            "PidsLimit": null,
            "Ulimits": [],
            "CpuCount": 0,
            "CpuPercent": 0,
            "IOMaximumIOps": 0,
            "IOMaximumBandwidth": 0,
            "MaskedPaths": [
                "/proc/asound",
                "/proc/acpi",
                "/proc/kcore",
                "/proc/keys",
                "/proc/latency_stats",
                "/proc/timer_list",
                "/proc/timer_stats",
                "/proc/sched_debug",
                "/proc/scsi",
                "/sys/firmware"
            ],
            "ReadonlyPaths": [
                "/proc/bus",
                "/proc/fs",
                "/proc/irq",
                "/proc/sys",
                "/proc/sysrq-trigger"
            ]
        },
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/c8b77f1281e2a923debc57ba8ee8a3e61b2eab01c3746707847c56aa504f4549-init/diff:/var/lib/docker/overlay2/plebc717q0dae0vpogboi82uj/diff:/var/lib/docker/overlay2/0vwf87fyclw8wmvgnjngza8ul/diff:/var/lib/docker/overlay2/02a45bf063940c5ed96d43abf699c49e729c0197a8922613a7b1e85454397fd9/diff:/var/lib/docker/overlay2/1f7886b749ec4d3a50ff5a88e082404c777b05cb8af10469eb8d32f283eaa2fd/diff:/var/lib/docker/overlay2/813de0000b1ac87c0ebbc260ab5db42a860e771927966b98a08a6eb942a7478e/diff:/var/lib/docker/overlay2/bb1ea71019466bdd2da7dccf480c104121842b694d6022f96367214f6f623557/diff:/var/lib/docker/overlay2/aa54f03b2bcd787f34371e483e4b14024920790f54d8bdf2dda70c828022d3d0/diff:/var/lib/docker/overlay2/3caedf6970d13d30fd04cb8553c19a1dc1012d1474474f9e38dd992eb5a08e08/diff:/var/lib/docker/overlay2/c2ff2ee7edd0d1efda1493a24508b0bb8132464f0ea3a600572bb823a6f43708/diff",
                "MergedDir": "/var/lib/docker/overlay2/c8b77f1281e2a923debc57ba8ee8a3e61b2eab01c3746707847c56aa504f4549/merged",
                "UpperDir": "/var/lib/docker/overlay2/c8b77f1281e2a923debc57ba8ee8a3e61b2eab01c3746707847c56aa504f4549/diff",
                "WorkDir": "/var/lib/docker/overlay2/c8b77f1281e2a923debc57ba8ee8a3e61b2eab01c3746707847c56aa504f4549/work"
            },
            "Name": "overlay2"
        },
        "Mounts": [],
        "Config": {
            "Hostname": "f915b41c43f7",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": true,
            "AttachStderr": true,
            "ExposedPorts": {
                "8080/tcp": {}
            },
            "Tty": false,
            "OpenStdin": false,
            "StdinOnce": false,
            "Env": [
                "PATH=/go/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "GOLANG_VERSION=1.23.4",
                "GOTOOLCHAIN=local",
                "GOPATH=/go"
            ],
            "Cmd": [
                "./main"
            ],
            "Image": "hello-world-go",
            "Volumes": null,
            "WorkingDir": "/go",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": {}
        },
        "NetworkSettings": {
            "Bridge": "",
            "SandboxID": "f790e6709650efe5af98f6caf40b365b541b8005f4da2a4a636297c26e2a13d4",
            "HairpinMode": false,
            "LinkLocalIPv6Address": "",
            "LinkLocalIPv6PrefixLen": 0,
            "Ports": {
                "8080/tcp": null
            },
            "SandboxKey": "/var/run/docker/netns/f790e6709650",
            "SecondaryIPAddresses": null,
            "SecondaryIPv6Addresses": null,
            "EndpointID": "01cb1873a9821ed1369e79274537ba2234676130a295cbfc5def7a8e0059101a",
            "Gateway": "172.17.0.1",
            "GlobalIPv6Address": "",
            "GlobalIPv6PrefixLen": 0,
            "IPAddress": "172.17.0.2",
            "IPPrefixLen": 16,
            "IPv6Gateway": "",
            "MacAddress": "02:42:ac:11:00:02",
            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "ee1f25dbee96b37d4acbdbaee780065e892468e515104b6e7c590be39365c3e5",
                    "EndpointID": "01cb1873a9821ed1369e79274537ba2234676130a295cbfc5def7a8e0059101a",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
                }
            }
        }
    }
]
Enter fullscreen mode Exit fullscreen mode

Now this might be a bit overwhelming, but it's a good starting point to understand what's going on with your container! Once you know what exactly you're looking for, you can use Go templates to extract specific information:

# Get IP address
$ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' myapp

# Get environment variables
$ docker inspect -f '{{range .Config.Env}}{{println .}}{{end}}' myapp
Enter fullscreen mode Exit fullscreen mode

Container Dumps - Advanced Debugging

For more serious issues, you can create a container dump:

$ docker container export myapp > container.tar
Enter fullscreen mode Exit fullscreen mode

This creates a tarball containing the container's entire filesystem, which you can then examine:

$ tar -tvf container.tar | grep main
-rwxr-xr-x 0/0      1839488 2024-12-14 10:00 ./main
Enter fullscreen mode Exit fullscreen mode

Resource Usage and Cleanup

Sometimes your apps might run out of disk space. You can check how much space Docker is using with docker system df:

$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          5         3         1.92GB    1.2GB
Containers      3         1         125MB     125MB
Local Volumes   2         2         256MB     0B
Enter fullscreen mode Exit fullscreen mode

Clean Up Resources

When debugging leads to many unused containers and images, clean up with:

$ docker system prune
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all dangling images
  - all dangling build cache

Are you sure you want to continue? [y/N]
Enter fullscreen mode Exit fullscreen mode

Add -a to remove all unused images, not just dangling ones:

$ docker system prune -a
Enter fullscreen mode Exit fullscreen mode

Real-World Example

Let's debug a common issue with our Go server. Imagine it's not responding on port 8080:

  1. Check if container is running:
$ docker ps
CONTAINER ID   IMAGE            STATUS          PORTS
# No container shown - it's not running
Enter fullscreen mode Exit fullscreen mode
  1. Check stopped containers:
$ docker ps -a
CONTAINER ID   IMAGE            STATUS                     PORTS
def456abc789   hello-world-go   Exited (1) 2 minutes ago
Enter fullscreen mode Exit fullscreen mode
  1. Check logs for error:
$ docker logs def456abc789
bind: address already in use
Enter fullscreen mode Exit fullscreen mode
  1. Inspect container for port bindings:
$ docker inspect def456abc789 -f '{{json .HostConfig.PortBindings}}'
{"8080/tcp":[{"HostIp":"","HostPort":"8080"}]}
Enter fullscreen mode Exit fullscreen mode

Now we know the issue: port 8080 is already in use on the host. We can fix this by using a different port:

$ docker run -p 8081:8080 hello-world-go
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Always check logs first (docker logs)
  2. Use meaningful container names for easier debugging
  3. Regularly clean up unused resources
  4. Monitor resource usage to prevent disk space issues
  5. Keep your Docker daemon and tools updated

Next Steps

Practice these debugging techniques with your own containers. Try to:

  • Simulate different failure scenarios
  • Extract specific information using docker inspect
  • Monitor resource usage over time

Tomorrow, we'll have our second quiz! Make sure you are comfortable with:

  • Debugging Techniques
  • Multi-Stage Builds
  • Docker Compose
  • Docker Networking
  • Environment Variables & Configuration

Until then, happy debugging! 🐳

Jonas

Top comments (0)