agentleFS
jars-demojars-demo/jars-skills/skills/docker/SKILL.md

docker

Skill0 starsChanged 31 days agoMITView on GitHub

Write, review, and fix Dockerfiles, Compose files, and container build configurations. Use when the user asks to write a Dockerfile, containerize an app, fix a slow build, reduce image size, write a docker-compose.yml, set up a multi-service stack, add a healthcheck, fix a build error, or debug a container that won't start.

  • Reads credentials
  • Deletes or force-pushes
  • Installs packages

55 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use ml-training-recipe, replication and 9 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • getcompanion-aiSkill

    ml-training-recipe

    Find implementable ML training recipes from papers, datasets, docs, and code. Use when the user wants to fine-tune, train, reproduce, or choose a practical ML method, dataset, hyperparameter setup, or benchmark recipe.

    Also in 3 projects that use this

  • getcompanion-aiSkill

    replication

    Plan a replication of a paper, claim, or benchmark, and execute only after an explicit environment choice. Use when the user asks to replicate results, reproduce an experiment, verify a claim empirically, or build a replication package.

    Also in 3 projects that use this

  • Sorcha-PlatformSkill

    scalar

    Generates and configures Scalar OpenAPI UI for API documentation. Use when: Adding API documentation to services, configuring OpenAPI endpoints, customizing documentation themes

    Also in 3 projects that use this

  • brainbytes-devSkill

    alpha-research

    Also in 3 projects that use this

  • JaimeParkerSkill

    paper-code-audit

    Perform three-way cross-validation of a research paper by comparing the original paper text (via Zotero), official code implementation (via Git), and personal Obsidian notes. Use this skill whenever the user wants to "audit a paper", "verify paper claims against code", "cross-check notes with implementation", "triangulate paper + code + notes", "find discrepancies between paper and code", or mentions wanting a deep, structured comparison of a paper's claims against its implementation and their own notes. Also trigger when the user asks to "analyze this paper thoroughly" with code available, or when they want to systematically reconcile what the paper says, what the code does, and what their notes claim.

    Also in 3 projects that use this

  • Sorcha-PlatformSkill

    redis

    Implements Redis caching, session management, and distributed coordination for the Sorcha platform. Use when: Adding caching layers, token revocation, rate limiting, SignalR backplane, or distributed state.

    Also in 5 projects that use this

  • +1 more from getcompanion-ai

The file

Show its rules and text

We split this skill into the rules it gives an agent

15 rules. 0 are common, 7 are distinctive, and 8 are very specific to this project.

  • 0

    Common

    Most of the 47 edited versions we read keep these.

  • 7

    Distinctive

    This author's own choices. Worth a look.

  • 8

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Write Dockerfiles and Compose files that build correctly, stay small, use layer caching well, and don't leak secrets or run as root.

    line 8
  2. Very specific:

    Read the project first: Check the runtime, package manager, build tool, and port before writing a single line.

    line 13
  3. Very specific:

    Never run as root in production images: Create a non-root user and switch to it before the final CMD.

    line 19
  4. Very specific:

    Respect the repo's existing Docker setup: If a Dockerfile already exists, read it before replacing it.

    line 21
  5. Very specific:

    Prefer slim / distroless for production.

    line 62
  6. Very specific:

    Check the project's required version exactly: node:22-bookworm-slim not node:slim.

    line 64
  7. Distinctive:

    Always use multi-stage for compiled languages and for Node/Python apps where dev dependencies must not ship to production.

    line 68
  8. Very specific:

    Always create or update .dockerignore to exclude:

    line 125
  9. Distinctive:

    If the app writes files (uploads, logs, SQLite), ensure the target directory is owned by the app user before switching:

    line 158
  10. Very specific:

    Never use CMD node dist/server.js (shell form) — the shell becomes PID 1 and swallows signals.

    line 181
  11. Distinctive:

    Add a healthcheck so Docker and Compose know when the service is actually ready:

    line 186
  12. Distinctive:

    Use Compose for local development and multi-service stacks.

    line 204
  13. Very specific:

    Never hardcode passwords in docker-compose.yml for anything beyond local dev.

    line 245
  14. Distinctive:

    Keep dev-only config out of the production Compose file:

    line 251
  15. Distinctive:

    Check the final image size and layer breakdown:

    line 287

“Common” is measured: kept by at least 6 in 10 of the 47 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Docker

Write Dockerfiles and Compose files that build correctly, stay small, use layer caching well, and don't leak secrets or run as root.

