docker
Docker and Docker Compose best practices — use when writing Dockerfiles, composing multi-service apps, or optimizing container builds. Covers layer caching, multi-stage builds, security hardening, and local dev patterns.
Works with
---
name: docker
description: Docker and Docker Compose best practices — use when writing Dockerfiles, composing multi-service apps, or optimizing container builds. Covers layer caching, multi-stage builds, security hardening, and local dev patterns.
license: MIT
---
# Docker
## Dockerfile best practices
### Multi-stage builds — keep production images small
```dockerfile
# syntax=docker/dockerfile:1
# --- Build stage ---
FROM node:22-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# --- Production stage ---
FROM node:22-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
# Create non-root user
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]
```
### Layer caching — order from least to most frequently changed
```dockerfile
# GOOD — dependencies cached unless package.json changes
COPY package*.json ./
RUN npm ci
COPY . . # source changes don't bust the dep cache
# BAD
COPY . . # any source change busts npm ci cache
RUN npm ci
```
### Python multi-stage
```dockerfile
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /install /usr/local
COPY src/ ./src/
RUN useradd -r -u 1001 appuser && chown -R appuser /app
USER appuser
CMD ["python", "-m", "src.main"]
```
## Security hardening
```dockerfile
# 1. Never run as root
USER nonroot
# 2. Use specific image digests in production (not :latest)
FROM node:22-slim@sha256:abc123...
# 3. No secrets in build args or ENV — use runtime secrets
# BAD: ARG DATABASE_URL
# GOOD: Pass at runtime via -e or Docker secrets
# 4. Minimal base images
FROM gcr.io/distroless/nodejs22-debian12 # no shell, no package manager
# 5. Read-only filesystem where possible
docker run --read-only --tmpfs /tmp my-image
```
## .dockerignore
Always include a `.dockerignore` to avoid copying unnecessary files:
```
.git
.github
node_modules
.next
dist
build
*.md
.env*
coverage
__pycache__
*.pyc
.pytest_cache
```
## Docker Compose for local development
```yaml
# compose.yaml (preferred filename over docker-compose.yml)
services:
app:
build:
context: .
target: builder # use build stage for dev (has dev deps)
ports:
- "3000:3000"
volumes:
- .:/app # mount source for hot reload
- /app/node_modules # anonymous volume — don't override node_modules
environment:
- NODE_ENV=development
depends_on:
db:
condition: service_healthy
command: npm run dev
db:
image: postgres:17-alpine
environment:
POSTGRES_DB: myapp
POSTGRES_USER: myapp
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./scripts/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U myapp"]
interval: 5s
timeout: 5s
retries: 5
ports:
- "5432:5432"
redis:
image: redis:7-alpine
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
volumes:
postgres_data:
```
## Useful commands
```bash
# Build with BuildKit (always use)
DOCKER_BUILDKIT=1 docker build .
# Multi-platform builds
docker buildx build --platform linux/amd64,linux/arm64 -t myimage:latest --push .
# Inspect layers and sizes
docker image history myimage:latest
# Clean up everything (dev machines)
docker system prune -af --volumes
# Run one-off command in compose service
docker compose run --rm app python manage.py migrate
# Follow logs from specific service
docker compose logs -f app
# Get a shell in a running container
docker compose exec app sh
```
## Health checks
```dockerfile
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
```
```yaml
# In compose.yaml
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
```
## Common pitfalls
- **PID 1 problem** — Node/Python processes don't handle signals correctly as PID 1. Use `tini` or `exec` form CMD: `CMD ["node", "server.js"]` not `CMD node server.js`
- **Volume permissions** — when mounting volumes, UIDs inside and outside container must match or files become inaccessible
- **Secrets in layers** — `RUN curl -H "Authorization: $TOKEN" ...` bakes the token into the image layer even if you delete it. Use `--secret` flag with BuildKit
- **`:latest` in production** — always pin to a specific digest or version tagMore Performance skills
seo-audit
coreyhaines31/marketingskills
When the user wants to audit, review, or diagnose SEO issues on their site. Also use when the user mentions "SEO audit," "technical SEO," "why am I not ranking," "SEO issues," "on-page SEO," "meta tags review," "SEO health check," "my traffic dropped," "lost rankings," "not showing up in Google," "site isn't ranking," "Google update hit me," "page speed," "core web vitals," "crawl errors," or "indexing issues." Use this even if the user just says something vague like "my SEO is bad" or "help with SEO" — start with an audit. For building pages at scale to target keywords, see programmatic-seo. For adding structured data, see schema. For AI search optimization, see ai-seo.
competitor-profiling
coreyhaines31/marketingskills
When the user wants to research, profile, or analyze competitors from their URLs. Also use when the user mentions 'competitor profile,' 'competitor research,' 'competitor analysis,' 'profile this competitor,' 'analyze competitor,' 'competitive intelligence,' 'competitor deep dive,' 'who are my competitors,' 'competitor landscape,' 'competitor dossier,' 'competitive audit,' or 'research these competitors.' Input is a list of competitor URLs. Output is structured competitor profile markdown files. For creating comparison/alternative pages from profiles, see competitors. For sales-specific battle cards, see sales-enablement.
prospecting
coreyhaines31/marketingskills
When the user wants to find, qualify, and build a list of prospects to reach out to — across B2B SaaS, general B2B, or local small businesses. Also use when the user mentions "prospecting," "build a prospect list," "find prospects," "find leads," "lead gen list," "find SaaS companies that," "find B2B companies," "find local businesses," "ICP-fit accounts," "who should we go after," "outbound list," "target account list," "find clients near me," "businesses without websites," "prospect research," "qualified leads," "find my first customers," "early adopters," "design partners," "beta users," or "who has this problem." Use this for the list-building and qualification phase. For writing the outbound copy after the list is built, see cold-email. For deep competitive research on specific accounts, see competitor-profiling.

