skills/docker-ops/SKILL.md
Docker containerization patterns, Dockerfile best practices, multi-stage builds, and Docker Compose. Use for: docker, Dockerfile, docker-compose, container, image, multi-stage build, docker build, docker run, .dockerignore, health check, distroless, scratch image, BuildKit, layer caching, container security.
npx skillsauth add 0xDarkMatter/claude-mods docker-opsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Comprehensive Docker patterns for building, running, and composing containerized applications.
| Practice | Do | Don't |
|----------|------|-------|
| Base image | FROM node:20-slim | FROM node:latest |
| Layer caching | Copy dependency files first, then source | COPY . . before RUN install |
| Package install | apt-get update && apt-get install -y ... && rm -rf /var/lib/apt/lists/* | Separate RUN for update and install |
| User | USER nonroot (create if needed) | Run as root in production |
| Multi-stage | Separate build and runtime stages | Ship compiler toolchains |
| Secrets | --mount=type=secret (BuildKit) | COPY .env . or ARG PASSWORD |
| ENTRYPOINT vs CMD | ENTRYPOINT for fixed binary, CMD for defaults | Relying on shell form for signal handling |
| WORKDIR | WORKDIR /app | RUN cd /app && ... |
| .dockerignore | Include .git, node_modules, __pycache__ | No .dockerignore at all |
| Labels | LABEL org.opencontainers.image.* | No metadata |
Choose your runtime base image by language:
Go ──────────── CGO disabled? ──── Yes ──► scratch or distroless/static
No ───► distroless/base or alpine
Rust ─────────── Static musl? ──── Yes ──► scratch or distroless/static
No ───► distroless/cc or debian-slim
Node.js ──────── Need native? ──── Yes ──► node:20-slim
No ───► node:20-alpine (smaller)
Python ────────── Need C libs? ─── Yes ──► python:3.12-slim
No ───► python:3.12-slim (still slim)
Java ──────────── JRE only ──────────────► eclipse-temurin:21-jre-alpine
See:
references/multi-stage-builds.mdfor complete annotated examples per language.
Docker caches each layer. A cache miss at layer N invalidates all subsequent layers.
| Trigger | Effect |
|---------|--------|
| Changed file in COPY/ADD | Invalidates this layer + all below |
| Changed RUN command text | Invalidates this layer + all below |
| Changed ARG value | Invalidates from the ARG declaration down |
| --no-cache flag | Invalidates everything |
| Base image update | Invalidates everything |
# 1. Base image (changes rarely)
FROM python:3.12-slim
# 2. System dependencies (changes rarely)
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# 3. Dependency files (changes occasionally)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 4. Application code (changes frequently)
COPY src/ ./src/
# 5. Runtime config (changes frequently)
CMD ["python", "-m", "app"]
Rule of thumb: Order layers from least-frequently-changed to most-frequently-changed.
# Version control
.git
.gitignore
# Dependencies (rebuilt in container)
node_modules
__pycache__
*.pyc
.venv
vendor/
# Build artifacts
dist/
build/
target/
*.egg-info
# IDE and editor
.vscode
.idea
*.swp
*.swo
# Docker files (prevent recursive context)
Dockerfile*
docker-compose*
.dockerignore
# Environment and secrets
.env
.env.*
*.pem
*.key
# Documentation and tests (unless needed)
docs/
tests/
*.md
LICENSE
Why it matters: Without .dockerignore, docker build sends the entire context directory to the daemon. A .git folder alone can add hundreds of megabytes.
services:
web:
build:
context: .
dockerfile: Dockerfile
target: production # Multi-stage target
image: myapp:latest
ports:
- "8080:8000"
environment:
DATABASE_URL: postgres://db:5432/app
env_file:
- .env
volumes:
- ./src:/app/src # Bind mount (dev)
- app-data:/app/data # Named volume (persistent)
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
restart: unless-stopped
networks:
- backend
volumes:
app-data: # Named volume (Docker-managed)
db-data:
driver: local
networks:
backend:
driver: bridge
frontend:
driver: bridge
See:
references/compose-patterns.mdfor full patterns including profiles, watch mode, and override files.
| Area | Recommendation |
|------|----------------|
| User | Run as non-root: RUN adduser -D appuser && USER appuser |
| Base image | Pin digest: FROM python:3.12-slim@sha256:abc123... |
| Filesystem | Read-only root: docker run --read-only --tmpfs /tmp |
| Capabilities | Drop all, add needed: --cap-drop=ALL --cap-add=NET_BIND_SERVICE |
| Secrets | BuildKit secrets: RUN --mount=type=secret,id=key cat /run/secrets/key |
| Scanning | Scan images: trivy image myapp:latest or grype myapp:latest |
| No latest | Always use specific tags and pin versions |
| Minimal image | Use distroless or scratch when possible |
| No SUID | RUN find / -perm /6000 -type f -exec chmod a-s {} + |
| Network | Use internal networks for backend services |
# Debian/Ubuntu-based
RUN groupadd -r appuser && useradd -r -g appuser -d /app -s /sbin/nologin appuser
COPY --chown=appuser:appuser . /app
USER appuser
# Alpine-based
RUN addgroup -S appuser && adduser -S -G appuser appuser
COPY --chown=appuser:appuser . /app
USER appuser
# Distroless (built-in nonroot user)
FROM gcr.io/distroless/static:nonroot
USER nonroot:nonroot
| Gotcha | Problem | Fix |
|--------|---------|-----|
| Large images | Shipping build tools, node_modules in final image | Multi-stage builds |
| Cache busting | COPY . . before RUN npm install | Copy lockfile first, install, then copy source |
| Secrets in layers | COPY .env . or ARG SECRET=... bakes secrets into image history | Use --mount=type=secret or runtime env vars |
| PID 1 problem | App doesn't receive SIGTERM, zombie processes | Use tini as init or exec form for CMD |
| Timezone | Container uses UTC | Set TZ env var or install tzdata |
| DNS caching | Alpine musl DNS issues | Use RUN apk add --no-cache libc6-compat or switch to slim |
| apt cache | apt-get update cached from old layer | Always combine update && install in one RUN |
| Missing signals | Shell form (CMD npm start) wraps in /bin/sh | Exec form: CMD ["node", "server.js"] |
| Build context size | Sending GB of data to daemon | Add .dockerignore, check with docker build --progress=plain |
| Layer explosion | Each RUN creates a layer | Chain related commands with && |
# Option 1: Use tini as init process
RUN apt-get update && apt-get install -y --no-install-recommends tini \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["tini", "--"]
CMD ["node", "server.js"]
# Option 2: Docker init flag (Docker 23.0+)
# docker run --init myapp
# Option 3: Node.js - handle signals in code
# process.on('SIGTERM', () => { server.close(); process.exit(0); });
# Build
docker build -t myapp:1.0 .
docker build -t myapp:1.0 --target production . # Multi-stage target
docker build --no-cache -t myapp:1.0 . # Force rebuild
# Run
docker run -d --name myapp -p 8080:8000 myapp:1.0
docker run --rm -it myapp:1.0 /bin/sh # Interactive debug
docker run --read-only --tmpfs /tmp myapp:1.0 # Read-only root
# Inspect
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
docker history myapp:1.0 # Layer breakdown
docker inspect myapp:1.0 | jq '.[0].Config' # Image config
# Debug running container
docker exec -it myapp /bin/sh
docker logs -f myapp
docker stats myapp
# Cleanup
docker system prune -a --volumes # Remove everything unused
docker image prune -a # Remove unused images
| File | Contents |
|------|----------|
| references/multi-stage-builds.md | Per-language multi-stage patterns (Go, Rust, Node, Python) |
| references/compose-patterns.md | Compose services, networking, profiles, watch, overrides |
| references/optimization.md | Image size, BuildKit, security scanning, debugging |
tools
Behavioural-first software supply chain defense - catches poisoned npm/PyPI packages in the publish-to-advisory window that CVE tools miss. Use BEFORE every install or version bump (not only when an attack is suspected) - the 7-day cooldown gate + behavioural score catches freshly-published malware that CVE tools won't see for days. Socket.dev integration (free CLI + GitHub app + depscore MCP for Claude Code), stale-OIDC audit, dependency cooldown policy, publish-token rotation, VS Code extension audit, and a self-integrity scan that detects worm persistence hooks injected into Claude Code / VS Code settings. Triggers on: pip install, uv add, uv tool install, npm install, pnpm add, yarn add, cargo add, go get, composer require, gem install, upgrade dependency, dependency upgrade, version bump, bump version, bump package, adding dependency, new dependency, vetting a dependency, vet package, is this package safe, safe to install, should I install, before installing, pre-install check, preinstall scan, preinstall-check, PyPI cooldown, npm cooldown, release cooldown, minimumReleaseAge, score a package, package score, depscore, socket score, supply chain, supply chain attack, malicious package, poisoned dependency, npm worm, Shai-Hulud, behavioural scanning, Socket.dev, socket scan, dependency security, postinstall malware, OIDC token theft, compromised maintainer, typosquat, dependency confusion, package provenance, SLSA, persistence hook, malicious VS Code extension.
testing
GitHub remote operations — repo creation, metadata (description/homepage/topics), releases, README 'Recent Updates' enforcement, and issue / PR management with preview-before-send discipline. Companion to git-ops (local) and push-gate (pre-push safety). Three modes: new (first publish), update (subsequent release), audit (read-only checklist), plus atomic operations for issues and PRs. Triggers on: push to github, publish repo, ship release, cut release, gh release, set topics, repo description, github metadata, recent updates section, audit github repo, repo visibility, make repo public, gh repo create, gh issue, gh pr, create issue, comment on issue, close issue, triage issue, create PR, review PR, merge PR, pre-merge check, pr checks.
tools
Defend the agent's instruction surface against adversarial content - hidden-Unicode prompt injection (Trojan Source bidi reordering, U+E0000 tag-block ASCII smuggling, zero-width text), homoglyph confusables, and poisoned context that a human reviewer can't see but the model obeys. Scan CLAUDE.md / AGENTS.md / SKILL.md / .cursorrules and MCP tool descriptions; sanitize fetched web pages, issue/PR bodies, and dependency READMEs before they enter context. Triggers on: prompt injection, hidden unicode, invisible characters, zero-width space, bidi override, Trojan Source, ASCII smuggling, tag characters, homoglyph, confusable, unicode steganography, poisoned CLAUDE.md, malicious tool description, MCP tool poisoning, instruction injection, jailbreak in file, is this file safe, sanitize untrusted content, scan for hidden text.
tools
Set tool permissions for Claude Code. Configures allowed commands, rules, and preferences in .claude/ directory. Triggers on: setperms, init tools, configure permissions, setup project, set permissions, init claude.