docker-deployment
SKILL.md
Docker Deployment Skill
Provides production-ready Docker configurations, multi-stage builds, and deployment best practices.
Purpose
This skill provides:
- Optimized Dockerfile patterns for different tech stacks
- Multi-stage build strategies
- Docker Compose configurations
- Container security best practices
- Docker registry integration
- Health checks and monitoring
When to Use
- "Create a Dockerfile for Node.js app"
- "Optimize Docker image size"
- "Set up Docker Compose for microservices"
- "Implement Docker health checks"
- "Deploy with Docker Swarm/Kubernetes"
Node.js Dockerfile (Multi-Stage Build)
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies (including dev dependencies for build)
RUN npm ci
# Copy source code
COPY . .
# Build the application
RUN npm run build
# Prune dev dependencies
RUN npm prune --production
# Production stage
FROM node:20-alpine AS production
# Add non-root user for security
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
# Copy built artifacts and production dependencies
COPY /app/dist ./dist
COPY /app/node_modules ./node_modules
COPY /app/package*.json ./
# Use non-root user
USER nodejs
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})"
# Start application
CMD ["node", "dist/index.js"]
Next.js Dockerfile
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
FROM node:20-alpine AS builder
WORKDIR /app
COPY /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED 1
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
COPY /app/public ./public
COPY /app/.next/standalone ./
COPY /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
CMD ["node", "server.js"]
Python FastAPI Dockerfile
FROM python:3.11-slim AS builder
WORKDIR /app
# Install build dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends gcc && \
rm -rf /var/lib/apt/lists/*
# Copy requirements
COPY requirements.txt .
# Install Python dependencies
RUN pip install --user --no-cache-dir -r requirements.txt
# Production stage
FROM python:3.11-slim
WORKDIR /app
# Copy Python dependencies from builder
COPY /root/.local /root/.local
# Copy application code
COPY . .
# Add local bin to PATH
ENV PATH=/root/.local/bin:$PATH
# Create non-root user
RUN useradd -m -u 1001 appuser && \
chown -R appuser:appuser /app
USER appuser
EXPOSE 8000
HEALTHCHECK \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health').read()"
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Docker Compose - Full Stack Application
version: '3.9'
services:
# Frontend (Next.js)
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NEXT_PUBLIC_API_URL=http://api:4000
depends_on:
api:
condition: service_healthy
networks:
- app-network
restart: unless-stopped
# Backend API (Node.js)
api:
build:
context: ./api
dockerfile: Dockerfile
ports:
- "4000:4000"
environment:
- DATABASE_URL=postgresql://postgres:password@postgres:5432/myapp
- REDIS_URL=redis://redis:6379
- NODE_ENV=production
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:4000/health')"]
interval: 10s
timeout: 3s
retries: 3
start_period: 30s
networks:
- app-network
restart: unless-stopped
volumes:
- ./api/uploads:/app/uploads
# PostgreSQL Database
postgres:
image: postgres:16-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=myapp
volumes:
- postgres-data:/var/lib/postgresql/data
- ./init-db.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 5
networks:
- app-network
restart: unless-stopped
# Redis Cache
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
networks:
- app-network
restart: unless-stopped
# Nginx Reverse Proxy
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- frontend
- api
networks:
- app-network
restart: unless-stopped
networks:
app-network:
driver: bridge
volumes:
postgres-data:
redis-data:
Docker Security Best Practices
Minimal Base Image
# Use distroless for minimal attack surface
FROM gcr.io/distroless/nodejs20-debian12
WORKDIR /app
COPY /app/dist ./dist
COPY /app/node_modules ./node_modules
CMD ["dist/index.js"]
Multi-Layer Security
FROM node:20-alpine
# Security: Run as non-root
RUN addgroup -g 1001 app && \
adduser -D -u 1001 -G app app
WORKDIR /app
# Security: Use specific versions
COPY package*.json ./
RUN npm ci --only=production && \
npm cache clean --force
# Security: Set file permissions
COPY . .
# Security: Drop capabilities
USER app
# Security: Read-only filesystem
# (mount volumes for writable areas)
VOLUME ["/app/data"]
EXPOSE 3000
CMD ["node", "index.js"]
.dockerignore
# Dependencies
node_modules
npm-debug.log
# Testing
coverage
.jest
*.test.js
# Environment
.env
.env.local
.env.*.local
# Git
.git
.gitignore
# CI/CD
.github
.gitlab-ci.yml
# Documentation
README.md
docs/
# Build artifacts
dist
build
*.log
# IDE
.vscode
.idea
*.swp
Docker Registry & CI/CD
GitHub Container Registry
# .github/workflows/docker-publish.yml
name: Docker Build & Push
on:
push:
branches: [ main ]
tags: [ 'v*' ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Log in to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
Health Checks
Node.js Health Endpoint
// health.ts
export function setupHealthCheck(app: Express) {
app.get('/health', async (req, res) => {
const checks = {
uptime: process.uptime(),
timestamp: Date.now(),
database: await checkDatabase(),
redis: await checkRedis(),
memory: process.memoryUsage(),
}
const isHealthy = checks.database && checks.redis
res.status(isHealthy ? 200 : 503).json(checks)
})
}
async function checkDatabase(): Promise<boolean> {
try {
await db.raw('SELECT 1')
return true
} catch {
return false
}
}
async function checkRedis(): Promise<boolean> {
try {
await redis.ping()
return true
} catch {
return false
}
}
Monitoring & Logging
Docker Compose with Logging
services:
app:
image: myapp:latest
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
labels:
- "prometheus.scrape=true"
- "prometheus.port=9090"
Prometheus Metrics Endpoint
// metrics.ts
import promClient from 'prom-client'
const register = new promClient.Registry()
promClient.collectDefaultMetrics({ register })
const httpRequestDuration = new promClient.Histogram({
name: 'http_request_duration_ms',
help: 'Duration of HTTP requests in ms',
labelNames: ['method', 'route', 'status_code'],
buckets: [10, 50, 100, 500, 1000, 5000],
})
register.registerMetric(httpRequestDuration)
export function setupMetrics(app: Express) {
app.get('/metrics', async (req, res) => {
res.set('Content-Type', register.contentType)
res.end(await register.metrics())
})
}
Best Practices Checklist
- ✅ Use multi-stage builds to minimize image size
- ✅ Run containers as non-root user
- ✅ Use specific base image versions (not
latest) - ✅ Implement health checks
- ✅ Set resource limits (CPU/memory)
- ✅ Use
.dockerignoreto exclude unnecessary files - ✅ Scan images for vulnerabilities (Snyk, Trivy)
- ✅ Use secrets management (not env vars for sensitive data)
- ✅ Implement proper logging
- ✅ Add monitoring and metrics
Integration with Agents
Works best with:
- devops-automation agent - Generates Docker configs
- security-auditor agent - Scans for container vulnerabilities
- performance-optimizer agent - Optimizes image size and startup time
Tools & Resources
- Docker: Official container platform
- Docker Compose: Multi-container orchestration
- Trivy: Vulnerability scanner
- Dive: Image layer analyzer
- Hadolint: Dockerfile linter
References
Weekly Installs
5
Repository
pfangueiro/clau…e-agentsGitHub Stars
2
First Seen
13 days ago
Security Audits
Installed on
gemini-cli5
opencode5
codebuddy5
github-copilot5
codex5
kimi-cli5