docker exec
docker exec runs a command inside a running container. Daily-driver for debugging: open a shell, tail a log, run a one-off migration, inspect filesystem.
exec, shells, file ops, debugging
EXAMPLE
# 1) Open a shell docker exec -it <container> sh # alpine / minimal docker exec -it <container> bash # debian / ubuntu docker exec -u root -it <container> sh # as root (even if image runs as non-root) # 2) One-off command docker exec <container> ls -la /app docker exec <container> cat /etc/os-release docker exec <container> env docker exec <container> ps aux # 3) Run with environment variables docker exec -e DEBUG=true <container> /app/bin/script docker exec -e LOG_LEVEL=debug -e VERBOSE=1 <container> npm run task # 4) Workdir docker exec -w /app <container> npm run lint docker exec -w /var/log <container> tail -f app.log # 5) Detach + interactive flags # -i : keep STDIN open (interactive) # -t : allocate a TTY (terminal) # -d : detached (run + return immediately) docker exec -d <container> /app/bin/long-running-task # 6) Real debugging patterns # Inspect filesystem docker exec -it web sh -c 'ls /app && cat /app/config.yml' # Test connectivity from inside docker exec -it web sh -c 'wget -qO- http://db:5432' docker exec -it web sh -c 'nc -zv db 5432' docker exec -it web nslookup db # in non-Alpine; alpine: apk add bind-tools first # Check process count + memory docker exec web ps -ef | head docker exec web cat /proc/1/status | grep VmRSS # Run a DB migration in the running app container docker exec -it web npm run migrate docker exec -it web ./manage.py migrate docker exec -it web rake db:migrate # Run a one-off Rails console / Django shell / Node REPL docker exec -it web rails console docker exec -it web python manage.py shell docker exec -it web node # 7) Copy files in / out (docker cp, not exec — but worth knowing) docker cp ./local.json web:/app/config/local.json docker cp web:/app/logs/app.log ./app.log docker cp web:/app/dist ./dist # whole directory # 8) Common gotchas # Permission denied: container's user can't read a path # → re-run with -u root for the debug command, then fix permissions in image # 'OCI runtime exec failed' — typically the container exited mid-command # → check `docker ps` (is it still up?); check container logs # Shell not available: distroless / scratch images docker exec -it distroless-app sh # ERROR: shell not in image # Workaround: # - Run a debug sidecar with shared PID namespace # - Or use kubectl debug (Kubernetes equivalent — ephemeral debug container) # - Or temporarily build a debug variant of your image # 9) Compose syntax docker compose exec web sh docker compose exec -e DEBUG=true web npm run task docker compose run --rm web npm run migrate # 'run' starts a fresh container instead of exec # 'exec' vs 'run': # exec : reuses the RUNNING container, current state, current network # run : new container from the same image, fresh state # 10) Debugging a stopped container # `exec` only works on RUNNING containers. For stopped: # - docker logs <container> → check last output # - docker inspect <container> → check exit code + restart policy # - docker commit <container> debug-img → snapshot the state # - docker run --rm -it debug-img sh → poke around # 11) Real workflows # Quick CPU / memory snapshot docker stats --no-stream <container> # Tail logs without exec docker logs -f --tail=100 web # Network namespace tools docker exec -it web sh -c 'apk add curl iproute2 || apt-get update && apt-get install -y curl iproute2' docker exec -it web ss -tlnp # Database REPL inside the DB container docker exec -it pg psql -U postgres -d myapp docker exec -it mysql mysql -u root -p docker exec -it redis redis-cli docker exec -it mongo mongosh # 12) Security — exec is privileged enough to be careful # - In production: restrict who can run docker on the host (docker group = effectively root) # - Log every exec session if it touches sensitive containers # - Kubernetes equivalent: kubectl exec — restrict via RBAC # - For 'investigative access' instead of full shell: deploy a sidecar with read-only mounts # 13) When you reach for exec a lot # Maybe your app needs: # - Better logs (structured JSON to stdout) # - Health endpoints (HTTP /health) # - Admin endpoints / commands (CLI in the binary) # - Observability (Prometheus metrics, distributed tracing) # Reduce the need to shell into prod containers. # 14) Aliases worth adding alias dex='docker exec -it' alias dexb='docker exec -it bash' # adjust for sh/bash alias dlog='docker logs -f --tail=100' alias dps='docker ps' alias dimg='docker images'
Why it matters
docker exec -it <c> sh is your default debugging move. For distroless images or stopped containers, use docker run from a snapshot, docker logs, or kubectl debug — exec only works on a live one with a shell.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…