DevOps Docker Standards
This skill provides Docker containerization best practices.
When to Use
- •Use this skill when creating or modifying Dockerfiles
- •Use this skill when setting up docker-compose configurations
- •Use this skill when optimizing container images
Instructions
1. Dockerfile Best Practices
Multi-Stage Builds (Mandatory)
ALWAYS use multi-stage builds to minimize final image size.
dockerfile
# Stage 1: Builder FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # Stage 2: Runner FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production # Create non-root user RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 appuser COPY --from=builder /app/dist ./dist COPY --from=builder /app/node_modules ./node_modules USER appuser EXPOSE 3000 CMD ["node", "dist/main.js"]
Base Images
- •Use
alpineorslimversions (e.g.,node:20-alpine). - •NEVER use
:latesttag. - •Pin specific versions for reproducibility.
dockerfile
# Good FROM node:20.10.0-alpine # Bad FROM node:latest
User Permissions
Implement a non-root user for security.
dockerfile
RUN addgroup --system --gid 1001 appgroup RUN adduser --system --uid 1001 appuser USER appuser
2. Layer Optimization
Order instructions from least to most frequently changed.
dockerfile
# Good order (least changed first) FROM node:20-alpine WORKDIR /app # Dependencies change less often COPY package*.json ./ RUN npm ci --only=production # Source changes more often COPY . . CMD ["node", "index.js"]
3. .dockerignore (Mandatory)
Create .dockerignore to exclude unnecessary files.
code
# .dockerignore .git .gitignore node_modules npm-debug.log Dockerfile docker-compose*.yml .env .env.* *.md .vscode .idea coverage dist .next
4. Docker Compose
yaml
# docker-compose.yml
version: '3.8'
services:
api:
container_name: myapp-api
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=${DATABASE_URL}
depends_on:
db:
condition: service_healthy
networks:
- app-network
restart: unless-stopped
db:
container_name: myapp-db
image: postgres:15-alpine
environment:
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: ${DB_NAME}
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
postgres-data:
5. Key Docker Compose Rules
- •Naming: Explicitly name containers (
container_name: my-app-api). - •Networks: Define a custom bridge network; do not use the default.
- •Healthchecks: Define for dependent services.
- •Volumes: Use named volumes for data persistence.
- •Restart Policy: Use
unless-stoppedoralways.
6. Environment Variables
Never hardcode secrets. Use .env file passing.
yaml
# docker-compose.yml
services:
api:
env_file:
- .env
environment:
# Override or add specific vars
- NODE_ENV=production
Create .env.example for documentation:
code
# .env.example DATABASE_URL=postgresql://user:pass@localhost:5432/mydb JWT_SECRET=your-secret-here
7. Production Checklist
- • Multi-stage build used
- • Non-root user configured
- • Specific image versions (no
:latest) - • .dockerignore present
- • Health checks defined
- • Resource limits set (optional but recommended)
- • Secrets not hardcoded