Ground rules

  • Read the project first. Check the runtime, package manager, build tool, and port before writing a single line. A Node.js app and a Python app need different base images, install steps, and signal handling.
  • Never copy secrets into the image. No .env files, no API keys, no credentials in COPY, ENV, or ARG that end up in the final layer. Use runtime environment variables or secrets mounts.
  • Never run as root in production images. Create a non-root user and switch to it before the final CMD.
  • Respect the repo's existing Docker setup. If a Dockerfile already exists, read it before replacing it.
  • Never push, publish, or deploy unless the user explicitly asks for that action.

Step 0: Read the project

Before writing anything:

# What runtime and version does the project need?
cat .nvmrc || cat .node-version || cat .python-version || cat .tool-versions

# What does the build/start look like?
cat package.json | grep -E '"scripts"' -A 10   # Node
cat pyproject.toml | grep -E 'build|start'      # Python
cat Makefile | head -30

# Does a Dockerfile already exist?
ls -la Dockerfile* docker-compose* .dockerignore

Note: the runtime version, the build command, the start command, the port the app listens on, and whether there are any native dependencies that need system packages.


Writing a Dockerfile

Use the right base image

StackDevelopmentProduction
Node.jsnode:<version>-bookwormnode:<version>-bookworm-slim
Pythonpython:<version>-bookwormpython:<version>-slim-bookworm
Gogolang:<version>-bookwormgcr.io/distroless/static-debian12
Javaeclipse-temurin:<version>-jdkeclipse-temurin:<version>-jre-jammy
Static binary—scratch or gcr.io/distroless/static
  • Pin the version tag. Never use latest — it breaks reproducible builds.
  • Prefer slim / distroless for production. They have fewer CVEs and smaller attack surface.
  • Check the project's required version exactly: node:22-bookworm-slim not node:slim.

Multi-stage builds

Always use multi-stage for compiled languages and for Node/Python apps where dev dependencies must not ship to production.

# ── Stage 1: build ──────────────────────────────────────────────
FROM node:22-bookworm-slim AS builder

WORKDIR /app

# Copy manifests first — cached as long as deps don't change
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts

COPY . .
RUN npm run build

# ── Stage 2: production ─────────────────────────────────────────
FROM node:22-bookworm-slim AS production

WORKDIR /app

# Install only production deps in the final stage
COPY package.json package-lock.json ./
RUN npm ci --omit=dev --ignore-scripts

# Copy the built output from the builder stage
COPY --from=builder /app/dist ./dist

# Non-root user
RUN addgroup --system --gid 1001 appgroup && \
    adduser --system --uid 1001 --ingroup appgroup appuser
USER appuser

EXPOSE 3000
CMD ["node", "dist/server.js"]

Layer caching: the most important optimisation

Docker rebuilds every layer after the first changed layer. Dependency installs are slow — put them before COPY . .:

# WRONG: invalidates the npm install on every code change
COPY . .
RUN npm ci

# CORRECT: npm install is cached until package.json changes
COPY package.json package-lock.json ./
RUN npm ci
COPY . .

The pattern: copy manifests → install → copy source → build.

.dockerignore

Always create or update .dockerignore to exclude:

.git
.env
.env.*
node_modules
__pycache__
*.pyc
dist
build
.pytest_cache
.coverage
*.log
README.md

Without .dockerignore, COPY . . sends node_modules (potentially hundreds of MB) and .env (secrets) into the build context.

Non-root user

# Debian/Ubuntu-based images
RUN addgroup --system --gid 1001 appgroup && \
    adduser --system --uid 1001 --ingroup appgroup appuser
USER appuser

# Alpine-based images
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

If the app writes files (uploads, logs, SQLite), ensure the target directory is owned by the app user before switching:

RUN mkdir -p /app/data && chown appuser:appgroup /app/data
USER appuser

Signal handling and PID 1

Node and Python do not handle SIGTERM correctly as PID 1. Use tini or the exec form of CMD to ensure clean shutdown:

# Option A: tini (explicit, works everywhere)
RUN apt-get install -y --no-install-recommends tini
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["node", "dist/server.js"]

# Option B: exec form directly (works when the process handles signals itself)
CMD ["node", "dist/server.js"]   # exec form — NOT ["sh", "-c", "node dist/server.js"]

Never use CMD node dist/server.js (shell form) — the shell becomes PID 1 and swallows signals.

Healthcheck

Add a healthcheck so Docker and Compose know when the service is actually ready:

