Docker Basics
Docker Basics
A container is an isolated user space that runs on top of the OS, letting the same application run anywhere with the same shape. Docker is the decisive moment that bundled containers into a standard tool and brought them to the mainstream. This piece covers Docker's origins, basic concepts (image / container / layer / volume / network), the core Dockerfile commands, multi-stage builds, BuildKit, and neighboring tools.
1. About Docker
| Event | Period |
|---|---|
| dotCloud starts as an internal tool (Solomon Hykes and others) | 2008–2013 |
| Docker open-sourced (PyCon 2013) | 2013-03 |
| Docker 0.9 — libcontainer introduced (LXC dependency removed) | 2014 |
| Docker 1.0 | 2014-06 |
| OCI (Open Container Initiative) launched — Linux Foundation | 2015 |
| Multi-stage build (Dockerfile) | Docker 17.05 / 2017 |
| BuildKit stabilized | 2018 |
| Docker Desktop license change (paid for large enterprises) | 2021 |
The two specifications OCI standardized — the image spec and the runtime spec — let runtimes other than Docker (containerd, CRI-O, Podman) handle the same images.
2. Core Vocabulary
| Term | Meaning |
|---|---|
| Image | An executable filesystem snapshot plus metadata. Immutable. |
| Container | A process-isolation unit launched from an image. Changes go into the top layer. |
| Layer | The unit of change in an image. The unit of cache and reuse. |
| Volume | Persistent data outside the container. |
| Network | Communication boundary between containers (bridge, host, overlay). |
| Registry | Image storage (Docker Hub, ghcr.io, ECR). |
3. Images and Layers
Each command in a Dockerfile (RUN, COPY, ADD) is a layer. The same command with the same input gets cache reuse. Ordering layers well makes a big difference in build time.
FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci # cache invalidates here when deps change
COPY . . # when only source changes, the layer above is reused
CMD ["node", "server.js"]
4. Core Dockerfile Commands
| Command | Role |
|---|---|
FROM |
Base image. Used multiple times in multi-stage. |
WORKDIR |
The current directory for subsequent commands. |
COPY / ADD |
File copy. ADD auto-extracts URLs and tar. COPY is generally recommended. |
RUN |
Executes at build time. Shell mode vs exec mode. |
ENV |
Environment variable. Pinned in the image. |
EXPOSE |
Metadata (documentation). The actual port mapping happens at runtime. |
CMD |
Default exec command. |
ENTRYPOINT |
Container entry point. Combines with CMD. |
CMD provides default arguments, ENTRYPOINT is the fixed command. Combine them — write ENTRYPOINT ["node"] CMD ["server.js"] and the arguments can be swapped in.
5. Multi-stage Build
Separate build and runtime stages to keep the final image small.
FROM node:22 AS build
WORKDIR /src
COPY . .
RUN npm ci && npm run build
FROM node:22-slim
WORKDIR /app
COPY --from=build /src/dist ./dist
COPY --from=build /src/node_modules ./node_modules
CMD ["node", "dist/server.js"]
Build tooling, source, and test artifacts never enter the final image.
6. BuildKit
A rewritten build engine that brings parallel execution, cache mounts, and secret mounts.
# syntax=docker/dockerfile:1.7
RUN --mount=type=cache,target=/root/.npm \
npm ci
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
npm publish
docker buildx runs on top of BuildKit and adds multi-architecture (arm64 / amd64) builds and remote builders.
7. Other Tools
| Tool | Note |
|---|---|
| Podman | Red Hat-led. Daemon-less model. Docker CLI compatible. |
| containerd | The runtime Docker spun out and donated to CNCF. Adopted as the standard by Kubernetes. |
| nerdctl | A Docker-compatible CLI for containerd. |
| LXC, LXD | The older form of Linux containers. Emphasizes system containers. |
| Buildah | A builder from the Podman camp. Works without a Dockerfile. |
8. Choosing a Base Image
- alpine — Small (a few MB). musl libc. Often runs into compatibility issues with glibc-based binaries.
- distroless (Google) — Runtime only, no OS tooling. Reduces the security surface.
- scratch — Completely empty. Suits static binaries (e.g., Go).
- slim variants (
debian:slim,node:slim) — A balance point.
9. Common Patterns
.dockerignore — similar to .gitignore. Shrinks the build context, cutting build time and image size.
node_modules
.git
*.log
.env*
Non-root user — reduces root exposure inside the container:
RUN useradd -m -u 10001 app
USER app
Healthcheck — orchestrators (compose, k8s) use it to decide on startup and restart:
HEALTHCHECK --interval=30s --timeout=3s CMD curl -fsS http://localhost:8080/health || exit 1
10. Common Pitfalls
COPY . . cache invalidation — once a single source file changes, the dependency-install step has to run again. Copy dependency files first; that's the canonical order.
Signal handling for the PID 1 process inside a container — wrappers like npm start may not forward SIGTERM to the child cleanly. Use exec mode (CMD ["node", "server.js"]) or tini.
Image size — node_modules, build cache, and OS package leftovers. Multi-stage plus a slim or distroless base makes a big difference.
Confusing Windows and Linux containers — Docker Desktop's mode switch changes the OS of the base image. On Windows, check daemon.json and the WSL2 backend setting.
The latest tag — breaks reproducibility. Pin explicit version tags or digests.
Dangling <none> images accumulate on rebuilds with the same tag — building myapp:dev again untags the previous image, leaving it as dangling. This is the normal mechanism, but without automatic cleanup the disk fills up fast. A single docker image prune -f at the end of every CI script prevents the buildup. The WSL2 backend stores everything in a sparse VHDX, so docker prune alone doesn't reclaim host disk — you also need Optimize-VHD -Mode Full or diskpart compact vdisk for the file to actually shrink.
Closing thoughts
Docker is the standard tool and starting line for containers. When multi-stage, BuildKit cache mounts, and .dockerignore are all in place, build time, image size, and reproducibility all improve together. Avoid the latest tag and pin explicit versions.
Next
- docker-compose-patterns
- caddy-not-nginx
Refer to the Docker docs, the Dockerfile reference, BuildKit, the OCI Image Spec, the OCI Runtime Spec, Podman, and Distroless.