Docker Logs & Debugging
Debugging Docker containers is an essential skill. This guide covers docker logs, docker events, docker inspect, and various troubleshooting techniques to diagnose and fix container issues.
The `docker logs` command retrieves logs from a container. It captures stdout (standard output) and stderr (standard error) from the container's main process. Logs are essential for debugging application errors, checking startup issues, and monitoring runtime behavior.
# View all logs
docker logs container_name
# Follow logs in real-time (like tail -f)
docker logs -f container_name
# Show last N lines
docker logs --tail 50 container_name
# Show logs since timestamp
docker logs --since 2024-01-01T10:00:00 container_name
# Show logs for last 10 minutes
docker logs --since 10m container_name
# Show logs with timestamps
docker logs -t container_name
# Show logs from a specific container ID
docker logs abc123def456
# Combine flags
docker logs -f --tail 100 --timestamps container_name
The `docker inspect` command returns detailed JSON information about containers, images, networks, or volumes. It's invaluable for debugging configuration issues, checking mount points, examining network settings, and understanding container state.
# Inspect container
docker inspect container_name
# Get specific fields using Go templating
docker inspect --format='{{.State.Status}}' container_name
docker inspect --format='{{.NetworkSettings.IPAddress}}' container_name
# Get multiple fields
docker inspect --format='{{.Name}} - {{.State.Status}}' container_name
# Get full state information
docker inspect --format='{{json .State}}' container_name | jq
# Get mount points
docker inspect --format='{{json .Mounts}}' container_name | jq
# Get environment variables
docker inspect --format='{{json .Config.Env}}' container_name | jq
# Get container exit code
docker inspect --format='{{.State.ExitCode}}' container_name
# Inspect image
docker inspect nginx:alpine
# Inspect network
docker inspect bridge
The `docker events` command streams real-time events from the Docker daemon. It shows container lifecycle events (start, stop, kill, die, pause, unpause), image events (pull, push, delete), and network events. This is useful for monitoring and debugging cluster behavior.
# Stream all events
docker events
# Filter by event type
docker events --filter event=start
docker events --filter event=stop
docker events --filter event=die
# Filter by container
docker events --filter container=container_name
# Filter by image
docker events --filter image=nginx
# Filter by time
docker events --since 10m
docker events --since 2024-01-01 --until 2024-01-02
# Filter by type
docker events --filter type=container
docker events --filter type=image
docker events --filter type=network
# Combine filters
docker events --filter event=die --filter container=web
The `docker diff` command shows changes to the container's filesystem since it started. It displays added (A), changed (C), or deleted (D) files. This is useful for understanding what files your container modifies and for debugging permission issues.
# Show filesystem changes
docker diff container_name
# Output format:
# C /etc/nginx/nginx.conf (changed)
# A /var/log/nginx/access.log (added)
# D /tmp/tempfile (deleted)
# Find which files were written
docker diff container_name | grep -E "^A"
# Check for configuration changes
docker diff container_name | grep -E "^C"
The `docker top` command displays running processes inside a container. It's similar to `top` on Linux and helps identify which processes are consuming CPU and memory.
# Show processes in container
docker top container_name
# Show with custom ps options
docker top container_name aux
# Check CPU usage of container processes
docker top container_name -o pid,pcpu,pmem,comm
# Monitor process list
watch -n 1 "docker top container_name"
The `docker stats` command shows real-time resource usage statistics for containers, including CPU, memory, network I/O, and block I/O. It's essential for performance debugging and capacity planning.
# Show stats for all running containers
docker stats
# Show stats for specific containers
docker stats container1 container2
# Show stats without streaming (one shot)
docker stats --no-stream
# Show stats with custom format
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
# Show all containers including stopped
docker stats --all
When a container fails to start or exits immediately, use these debugging steps:
# Step 1: Check container status and exit code
docker ps -a
docker inspect container_name --format='{{.State}}'
# Step 2: View logs (even for stopped containers)
docker logs container_name
# Step 3: Check container exit code
docker inspect container_name --format='{{.State.ExitCode}}'
# Step 4: Run an interactive shell to investigate
docker run -it --rm image_name sh
# Step 5: Override entrypoint for debugging
docker run -it --rm --entrypoint /bin/sh image_name
# Step 6: Check resource limits
docker inspect container_name --format='{{.HostConfig.Memory}}'
docker inspect container_name --format='{{.HostConfig.NanoCpus}}'
# Step 7: Check volume mounts
docker inspect container_name --format='{{json .Mounts}}' | jq
Docker supports multiple logging drivers to send container logs to different destinations. The default is `json-file` (local disk). For production, consider using `fluentd`, `splunk`, `awslogs`, or `gelf`.
# Configure logging driver for a container
docker run --log-driver=json-file --log-opt max-size=10m --log-opt max-file=3 nginx
# Use syslog driver
docker run --log-driver=syslog --log-opt syslog-address=udp://localhost:514 nginx
# Use fluentd driver
docker run --log-driver=fluentd --log-opt fluentd-address=localhost:24224 nginx
# Set default logging in daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
# Check container's logging driver
docker inspect container_name --format='{{.HostConfig.LogConfig}}'
# Scenario 1: Container exits immediately
docker logs container_name
# Look for error messages
# Scenario 2: Container runs but no network access
docker exec container_name curl localhost:8080
docker exec container_name nslookup google.com
# Scenario 3: Permission denied errors
docker exec container_name ls -la /data
docker inspect container_name --format='{{json .Config.User}}'
# Scenario 4: Container is slow
docker stats container_name
docker top container_name
# Scenario 5: Disk space full
docker system df
docker system prune -a
# Scenario 6: Port already in use
docker ps --filter "publish=8080"
lsof -i :8080 # on Linux/macOS
The `docker exec` command allows you to run commands inside a running container. This is the most powerful debugging tool for inspecting the container's filesystem, checking processes, and testing network connectivity.
# Get interactive shell
docker exec -it container_name bash
docker exec -it container_name sh
# Run a single command
docker exec container_name ls -la /app
docker exec container_name cat /etc/nginx/nginx.conf
# Check environment variables
docker exec container_name env
# Check network connectivity
docker exec container_name curl http://google.com
docker exec container_name ping database
# Check DNS resolution
docker exec container_name nslookup database
docker exec container_name cat /etc/resolv.conf
# Check open ports
docker exec container_name netstat -tulpn
docker exec container_name ss -tulpn
- Use structured logging - Log in JSON format for easier parsing.
- Set log rotation limits - Prevent disk space exhaustion with `max-size` and `max-file`.
- Use container names - Easy to reference in commands.
- Label your containers - Add labels like `project`, `environment` for filtering.
- Enable debug mode - Set `"debug": true` in daemon.json for verbose daemon logs.
- Use docker system events - Monitor cluster-wide events for anomalies.
- Keep images minimal - Smaller images have fewer moving parts and are easier to debug.
- Implement health checks - Let Docker detect unhealthy containers.
Mastering Docker logs and debugging commands will save you hours of troubleshooting. Practice these commands to become proficient in container debugging.