01A Systematic Approach to Docker Debugging
When a Docker container isn't working, there's a temptation to start changing random things — different images, different ports, different environment variables — until something works. I've been there. It's frustrating and slow.
Over the years, I've developed a systematic debugging approach that solves most Docker Compose issues in under 10 minutes. The key insight is that 90% of problems fall into just four categories: container not starting, container starting but crashing, networking issues, and volume/permission problems. Each has a specific diagnostic path.
02Container Won't Start
If docker compose up shows an error or the container immediately exits, start here:
[terminal]
1# Check container status and exit codes2docker compose ps -a34# Read the logs (most answers are here)5docker compose logs servicename67# Check if the image exists and can be pulled8docker compose pull servicename910# Validate your compose file syntax11docker compose config1213# Check for port conflicts14docker compose ps --format "table {{.Name}} {{.Ports}}"15# Or check host ports directly16ss -tlnp | grep :808003Container Starts Then Crashes
A container that starts and immediately exits is usually a configuration problem. The exit code tells you what happened:
Exit code 0: The container completed successfully. If you expected it to run continuously, check that the entrypoint/command keeps a foreground process running.
Exit code 1: Generic application error. Read the logs carefully — the error message is almost always there.
Exit code 137: Killed by the system (OOM). The container ran out of memory. Increase the memory limit or reduce the application's memory usage.
Exit code 139: Segmentation fault. Usually a bug in the application or incompatible architecture (running an amd64 image on arm64).
[terminal]
1# Check exit code2docker inspect --format='{{.State.ExitCode}}' container_name34# Check if OOM killed5docker inspect --format='{{.State.OOMKilled}}' container_name67# Run the container interactively to debug8docker compose run --rm servicename sh910# Check resource usage of running containers11docker stats --no-streamdocker compose run --rm servicename sh is your best friend for debugging. It starts a new container with the same configuration but drops you into a shell where you can inspect files, test connectivity, and run commands manually.
04Networking Issues
"Connection refused" between containers is the most common networking problem. The diagnostic steps:
Verify containers are on the same network: docker network inspect networkname shows which containers are connected. Containers on different networks can't communicate.
Use the service name, not container_name: Docker Compose DNS resolves service names (the key in your YAML), not container_name values.
Check the target port is the container port, not the host port: When connecting between containers, use the internal port (e.g., 5432 for PostgreSQL), not the mapped host port.
[terminal]
1# List networks and their containers2docker network ls3docker network inspect myapp_default45# Test connectivity from inside a container6docker compose exec app ping db7docker compose exec app nslookup db89# Check if a port is listening inside the container10docker compose exec db ss -tlnp05Volume and Permission Problems
Permission denied errors with volumes are extremely common, especially with non-root containers. The issue is a mismatch between the user inside the container and the owner of the mounted files.
Diagnosis: Check what user the container runs as (docker compose exec servicename id) and what user owns the files on the host (ls -la on the volume path).
Common fixes:
- Set user: "1000:1000" in your compose file to match your host user
- Use named volumes instead of bind mounts (Docker manages permissions)
- Run an init container that sets correct permissions before the main container starts
- Set PUID and PGID environment variables (supported by linuxserver.io images)
Permission issues with volumes account for roughly a third of all Docker Compose problems I help people debug. Getting the user/group mapping right from the start saves hours of frustration. The troubleshooting sections in our recipes on docker.recipes address these permission patterns for each specific service.