Agent skill
faion-docker-skill
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/faion-docker-skill
SKILL.md
Docker Operations Mastery
Container Development and Deployment Best Practices (2025-2026)
Quick Reference
| Area | Key Elements |
|---|---|
| Dockerfile | FROM, RUN, COPY, WORKDIR, ENV, CMD, ENTRYPOINT |
| Multi-stage | Builder pattern, minimal runtime images |
| Compose | Services, networks, volumes, dependencies |
| Optimization | Layer caching, image size, build time |
| Security | Non-root users, secrets, scanning |
| Networking | Bridge, host, overlay, custom networks |
| Volumes | Named volumes, bind mounts, tmpfs |
| Registry | Push, pull, tagging, private registries |
Core Principles
1. Build Once, Run Anywhere
Source Code
|
v
Dockerfile --> docker build --> Image --> docker run --> Container
|
v
Registry (push/pull)
2. Image Layering
Docker images are built in layers. Each instruction creates a new layer.
Layer 4: CMD ["python", "app.py"] (0 MB)
Layer 3: COPY . /app (50 MB)
Layer 2: RUN pip install -r req.txt (200 MB)
Layer 1: FROM python:3.12-slim (150 MB)
Rule: Order instructions from least to most frequently changing for optimal caching.
Dockerfile Patterns
Base Image Selection
| Image Type | Example | Size | Use Case |
|---|---|---|---|
| Full | python:3.12 |
~900MB | Development, debugging |
| Slim | python:3.12-slim |
~150MB | Production balance |
| Alpine | python:3.12-alpine |
~50MB | Minimal size |
| Distroless | gcr.io/distroless/python3 |
~30MB | Maximum security |
Recommendation: Start with -slim, move to Alpine/Distroless for production.
Essential Instructions
# Base image - always pin version
FROM python:3.12-slim
# Labels for metadata
LABEL maintainer="[email protected]"
LABEL version="1.0.0"
LABEL description="Production API service"
# Set working directory
WORKDIR /app
# Environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
# Install system dependencies (combine RUN commands)
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# Copy dependency files first (for layer caching)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Create non-root user
RUN useradd --create-home --shell /bin/bash appuser
USER appuser
# Expose port (documentation only)
EXPOSE 8000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
# Entry point and command
ENTRYPOINT ["python"]
CMD ["app.py"]
CMD vs ENTRYPOINT
| Instruction | Purpose | Override |
|---|---|---|
| ENTRYPOINT | Defines executable | --entrypoint flag |
| CMD | Default arguments | Command line args |
# Pattern 1: ENTRYPOINT for fixed command
ENTRYPOINT ["python", "app.py"]
CMD ["--port", "8000"] # docker run myapp --port 9000
# Pattern 2: CMD for flexible command
CMD ["python", "app.py"] # docker run myapp sh (replaces entirely)
# Pattern 3: Combined (recommended)
ENTRYPOINT ["./docker-entrypoint.sh"]
CMD ["gunicorn", "app:app"]
Shell Form vs Exec Form
# Exec form (recommended) - runs directly
CMD ["python", "app.py"]
ENTRYPOINT ["./entrypoint.sh"]
# Shell form - runs via /bin/sh -c
CMD python app.py
ENTRYPOINT ./entrypoint.sh # Cannot receive signals properly
Always use exec form for proper signal handling.
Multi-stage Builds
Basic Pattern
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Runtime
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Result: Build tools not in final image, reduced size by ~90%.
Python Multi-stage
# Stage 1: Build dependencies
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 \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# Create virtual environment
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Stage 2: Runtime
FROM python:3.12-slim AS runtime
WORKDIR /app
# Install runtime dependencies only
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq5 \
&& rm -rf /var/lib/apt/lists/* \
&& useradd --create-home appuser
# Copy virtual environment from builder
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# Copy application code
COPY --chown=appuser:appuser . .
USER appuser
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]
Go Multi-stage (CGO disabled)
# Stage 1: Build
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o /app/server
# Stage 2: Runtime (scratch = empty image)
FROM scratch
COPY --from=builder /app/server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/server"]
Result: Final image ~10-20MB.
TypeScript Multi-stage
# Stage 1: Dependencies
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci
# Stage 2: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Stage 3: Production dependencies
FROM node:20-alpine AS prod-deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
# Stage 4: Runtime
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 nextjs
COPY --from=builder /app/dist ./dist
COPY --from=prod-deps /app/node_modules ./node_modules
USER nextjs
EXPOSE 3000
CMD ["node", "dist/index.js"]
Docker Compose
Basic Configuration
# docker-compose.yml
version: "3.9"
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
- BUILD_ENV=production
image: myapp:latest
container_name: myapp
restart: unless-stopped
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://user:pass@db:5432/mydb
env_file:
- .env
depends_on:
db:
condition: service_healthy
volumes:
- ./data:/app/data
networks:
- app-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
db:
image: postgres:15-alpine
container_name: myapp-db
restart: unless-stopped
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- db_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
networks:
- app-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: myapp-redis
restart: unless-stopped
command: redis-server --appendonly yes
volumes:
- redis_data:/data
networks:
- app-network
volumes:
db_data:
redis_data:
networks:
app-network:
driver: bridge
Development vs Production
# docker-compose.yml (base)
version: "3.9"
services:
app:
build: .
networks:
- app-network
networks:
app-network:
# docker-compose.override.yml (development, auto-loaded)
version: "3.9"
services:
app:
build:
target: development
volumes:
- .:/app
- /app/node_modules
ports:
- "3000:3000"
environment:
- DEBUG=true
command: npm run dev
# docker-compose.prod.yml (production)
version: "3.9"
services:
app:
build:
target: production
restart: unless-stopped
ports:
- "80:3000"
environment:
- NODE_ENV=production
deploy:
replicas: 3
resources:
limits:
cpus: "0.5"
memory: 512M
Usage:
# Development (uses override automatically)
docker compose up
# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
Service Dependencies
services:
app:
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
migrations:
condition: service_completed_successfully
migrations:
build: .
command: python manage.py migrate
depends_on:
db:
condition: service_healthy
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 5s
timeout: 5s
retries: 5
Image Optimization
Layer Caching Strategy
# BAD: Invalidates cache on any code change
COPY . .
RUN pip install -r requirements.txt
# GOOD: Dependencies cached separately
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
Reducing Image Size
| Technique | Example | Impact |
|---|---|---|
| Use slim/alpine | python:3.12-slim vs python:3.12 |
-80% |
| Multi-stage builds | Separate build/runtime | -50-90% |
| Remove cache | rm -rf /var/lib/apt/lists/* |
-50MB |
| Combine RUN | Multiple commands in one RUN | -5-10% |
| Use .dockerignore | Exclude unnecessary files | Variable |
| No dev dependencies | npm ci --omit=dev |
-30-50% |
.dockerignore
# Git
.git
.gitignore
# Dependencies
node_modules
venv
__pycache__
*.pyc
# Build artifacts
dist
build
*.egg-info
# IDE
.vscode
.idea
*.swp
# Docker
Dockerfile*
docker-compose*
.docker
# Environment
.env
.env.*
*.local
# Tests
tests
test
coverage
.pytest_cache
.coverage
# Documentation
docs
*.md
!README.md
# Misc
*.log
tmp
temp
Analyzing Image Size
# View image layers
docker history myapp:latest
# Detailed size analysis
docker image inspect myapp:latest --format='{{.Size}}'
# Use dive for deep analysis
dive myapp:latest
# Compare images
docker images --filter "reference=myapp" --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
Container Networking
Network Types
| Type | Use Case | Command |
|---|---|---|
| bridge (default) | Container-to-container on same host | docker network create mynet |
| host | Container uses host network | --network host |
| none | No networking | --network none |
| overlay | Multi-host communication (Swarm) | docker network create -d overlay mynet |
| macvlan | Container with MAC address | docker network create -d macvlan ... |
Custom Bridge Network
# Create network
docker network create --driver bridge \
--subnet=172.20.0.0/16 \
--gateway=172.20.0.1 \
app-network
# Run container on network
docker run -d --name app --network app-network myapp
# Connect running container
docker network connect app-network existing-container
# Inspect network
docker network inspect app-network
DNS and Service Discovery
# docker-compose.yml
services:
app:
networks:
app-network:
aliases:
- api
- backend
db:
networks:
app-network:
networks:
app-network:
Containers can reach each other by service name: postgres://db:5432/mydb
Port Mapping
# Map container port to host
docker run -p 8080:80 nginx # host:container
docker run -p 127.0.0.1:8080:80 nginx # bind to localhost only
docker run -p 8080-8090:80-90 nginx # port range
docker run -P nginx # auto-map EXPOSE ports
Volume Management
Volume Types
| Type | Syntax | Use Case |
|---|---|---|
| Named volume | mydata:/app/data |
Persistent data |
| Bind mount | ./src:/app/src |
Development, configs |
| tmpfs | --tmpfs /tmp |
Temporary, sensitive data |
Named Volumes
# Create volume
docker volume create app-data
# Use in container
docker run -v app-data:/app/data myapp
# Inspect volume
docker volume inspect app-data
# Backup volume
docker run --rm -v app-data:/data -v $(pwd):/backup alpine \
tar czf /backup/backup.tar.gz -C /data .
# Restore volume
docker run --rm -v app-data:/data -v $(pwd):/backup alpine \
tar xzf /backup/backup.tar.gz -C /data
Compose Volumes
services:
app:
volumes:
# Named volume
- app-data:/app/data
# Bind mount
- ./config:/app/config:ro
# Anonymous volume (preserved on rebuild)
- /app/node_modules
# tmpfs (in-memory)
- type: tmpfs
target: /tmp
tmpfs:
size: 100m
volumes:
app-data:
driver: local
driver_opts:
type: none
device: /path/on/host
o: bind
Volume Best Practices
- Use named volumes for persistent data (databases, uploads)
- Use bind mounts for development (source code, configs)
- Use read-only where possible (
:roflag) - Backup volumes regularly
- Clean unused volumes:
docker volume prune
Registry Operations
Docker Hub
# Login
docker login
# Tag image
docker tag myapp:latest username/myapp:v1.0.0
# Push to registry
docker push username/myapp:v1.0.0
# Pull from registry
docker pull username/myapp:v1.0.0
Private Registry
# Run local registry
docker run -d -p 5000:5000 --name registry registry:2
# Tag for private registry
docker tag myapp:latest localhost:5000/myapp:v1.0.0
# Push to private registry
docker push localhost:5000/myapp:v1.0.0
# Pull from private registry
docker pull localhost:5000/myapp:v1.0.0
AWS ECR
# Get login token
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin 123456789.dkr.ecr.us-east-1.amazonaws.com
# Tag for ECR
docker tag myapp:latest 123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:v1.0.0
# Push to ECR
docker push 123456789.dkr.ecr.us-east-1.amazonaws.com/myapp:v1.0.0
Image Tagging Strategy
| Tag | Purpose | Example |
|---|---|---|
latest |
Most recent build | myapp:latest |
| Semantic version | Release version | myapp:1.2.3 |
| Git SHA | Specific commit | myapp:abc1234 |
| Branch | Feature branches | myapp:feature-login |
| Date | Build timestamp | myapp:2026-01-18 |
Recommended: Use semantic versioning + git SHA for production.
# Tag with multiple tags
docker build -t myapp:latest \
-t myapp:v1.2.3 \
-t myapp:$(git rev-parse --short HEAD) \
.
Security Best Practices
Run as Non-root User
# Create user
RUN useradd --create-home --shell /bin/bash --uid 1000 appuser
# Copy files with correct ownership
COPY --chown=appuser:appuser . .
# Switch to user
USER appuser
Secrets Management
# docker-compose.yml
services:
app:
secrets:
- db_password
- api_key
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
external: true # Created via: docker secret create api_key key.txt
Access in container: /run/secrets/db_password
Security Scanning
# Scan with Docker Scout
docker scout cves myapp:latest
# Scan with Trivy
trivy image myapp:latest
# Scan with Snyk
snyk container test myapp:latest
Security Checklist
- Use specific image tags (not
latestin production) - Run as non-root user
- Use read-only filesystem where possible
- Drop all capabilities:
--cap-drop ALL - Add only needed capabilities:
--cap-add NET_BIND_SERVICE - Scan images for vulnerabilities
- Use secrets for sensitive data (not ENV)
- Set resource limits
- Use distroless/minimal base images
- Keep images updated
Secure Compose Example
services:
app:
image: myapp:v1.0.0
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
deploy:
resources:
limits:
cpus: "0.5"
memory: 256M
reservations:
cpus: "0.25"
memory: 128M
Health Checks
Dockerfile HEALTHCHECK
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
Compose Healthcheck
services:
app:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
Health Check Options
| Option | Description |
|---|---|
--interval |
Time between checks (default: 30s) |
--timeout |
Maximum time to wait for check (default: 30s) |
--start-period |
Grace period for container startup |
--retries |
Consecutive failures before unhealthy |
Common Commands
Build
# Build image
docker build -t myapp:latest .
# Build with different Dockerfile
docker build -f Dockerfile.prod -t myapp:prod .
# Build with build args
docker build --build-arg VERSION=1.0.0 -t myapp:1.0.0 .
# Build without cache
docker build --no-cache -t myapp:latest .
# Build with target stage
docker build --target builder -t myapp:builder .
Run
# Run interactive
docker run -it --rm myapp:latest bash
# Run detached
docker run -d --name myapp myapp:latest
# Run with environment
docker run -e DATABASE_URL=postgres://... myapp
# Run with port mapping
docker run -p 8080:80 myapp
# Run with volume
docker run -v $(pwd)/data:/app/data myapp
# Run with resource limits
docker run --memory=512m --cpus=0.5 myapp
Compose
# Start services
docker compose up -d
# Build and start
docker compose up -d --build
# View logs
docker compose logs -f app
# Stop services
docker compose down
# Stop and remove volumes
docker compose down -v
# Execute command in running service
docker compose exec app bash
# Scale service
docker compose up -d --scale app=3
Maintenance
# View running containers
docker ps
# View all containers
docker ps -a
# View logs
docker logs -f container_name
# Execute in container
docker exec -it container_name bash
# Copy files
docker cp container_name:/app/file.txt ./file.txt
# Prune unused resources
docker system prune -a --volumes
Debugging
Container Inspection
# Inspect container
docker inspect container_name
# View processes
docker top container_name
# Resource usage
docker stats container_name
# View logs with timestamps
docker logs --timestamps container_name
# Follow logs
docker logs -f --tail 100 container_name
Network Debugging
# List networks
docker network ls
# Inspect network
docker network inspect bridge
# Test connectivity from container
docker exec -it app ping db
docker exec -it app nslookup db
Build Debugging
# Build with verbose output
docker build --progress=plain -t myapp .
# Build specific stage
docker build --target builder -t myapp:debug .
# Run shell in build stage
docker run -it --rm myapp:debug sh
Anti-patterns
| Anti-pattern | Problem | Solution |
|---|---|---|
Using latest tag |
Unpredictable deployments | Pin specific versions |
| Root user | Security vulnerability | Create non-root user |
| Secrets in ENV | Visible in inspect/logs | Use Docker secrets |
| Large images | Slow deploys, more vulnerabilities | Multi-stage builds |
| Ignoring .dockerignore | Large context, slow builds | Proper exclusions |
| Not using health checks | Silent failures | Add HEALTHCHECK |
| Hardcoding config | Inflexible containers | Use ENV/secrets |
| Single RUN per line | Many layers, large image | Combine RUN commands |
Quick Audits
Dockerfile Checklist
- Base image version pinned
- Non-root user configured
- .dockerignore present
- Multi-stage build (if applicable)
- Layer caching optimized
- HEALTHCHECK defined
- Labels for metadata
- Exec form for CMD/ENTRYPOINT
Security Checklist
- No secrets in image
- Running as non-root
- Read-only filesystem (if possible)
- Resource limits set
- Image scanned for vulnerabilities
- Base image updated recently
Production Checklist
- Image tagged with version
- Health checks configured
- Logging to stdout/stderr
- Graceful shutdown handled
- Environment variables documented
- Resource limits defined
- Restart policy set
Tools
| Tool | Purpose |
|---|---|
| Docker Desktop | GUI for Docker management |
| Docker Scout | Vulnerability scanning |
| Dive | Image layer analysis |
| Hadolint | Dockerfile linting |
| Trivy | Security scanning |
| Buildx | Multi-platform builds |
| Docker Compose | Multi-container orchestration |
| Lazydocker | Terminal UI for Docker |
Sources
- Docker Documentation
- Docker Best Practices
- Docker Compose Specification
- Docker Security
- OWASP Docker Security Cheat Sheet
- Hadolint Rules
Methodologies
| ID | Name | File |
|---|---|---|
| M-DO-001 | Cicd Github Actions | methodologies/M-DO-001_cicd_github_actions.md |
| M-DO-002 | Cicd Gitlab Ci | methodologies/M-DO-002_cicd_gitlab_ci.md |
| M-DO-003 | Docker Basics | methodologies/M-DO-003_docker_basics.md |
| M-DO-004 | Docker Compose | methodologies/M-DO-004_docker_compose.md |
| M-DO-005 | Kubernetes Basics | methodologies/M-DO-005_kubernetes_basics.md |
| M-DO-006 | Helm Charts | methodologies/M-DO-006_helm_charts.md |
| M-DO-007 | Aws Ec2 | methodologies/M-DO-007_aws_ec2.md |
| M-DO-008 | Aws Lambda | methodologies/M-DO-008_aws_lambda.md |
| M-DO-009 | Terraform Basics | methodologies/M-DO-009_terraform_basics.md |
| M-DO-010 | Infrastructure Patterns | methodologies/M-DO-010_infrastructure_patterns.md |
| M-DO-011 | Monitoring Prometheus | methodologies/M-DO-011_monitoring_prometheus.md |
| M-DO-012 | Logging Elk | methodologies/M-DO-012_logging_elk.md |
| M-DO-013 | Tracing Jaeger | methodologies/M-DO-013_tracing_jaeger.md |
| M-DO-014 | Secrets Management | methodologies/M-DO-014_secrets_management.md |
| M-DO-015 | Ssl Certificates | methodologies/M-DO-015_ssl_certificates.md |
| M-DO-016 | Backup Recovery | methodologies/M-DO-016_backup_recovery.md |
| M-DO-017 | Networking Basics | methodologies/M-DO-017_networking_basics.md |
| M-DO-018 | Dns Route53 | methodologies/M-DO-018_dns_route53.md |
| M-DO-019 | Cdn Cloudfront | methodologies/M-DO-019_cdn_cloudfront.md |
| M-DO-020 | Container Registry | methodologies/M-DO-020_container_registry.md |
| M-DO-021 | Security Scanning | methodologies/M-DO-021_security_scanning.md |
| M-DO-022 | Cost Optimization | methodologies/M-DO-022_cost_optimization.md |
| M-DO-023 | Database Operations | methodologies/M-DO-023_database_operations.md |
| M-DO-024 | Feature Flags | methodologies/M-DO-024_feature_flags.md |
| M-DO-025 | Incident Management | methodologies/M-DO-025_incident_management.md |
| M-DO-026 | Gitops | methodologies/M-DO-026_gitops.md |
| M-DO-027 | Service Mesh | methodologies/M-DO-027_service_mesh.md |
| M-DO-028 | Slo Sli | methodologies/M-DO-028_slo_sli.md |
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?