docker-kubernetes
Dockerfile best practices, multi-stage builds, docker-compose patterns, and Kubernetes concepts
When & Why to Use This Skill
This Claude skill provides comprehensive guidance on Docker and Kubernetes, focusing on containerization best practices, multi-stage builds, and efficient orchestration. It helps developers and DevOps engineers optimize image sizes, enhance container security, and manage complex microservices architectures using Docker Compose and Kubernetes manifests to ensure scalable and reproducible deployments.
Use Cases
- Optimizing Dockerfiles: Implementing multi-stage builds and layer caching to create minimal, high-performance production images.
- Local Environment Orchestration: Using Docker Compose patterns to manage multi-container applications with defined dependencies and health checks.
- Kubernetes Deployment: Designing resilient cloud-native applications using Pods, Deployments, and Services with proper resource limits and probes.
- Security Hardening: Applying container security best practices such as non-root user execution, secret management, and minimizing image attack surfaces.
- CI/CD Pipeline Integration: Creating reproducible build environments and deployment scripts for automated software delivery workflows.
| name | Docker & Kubernetes |
|---|---|
| description | Dockerfile best practices, multi-stage builds, docker-compose patterns, and Kubernetes concepts |
Docker & Kubernetes
When to Use
Perfect for:
- Containerizing applications for consistent deployment
- Microservices architecture
- CI/CD pipelines with reproducible builds
- Local development environments matching production
- Scaling applications across multiple machines
Not ideal for:
- GUI desktop applications (limited container benefits)
- Real-time high-performance computing (overhead)
- Single-server monoliths (overkill unless scaling needs exist)
Quick Reference
Dockerfile Best Practices
# Bad - large final image, hard to debug
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y python3 python3-pip
COPY . /app
WORKDIR /app
RUN pip install -r requirements.txt
CMD ["python3", "app.py"]
# Good - multi-stage, minimal final image, clear layers
FROM python:3.11-slim as builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
FROM python:3.11-slim
# Use non-root user
RUN useradd -m -u 1000 appuser
WORKDIR /app
# Copy only necessary files from builder
COPY --from=builder /root/.local /home/appuser/.local
COPY --chown=appuser:appuser app.py .
USER appuser
ENV PATH=/home/appuser/.local/bin:$PATH
ENV PYTHONUNBUFFERED=1
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD python -c "import requests; requests.get('http://localhost:8000/health')"
EXPOSE 8000
CMD ["python", "app.py"]
Multi-Stage Build Pattern
# Stage 1: Build
FROM node:18-alpine as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY . .
RUN npm run build
# Stage 2: Runtime
FROM node:18-alpine
RUN apk add --no-cache dumb-init
RUN addgroup -g 1000 app && adduser -u 1000 -G app -s /bin/sh -D app
WORKDIR /app
# Copy only runtime dependencies and built app
COPY --from=builder --chown=app:app /app/node_modules ./node_modules
COPY --from=builder --chown=app:app /app/dist ./dist
COPY --chown=app:app package.json .
USER app
EXPOSE 3000
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "dist/index.js"]
Docker Image Optimization
# Layer caching - order matters (least to most frequently changed)
FROM python:3.11-slim
# Stable dependency installation
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Application code (changes frequently)
COPY . /app
WORKDIR /app
CMD ["python", "app.py"]
Environment Configuration
# Build arguments (build-time)
FROM python:3.11-slim
ARG BUILD_DATE
ARG VCS_REF
ARG VERSION=1.0.0
LABEL org.label-schema.build-date=$BUILD_DATE \
org.label-schema.vcs-ref=$VCS_REF \
org.label-schema.version=$VERSION
# Runtime environment variables
ENV APP_ENV=production \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PORT=8000
EXPOSE $PORT
Docker Compose Pattern
version: '3.8'
services:
web:
build:
context: .
dockerfile: Dockerfile
container_name: myapp_web
ports:
- "8000:8000"
environment:
DATABASE_URL: postgresql://user:pass@db:5432/myapp
REDIS_URL: redis://cache:6379/0
depends_on:
db:
condition: service_healthy
cache:
condition: service_started
volumes:
- ./app:/app # Development only
networks:
- app_network
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
db:
image: postgres:15-alpine
container_name: myapp_db
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: myapp
volumes:
- db_data:/var/lib/postgresql/data
- ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- app_network
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user"]
interval: 10s
timeout: 5s
retries: 5
cache:
image: redis:7-alpine
container_name: myapp_cache
ports:
- "6379:6379"
volumes:
- cache_data:/data
networks:
- app_network
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
db_data:
cache_data:
networks:
app_network:
driver: bridge
Security Best Practices
# Use official base images
FROM python:3.11-slim
# Run as non-root user
RUN useradd -m -u 1000 appuser
USER appuser
# Minimize layer count and image size
RUN apt-get update && \
apt-get install -y --no-install-recommends curl && \
rm -rf /var/lib/apt/lists/*
# Use specific image tags (never "latest")
FROM postgres:15.1-alpine
# Set read-only filesystem where possible
RUN chmod -R 755 /app
# Use secrets management for sensitive data (Docker Swarm/Kubernetes)
# Never hardcode secrets in Dockerfile
Deep Dive
Health Checks
# HTTP-based health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
# Command-based health check
HEALTHCHECK --interval=30s --timeout=10s \
CMD python -c "import requests; requests.get('http://localhost:8000/health')"
# Shell command health check
HEALTHCHECK --interval=10s --timeout=5s \
CMD ["CMD-SHELL", "pg_isready -U postgres || exit 1"]
Docker Networking
# Bridge network (default, containers can communicate by name)
version: '3.8'
services:
web:
image: myapp
networks:
- backend
db:
image: postgres
networks:
- backend
networks:
backend:
driver: bridge
# Host network (container shares host's network - performance critical)
services:
high_perf:
image: myapp
network_mode: host # Performance, but less isolated
# Overlay network (for Swarm mode)
networks:
distributed:
driver: overlay
driver_opts:
com.docker.network.driver.overlay.vxlan_list: "4789"
Volume Management
# Named volumes (managed by Docker, persistent)
services:
db:
image: postgres
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
driver: local
# Bind mounts (host directory mounted into container)
services:
web:
image: myapp
volumes:
- /host/path:/container/path:ro # Read-only
# Tmpfs volumes (in-memory, lost on container restart)
services:
app:
image: myapp
tmpfs:
- /tmp
- /run
Container Logging
services:
app:
image: myapp
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
labels: "service=myapp,env=production"
# Alternative: Log to syslog
app_syslog:
image: myapp
logging:
driver: syslog
options:
syslog-address: "udp://localhost:514"
syslog-facility: "daemon"
# Alternative: Log to ELK stack
app_elk:
image: myapp
logging:
driver: splunk
options:
splunk-token: ${SPLUNK_TOKEN}
splunk-url: https://localhost:8088
Kubernetes Basics
Pod (Smallest Kubernetes Unit)
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: web
image: myapp:1.0.0
ports:
- containerPort: 8000
env:
- name: APP_ENV
value: "production"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secret
key: url
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /ready
port: 8000
initialDelaySeconds: 5
periodSeconds: 10
Deployment (Stateless Application)
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
labels:
app: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: web
image: myapp:1.0.0
ports:
- containerPort: 8000
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secret
key: url
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp
topologyKey: kubernetes.io/hostname
Service (Network Access)
apiVersion: v1
kind: Service
metadata:
name: myapp-service
spec:
type: LoadBalancer # or ClusterIP, NodePort
selector:
app: myapp
ports:
- name: http
port: 80
targetPort: 8000
protocol: TCP
sessionAffinity: ClientIP
ConfigMap & Secret
---
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: "production"
LOG_LEVEL: "info"
config.json: |
{
"timeout": 30,
"retries": 3
}
---
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
data:
url: cG9zdGdyZXM6Ly91c2VyOnBhc3NAZGI6NTQzMi9teWFwcA== # base64 encoded
Anti-Patterns
DON'T: Use "latest" Tag
# Bad - unpredictable, breaks reproducibility
FROM node:latest
FROM python:latest
# Good - specific version
FROM node:18.17.0-alpine
FROM python:3.11.5-slim
DON'T: Run as Root
# Bad - security vulnerability
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y myapp
CMD ["myapp"]
# Good - use non-root user
FROM ubuntu:22.04
RUN useradd -m -u 1000 appuser
USER appuser
CMD ["myapp"]
DON'T: Layer Multiple Commands
# Bad - creates extra layers
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y vim
RUN apt-get clean
# Good - single RUN with && chains
RUN apt-get update && \
apt-get install -y curl vim && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
DON'T: Copy Everything
# Bad - includes unnecessary files
COPY . /app
# Good - be selective
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY src/ ./src/
COPY config/ ./config/
DON'T: Ignore Resource Limits
# Bad - no resource limits, can consume entire node
spec:
containers:
- name: app
image: myapp
# Good - set requests and limits
spec:
containers:
- name: app
image: myapp
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
DON'T: Skip Health Checks
# Bad - no way to detect failing app
FROM mybase
COPY app /app
CMD ["app"]
# Good - include health check
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
CMD ["app"]
DON'T: Hardcode Configuration
# Bad - configuration baked into image
ENV DATABASE_URL=postgresql://prod-db:5432/myapp
ENV API_KEY=sk_live_xxx
# Good - use environment variables and secrets
# Leave empty or use defaults for development
ENV DATABASE_URL=postgresql://localhost:5432/myapp
# Use Kubernetes Secrets or docker-compose .env file
DON'T: Combine Multiple Applications
# Bad - violates single responsibility
FROM ubuntu
RUN apt-get install -y nginx python flask
COPY . /app
CMD ["supervisord"] # Running multiple services
# Good - one container per concern
FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf
---
FROM python:3.11
COPY app.py /app/
CMD ["python", "app.py"]