"Install PostgreSQL, then Redis, then Elasticsearch, configure these 12 environment variables, make sure you're on Node 20 not 18, and oh — the tests need Python 3.11."
Sound like your onboarding doc? Here's the Docker version: docker compose up. Done. New dev writes code in 15 minutes.
The 3 Commands That Cover 80% of Docker
You don't need to learn everything. Start here:
# Run any service instantly
docker run -d -p 8080:80 nginx:latest
# Build your own app into an image
docker build -t my-app:1.0 .
# Start your entire stack (app + db + cache)
docker compose up -d
Open http://localhost:8080 after the first command — you'll see Nginx running. No install, no config, no conflicts.
Your First Dockerfile (Copy This)
A Dockerfile is a recipe for turning your code into a container. Here's one for a Node.js app:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
The trick: COPY package*.json before COPY . . means Docker caches your npm ci step. Change your code? Rebuild takes 2 seconds instead of 30.
Build it: docker build -t my-app:1.0 .
Run it: docker run -d -p 3000:3000 my-app:1.0
For Python/Flask, same pattern:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["python", "app.py"]
Docker Compose: The Real Power
Your app needs a database and Redis? One file, one command:
version: "3.9"
services:
app:
build: .
ports:
- "3000:3000"
environment:
DATABASE_URL: postgres://user:pass@db:5432/mydb
REDIS_URL: redis://cache:6379
depends_on:
- db
- cache
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data
cache:
image: redis:7-alpine
volumes:
pgdata:
docker compose up -d # start everything
docker compose down # stop everything
docker compose up -d --build # rebuild after code changes
docker compose down -v # stop + delete database data
The pgdata volume means your database survives container restarts. Remove it with -v only when you want a fresh start.
The 10 Commands Cheat Sheet
| Command | What It Does |
|---|---|
docker run -d -p 8080:80 nginx |
Run a container |
docker build -t app:1.0 . |
Build an image |
docker ps |
List running containers |
docker ps -a |
List all containers |
docker logs -f my-app |
Follow container logs |
docker exec -it my-app sh |
Shell into a container |
docker stop my-app |
Stop a container |
docker rm my-app |
Remove a container |
docker compose up -d |
Start all services |
docker compose down |
Stop all services |
Before You Deploy: Quick Checklist
- ✅ Using
alpineorslimbase image (not the 1 GB default) - ✅
.dockerignoreexcludesnode_modules,.git,.env - ✅ Container runs as non-root (
USER node) - ✅ Secrets passed via
environment, never hardcoded - ✅ Volumes configured for database data
- ✅ Health check added:
HEALTHCHECK CMD curl -f http://localhost:3000/health || exit 1 - ✅ Tested with
docker compose upon a clean machine
Common Gotchas
"My container exits immediately." Your app probably crashes on startup. Check logs: docker logs my-app. Most common cause: missing environment variable that's set on your machine but not in the container.
"Database is empty after restart." You forgot the volume. Without volumes: in docker-compose.yml, data lives inside the container and dies with it.
"Port already in use." Something else is running on that port. Either stop it or change the host port: -p 3001:3000 maps host port 3001 to container port 3000.
"Image is 1.2 GB." Use node:20-alpine instead of node:20. Add .dockerignore. Use multi-stage builds for compiled languages. Typical reduction: 1 GB → 100 MB.
📖 The full guide covers installation walkthroughs for Windows/macOS/Linux, Python Dockerfile examples, Docker Desktop licensing (free vs paid), multi-stage builds, and a production-readiness checklist.
Top comments (0)