From docker-deploy
Use when creating Dockerfiles, docker-compose configs, or containerizing applications. Covers multi-stage builds, image optimization, compose patterns for dev and production, health checks, signal handling, and security hardening.
npx claudepluginhub sagargupta16/claude-skills --plugin docker-deployThis skill uses the workspace's default tool permissions.
| Task | Approach |
Acquire memory dumps from live systems/VMs and analyze with Volatility 3 for processes, networks, DLLs, injections in incident response or malware hunts.
Provides x86-64/ARM disassembly patterns, calling conventions, control flow recognition for static analysis of executables and compiled binaries.
Identifies anti-debugging checks like IsDebuggerPresent, NtQueryInformationProcess in Windows binaries; suggests bypasses via patches/hooks/scripts for malware analysis, CTFs, authorized RE.
| Task | Approach |
|---|---|
| New Dockerfile | Choose template by language below |
| Optimize image | Multi-stage build + Alpine/distroless base |
| Dev environment | docker-compose with hot-reload and volumes |
| Production | Multi-stage, non-root user, health checks |
| Debugging | docker logs, docker exec, build with --progress=plain |
# Build stage -- check https://hub.docker.com/_/python for latest
FROM python:3.13-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
# Runtime stage
FROM python:3.13-slim
WORKDIR /app
RUN adduser --disabled-password --no-create-home appuser
COPY --from=builder /install /usr/local
COPY . .
USER appuser
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
# Build stage -- check https://hub.docker.com/_/node for latest LTS
FROM node:22-alpine AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build
# Runtime stage
FROM node:22-alpine
WORKDIR /app
RUN adduser -D appuser
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json .
USER appuser
EXPOSE 3000
CMD ["node", "dist/index.js"]
# Build stage -- check https://hub.docker.com/_/golang for latest
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /app/server .
# Runtime stage
FROM gcr.io/distroless/static-debian12
COPY --from=builder /app/server /server
USER nonroot
EXPOSE 8080
ENTRYPOINT ["/server"]
# Build stage -- check https://hub.docker.com/_/rust for latest
FROM rust:1.82-slim AS builder
WORKDIR /app
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build --release && rm -rf src
COPY . .
RUN cargo build --release
# Runtime stage
FROM gcr.io/distroless/cc-debian12
COPY --from=builder /app/target/release/app /app
USER nonroot
EXPOSE 8080
ENTRYPOINT ["/app"]
services:
app:
build: .
ports:
- "8000:8000"
volumes:
- .:/app # Hot-reload via volume mount
- /app/node_modules # Exclude node_modules from mount
environment:
- DEBUG=true
depends_on:
db:
condition: service_healthy
db:
image: mongo:8
ports:
- "27017:27017"
volumes:
- db_data:/data/db
healthcheck:
test: mongosh --eval "db.runCommand('ping').ok"
interval: 10s
timeout: 5s
retries: 3
volumes:
db_data:
services:
app:
image: ghcr.io/org/app:latest
ports:
- "8000:8000"
env_file: .env
restart: unless-stopped
deploy:
resources:
limits:
memory: 512M
cpus: "0.5"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
depends_on:
db:
condition: service_healthy
db:
image: mongo:8
volumes:
- db_data:/data/db
restart: unless-stopped
healthcheck:
test: mongosh --eval "db.runCommand('ping').ok"
interval: 30s
timeout: 10s
retries: 3
volumes:
db_data:
Always create a .dockerignore to keep images small and avoid leaking secrets:
.git
.gitignore
node_modules
__pycache__
*.pyc
.env
.env.*
.vscode
.idea
*.md
!README.md
docker-compose*.yml
Dockerfile*
.dockerignore
tests/
coverage/
.pytest_cache/
dist/
build/
| Use Case | Base Image | Size |
|---|---|---|
| Python apps | python:<version>-slim | ~150MB |
| Python minimal | python:<version>-alpine | ~50MB |
| Node.js apps | node:<lts>-alpine | ~130MB |
| Go apps | gcr.io/distroless/static | ~2MB |
| Rust apps | gcr.io/distroless/cc | ~20MB |
| Static files | nginx:alpine | ~40MB |
Order instructions from least to most frequently changing:
# 1. Base image (rarely changes)
FROM python:3.13-slim
# 2. System deps (rarely changes)
RUN apt-get update && apt-get install -y --no-install-recommends curl
# 3. App deps (changes when lockfile changes)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 4. App code (changes most often - LAST)
COPY . .
# HTTP health check
HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=15s \
CMD curl -f http://localhost:8000/health || exit 1
# TCP health check (no curl needed)
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
CMD nc -z localhost 8000 || exit 1
Use exec form for CMD/ENTRYPOINT to receive signals correctly:
# GOOD: exec form - PID 1, receives SIGTERM
CMD ["uvicorn", "main:app", "--host", "0.0.0.0"]
# BAD: shell form - shell is PID 1, app doesn't get signals
CMD uvicorn main:app --host 0.0.0.0
For Node.js, handle SIGTERM explicitly:
process.on("SIGTERM", () => {
server.close(() => process.exit(0));
});
| Practice | Implementation |
|---|---|
| Non-root user | RUN adduser -D appuser + USER appuser |
| No secrets in image | Use env vars or mounted secrets at runtime |
| Pin base image digests | FROM python:3.13-slim@sha256:abc... for production |
| Scan for vulnerabilities | docker scout cves or trivy image |
| Read-only filesystem | docker run --read-only --tmpdir /tmp |
| No unnecessary packages | --no-install-recommends for apt |
| Don't | Do Instead |
|---|---|
| Run as root | Create and switch to non-root user |
Skip .dockerignore | Always create one (prevents leaking .env, .git) |
COPY . . before installing deps | Copy lockfile first, install, then copy code |
Use latest tag in production | Pin specific versions or digests |
| Store secrets in image layers | Use runtime env vars or mounted secrets |
| Install dev dependencies in prod image | Use multi-stage builds |
Use alpine with Python C extensions | Use slim instead (musl vs glibc issues) |
Ignore SIGTERM handling | Use exec form CMD + signal handlers |