Docker is the most widely used containerisation tool in software development. Here is a practical guide to get from zero knowledge to a working development environment.
What Docker Actually Solves
The classic developer problem: “It works on my machine.” Docker solves this by packaging an application with its entire environment (OS libraries, runtime, dependencies, configuration) into a container that runs identically on any machine with Docker installed. For development: your local environment matches the production environment. For deployment: the same container image runs in CI, staging, and production. For onboarding: new developers run one command instead of a 20-step setup document.
Core Concepts
Image: a snapshot of a filesystem and runtime environment, built from a Dockerfile. Container: a running instance of an image — you can run many containers from the same image. Dockerfile: a script of instructions for building an image (FROM, RUN, COPY, EXPOSE, CMD). Registry: a repository for images — Docker Hub is the public registry, private registries exist for enterprise use. Volume: persistent storage that survives container restarts. Network: how containers communicate with each other and the outside world.
A Working Example
A simple Node.js app Dockerfile:
FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . EXPOSE 3000 CMD ["node", "server.js"]
Build: docker build -t my-app .
Run: docker run -p 3000:3000 my-app
The -p 3000:3000 maps port 3000 on your machine to port 3000 in the container. The app is now accessible at localhost:3000.
Docker Compose for Multi-Service Applications
Most applications have multiple services (web app, database, cache). Docker Compose lets you define and run them together. A minimal docker-compose.yml:
services:
app:
build: .
ports:
- "3000:3000"
depends_on:
- db
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: password
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Run everything: docker compose up. Stop everything: docker compose down. The database data persists in the pgdata volume across restarts.
Common Development Patterns
Volume mounting for live reload: docker run -v $(pwd):/app my-app mounts your local directory into the container — code changes reflect without rebuilding. Environment variables: use --env-file .env to pass local variables to a container. Multi-stage builds: build in one image (node, python) and copy the result into a smaller runtime image to reduce production image size. Docker Desktop (Mac/Windows) provides a GUI for managing containers and images during development.



