--- name: docker-kubernetes description: Docker containerization and Kubernetes orchestration patterns. Use when building containers, writing Dockerfiles, or deploying to Kubernetes. --- # Docker & Kubernetes Skill ## Dockerfile Best Practices ### Multi-Stage Build (Python) ```dockerfile # Build stage FROM python:3.12-slim as builder WORKDIR /app # Install build dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ && rm -rf /var/lib/apt/lists/* # Install Python dependencies COPY pyproject.toml uv.lock ./ RUN pip install uv && uv sync --frozen --no-dev # Production stage FROM python:3.12-slim as production WORKDIR /app # Create non-root user RUN groupadd -r appuser && useradd -r -g appuser appuser # Copy only necessary files from builder COPY --from=builder /app/.venv /app/.venv COPY src/ ./src/ # Set environment ENV PATH="/app/.venv/bin:$PATH" ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1 # Switch to non-root user USER appuser EXPOSE 8000 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"] ``` ### Multi-Stage Build (Node.js) ```dockerfile # Build stage FROM node:22-alpine as builder WORKDIR /app # Install dependencies first (layer caching) COPY package*.json ./ RUN npm ci # Build application COPY . . RUN npm run build # Production stage FROM node:22-alpine as production WORKDIR /app # Create non-root user RUN addgroup -S appuser && adduser -S appuser -G appuser # Copy only production dependencies and built files COPY --from=builder /app/package*.json ./ RUN npm ci --only=production && npm cache clean --force COPY --from=builder /app/dist ./dist USER appuser EXPOSE 3000 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1 CMD ["node", "dist/main.js"] ``` ### Multi-Stage Build (Rust) ```dockerfile # Build stage FROM rust:1.75-slim as builder WORKDIR /app # Create a dummy project for dependency caching RUN cargo new --bin app WORKDIR /app/app # Copy manifests and build dependencies COPY Cargo.toml Cargo.lock ./ RUN cargo build --release && rm -rf src # Copy source and build COPY src ./src RUN touch src/main.rs && cargo build --release # Production stage FROM debian:bookworm-slim as production # Install runtime dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ && rm -rf /var/lib/apt/lists/* # Create non-root user RUN groupadd -r appuser && useradd -r -g appuser appuser COPY --from=builder /app/app/target/release/app /usr/local/bin/app USER appuser EXPOSE 8080 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD ["/usr/local/bin/app", "health"] CMD ["/usr/local/bin/app"] ``` ## Docker Compose ### Development Setup ```yaml # docker-compose.yml services: app: build: context: . target: development ports: - "8000:8000" volumes: - .:/app - /app/.venv # Exclude venv from mount environment: - DATABASE_URL=postgresql://user:pass@db:5432/myapp - REDIS_URL=redis://redis:6379/0 - DEBUG=true depends_on: db: condition: service_healthy redis: condition: service_started db: image: postgres:16-alpine environment: POSTGRES_USER: user POSTGRES_PASSWORD: pass POSTGRES_DB: myapp volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U user -d myapp"] interval: 5s timeout: 5s retries: 5 redis: image: redis:7-alpine volumes: - redis_data:/data volumes: postgres_data: redis_data: ``` ### Production Setup ```yaml # docker-compose.prod.yml services: app: image: ${REGISTRY}/myapp:${VERSION} deploy: replicas: 3 resources: limits: cpus: '0.5' memory: 512M reservations: cpus: '0.25' memory: 256M restart_policy: condition: on-failure delay: 5s max_attempts: 3 environment: - DATABASE_URL_FILE=/run/secrets/db_url secrets: - db_url healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s secrets: db_url: external: true ``` ## Kubernetes Manifests ### Deployment ```yaml # k8s/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: myapp labels: app: myapp spec: replicas: 3 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 1000 containers: - name: myapp image: myregistry/myapp:v1.0.0 ports: - containerPort: 8000 resources: requests: cpu: "100m" memory: "128Mi" limits: cpu: "500m" memory: "512Mi" env: - name: DATABASE_URL valueFrom: secretKeyRef: name: myapp-secrets key: database-url livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 10 periodSeconds: 10 readinessProbe: httpGet: path: /ready port: 8000 initialDelaySeconds: 5 periodSeconds: 5 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL ``` ### Service ```yaml # k8s/service.yaml apiVersion: v1 kind: Service metadata: name: myapp spec: selector: app: myapp ports: - port: 80 targetPort: 8000 type: ClusterIP --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt-prod spec: tls: - hosts: - myapp.example.com secretName: myapp-tls rules: - host: myapp.example.com http: paths: - path: / pathType: Prefix backend: service: name: myapp port: number: 80 ``` ### ConfigMap and Secrets ```yaml # k8s/config.yaml apiVersion: v1 kind: ConfigMap metadata: name: myapp-config data: LOG_LEVEL: "info" CACHE_TTL: "3600" --- apiVersion: v1 kind: Secret metadata: name: myapp-secrets type: Opaque stringData: database-url: postgresql://user:pass@db:5432/myapp # Use sealed-secrets in production ``` ### Horizontal Pod Autoscaler ```yaml # k8s/hpa.yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: myapp spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: myapp minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80 ``` ## Helm Chart Structure ``` myapp-chart/ ├── Chart.yaml ├── values.yaml ├── values-prod.yaml ├── templates/ │ ├── _helpers.tpl │ ├── deployment.yaml │ ├── service.yaml │ ├── ingress.yaml │ ├── configmap.yaml │ ├── secret.yaml │ └── hpa.yaml └── charts/ ``` ### values.yaml ```yaml replicaCount: 2 image: repository: myregistry/myapp tag: latest pullPolicy: IfNotPresent service: type: ClusterIP port: 80 ingress: enabled: true host: myapp.example.com tls: true resources: requests: cpu: 100m memory: 128Mi limits: cpu: 500m memory: 512Mi autoscaling: enabled: true minReplicas: 2 maxReplicas: 10 targetCPUUtilization: 70 ``` ## Commands ```bash # Docker docker build -t myapp:latest . docker build --target development -t myapp:dev . docker run -p 8000:8000 myapp:latest docker compose up -d docker compose logs -f app docker compose down -v # Kubernetes kubectl apply -f k8s/ kubectl get pods -l app=myapp kubectl logs -f deployment/myapp kubectl rollout status deployment/myapp kubectl rollout undo deployment/myapp kubectl port-forward svc/myapp 8000:80 # Helm helm install myapp ./myapp-chart helm upgrade myapp ./myapp-chart -f values-prod.yaml helm rollback myapp 1 helm uninstall myapp ``` ## Security Checklist - [ ] Run as non-root user - [ ] Use multi-stage builds (minimal final image) - [ ] Pin base image versions - [ ] Scan images for vulnerabilities (Trivy, Snyk) - [ ] No secrets in images or environment variables - [ ] Read-only root filesystem where possible - [ ] Drop all capabilities, add only needed ones - [ ] Set resource limits - [ ] Use network policies - [ ] Enable Pod Security Standards