| name | docker |
| description | Docker containerization - images, containers, volumes, networking, docker-compose, best practices |
| metadata | {"language":"bash","audience":"developers"} |
Overview
Docker is a platform for developing, shipping, and running applications in containers. Use this skill when working with Docker or Docker Compose.
Installation
Docker Engine
sudo apt update
sudo apt install docker.io
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER
Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
Verify installation:
docker --version
docker-compose --version
Basic Concepts
Images
- Image: A read-only template for creating containers
- Container: A runnable instance of an image
- Tag: Version identifier for images (e.g.,
nginx:latest)
- Registry: Storage for images (Docker Hub, GHCR, ECR, etc.)
Common Commands
docker images
docker image ls
docker pull nginx:latest
docker rmi nginx:latest
docker build -t myapp:latest .
docker tag myapp:latest registry.io/myapp:latest
docker push registry.io/myapp:latest
Docker Contexts
Docker contexts allow you to manage connections to multiple Docker hosts from a single Docker CLI. Useful for switching between local Docker, remote servers, or Kubernetes clusters.
Basic Context Management
docker context ls
docker context show
docker context use my-remote-host
docker context create my-remote-host \
--docker "host=ssh://user@remote-server:22"
docker context create my-context --docker "host=tcp://localhost:2375"
docker context inspect my-remote-host
docker context rm my-remote-host
SSH Context
Connect to a remote Docker host via SSH:
docker context create production \
--docker "host=ssh://user@production-server"
docker context use production
docker ps
docker run -d nginx:latest
Kubernetes Context
kubectl config get-contexts
docker context create k8s-prod \
--kubernetes "context-name=production"
docker context use k8s-prod
Use with Docker Compose
docker --context my-remote-host compose up -d
COMPOSE_DOCKER_CLI_HOST=1 docker compose up -d
Best Practices
- Name meaningfully - Use prefixes like
local-, prod-, dev-
- Test before switching - Use
docker context inspect to verify
- Keep local default - Keep
default or local for local development
- Document remote connections - Note SSH keys and endpoints
docker context create local
docker context create dev-server --docker "host=ssh://dev@dev-server"
docker context create prod-server --docker "host=ssh://prod@prod-server"
docker context use dev-server
Dockerfile
Best Practices
- Use multi-stage builds - Reduce final image size
- Order commands by change frequency - Cache unchanged layers
- Use specific tags - Avoid
latest in production
- Use .dockerignore - Exclude unnecessary files
- Run as non-root - Security best practice
- Use official base images - Better security and maintenance
Node.js Example
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER node
EXPOSE 3000
CMD ["node", "dist/index.js"]
Python Example
FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY . .
ENV PATH=/root/.local/bin:$PATH
EXPOSE 8000
CMD ["python", "main.py"]
.dockerignore
node_modules
.git
.gitignore
.env
.env.*
README.md
dist
build
coverage
*.log
.DS_Store
Containers
Run a Container
docker run -d myapp:latest
docker run -d -p 8080:3000 myapp:latest
docker run -d -v /host/path:/container/path myapp:latest
docker run -d -e NODE_ENV=production -e API_KEY=xxx myapp:latest
docker run -d --name my-container myapp:latest
docker run -it ubuntu:latest /bin/bash
docker run --rm myapp:latest
Container Management
docker ps
docker ps -a
docker stop my-container
docker start my-container
docker restart my-container
docker rm my-container
docker container prune
docker logs -f my-container
docker exec -it my-container sh
docker inspect my-container
docker stats my-container
Volumes
Named Volumes
docker volume create my-data
docker volume ls
docker volume inspect my-data
docker volume rm my-data
Bind Mounts
docker run -v /host/path:/container/path myapp:latest
docker run -v /host/path:/container/path:ro myapp:latest
Use in Dockerfile
VOLUME /app/data
Networking
Networks
docker network create my-network
docker network ls
docker network connect my-network my-container
docker network disconnect my-network my-container
Port Exposure
EXPOSE 3000 8080
Docker Compose
Basic Structure
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
volumes:
- ./data:/app/data
depends_on:
- db
restart: unless-stopped
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- db-data:/var/lib/postgresql/data
restart: unless-stopped
volumes:
db-data:
Common Commands
docker-compose up -d
docker-compose up -d --build
docker-compose down
docker-compose down -v
docker-compose logs -f
docker-compose ps
docker-compose exec app sh
docker-compose up -d --scale app=3
Healthchecks
services:
app:
build: .
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Profiles
services:
app:
build: .
debug:
build: .
profiles:
- debug
command: ["sleep", "infinity"]
Run with profile: docker-compose --profile debug up
Development
Development with Volumes
services:
app:
build:
context: .
target: development
volumes:
- .:/app
- /app/node_modules
environment:
- NODE_ENV=development
command: npm run dev
Hot Reload
For Node.js with nodemon:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]
Security Best Practices
- Don't run as root - Use
USER directive
- Scan for vulnerabilities - Use
docker scout or trivy
- Use specific tags - Not
latest
- Read-only containers - Use
--read-only flag
- Limit capabilities - Use
--cap-drop and --cap-add
- Secrets management - Use Docker secrets or environment variables
- Multi-stage builds - Minimize attack surface
docker scout cves myapp:latest
docker run \
--read-only \
--cap-drop ALL \
--user 1000:1000 \
myapp:latest
Debugging
docker run -it --rm myapp:latest sh
dive myapp:latest
docker history myapp:latest
docker exec sh
docker cp my-container:/app/logs ./logs
Common Patterns
Node.js + Nginx
services:
app:
build: ./app
expose:
- "3000"
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- app
Database + Backup
services:
db:
image: postgres:15-alpine
volumes:
- db-data:/var/lib/postgresql/data
backup:
image: postgres:15-alpine
volumes:
- ./backups:/backups
command: >
sh -c "while true; do
pg_dump -h db -U postgres mydb > /backups/backup-$$(date +%Y%m%d-%H%M%S).sql;
sleep 86400;
done"
depends_on:
- db
Tips
- Use
docker system prune -a to clean up unused resources
- Use
--force-rm when building to remove intermediate containers
- Use
-f flag to force operations
- Use
--no-cache for clean builds
- Tag images before pushing to registries
- Use
docker-compose config to validate compose files