Container Debugging: Finding and Fixing Problems
Things break. Applications crash. Containers fail. That's reality. Knowing how to debug makes the difference between hours of frustration and minutes of solution.
🎯 The Big Picture​
Think of container debugging like being a detective. You have clues (logs, status, events). You investigate (inspect, exec, test). You find the problem. You fix it.
Debugging is systematic. Methodical. It works.
The Debugging Mindset​
Rule #1: Don't panic.
Problems happen. They always do. Panicking doesn't help. A systematic approach does.
Rule #2: Gather evidence first.
Don't guess. Don't assume. Look at the evidence. Logs. Status. Events. Then form a hypothesis.
Rule #3: Test your hypothesis.
Don't just guess. Test it. Verify it. Then fix it.
Step 1: Check Container Status​
First, see what state the container is in:
docker ps -a
Look for:
- Is it running? (
Up) - Is it stopped? (
Exited) - Is it restarting? (
Restarting) - Exit code? (0 = success, non-zero = error)
Example:
CONTAINER ID STATUS EXIT CODE
abc123def456 Up 2 hours 0
def456ghi789 Exited (1) 5 minutes ago 1
Exit code 1 means error. That's your first clue.
Step 2: Check Logs​
Logs tell you what happened:
# View all logs
docker logs web
# View last 100 lines
docker logs --tail 100 web
# Follow logs
docker logs -f web
# Previous container instance (if restarted)
docker logs --previous web
Look for:
- Error messages
- Stack traces
- Warning messages
- Application errors
Example log output:
ERROR: Database connection failed
at connect.js:25
Error: connect ECONNREFUSED 127.0.0.1:5432
That's your problem. Database connection failed.
Step 3: Inspect the Container​
Get detailed information:
docker inspect web
Look for:
- Configuration
- Environment variables
- Network settings
- Mounts
- Resource limits
Get specific information:
# Get exit code
docker inspect -f '{{.State.ExitCode}}' web
# Get error message
docker inspect -f '{{.State.Error}}' web
# Get environment variables
docker inspect -f '{{.Config.Env}}' web
# Get network settings
docker inspect -f '{{.NetworkSettings}}' web
Step 4: Execute Commands Inside Container​
Run commands to investigate:
# Get a shell
docker exec -it web /bin/bash
# Check processes
docker exec web ps aux
# Check files
docker exec web ls -la /app
# Check network
docker exec web netstat -tulpn
# Check environment variables
docker exec web env
# Test connectivity
docker exec web ping db.example.com
Think of it as: Going inside the container. Looking around. Testing things.
Common Problems and Solutions​
Problem 1: Container Exits Immediately​
Symptoms:
- Container starts
- Immediately exits
- Exit code non-zero
Debugging:
# Check logs
docker logs web
# Check exit code
docker inspect -f '{{.State.ExitCode}}' web
# Run interactively to see errors
docker run -it my-app /bin/bash
# Then try running the command manually
Common causes:
- Application crashes on startup
- Missing configuration
- Wrong command
- Port already in use
Solutions:
- Fix application code
- Add missing configuration
- Fix command in Dockerfile
- Change port mapping
Problem 2: Application Not Accessible​
Symptoms:
- Container is running
- Can't access application
- Connection refused
Debugging:
# Check if container is running
docker ps
# Check port mapping
docker port web
# Check if application is listening
docker exec web netstat -tulpn
# Test from inside container
docker exec web curl localhost:3000
Common causes:
- Wrong port mapping
- Application not listening on expected port
- Firewall blocking
- Application binding to wrong interface
Solutions:
- Fix port mapping:
-p 8080:3000 - Check application listens on
0.0.0.0, not127.0.0.1 - Check firewall rules
- Verify application configuration
Problem 3: Container Keeps Restarting​
Symptoms:
- Container status: Restarting
- Keeps crashing and restarting
- High restart count
Debugging:
# Check logs
docker logs web
# Check previous instance logs
docker logs --previous web
# Check restart policy
docker inspect -f '{{.HostConfig.RestartPolicy}}' web
# Temporarily disable restart to see error
docker update --restart=no web
docker start web
# Now it will exit and stay exited, showing the error
Common causes:
- Application crashes on startup
- Missing dependencies
- Configuration errors
- Resource limits too low
Solutions:
- Fix application code
- Install missing dependencies
- Fix configuration
- Increase resource limits
Problem 4: Can't Connect to Database​
Symptoms:
- Application can't connect to database
- Connection refused errors
- Timeout errors
Debugging:
# Check if database container is running
docker ps | grep postgres
# Test connectivity from app container
docker exec web ping postgres-container
# Test database port
docker exec web nc -zv postgres-container 5432
# Check environment variables
docker exec web env | grep DB
Common causes:
- Database container not running
- Wrong hostname (use container name, not localhost)
- Wrong port
- Network not connected
Solutions:
- Start database container
- Use container name as hostname:
postgres-container - Verify port:
5432 - Connect containers to same network
Problem 5: Out of Memory​
Symptoms:
- Container killed
- Exit code 137 (OOM killed)
- High memory usage
Debugging:
# Check memory usage
docker stats web
# Check memory limits
docker inspect -f '{{.HostConfig.Memory}}' web
# Check system memory
free -h
Common causes:
- Memory limit too low
- Memory leak in application
- Too many processes
Solutions:
- Increase memory limit:
--memory=512m - Fix memory leak
- Optimize application
- Reduce number of processes
The Detective Analogy​
Think of debugging like being a detective:
Step 1 (Check status): "What's the crime scene?" (container status)
Step 2 (Check logs): "What do the witnesses say?" (logs)
Step 3 (Inspect): "What evidence is there?" (inspect container)
Step 4 (Execute): "Let me investigate" (exec commands)
Step 5 (Fix): "I found the culprit" (fix the problem)
Once you see it this way, debugging becomes systematic.
Real-World Example: Debugging a Production Issue​
Problem: Application is slow. Users complaining.
1. Check container status:
docker ps
# Container is running, but slow
2. Check logs:
docker logs --tail 100 web
# See: "Database query taking 5 seconds"
3. Check resource usage:
docker stats web
# CPU: 100%, Memory: 512MB/512MB
4. Execute command to check database:
docker exec web psql -h db -U user -d mydb -c "SELECT * FROM slow_table"
# Query takes 10 seconds
5. Found the problem:
- Slow database query
- No index on table
- CPU at 100%
6. Fix:
- Add database index
- Optimize query
- Increase CPU limit
Problem solved. Systematic debugging worked.
Debugging Tools​
docker exec​
Run commands inside container:
docker exec -it web /bin/bash
docker logs​
View application logs:
docker logs -f web
docker stats​
Monitor resource usage:
docker stats web
docker inspect​
Get detailed information:
docker inspect web
docker top​
See running processes:
docker top web
My Take: Debugging Workflow​
Here's my systematic approach:
1. Check status - Is it running? What's the exit code?
2. Check logs - What errors do I see?
3. Inspect container - What's the configuration?
4. Execute commands - Test things inside container
5. Form hypothesis - Based on evidence
6. Test hypothesis - Verify it
7. Fix the problem - Apply solution
8. Verify fix - Confirm it works
This process works. Every time.
Memory Tip: The Detective Analogy​
Container debugging = Detective work
Check status: Examine crime scene Check logs: Interview witnesses Inspect: Gather evidence Execute: Investigate Fix: Solve the case
Once you see it this way, debugging becomes systematic.
Common Mistakes​
- Not checking logs first: Missing obvious errors
- Guessing instead of investigating: Wastes time
- Not using exec: Can't test inside container
- Ignoring exit codes: Missing important clues
- Not being systematic: Random debugging doesn't work
Hands-On Exercise: Debug a Problem​
1. Create a broken container:
docker run -d --name broken nginx
# Then stop it
docker stop broken
2. Debug why it stopped:
# Check status
docker ps -a | grep broken
# Check logs
docker logs broken
# Inspect
docker inspect broken
3. Fix it:
# Restart it
docker start broken
# Verify it's running
docker ps | grep broken
Key Takeaways​
- Debugging is systematic - Follow a process
- Check status first - Know the state
- Check logs - See what happened
- Inspect container - Get details
- Execute commands - Test inside container
- Form hypothesis - Based on evidence
- Test and fix - Verify solution
What's Next?​
Congratulations! You've completed the Containers module. Now let's learn about Docker networking. Next: Docker Networks.
Remember: Debugging is systematic. Don't panic. Gather evidence. Form hypothesis. Test it. Fix it. This process works.