Docker · Lesson 0003
Inspect config, exec a shell
When logs alone are not enough: read the container’s full config as JSON, then run a one-off command (or a shell) inside the running process isolation — without Docker Desktop.
Mission link: Production debugging is CLI-first.
inspect answers “what was this container configured as?”
exec answers “what does the filesystem / process look like
from the inside?” Both skills transfer when AI-generated stacks misbehave.
Continues lesson 0002 · cheat sheets pull/tags/logs · first-run CLI
The debugging ladder so far
docker ps/docker ps -a— is it running or exited?docker logs— what did the main process print?- This lesson:
docker inspect— full config and network facts. - This lesson:
docker exec— run a command inside the live container.
logs = the flight recorder · inspect = the blueprint of the plane · exec = climbing into the cabin while it’s flying. Different questions, same “why is this broken?” mission.
Two tools, two jobs
docker inspect
Print low-level JSON about a Docker object (container, image, …). No process starts. You read config: image used, env, ports, state, network addresses. (inspect reference)
docker exec
Run a new command in a running container. Only works while PID 1 is up; the exec process is not restarted if the container restarts. (exec reference)
inspect: read the blueprint
Default output is a JSON array — useful, noisy. In practice you almost
always pass -f / --format with a Go template to
print one fact. Official docs show patterns for IP, image name, ports, and
subsections as JSON.
(format option)
# Full JSON (pipe to less if long)
docker inspect lesson3
# Which image is this container actually running?
docker inspect -f '{{.Config.Image}}' lesson3
# Container IP on the bridge network (when present)
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' lesson3
# Pretty-print just the Config object as JSON
docker inspect -f '{{json .Config}}' lesson3
Template examples from the
official inspect docs
(image name, network IP, json helper).
exec: work from the inside
docker exec is not “attach to the main process.” It starts a
separate command in the same container namespaces. The command must be an
executable that exists in the image; chain with
sh -c "…" when you need shell features.
(exec description)
docker exec lesson3 ls /usr/share/nginx/html— one-shot, non-interactive.docker exec -it lesson3 sh— interactive shell (-ikeep STDIN,-tallocate a TTY).- Exit the shell with
exitor Ctrl+D — the main nginx process keeps running.
exec fails if the container is stopped or paused. Check
docker ps first. Inspect still works on stopped containers
(you can read why it exited from state fields) — another reason both tools
matter.
Check: inspect vs exec vs logs
You need the image name and port maps as data. Which tool?
Why do people write docker exec -it name sh?
Skill: run → inspect → exec → clean
Do this in your terminal. Engine must be running. Reuse
nginx:alpine from lesson 0002 if you still have it locally
(docker image ls).
-
Start a named container
If the name is taken:docker run -d -p 8080:80 --name lesson3 nginx:alpinedocker rm -f lesson3first. If 8080 is busy:-p 18080:80instead. -
Confirm running, then inspect (full JSON)
Scroll: look fordocker ps docker inspect lesson3 | lessConfig,NetworkSettings,State. Quitlesswith q. (inspect defaults to a JSON array.) -
Format: image name only
Expect something likedocker inspect -f '{{.Config.Image}}' lesson3nginx:alpine. This is the official “get instance’s image name” pattern. -
Format: container IP (if any)
On Docker Desktop you often still use published ports (docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' lesson3localhost:8080) rather than this IP from the Mac host — but the field is real and useful when containers talk to each other on a user-defined network (later). -
One-shot exec: list the web root
You should seedocker exec lesson3 ls -la /usr/share/nginx/htmlindex.html(and maybe other static files). No-itneeded for a single non-interactive command. -
Interactive shell, then leave
Official pattern:docker exec -it lesson3 sh # inside the container: pwd hostname cat /usr/share/nginx/html/index.html | head exitdocker exec -it … sh. Afterexit,docker psstill showslesson3— you only left the exec shell, not the main process. (exec examples) -
Prove exec does not replace the main process
The welcome page still works; access lines may appear in logs. Exec was a side command, not a takeover of nginx.open http://localhost:8080 docker logs --tail 5 lesson3 -
Clean up
Imagedocker stop lesson3 docker rm lesson3nginx:alpineremains for next time.
exec as root inside a container is powerful — and common on
default images. Later, when you ship TypeScript apps, you’ll prefer
non-root users and treat shell access as a break-glass debug tool, not
“how we deploy changes.” For now: learn the tool; don’t leave shells
open on shared machines.
Check: what stays running?
You exit an exec -it … sh session. What happens?
Container is stopped. Which command still works?
Why this matters for shipping
- Local: verify AI-started containers (env, image tag, ports) without a GUI.
- Reliable: same inspect fields in CI/prod as on your Mac.
- Maintain: logs → inspect → exec is a standard “something’s wrong” path.
- Secure (preview): know when you’re root inside; prefer least privilege later.
Primary source (read this next)
docker container exec — Docker Docs (official CLI reference)
Read the description (running container only; not restarted with the
container) and the -it shell example. Keep
docker inspect
open for the --format recipes (image, IP, ports, json).
Quick reference (commands from this lesson)
docker run -d -p 8080:80 --name lesson3 nginx:alpine
docker inspect lesson3
docker inspect -f '{{.Config.Image}}' lesson3
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' lesson3
docker exec lesson3 ls -la /usr/share/nginx/html
docker exec -it lesson3 sh
docker stop lesson3 && docker rm lesson3