2. Docker architecture and core CLI
2.1 The moving parts
| Piece | Role |
|---|---|
docker CLI |
client; talks to the daemon over a Unix socket or TCP |
dockerd |
the daemon: images, networks, volumes, the API |
| BuildKit | the build engine behind docker build/docker buildx (parallel stages, cache mounts, secrets, multi-arch) |
containerd |
image pull/unpack, container lifecycle |
| registry | stores images: Docker Hub, GHCR, ECR, GAR, ACR, Harbor |
War story: access to
/var/run/docker.sockis root on the host. Anyone who candocker run -v /:/hostowns the machine. Teams that mount the socket into CI jobs or "monitoring" containers have handed out root. Treat the socket like an SSH key to root.
2.2 The 20 commands you will use daily
# images
docker pull nginx:1.27-alpine
docker images # or: docker image ls
docker image history nginx:1.27-alpine # layers and their sizes
docker image inspect nginx:1.27-alpine | jq '.[0].Config'
docker rmi <image> # remove
docker image prune -a # remove unused images
# containers
docker run -d --name web -p 8080:80 nginx:1.27-alpine # detached, port 8080 -> 80
docker ps # running; -a for all
docker logs -f --tail 100 web # follow logs
docker exec -it web sh # shell inside a running container
docker stop web # SIGTERM, then SIGKILL after 10s
docker kill web # SIGKILL now
docker rm -f web # stop + remove
docker inspect web | jq '.[0].State' # status, exit code, OOMKilled flag
docker stats # live CPU/mem/net/io per container
docker top web # processes inside, seen from the host
docker cp web:/etc/nginx/nginx.conf ./ # copy files out (or in)
# housekeeping
docker system df # what is using disk
docker system prune # remove stopped containers, dangling images, unused networks
2.3 The run flags that matter in production
docker run -d \
--name orders \
--restart unless-stopped \ # auto-recovery: restart on crash and after daemon restart
--memory 256m --memory-swap 256m \ # hard limit, no swap
--cpus 0.5 \ # CFS quota: half a core
--pids-limit 200 \ # fork-bomb protection
--read-only --tmpfs /tmp \ # immutable root filesystem
--cap-drop ALL \ # no Linux capabilities
--security-opt no-new-privileges \ # setuid binaries can't escalate
--user 65532:65532 \ # non-root
--health-cmd 'wget -qO- http://localhost:8080/readyz || exit 1' \
--health-interval 10s --health-retries 3 \
-e DATABASE_URL \ # pass through from your shell, not hard-coded
-p 127.0.0.1:8080:8080 \ # bind to localhost only, not 0.0.0.0
ghcr.io/acme/orbit-orders:1.4.2
Restart policies: no (default), on-failure[:max], always,
unless-stopped. This is single-host auto-recovery. Kubernetes replaces it
with controllers (§22).
Best practice: publish ports to
127.0.0.1on dev machines and servers.-p 5432:5432on a cloud VM binds to every interface, and Docker's iptables rules bypassufw. Many leaked databases were exposed exactly like this.