A practical guide to debugging Docker containers like a real DevOps engineer.

Imagine this situation.

You deploy your application using Docker. Everything looks perfect.

docker ps 

Output:

CONTAINER ID IMAGE STATUS a1b2c3d4 my-app:latest Up 10 minutes 

Your container is running. Docker reports no problems. You feel confident.

Then someone messages you:

"Hey, the application is down. Can you fix it?"

You check the container again.

Still running.

You restart it.

Still broken.

You rebuild the image.

Still broken.

Welcome to the real world of DevOps. 😅

A running container does not necessarily mean a healthy application.

Let's learn how to troubleshoot Docker like an engineer instead of randomly restarting containers.

🧠 1. Understand the Difference Between Running and Healthy

Docker can tell you whether a container's main process is running. It cannot automatically guarantee that your application is working correctly.

For example, your container might be running while:

  • The application cannot connect to its database.
  • The API is returning HTTP 500 errors.
  • The application is listening on the wrong port.
  • A required environment variable is missing.
  • The application is responding too slowly.
  • A dependency has crashed.

Think of it like this:

Docker container: RUNNING ✅ Application: BROKEN ❌ Database: UNREACHABLE ❌ Users: ANGRY 😭 

Your job as a DevOps engineer is to discover where the actual failure is happening.

🔍 2. Start With the Logs

Never begin by randomly restarting everything. First, investigate.

Check the application logs:

docker logs my-app 

Follow logs in real time:

docker logs -f my-app 

Show the latest 100 lines:

docker logs --tail 100 my-app 

Include timestamps:

docker logs -t my-app 

Look for errors such as:

Connection refused Database connection failed Address already in use Permission denied Missing environment variable 

Pro tip: Logs are often the fastest way to identify the root cause. Read them before changing anything.

🛠️ 3. Inspect the Container

Sometimes the problem is not visible in the logs.

Inspect the container configuration:

docker inspect my-app 

Check its state:

docker inspect -f '{{.State.Status}}' my-app 

Check its exit code:

docker inspect -f '{{.State.ExitCode}}' my-app 

Check whether Docker reports it as healthy:

docker inspect -f '{{.State.Health.Status}}' my-app 

Note: The last command requires a health check to be configured. Without one, Docker may return an empty value.

Inspecting a container helps you investigate its configuration, state, network settings, mounts, and other runtime details.

🌐 4. Check Port Mapping

Your application might be listening on port 8080 inside the container, but you may have exposed a different port—or forgotten to publish it.

Check published ports:

docker port my-app 

Start a container with the correct mapping:

docker run -d \ --name my-app \ -p 8080:8080 \ my-app:latest 

The mapping follows this pattern:

-p HOST_PORT:CONTAINER_PORT 

For example:

Your browser | v localhost:8080 | v Docker host port 8080 | v Container port 8080 | v Application 

Remember: publishing a port does not make an application listen on that port. Your application must actually be listening on the expected interface and port.

💾 5. Check Whether the Container Is Running Out of Resources

An application can become slow or crash when it runs out of memory or struggles with CPU usage.

Check resource consumption:

docker stats 

Example:

CONTAINER CPU % MEM USAGE / LIMIT my-app 95% 480MiB / 512MiB database 15% 300MiB / 1GiB 

In this hypothetical example, my-app is consuming almost all its memory limit.

Investigate further before changing resource limits. A memory leak, excessive traffic, or inefficient application code could be the real problem.

Useful commands:

docker ps -a docker system df docker events 

These help you inspect container states, Docker disk usage, and Docker events.

Important: Avoid running docker system prune -a as a routine troubleshooting step. It can remove unused images and other resources you may still need.

❤️ 6. Add a Docker Health Check

Here's one way to improve your container monitoring.

A health check lets Docker periodically test whether an application is responding to a defined check.

Example Dockerfile:

FROM nginx:alpine COPY index.html /usr/share/nginx/html/index.html HEALTHCHECK --interval=30s \ --timeout=5s \ --start-period=10s \ --retries=3 \ CMD wget -q -O /dev/null http://127.0.0.1/ || exit 1 

This example uses a lightweight Nginx image and checks whether its HTTP endpoint responds successfully.

Check the health status:

docker ps 

A configured health check can report statuses such as:

starting healthy unhealthy 

But remember: a health check is only as good as the test you define. A successful HTTP response does not necessarily mean every feature of your application is working.

🔗 7. Investigate Network and Database Problems

Suppose your application depends on a PostgreSQL database.

Your application container is running, but database connections keep failing.

First, inspect your Docker networks:

docker network ls 

Inspect the network used by your containers:

docker network inspect my-network 

If both services need to communicate, make sure they share an appropriate network.

With Docker Compose, services on the same default network can usually reach each other using their service names.

Example:

services: app: build: . ports: - "8080:8080" environment: DATABASE_URL: postgres://app:password@db:5432/appdb depends_on: - db db: image: postgres:17 environment: POSTGRES_USER: app POSTGRES_PASSWORD: password POSTGRES_DB: appdb 

Here, db is the database service name.

Important: This is a learning example, not a production-ready configuration. Use secrets rather than hardcoded passwords, persistent storage for database data, and application-level retry logic. Also, depends_on alone does not guarantee that PostgreSQL is ready to accept connections.

🧪 8. Build Your Own Docker Troubleshooting Checklist

When an application goes down, follow this order:

  1. Check the state: docker ps -a
  2. Read the logs: docker logs my-app
  3. Inspect configuration: docker inspect my-app
  4. Check resource usage: docker stats
  5. Verify port mapping: docker port my-app
  6. Investigate networking: docker network inspect my-network
  7. Test the application endpoint: use curl or an appropriate health check.
  8. Apply a fix: change the configuration or code based on evidence.
  9. Verify recovery: repeat the relevant tests and check the logs.

The goal is not simply to make the error disappear.

The goal is to understand why it happened and how to prevent it from happening again.

🚀 9. Take It Further: Build a Container Monitoring Project

Want to turn this knowledge into a portfolio project?

Build a small Docker monitoring stack using:

  • Docker Compose to run the services.
  • Prometheus to collect metrics.
  • Grafana to visualize performance.
  • cAdvisor to expose container resource metrics.
  • Alerting to notify you about important failures.

A simplified architecture:

Docker Containers | v cAdvisor | v Prometheus | v Grafana | v Dashboards & Alerts 

Track CPU usage, memory consumption, container restarts, and application availability.

Document one simulated failure, your investigation, the root cause, and the fix. That gives you a concrete project to discuss during DevOps interviews.

🎯 Final Thoughts

Docker makes packaging and running applications easier, but it does not eliminate production problems.

Good DevOps engineers do not blindly restart containers. They collect evidence, understand system behavior, identify root causes, and verify their fixes.

The next time someone says, "The container is running, but the application is down," you'll know where to start.

Your challenge: Run a Docker container, inspect its logs, configure a health check, and deliberately introduce a failure in a local test environment. Can you diagnose the problem without immediately restarting the container?

Share what you discover in the comments! 👇

📚 Keep Building Your DevOps Skills

If you want structured resources to help you learn these tools, explore my guides:

Learn by building, break things in a safe lab, and become better at fixing them.