HEALTHCHECK --interval=10s --timeout=5s --start-period=15s --retries=3 \
  CMD node -e "require('http').get('http://localhost:3000/health', r => process.exit(r.statusCode === 200 ? 0 : 1)).on('error', () => process.exit(1))"

For distroless or minimal images with no shell, use exec form:

HEALTHCHECK --interval=10s --timeout=5s --start-period=15s --retries=3 \
  CMD ["/usr/bin/grpc_health_probe", "-addr=:50051"]

Writing a docker-compose.yml

Use Compose for local development and multi-service stacks. Use explicit service names, pinned image versions, and health-gated dependencies.

services:
  app:
    build:
      context: .
      target: production      # target the prod stage, not the builder
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://postgres:postgres@db:5432/myapp
    depends_on:
      db:
        condition: service_healthy   # wait for the real healthcheck, not just "started"
    restart: unless-stopped

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: myapp
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 10
      start_period: 10s

volumes:
  postgres_data:

Key rules:

  • depends_on: condition: service_healthy — not just depends_on: db. Without the condition, Compose starts the dependent before the database is ready to accept connections.
  • Never hardcode passwords in docker-compose.yml for anything beyond local dev. Use docker-compose.override.yml or a .env file that is in .gitignore.
  • Pin image versions: postgres:16-alpine, not postgres:latest.

Development override

Keep dev-only config out of the production Compose file:

# docker-compose.override.yml  (loaded automatically in dev, not in CI)
services:
  app:
    build:
      target: builder          # use the dev stage with hot reload
    volumes:
      - .:/app                 # mount source for live reload
      - /app/node_modules      # anonymous volume to prevent host modules overwriting container's
    environment:
      - NODE_ENV=development
    command: npm run dev

Reducing image size

  1. Use multi-stage builds — build tooling stays in the builder stage.
  2. Use slim or distroless base images — node:22-bookworm-slim is ~200MB vs ~1GB for node:22.
  3. Combine RUN commands to avoid intermediate layers with leftover apt cache:
    # WRONG: leaves apt cache in a layer
    RUN apt-get update
    RUN apt-get install -y curl
    
    # CORRECT: clean up in the same layer
    RUN apt-get update && \
        apt-get install -y --no-install-recommends curl && \
        rm -rf /var/lib/apt/lists/*
  4. Use --no-install-recommends with apt to skip optional packages.
  5. Don't install dev tools in the production stage — debuggers, compilers, test runners.

Check the final image size and layer breakdown:

docker build -t myapp .
docker images myapp
docker history myapp   # layer-by-layer size breakdown

Debugging build failures

Build fails during package install

# Run the failing RUN step interactively to see the real error
docker run --rm -it <base-image> bash
# then run the install command manually

Build produces wrong output

# Inspect the builder stage specifically
docker build --target builder -t myapp-debug .
docker run --rm -it myapp-debug bash
ls dist/   # did the build output land where you expected?

Container exits immediately

docker run --rm myapp           # run without -d to see output
docker logs <container-id>      # if it was already started
docker inspect <container-id>   # check exit code and OOMKilled

Container starts but app misbehaves

# Check what's actually running inside
docker exec -it <container> sh   # or bash if available
env                              # are environment variables set correctly?
ps aux                           # is the process actually running?

Common mistakes

MistakeFix
COPY . . before npm installCopy manifests first, install, then copy source
latest tag on base imagePin the exact version: node:22-bookworm-slim
.env not in .dockerignoreAdd .env* to .dockerignore
Running as rootAdd a non-root user, USER appuser before CMD
Shell form CMD: CMD npm startExec form: CMD ["node", "dist/server.js"]
depends_on: db without conditionAdd condition: service_healthy
apt cache left in layerrm -rf /var/lib/apt/lists/* in the same RUN
Dev dependencies in production imageUse multi-stage, npm ci --omit=dev in final stage
Secrets in ENV or ARGUse runtime env vars or --secret mounts

Checklist before finishing

  • Base image version is pinned, not latest
  • Multi-stage build separates build tooling from the runtime image
  • COPY of manifests comes before dependency install
  • .dockerignore excludes .env, node_modules, .git, build output
  • No secrets in ENV, ARG, or COPY
  • Non-root user created and active before CMD
  • CMD uses exec form, not shell form
  • Healthcheck defined with a real probe (not just CMD true)
  • docker build runs without error
  • docker run starts the container and the app responds on the expected port
  • For Compose: depends_on uses condition: service_healthy where needed

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.