Debugging Running Docker Containers Without Restarting Them

Something is wrong with your container. It is running but not behaving. You could rebuild and redeploy, but that might hide the problem. Here is how to investigate a running container without restarting it.

docker exec

The obvious one. Drop into a shell:

docker exec -it mycontainer sh

Use sh not bash because Alpine images do not have bash. Once inside, you can poke around:

# Check what processes are running
ps aux

# Look at environment variables
env | sort

# Test network connectivity
wget -qO- http://other-service:3000/health

# Check disk usage
df -h

But what if the container has no shell? Minimal images built FROM scratch or distroless images strip everything out.

docker logs

Before exec-ing into anything, check the logs:

# Last 100 lines
docker logs --tail 100 mycontainer

# Follow in real time
docker logs -f mycontainer

# Logs since a specific time
docker logs --since 2026-03-29T10:00:00 mycontainer

# With timestamps
docker logs -t mycontainer

The --since flag is underrated. When a container has been running for weeks, you do not want to scroll through megabytes of old logs.

docker inspect

This tells you everything about the container’s configuration:

# Full JSON dump
docker inspect mycontainer

# Just the IP address
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mycontainer

# Environment variables
docker inspect -f '{{json .Config.Env}}' mycontainer | jq .

# Mount points
docker inspect -f '{{json .Mounts}}' mycontainer | jq .

# Port mappings
docker inspect -f '{{json .NetworkSettings.Ports}}' mycontainer | jq .

# Health check status
docker inspect -f '{{json .State.Health}}' mycontainer | jq .

docker cp

Copy files in or out of a running container:

# Copy a config file out for inspection
docker cp mycontainer:/etc/nginx/nginx.conf ./nginx.conf

# Copy a fix in
docker cp ./fixed-config.json mycontainer:/app/config.json

This works even if the container has no shell or text editor.

nsenter: The Nuclear Option

When docker exec is not enough or the container has no shell, nsenter lets you enter the container’s namespaces from the host:

# Get the container's PID
PID=$(docker inspect -f '{{.State.Pid}}' mycontainer)

# Enter its network namespace
sudo nsenter -t $PID -n ss -tlnp

# Enter all namespaces (like exec but from the host)
sudo nsenter -t $PID -m -u -i -n -p -- /bin/sh

This is useful for network debugging. You can run tcpdump, ss, or ip inside the container’s network namespace even if those tools are not installed in the container.

docker diff

See what files changed since the container started:

docker diff mycontainer

Output looks like:

C /app
A /app/data/cache.db
C /tmp
A /tmp/something-unexpected

A means added, C means changed, D means deleted. This is great for finding containers that are writing to unexpected places.

Debugging Network Issues

When containers cannot talk to each other:

# Check which networks a container is on
docker inspect mycontainer -f '{{json .NetworkSettings.Networks}}' | jq 'keys'

# Ping from one container to another
docker exec web ping -c 3 api

# Check DNS resolution
docker exec web nslookup api

# List all containers on a network
docker network inspect mynetwork -f '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{end}}'

One-Liner Health Checks

# Which containers are unhealthy?
docker ps --filter health=unhealthy --format '{{.Names}}: {{.Status}}'

# Which containers restarted recently?
docker ps --format '{{.Names}}: {{.Status}}' | grep -i restarting

# Resource usage snapshot
docker stats --no-stream --format 'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}'

The instinct to restart a broken container is strong. But nine times out of ten, the information you need to fix the actual problem is sitting right there in the logs, the inspect output, or the filesystem diff. Restarting just resets the evidence.

← all articles wleeaf.dev →