Devops
Beginner to Advanced
Docker Mastery
Docker Complete Guide: Containers from Zero to Production
Master Docker with hands-on examples — Dockerfiles, multi-stage builds, Docker Compose, networking, volumes, and production security best practices.
What is Docker?
Docker packages your application and all its dependencies into a container — a lightweight, isolated, portable unit that runs identically on any machine.
Container vs VM
Containers share the host OS kernel (seconds to start, ~MB). VMs run a full OS (minutes to start, ~GB). Docker gives you isolation at a fraction of the overhead.Install Docker
# Ubuntu / Debian (one-liner)
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER
newgrp docker
# Verify
docker version
docker run --rm hello-world
Core Concepts
| Concept | Description |
|---|---|
| Image | Read-only template (built from Dockerfile) |
| Container | Running instance of an image |
| Dockerfile | Instructions to build an image |
| Registry | Storage for images (Docker Hub, AWS ECR, GHCR) |
| Volume | Persistent data storage |
| Network | Communication layer between containers |
Write a Production Dockerfile
# Dockerfile — Node.js Application
# Stage 1: Install dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Stage 2: Build application
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 3: Production image (minimal)
FROM node:20-alpine AS production
ENV NODE_ENV=production
WORKDIR /app
# Security: run as non-root
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget --quiet --tries=1 --spider http://localhost:3000/health || exit 1
CMD ["node", "dist/server.js"]
# Build
docker build -t myapp:1.0.0 .
docker build -t myapp:1.0.0 --platform linux/amd64 . # for M1/M2 Macs
# Run
docker run -d -p 3000:3000 --name myapp \
--env-file .env \
--memory 512m --cpus 0.5 \
myapp:1.0.0
# Inspect
docker logs -f myapp
docker stats myapp
docker exec -it myapp /bin/sh
Docker Compose — Multi-Container Apps
# docker-compose.yml
version: '3.9'
services:
app:
build: { context: ., target: production }
ports: ["3000:3000"]
environment:
NODE_ENV: production
DB_HOST: postgres
REDIS_URL: redis://redis:6379
depends_on:
postgres: { condition: service_healthy }
redis: { condition: service_started }
restart: unless-stopped
networks: [app-net]
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: appuser
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- pg_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d myapp"]
interval: 10s
timeout: 5s
retries: 5
networks: [app-net]
redis:
image: redis:7-alpine
command: redis-server --appendonly yes --maxmemory 256mb
volumes: [redis_data:/data]
networks: [app-net]
nginx:
image: nginx:1.25-alpine
ports: ["80:80", "443:443"]
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on: [app]
networks: [app-net]
volumes:
pg_data:
redis_data:
networks:
app-net:
driver: bridge
docker compose up -d # start all services
docker compose logs -f app # follow app logs
docker compose ps # status
docker compose exec app sh # shell into app
docker compose down -v # stop + remove volumes
Essential Commands
# === Images ===
docker pull nginx:alpine
docker build -t myapp:latest .
docker images
docker rmi myapp:latest
docker image prune -a # remove unused images
# === Containers ===
docker run -d -p 80:80 --name web nginx:alpine
docker ps -a
docker stop web && docker rm web
docker restart web
docker inspect web
# === Volumes ===
docker volume create appdata
docker run -v appdata:/data nginx
# === Networks ===
docker network create mynet
docker run --network mynet --name db postgres:16
docker network inspect mynet
# === Registry ===
docker login ghcr.io
docker tag myapp:latest ghcr.io/username/myapp:v1.0
docker push ghcr.io/username/myapp:v1.0
.dockerignore
node_modules/
.git/
.github/
*.md
.env
.env.*
Dockerfile*
docker-compose*
coverage/
dist/
.DS_Store
Production Security Checklist
- ✅ Never run as root — always add
USERdirective - ✅ Use specific image tags — never
latestin prod - ✅ Scan images:
docker scout cves myapp:1.0.0 - ✅ Secrets via env files or Docker Secrets — never baked into image
- ✅ Read-only filesystem:
--read-onlywith tmpfs for writable dirs - ✅ Resource limits:
--memoryand--cpus
Best Practices Summary
- Multi-stage builds — dramatically reduce final image size
- Non-root user —
RUN adduser+USERdirective - HEALTHCHECK — define in every production Dockerfile
- Layer caching — copy
package.jsonbefore source code - Specific tags — pin exact versions for reproducible builds
- Scan images — integrate Docker Scout or Trivy in CI/CD
Found an error or want to suggest a topic?
Help us improve! Submit feedback, report mistakes, or request new tutorials via our Google Form.
Open Google Form