一键导入
docker
Use when writing Dockerfiles, configuring docker-compose, optimizing container images, debugging container networking, or hardening Docker security.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when writing Dockerfiles, configuring docker-compose, optimizing container images, debugging container networking, or hardening Docker security.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when designing functions, modeling data, choosing types, drawing module boundaries, or deciding what depends on what. Use when evaluating architecture, extracting abstractions, or shaping vertical slices.
Use when writing, reviewing, or refactoring code in any language. Use for architecture decisions, system design, component boundaries, and code quality judgment. Always relevant when touching source code.
Use when writing or reviewing comments, docstrings, names, control flow, or file organization. Use when evaluating readability, choosing identifiers, splitting files, or applying naming conventions. Use when removing AI tells (slop) from code prose — comments, docs, error messages, commit messages, PR descriptions. Covers the visible surface of code.
Run kirby's review engine on a PR or a commit, OUTSIDE the orchestrator loop. Local output only — findings are presented in-conversation, nothing is posted, no Provider config needed.
Launch kirby-bot orchestrator in background, relay phase transitions live from run.jsonl.
Extract and organize existing code into reusable modules, functions, and components with thoughtful APIs.
| name | docker |
| description | Use when writing Dockerfiles, configuring docker-compose, optimizing container images, debugging container networking, or hardening Docker security. |
:latest tag = unreproducible builds. Pin exact versions: node:22.12-alpine3.20.COPY . . before npm ci = cache bust on every code change. Copy lockfile first, install, THEN copy source.node_modules. Use anonymous volume trick: - /app/node_modules.NOW() equivalent: container time drifts if host NTP is off. Mount /etc/localtime read-only or set TZ env.docker compose down -v destroys named volumes. Data gone. Never use -v casually.EXPOSE is documentation only — does NOT publish ports. You still need -p or ports: in compose.deps -> build -> dev -> production.RUN per logical step. Combine related commands with && to reduce layers, but keep readability.COPY package.json package-lock.json ./ then RUN npm ci BEFORE COPY . . — cache dependencies layer.# npm
RUN --mount=type=cache,target=/root/.npm npm ci
# pnpm
RUN --mount=type=cache,target=/root/.local/share/pnpm/store pnpm install --frozen-lockfile
# pip/uv
RUN --mount=type=cache,target=/root/.cache/uv uv pip install -r requirements.txt
--frozen-lockfile (pnpm/yarn) or npm ci — never npm install in CI/Docker. Lockfile is law.ENTRYPOINT ["node"] + CMD ["server.js"]. CMD-alone is a smell: it conflates binary and args and loses clean runtime override. Exec form ["..."] always, never shell form CMD node server.js (shell form wraps in /bin/sh -c, breaks signal handling). Override CMD at runtime: docker run myapp worker.js.docker buildx build --platform linux/amd64,linux/arm64 -t myapp:v1 --push .. Create builder: docker buildx create --use. For compiled languages, use cross-compilation in build stage. For interpreted languages (Node, Python), it usually just works.-slim if native deps have musl issues (psycopg2, sharp, etc.).gcr.io/distroless/nodejs22-debian12 or gcr.io/distroless/static-debian12 as final stage. No shell, no package manager = minimal attack surface. Debug variant available: :debug tag adds busybox shell. When distroless is too restrictive, use *-slim variants.LABEL org.opencontainers.image.source="https://github.com/org/repo", org.opencontainers.image.version="1.2.0", org.opencontainers.image.revision="$(git rev-parse HEAD)". Enables docker inspect to trace a running image back to its source commit. An image with no labels is untraceable in an incident.# -- Stage 1: Dependencies (cached independently from source code) --
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# -- Stage 2: Dev (hot-reload, debug tools, volume-mounted source) --
FROM node:22-alpine AS dev
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"]
# -- Stage 3: Build (compile/bundle — tools stay here, never ship) --
FROM node:22-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build && npm prune --production
# -- Stage 4: Production (minimal image, non-root, healthcheck) --
FROM node:22-alpine AS production
WORKDIR /app
# OCI labels for traceability — trace any running image back to its source commit.
LABEL org.opencontainers.image.source="https://github.com/org/repo" \
org.opencontainers.image.version="1.2.0" \
org.opencontainers.image.revision="$GIT_SHA"
# tini as PID 1 — forwards SIGTERM and reaps zombies. apk add it, never skip it.
RUN apk add --no-cache tini
# Non-root user — NEVER run prod as root
RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001
USER appuser
COPY --from=build --chown=appuser:appgroup /app/dist ./dist
COPY --from=build --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=build --chown=appuser:appgroup /app/package.json ./
ENV NODE_ENV=production
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/health || exit 1
# ENTRYPOINT = the init + binary, CMD = default args (override-able at runtime).
ENTRYPOINT ["tini", "--", "node"]
CMD ["dist/server.js"]
Signal handling: Signal handling with tini or dumb-init — PID 1 in containers doesn't get default signal handling. Use tini as entrypoint to properly forward signals and reap zombies: ENTRYPOINT ["tini", "--"] then CMD ["node", "server.js"]. Or use docker run --init. Without this, SIGTERM is silently ignored = ungraceful shutdown.
Every production stage MUST have ALL of these — verify each one before you finish:
:latest), Alpine/slim variantorg.opencontainers.image.source / .version / .revisionRUN apk add --no-cache tini (or dumb-init) — init for PID 1USER + --chown on every COPYENV NODE_ENV=productionHEALTHCHECKENTRYPOINT (init + binary) AND CMD (default args) — BOTH, exec form, never CMD aloneA weak signal here is silent: skip tini and SIGTERM is dropped; skip labels and the image is untraceable; ship CMD-alone and you lose clean runtime arg override. Don't skip the boring ones.
# Target a specific stage
docker build --target dev -t myapp:dev .
docker build --target production -t myapp:prod .
depends_on with condition: service_healthy — don't just depend, wait for READY.env_file: .env for secrets. NEVER hardcode secrets in compose file. .env in .gitignore.docker-compose.override.yml auto-loads for dev. Explicit -f for prod.docker compose watch replaces manual bind mounts with declarative file sync. Config in compose.yaml: develop: watch: [{action: sync, path: ./src, target: /app/src}, {action: rebuild, path: package.json}]. Auto-syncs source changes, rebuilds on dependency changes.profiles: [debug] on services like debug tools, admin panels, monitoring. Start normally: docker compose up. Include debug tools: docker compose --profile debug up. Keeps default stack lean.cap_drop: [ALL] and security_opt: [no-new-privileges:true] go on app, db, redis, ALL of them. Don't harden only the app and leave the datastore wide open.# docker-compose.yml — standard web app stack
services:
app:
build:
context: .
target: dev
ports:
- "3000:3000"
volumes:
- .:/app # Bind mount: hot-reload source changes
- /app/node_modules # Anonymous volume: preserve container deps
env_file: .env # ALL secrets in .env (gitignored), NEVER inline
environment:
- NODE_ENV=development
depends_on:
db:
condition: service_healthy
# Security defaults — include even in dev
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
read_only: true
tmpfs:
- /tmp
deploy:
resources:
limits:
memory: 1G
cpus: '1.0'
db:
image: postgres:16-alpine
ports:
- "127.0.0.1:5432:5432" # localhost only — not exposed to network
env_file: .env # POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB in .env
volumes:
- pgdata:/var/lib/postgresql/data
- ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql
security_opt: # Same hardening as app — every service, no exceptions
- no-new-privileges:true
cap_drop:
- ALL
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 5
redis:
image: redis:7-alpine
ports:
- "127.0.0.1:6379:6379" # localhost only
volumes:
- redisdata:/data
security_opt: # Same hardening as app — every service, no exceptions
- no-new-privileges:true
cap_drop:
- ALL
volumes:
pgdata:
redisdata:
# .env (gitignored):
# DATABASE_URL=postgres://postgres:postgres@db:5432/app_dev
# REDIS_URL=redis://redis:6379/0
# POSTGRES_USER=postgres
# POSTGRES_PASSWORD=postgres
# POSTGRES_DB=app_dev
pgdata:/var/lib/...): persistent data, survives docker compose down. Docker-managed../src:/app/src): dev only. Maps host dir into container for hot-reload./app/node_modules): prevents bind mount from overwriting container-generated content.db:5432 not localhost:5432 from another container.127.0.0.1 for dev-only ports: "127.0.0.1:5432:5432". Prevents external access.ports: entirely for internal services. Only expose through reverse proxy.# Network isolation: frontend cannot reach db
services:
frontend:
networks: [frontend-net]
api:
networks: [frontend-net, backend-net]
db:
networks: [backend-net]
networks:
frontend-net:
backend-net:
RUN addgroup ... && adduser ... then USER appuser.security_opt: [no-new-privileges:true] — prevents privilege escalation inside container.read_only: true with explicit tmpfs for writable dirs — minimizes attack surface.cap_drop: [ALL] then cap_add only what's needed. Principle of least privilege. Apply to EVERY service — app, db, redis, all of them — not just the app. A database left with full default capabilities is the soft target attackers pivot to.:latest. Reproducible builds = auditable builds.COPY or ARG secrets into image layers. Use RUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci for private registry auth. Pass secrets at build time: docker build --secret id=npmrc,src=.npmrc. Secrets never appear in image history.trivy image myapp:latest before pushing. Fail CI on HIGH/CRITICAL CVEs: trivy image --severity HIGH,CRITICAL --exit-code 1. For Dockerfile linting, use hadolint Dockerfile to catch anti-patterns before building. Both tools are fast and free.# Production-hardened compose service
services:
app:
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
- /app/.cache
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE # Only if binding port < 1024
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
node_modules
.git
.env
.env.*
dist
coverage
*.log
.next
.cache
docker-compose*.yml
Dockerfile*
README.md
tests/
deploy.resources.limits on every production service.(docker_memory * 0.6) / container_count = safe per-container limit.# Logs
docker compose logs -f app # Follow app logs in real-time
docker compose logs --tail=50 db # Last 50 lines from db
# Shell into running container
docker compose exec app sh
docker compose exec db psql -U postgres
# Status and resources
docker compose ps # Service status
docker stats # Live CPU/memory per container
# Network debugging
docker compose exec app nslookup db # DNS resolution check
docker compose exec app wget -qO- http://api:3000/health
# Rebuild
docker compose up --build # Rebuild images then start
docker compose build --no-cache app # Full rebuild, no cache
# Cleanup
docker compose down # Stop + remove containers
docker system prune # Remove unused images/containers/networks
# docker compose down -v # DANGER: removes volumes = data loss
docker compose in production without orchestrator. Use K8s, ECS, or Swarm for real deployments.docker-compose.yml or baked into image layers. Use .env files (gitignored) or Docker secrets.npm install instead of npm ci in Docker. Lockfile drift = unreproducible builds.depends_on only waits for container start, not service ready.