Docker for Beginners: From Zero to Running a Full Stack Locally in 10 Minutes
Source: Dev.to
Run any service instantly
docker run -d -p 8080:80 nginx:latest
Open after the command — you’ll see Nginx running. No install, no config, no conflicts.
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
Dockerfile 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"]
Tip: Copying package*.json before the rest of the source lets Docker cache the npm ci step. After code changes, rebuilding takes a few seconds instead of tens.
Build and run
docker build -t my-app:1.0 .
docker run -d -p 3000:3000 my-app:1.0
Dockerfile for a Python/Flask app
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 example (app + PostgreSQL + Redis)
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:
Typical workflow
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 ensures the database persists across container restarts. Use -v only when you want a fresh start.
Common Docker commands
| 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 | Open a shell inside 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 |
Best‑practice checklist
- ✅ Use Alpine or Slim base images (instead of the default ~1 GB images)
- ✅ Add a
.dockerignoreto excludenode_modules,.git,.env, etc. - ✅ Run the container as a non‑root user (e.g.,
USER node) - ✅ Pass secrets via environment variables, never hard‑code them
- ✅ Configure volumes for persistent data (e.g., database files)
- ✅ Add a health check, e.g.:
HEALTHCHECK CMD curl -f http://localhost:3000/health || exit 1 - ✅ Verify the setup on a clean machine with
docker compose up
Troubleshooting tips
- Container exits immediately – The app likely crashes on startup. Check logs with
docker logs <container>. A common cause is a missing environment variable. - Database is empty after restart – Ensure you have a volume defined for the database data; otherwise the data lives inside the container and is lost when it stops.
- Port already in use – Something else is bound to the host port. Stop that process or map a different host port, e.g.,
-p 3001:3000. - Image is too large – Switch to a smaller base image (
node:20-alpine), add a.dockerignore, and consider multi‑stage builds for compiled languages. Typical reduction: 1 GB → ~100 MB.
Further reading
The full guide covers installation walkthroughs for Windows/macOS/Linux, additional Python Dockerfile examples, Docker Desktop licensing (free vs. paid), multi‑stage builds, and a production‑readiness checklist.