Files
APAW/.kilo/rules/docker.md

9.4 KiB

Docker & Containerization Rules

Essential rules for Docker, Docker Compose, Docker Swarm, and container technologies.

Dockerfile Best Practices

Layer Optimization

  • Minimize layers by combining commands
  • Order layers from least to most frequently changing
  • Use multi-stage builds to reduce image size
  • Clean up package manager caches
# ✅ Good: Multi-stage build with layer optimization
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
USER node
EXPOSE 3000
CMD ["node", "server.js"]

# ❌ Bad: Single stage, many layers
FROM node:20
RUN npm install -g nodemon
WORKDIR /app
COPY . .
RUN npm install
EXPOSE 3000
CMD ["nodemon", "server.js"]

Security

  • Run as non-root user
  • Use specific image versions, not latest
  • Scan images for vulnerabilities
  • Don't store secrets in images
# ✅ Good
FROM node:20-alpine
RUN addgroup -g 1001 appgroup && \
    adduser -u 1001 -G appgroup -D appuser
WORKDIR /app
COPY --chown=appuser:appgroup . .
USER appuser
CMD ["node", "server.js"]

# ❌ Bad
FROM node:latest  # Unpredictable version
# Running as root (default)
COPY . .
CMD ["node", "server.js"]

Caching Strategy

# ✅ Good: Dependencies cached separately
COPY package*.json ./
RUN npm ci
COPY . .

# ❌ Bad: All code copied before dependencies
COPY . .
RUN npm install

Docker Compose

Service Structure

  • Use version 3.8+ for modern features
  • Define services in logical order
  • Use environment variables for configuration
  • Set resource limits
# ✅ Good
version: '3.8'

services:
  app:
    image: myapp:latest
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgres://db:5432/app
    depends_on:
      db:
        condition: service_healthy
    networks:
      - app-network
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

  db:
    image: postgres:15-alpine
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    networks:
      - app-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $POSTGRES_USER"]
      interval: 10s
      timeout: 5s
      retries: 5

networks:
  app-network:
    driver: bridge

volumes:
  postgres-data:

Environment Variables

  • Use .env files for local development
  • Never commit .env files with secrets
  • Use Docker secrets for sensitive data in Swarm
# .env (gitignored)
NODE_ENV=production
DB_PASSWORD=secure_password_here
JWT_SECRET=your_jwt_secret_here
# docker-compose.yml
services:
  app:
    env_file:
      - .env
    # OR explicit for non-sensitive
    environment:
      - NODE_ENV=production
    # Secrets for sensitive data in Swarm
    secrets:
      - db_password

Network Patterns

# ✅ Good: Separated networks for security
networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true  # No external access

services:
  web:
    networks:
      - frontend
      - backend
  api:
    networks:
      - backend
  db:
    networks:
      - backend

Volume Management

# ✅ Good: Named volumes with labels
volumes:
  postgres-data:
    driver: local
    labels:
      - "app=myapp"
      - "type=database"

services:
  db:
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./init-scripts:/docker-entrypoint-initdb.d:ro

Docker Swarm

Service Deployment

# docker-compose.yml (Swarm compatible)
version: '3.8'

services:
  api:
    image: myapp/api:latest
    deploy:
      mode: replicated
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
        failure_action: rollback
      rollback_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
      placement:
        constraints:
          - node.role == worker
        preferences:
          - spread: node.id
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M
    networks:
      - app-network
    secrets:
      - db_password
      - jwt_secret
    configs:
      - app_config

networks:
  app-network:
    driver: overlay
    attachable: true

secrets:
  db_password:
    external: true
  jwt_secret:
    external: true

configs:
  app_config:
    external: true

Stack Deployment

# Deploy stack
docker stack deploy -c docker-compose.yml mystack

# List services
docker stack services mystack

# Scale service
docker service scale mystack_api=5

# Update service
docker service update --image myapp/api:v2 mystack_api

# Rollback
docker service rollback mystack_api

Health Checks

services:
  api:
    # Health check in Dockerfile
    healthcheck:
      test: ["CMD", "node", "healthcheck.js"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s

    # Or in compose
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      timeout: 10s
      retries: 3

Secrets Management

# Create secret
echo "my_secret_password" | docker secret create db_password -

# Create secret from file
docker secret create jwt_secret ./jwt_secret.txt

# List secrets
docker secret ls

# Use in compose
secrets:
  db_password:
    external: true

Config Management

# Create config
docker config create app_config ./config.json

# Use in compose
configs:
  app_config:
    external: true

services:
  api:
    configs:
      - app_config

Container Security

Image Security

# Scan image for vulnerabilities
docker scout vulnerabilities myapp:latest
trivy image myapp:latest

# Check image for secrets
gitleaks --image myapp:latest

Runtime Security

# ✅ Good: Security measures
FROM node:20-alpine

# Create non-root user
RUN addgroup -g 1001 appgroup && \
    adduser -u 1001 -G appgroup -D appuser

# Set read-only filesystem
RUN chmod -R 755 /app && \
    chown -R appuser:appgroup /app

WORKDIR /app
COPY --chown=appuser:appgroup . .

# Drop all capabilities
USER appuser
VOLUME ["/tmp"]

CMD ["node", "server.js"]

Network Security

# ✅ Good: Limited network access
services:
  api:
    networks:
      - backend
    # No ports exposed to host

  db:
    networks:
      - backend
    # Internal network only

networks:
  backend:
    internal: true  # No internet access

Resource Limits

services:
  api:
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M

Common Patterns

Development Setup

# docker-compose.dev.yml
version: '3.8'
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile.dev
    volumes:
      - .:/app
      - /app/node_modules
    environment:
      - NODE_ENV=development
    ports:
      - "3000:3000"
    command: npm run dev

Production Setup

# docker-compose.prod.yml
version: '3.8'
services:
  app:
    image: myapp:${VERSION}
    environment:
      - NODE_ENV=production
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 10s
    healthcheck:
      test: ["CMD", "node", "healthcheck.js"]
      interval: 30s
      timeout: 10s
      retries: 3

Multi-Environment

# Override files
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

Logging

services:
  app:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        labels: "app,environment"

CI/CD Integration

Build Pipeline

# .github/workflows/docker.yml
name: Docker Build

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Build image
        run: docker build -t myapp:${{ github.sha }} .
      
      - name: Scan image
        run: trivy image myapp:${{ github.sha }}
      
      - name: Push to registry
        run: |
          echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USER }} --password-stdin
          docker push myapp:${{ github.sha }}

Troubleshooting

Common Commands

# View logs
docker-compose logs -f app

# Execute in container
docker-compose exec app sh

# Check health
docker inspect --format='{{.State.Health.Status}}' <container>

# View resource usage
docker stats

# Remove unused resources
docker system prune -a

# Debug network
docker network inspect app-network

# Swarm diagnostics
docker node ls
docker service ps mystack_api

Prohibitions

  • DO NOT run containers as root
  • DO NOT use latest tag in production
  • DO NOT expose unnecessary ports
  • DO NOT store secrets in images
  • DO NOT use privileged mode unnecessarily
  • DO NOT mount host directories without restrictions
  • DO NOT skip health checks in production
  • DO NOT ignore vulnerability scans