On this page
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, using docker exec, docker logs, docker inspect, docker cp, nsenter and docker diff.
docker exec#
The obvious one. Drop into a shell:
docker exec -it mycontainer shUse 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 -hBut 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 mycontainerThe --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.jsonThis 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/shThis 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 mycontainerOutput looks like:
C /app
A /app/data/cache.db
C /tmp
A /tmp/something-unexpectedA 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.