Docker: Images, Containers, Volumes and Compose Reference Guide
By DevShelfHub
Images, containers, volumes, networks, Compose, multi-stage builds, and BuildKit — the day-to-day Docker commands and Compose snippets for Docker Engine 25+ and Compose v2. Covers the full workflow from Dockerfile authoring through registry push and production cleanup.
This sheet assumes docker compose (Go plugin) — not the
deprecated docker-compose Python tool. BuildKit is the default
builder; the --mount=type=cache and
--platform flags assume it’s on.
smoke test · daily-loop commandsSetup
bash
# Sanity check
docker version # client + daemon versions
docker info # storage driver, registry mirrors
# Daily quick-loop
docker run --rm -it alpine sh # throwaway shell
docker run --rm -p 8080:80 nginx:alpine # publish a port
docker run --rm -e ENV=prod -v $(pwd):/app -w /app node:22 # env + bind mount
# Auth to a registry
docker login ghcr.io # GitHub container registry
docker logout ghcr.io
# Clean up reclaimable disk
docker system df # show usage
docker system prune -af --volumes # everything not in use
Cross-arch image. Push to registry as manifest list.
--cache-from / --cache-to type=registry,ref=…
Share cache across CI runners.
.dockerignore
Excludes from build context. Add .git, .venv, node_modules.
Order layers by change frequency. Put COPY requirements.txt +
pip installbeforeCOPY .. Source edits
shouldn’t bust the dependency layer.
persistenceVolumes
docker volume create data
Named volume managed by Docker.
docker run -v data:/var/lib/data IMAGE
Mount named volume.
docker run -v $(pwd):/app IMAGE
Bind mount host path. Dev-only.
--mount type=bind,source=…,target=…,readonly
Modern syntax. Explicit type.
--tmpfs /scratch
RAM-backed scratch dir. Disappears with the container.
docker volume ls / inspect / rm
Manage volumes.
docker volume prune
Remove unused volumes. Read this before running.
Bind mounts shadow the in-image contents at the same path. If /app in the
image has files and you bind-mount over it, those files vanish for the container.
container connectivityNetworks
docker network ls
Default networks: bridge, host, none.
docker network create app
User-defined bridge. Containers can DNS each other by name.
docker run --network app --name db postgres
Attach a container to a network.
docker network connect app api
Attach a running container.
--network host
Share host network. Linux only; bypasses port publishing.
--add-host host.docker.internal:host-gateway
Reach the host machine from inside a container.
-p 127.0.0.1:8000:8000
Publish only to localhost. Important for dev daemons.
docker run --rm -it --network container:NAME nicolaka/netshoot
Network diag in target container’s namespace.
docker run --rm -it --pid container:NAME alpine sh
Share PID namespace. Inspect target’s processes.
docker inspect --format '{{json .State}}' NAME
Exit codes, OOM, restart counts.
docker top NAME
Processes inside the container.
docker events --filter container=NAME
Live event stream.
docker system df -v
Find which image / volume is hogging disk.
build → push → runEnd-to-end · Build, push, run
Multi-arch BuildKit build, push to GHCR, run locally with env + restart policy, tail logs, tear down.
bash
# Build, tag, run, ship — the full local-to-registry loop.
# 1 · Build for multiple platforms with BuildKit
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag ghcr.io/me/api:0.4.1 \
--tag ghcr.io/me/api:latest \
--push .
# 2 · Inspect the result
docker image inspect ghcr.io/me/api:0.4.1 --format '{{.Size}}'
docker history ghcr.io/me/api:0.4.1
# 3 · Run locally
docker run -d --name api \
-p 8000:8000 \
-e DATABASE_URL=postgres://app:app@db:5432/app \
--restart unless-stopped \
ghcr.io/me/api:0.4.1
# 4 · Tail logs and exec into the running container
docker logs -f --tail 100 api
docker exec -it api sh
# 5 · Tear down
docker stop api && docker rm api
Best practiceGood to know
Pin tags.python:3.13-slim beats python:latest. For
reproducibility, pin by digest: python:3.13-slim@sha256:….
One process per container.
No supervisord. If you need two, run two containers and let
Compose / Kubernetes wire them. Signals + logs only work cleanly with one.
Multi-stage by default.
Final image gets the artefact, not the toolchain. Cuts size 5–10× on most stacks and shrinks the
attack surface.
Common trapsWatch out for
Never put secrets in ENV or ARG.
They show up in docker history and image inspect. Use
--mount=type=secret at build time or runtime secrets (Compose / k8s).
latest isn’t magic.
It’s just a tag. If you don’t push it, it’s whatever someone last pushed manually. Pin to a
version or digest in production.
Bind mounts hide image files.-v $(pwd):/app over an /app that already has
a node_modules in the image will erase it for the container. Mount
sub-paths or use named volumes for vendored deps.
What is the difference between a Docker image and a container?
An image is a read-only blueprint built from a Dockerfile — it contains the filesystem layers and metadata. A container is a running instance of an image with its own writable layer, network, and process space. One image can spawn many containers.
How do I run a Docker container in the background?
Use docker run -d to detach. Add -p 8080:8000 to publish ports and --name app to give it a stable name. Check it with docker ps and follow its logs with docker logs -f app.
What is Docker Compose used for?
Docker Compose defines and runs multi-container applications with a single docker-compose.yml file. It manages service dependencies, shared networks, and named volumes. Use docker compose up -d --build to start everything, and docker compose down -v to tear it down.
How do I reduce Docker image size?
Use multi-stage builds to discard build tooling from the final image, choose a minimal base image (alpine or distroless), combine RUN commands to squash layers, and add a .dockerignore file to exclude node_modules and .git from the build context.
How do I persist data in Docker?
Use named volumes (docker volume create my-vol) for managed persistence, or bind mounts (-v $(pwd)/data:/app/data) to map a host directory into the container. Named volumes are preferred for databases; bind mounts are convenient for development hot-reload.
How do I access a running container shell?
Run docker exec -it CONTAINER_ID sh (or bash if available). Use docker exec -it $(docker ps -qf name=app) sh to resolve the container by name. For a stopped container, start it with docker start -ai CONTAINER_ID to attach to its original command.