Skip to main content

Docker Debugging

Introduction​

Docker has revolutionized how we build, ship, and run applications by providing a consistent environment across different stages of development. However, when things go wrong in containerized applications, debugging can be challenging due to the isolated nature of containers. This guide will walk you through effective strategies and tools for debugging Docker containers, helping you quickly identify and resolve issues to maintain optimal performance.

Understanding Docker Container Lifecycle​

Before diving into debugging techniques, it's important to understand how Docker containers operate:

Debugging can occur at various stages, but most commonly when a container is running or when it unexpectedly stops.

Essential Docker Debugging Commands​

Inspecting Container Logs​

The first step in debugging any Docker container is examining its logs:

bash
# Basic log viewing
docker logs container_name_or_id

# Follow logs in real-time
docker logs -f container_name_or_id

# Show timestamps
docker logs --timestamps container_name_or_id

# Show only the last 100 lines
docker logs --tail 100 container_name_or_id

Example output:

2023-05-15T14:32:18.215Z INFO  Server started on port 3000
2023-05-15T14:32:45.123Z ERROR Database connection failed: timeout
2023-05-15T14:32:50.876Z INFO Retrying database connection...
2023-05-15T14:33:01.345Z INFO Database connected successfully

Inspecting Container Details​

To get detailed information about a container:

bash
docker inspect container_name_or_id

This command returns a JSON object with comprehensive information about the container, including:

  • Network settings
  • Mount points
  • Environment variables
  • Resource constraints
  • Current state

For a more focused approach, use the format option to extract specific information:

bash
# Get IP address
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container_name_or_id

# Get environment variables
docker inspect --format='{{.Config.Env}}' container_name_or_id

Interactive Debugging with Shell Access​

Sometimes you need to explore from inside the container:

bash
# Access a running container with bash (if available)
docker exec -it container_name_or_id bash

# If bash is not available, try sh
docker exec -it container_name_or_id sh

Once inside, you can:

  • Check running processes with ps aux
  • Examine file contents
  • Check network connectivity
  • Verify environment variables with env

Advanced Debugging Techniques​

Debugging Container Startup Issues​

If your container fails to start, these approaches can help:

  1. Start with interactive mode:
bash
docker run -it --entrypoint sh your_image

This bypasses the default entry point and gives you a shell to investigate.

  1. Check for dependency issues:
bash
# Create a Dockerfile for debugging
FROM your_problematic_image
CMD ["sleep", "3600"]

Build and run this image, then exec into it to investigate without it immediately exiting.

Monitoring Resource Usage​

Performance issues often stem from resource constraints:

bash
# View real-time container stats
docker stats container_name_or_id

# Get more detailed process information
docker top container_name_or_id

Example output from docker stats:

CONTAINER ID   NAME         CPU %     MEM USAGE / LIMIT     MEM %     NET I/O          BLOCK I/O        PIDS
c8f53ba47acc web-server 0.15% 45.57MiB / 7.772GiB 0.57% 648B / 648B 0B / 0B 4

Debugging Network Issues​

Container network problems are common debugging scenarios:

bash
# Check what ports are exposed
docker port container_name_or_id

# Install network tools inside container
docker exec -it container_name_or_id sh -c "apt-get update && apt-get install -y iputils-ping net-tools"

# Test connectivity from inside
docker exec -it container_name_or_id ping google.com

Inspecting Docker Events​

The events stream can reveal important system-wide information:

bash
docker events

For targeted debugging, filter events by container:

bash
docker events --filter container=container_name_or_id

Debugging Multi-Container Applications​

Docker Compose applications require additional debugging strategies:

Viewing Logs from All Services​

bash
docker-compose logs

# Follow logs from specific service
docker-compose logs -f service_name

Selective Service Startup​

bash
# Start only specific services
docker-compose up database api

# Rebuild a specific service
docker-compose up --build service_name

Performance Debugging​

Identifying CPU and Memory Issues​

bash
# Create a process list showing resource usage
docker exec container_name_or_id ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu

# Check memory allocation details
docker exec container_name_or_id cat /proc/meminfo

Identifying I/O Bottlenecks​

For applications experiencing slowdowns:

bash
# Install iostat (if not available)
docker exec -it container_name_or_id sh -c "apt-get update && apt-get install -y sysstat"

# Monitor I/O activity
docker exec container_name_or_id iostat -x 1 5

Practical Debugging Walkthrough​

Let's walk through a common debugging scenario:

Scenario: Node.js Application with High Memory Usage​

  1. Identify the issue:
bash
docker stats app_container

You notice memory usage climbing steadily.

  1. Check application logs:
bash
docker logs app_container

No obvious errors, but response times are increasing.

  1. Inspect running processes:
bash
docker exec app_container ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%mem

Output shows Node.js process consuming large amounts of memory.

  1. Generate heap dump (Node.js specific):
bash
docker exec app_container node --inspect=0.0.0.0:9229

Then connect with Chrome DevTools to examine memory usage.

  1. Fix and verify:

After fixing a memory leak in the code:

bash
# Rebuild and restart the container
docker-compose up -d --build app_service

# Verify the fix
docker stats app_container

Using Docker Debugging Tools​

Docker Desktop Extension​

If you're using Docker Desktop, the built-in dashboard provides:

  • Container logs
  • Shell access
  • Port information
  • Resource usage graphs

Debug with Visual Studio Code​

VS Code's Docker extension enables:

  • Attaching debuggers to containers
  • Setting breakpoints in containerized code
  • Viewing logs directly in the editor

Add this to your .vscode/launch.json for Node.js debugging:

json
{
"type": "node",
"request": "attach",
"name": "Docker: Attach to Node",
"port": 9229,
"address": "localhost",
"localRoot": "${workspaceFolder}",
"remoteRoot": "/app",
"protocol": "inspector"
}

Best Practices for Docker Debugging​

  1. Use proper logging:

    • Implement structured logging (JSON format)
    • Include contextual information (request IDs, timestamps)
    • Set appropriate log levels
  2. Build debugging-friendly images:

    • Include troubleshooting tools in development images
    • Consider multi-stage builds with debuggable development stages
  3. Implement health checks:

    dockerfile
    HEALTHCHECK --interval=5s --timeout=3s CMD curl -f http://localhost/ || exit 1
  4. Set resource limits:

    bash
    docker run --memory=512m --cpus=0.5 your_image

    This makes resource issues more apparent before production.

Summary​

Debugging Docker containers requires understanding both container-specific concepts and traditional debugging techniques. By mastering the tools and approaches covered in this guide, you'll be able to:

  • Quickly identify the source of problems in containerized applications
  • Resolve issues before they impact production environments
  • Improve the overall performance and reliability of your Docker deployments

Remember that effective debugging is a proactive process. Implementing proper monitoring, logging, and health checks can prevent many issues before they require intensive debugging.

Additional Resources​

Exercises​

  1. Debug a container that starts and immediately exits. Identify the cause and fix it.
  2. Set up health checks for a web application container and observe how Docker handles unhealthy containers.
  3. Create a multi-container application with Docker Compose and practice debugging communication issues between services.
  4. Implement a monitoring solution that alerts you when a container's memory usage exceeds 80%.


If you spot any mistakes on this website, please let me know at feedback@compilenrun.com. I’d greatly appreciate your feedback! :)