✦ For everyone, free.

Practical knowledge for real and everyday life

Home

19.2.4.5 Logs Startup Debugging

A focused guide to Logs Startup Debugging, connecting core concepts with practical Docker and container operations.

Startup debugging with docker logs focuses on diagnosing why a container fails to start, exits immediately after starting, or enters a crash loop. Container startup failures are among the most common issues encountered in Docker environments, and docker logs provides direct access to the output that reveals what went wrong before or during the container's initialization phase.

The Core Problem: Containers That Exit Immediately

A container that exits immediately after docker run — with no output in the terminal — is typically in the exited state before there is time to observe it:

docker run myapp:1.0.0
# Shell returns immediately, container never appears in docker ps

Check if it exited:

docker ps -a -l
CONTAINER ID   IMAGE          COMMAND    CREATED         STATUS                     NAMES
a1b2c3d4e5f6   myapp:1.0.0   "./run"    5 seconds ago   Exited (1) 4 seconds ago   hopeful_einstein

The exit code 1 indicates an application error. Read the logs immediately:

docker logs a1b2c3d4e5f6

Accessing Logs After Exit

docker logs works on stopped containers just as it does on running ones. The container does not need to be running to retrieve its output:

docker logs hopeful_einstein

This retrieves all output the container produced before it exited.

Using --tail to Focus on the Last Lines

If a container ran for a while before failing, there may be thousands of log lines. The failure message is typically at the end:

docker logs --tail 50 my-container

Startup Error Patterns

Missing environment variable
panic: DATABASE_URL environment variable is required but not set

Fix:

docker run -e DATABASE_URL="postgres://user:pass@db:5432/mydb" myapp:1.0.0
Database connection failure
Error: connect ECONNREFUSED 127.0.0.1:5432

The application is trying to connect to a database on localhost, but the database is not running in the same container. The container needs to be connected to the network where the database container resides, and the host address needs to point to the database container, not localhost.

Port already in use
Error: listen EADDRINUSE: address already in use :::8080

This happens inside the container when the application's configured port is already bound. It typically indicates a configuration issue where the application is hardcoded to a port that conflicts with something else in the same container.

Missing required file
Error: configuration file not found: /app/config.yaml

The container is missing a file that was expected to be present. This is typically a missing volume mount or a file that was not copied into the image:

docker run -v /host/config.yaml:/app/config.yaml myapp:1.0.0
Permission denied
Error: /data/storage: permission denied

The user running inside the container does not have write permission to the mounted path. Either change the ownership of the host directory or run the container as a different user.

The Crash Loop Diagnostic Pattern

When a container has a restart policy and keeps restarting, docker ps shows:

STATUS
Restarting (1) 3 seconds ago

Getting logs from a container in a crash loop requires timing or the --since filter:

docker logs --since 1m my-container

Or following the logs to catch each crash as it happens:

docker logs -f my-container

Each restart appends new output to the same log stream, so the history shows all restart attempts.

Debugging Startup with an Override Command

When the container's default command fails too quickly to diagnose, override it with a shell to explore interactively:

docker run -it --rm --entrypoint /bin/sh myapp:1.0.0

Inside the container, run the application command manually:

./run
# See the error output directly

Or inspect environment variables, file paths, and permissions:

env | grep DATABASE
ls -la /app/config.yaml
cat /etc/hosts

This approach is particularly useful when the application exits before writing any output (e.g., a segfault or a binary that fails during initialization before any logging framework is configured).

Using docker run Without -d to See Output Directly

Running in foreground mode (without -d) shows all output directly:

docker run myapp:1.0.0

The terminal is attached to the container's stdout and stderr, and all output appears in real time. This is often the fastest debugging approach for new containers.

Checking Exit Code After Startup Failure

docker inspect --format '{{.State.ExitCode}}' a1b2c3d4e5f6
docker inspect --format '{{.State.OOMKilled}}' a1b2c3d4e5f6

OOMKilled: true means the container was killed by the OOM (Out of Memory) killer — the process used more memory than the limit allowed. Increase the memory limit:

docker run --memory 512m myapp:1.0.0

Startup Debugging Workflow

docker run myapp:1.0.0 docker ps -a -l docker logs <id> Identify the error Fix and redeploy
  1. Run the container.
  2. Check its status with docker ps -a -l.
  3. Read its output with docker logs.
  4. Identify the error from the output.
  5. Fix the configuration, environment, or application code and redeploy.