agentleFS
michaelsvanbeekmichaelsvanbeek/personal-agent-skills/skills/docker/SKILL.md

docker

Skill1 starsChanged 7 months agoMITView on GitHub

Docker and container best practices with security-first, rootless design. Use when: writing Dockerfiles, building container images, creating docker-compose files, hardening containers, setting up local dev environments, configuring container registries, auditing existing Dockerfiles for security and size, or improving container build pipelines.

  • Reads credentials
  • 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 10 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

25 rules. 0 are common, 16 are distinctive, and 9 are very specific to this project.

  • 0

    Common

    Most of the 47 edited versions we read keep these.

  • 16

    Distinctive

    This author's own choices. Worth a look.

  • 9

    Very specific

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

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Every container should run with the least privilege, the smallest attack surface, and no capability beyond what its process requires.

    line 24
  2. Distinctive:

    Always use multi-stage builds to separate build dependencies from the runtime image:

    line 32
  3. Very specific:

    Use --no-cache-dir (pip) and npm ci to avoid caching download artifacts in the image.

    line 84
  4. Very specific:

    Use -slim or -alpine base images.

    line 89
  5. Distinctive:

    Prefer official images from Docker Hub or verified publishers.

    line 91
  6. Very specific:

    Every Dockerfile must include a USER instruction that switches to a non-root user before CMD/ENTRYPOINT.

    line 101
  7. Distinctive:

    Create the user in the Dockerfile:

    line 102
  8. Very specific:

    Never use chmod 777. Use the minimum permissions needed.

    line 115
  9. Distinctive:

    Always set memory and CPU limits to prevent a runaway container from starving the host:

    line 164
  10. Distinctive:

    Place services on internal networks that are not exposed to the host unless needed.

    line 181
  11. Distinctive:

    Only expose ports that must be reachable externally.

    line 182
  12. Distinctive:

    Use service names for inter-container communication, not host networking.

    line 183
  13. Distinctive:

    Run scans in CI on every image build.

    line 215
  14. Very specific:

    Always include a .dockerignore to exclude unnecessary files from the build context:

    line 223
  15. Very specific:

    Use healthcheck on service dependencies.

    line 307
  16. Distinctive:

    Use Docker secrets or env_file for credentials.

    line 308
  17. Distinctive:

    Use named volumes for persistent data (databases, uploads).

    line 310
  18. Very specific:

    Always tag the latest stable build as myapp:latest in addition to the version tag.

    line 321
  19. Very specific:

    Never deploy :latest in production — always use a specific version or SHA tag.

    line 322
  20. Distinctive:

    Use a consistent registry per organization.

    line 323
  21. Distinctive:

    Every container should include a health check:

    line 329
  22. Very specific:

    Use a lightweight check (dedicated /health endpoint) that verifies the process is responsive, not a full dependency check.

    line 336
  23. Distinctive:

    Use this checklist when reviewing docker-compose files (homelab, production, or development):

    line 342
  24. Distinctive:

    If a service requires the Docker socket (monitoring tools, Portainer, Traefik):

    line 435
  25. Distinctive:

    Prefer a socket proxy (e.g., Tecnativa/docker-socket-proxy) that filters API calls:

    line 439

“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 and Container Standards

When to Use

  • Writing or reviewing Dockerfiles
  • Building container images for deployment
  • Creating docker-compose configurations for local dev
  • Hardening containers for production
  • Setting up CI/CD container pipelines
  • Auditing existing Dockerfiles for security issues (running as root, missing health checks, bloated images)
  • Reducing image size via multi-stage builds and dependency cleanup
  • Reviewing docker-compose files for isolation, volume, and network hygiene

Core Principle: Minimal, Rootless, Isolated

Every container should run with the least privilege, the smallest attack surface, and no capability beyond what its process requires.


Dockerfile Best Practices

Multi-Stage Builds

Always use multi-stage builds to separate build dependencies from the runtime image:

# Stage 1: Build
FROM python:3.12-slim AS builder

WORKDIR /app
COPY pyproject.toml .
RUN pip install --no-cache-dir --target=/deps .

COPY src/ src/

# Stage 2: Runtime
FROM python:3.12-slim AS runtime

# Create non-root user
RUN groupadd -r appuser && useradd -r -g appuser -d /app -s /sbin/nologin appuser

WORKDIR /app
COPY --from=builder /deps /usr/local/lib/python3.12/site-packages/
COPY --from=builder /app/src src/

USER appuser
EXPOSE 8000
CMD ["python", "-m", "uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]

Node.js Example

FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json .
RUN npm ci --production=false
COPY . .
RUN npm run build

FROM node:22-alpine AS runtime
RUN addgroup -S appuser && adduser -S appuser -G appuser
WORKDIR /app
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/main.js"]

Layer Optimization

  • Copy dependency manifests first (package.json, pyproject.toml), install, then copy source. This maximizes layer caching.
  • Combine RUN commands with && to reduce layers.
  • Use --no-cache-dir (pip) and npm ci to avoid caching download artifacts in the image.
  • Order instructions from least to most frequently changing.

Image Selection

  • Use -slim or -alpine base images. Never use full OS images.
  • Pin image tags to specific versions: python:3.12.3-slim, not python:latest.
  • Prefer official images from Docker Hub or verified publishers.

Rootless Containers

Never run containers as root. This is the single most impactful security measure.

Rules

  • Every Dockerfile must include a USER instruction that switches to a non-root user before CMD/ENTRYPOINT.
  • Create the user in the Dockerfile:
    # Debian/Ubuntu-based
    RUN groupadd -r appuser && useradd -r -g appuser -d /app -s /sbin/nologin appuser
    
    # Alpine-based
    RUN addgroup -S appuser && adduser -S appuser -G appuser
  • Application files should be owned by root and readable by the app user. Only specific directories (data, logs, tmp) should be writable:
    COPY --chown=root:root src/ src/
    RUN mkdir -p /app/data && chown appuser:appuser /app/data
  • Never use chmod 777. Use the minimum permissions needed.

Rootless Docker Daemon

For production hosts, prefer rootless Docker mode or Podman (rootless by default):

# Install rootless Docker
dockerd-rootless-setuptool.sh install

# Or use Podman (drop-in replacement)
podman run --rm -p 8000:8000 myimage

Container Security

Drop Capabilities

Containers inherit Linux capabilities they don't need. Drop all and add back only what's required:

# docker-compose.yml
services:
  app:
    cap_drop:
      - ALL
    cap_add: []  # add specific caps only if truly needed
    security_opt:
      - no-new-privileges:true

Read-Only Filesystem

Mount the container filesystem as read-only. Provide writable volumes only for directories that need writes:

services:
  app:
    read_only: true
    tmpfs:
      - /tmp
    volumes:
      - app-data:/app/data

Resource Limits

Always set memory and CPU limits to prevent a runaway container from starving the host:

services:
  app:
    deploy:
      resources:
        limits:
          memory: 512M
          cpus: "1.0"
        reservations:
          memory: 256M
          cpus: "0.5"

Network Isolation

  • Place services on internal networks that are not exposed to the host unless needed.
  • Only expose ports that must be reachable externally.
  • Use service names for inter-container communication, not host networking.
networks:
  backend:
    internal: true  # not reachable from host
  frontend:
    # reachable from host

services:
  api:
    networks: [backend, frontend]
    ports: ["8000:8000"]
  db:
    networks: [backend]  # only reachable by api, not from host

Image Scanning

Scan images for known vulnerabilities before deploying:

# Docker Scout (built-in)
docker scout cves myimage:latest

# Trivy (open source)
trivy image myimage:latest

# Grype
grype myimage:latest
  • Run scans in CI on every image build.
  • Block deployment if critical/high severity CVEs are found.
  • Rebuild images regularly to pick up base image security patches.

.dockerignore

Always include a .dockerignore to exclude unnecessary files from the build context:

.git
.gitignore
.env
.env.*
node_modules
__pycache__
*.pyc
.pytest_cache
.mypy_cache
.ruff_cache
dist
build
.serverless
*.md
.vscode
.idea
docker-compose*.yml
Dockerfile*

Docker Compose for Local Development

Structure

version: "3.9"

services:
  app:
    build:
      context: .
      target: runtime
    ports:
      - "8000:8000"
    environment:
      - ENVIRONMENT=dev
    env_file:
      - .env
    volumes:
      - ./src:/app/src  # hot-reload in dev
    depends_on:
      db:
        condition: service_healthy
    cap_drop: [ALL]
    security_opt: [no-new-privileges:true]
    read_only: true
    tmpfs: [/tmp]

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: app
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      timeout: 3s
      retries: 5
    cap_drop: [ALL]
    cap_add: [CHOWN, SETUID, SETGID, FOWNER, DAC_READ_SEARCH]
    networks: [backend]

networks:
  backend:
    internal: true

volumes:
  db-data:

secrets:
  db_password:
    file: ./secrets/db_password.txt

Best Practices

  • Use healthcheck on service dependencies. Use depends_on with condition: service_healthy.
  • Use Docker secrets or env_file for credentials. Never put secrets directly in the compose file.
  • Mount source code as a volume for hot-reload in development. Do not do this in production images.
  • Use named volumes for persistent data (databases, uploads).

Image Naming and Tagging

registry/organization/service:tag
  • Tag with semantic version and git SHA: myapp:1.2.3, myapp:abc1234.
  • Always tag the latest stable build as myapp:latest in addition to the version tag.
  • Never deploy :latest in production — always use a specific version or SHA tag.
  • Use a consistent registry per organization.

Health Checks

Every container should include a health check:

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD curl -f http://localhost:8000/health || exit 1

Use a lightweight check (dedicated /health endpoint) that verifies the process is responsive, not a full dependency check.


Compose Audit Checklist

Use this checklist when reviewing docker-compose files (homelab, production, or development):

Security Audit

CheckWhat to look for
No rootEvery service has user: set or the image runs as non-root by default. If unsure, add user: "1000:1000".
Capabilities droppedEvery service has cap_drop: [ALL]. Only add back specific caps with cap_add: when required.
No new privilegesEvery service has security_opt: [no-new-privileges:true].
Read-only filesystemEvery service has read_only: true with explicit tmpfs: and writable volumes: for dirs that need writes.
No privileged modeNo service uses privileged: true. Find the specific capability needed instead.
No host networkingNo service uses network_mode: host. Use bridge networks with explicit port mapping.
No host PID/IPCNo service uses pid: host or ipc: host.
Secrets not in envPasswords and tokens use Docker secrets (secrets:) or _FILE env conventions, not plaintext environment:.
Limited portsOnly expose ports that need external access. Use internal networks for service-to-service communication.
Resource limitsEvery service has deploy.resources.limits for memory and CPU.
Pinned imagesImage tags use specific versions, not :latest.

Reliability Audit

CheckWhat to look for
Health checksEvery service has a healthcheck: with appropriate interval, timeout, retries.
Dependency orderingServices use depends_on: with condition: service_healthy, not just service name.
Restart policyEvery service has restart: unless-stopped or restart: on-failure.
Named volumesPersistent data uses named volumes, not bind mounts to host paths (except dev hot-reload).
Logging configServices have logging: configured with max-size and max-file to prevent disk fill.
Backup strategyVolumes containing data (databases, configs) have a documented backup method.

Network Audit

CheckWhat to look for
Internal networksBackend databases and services are on internal: true networks.
SegmentationFrontend and backend on separate networks. Only proxy/gateway bridges them.
No default networkIf using multiple networks, don't rely on the default network — name them explicitly.

Example: Hardened Homelab Service

services:
  jellyfin:
    image: jellyfin/jellyfin:10.9.4
    user: "1000:1000"
    read_only: true
    cap_drop: [ALL]
    security_opt: [no-new-privileges:true]
    tmpfs:
      - /tmp
    volumes:
      - jellyfin-config:/config
      - jellyfin-cache:/cache
      - /media/library:/media:ro  # media is read-only
    ports:
      - "8096:8096"
    networks: [frontend]
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 4G
          cpus: "2.0"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8096/health"]
      interval: 30s
      timeout: 5s
      retries: 3
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

networks:
  frontend:

volumes:
  jellyfin-config:
  jellyfin-cache:

Common Homelab Fixes

Service TypeTypical issueFix
Media serversRun as rootSet user: "1000:1000" and chown data dirs
DatabasesNo resource limitsAdd memory limit (Postgres: 1-2G, Redis: 256M-1G)
Reverse proxiesprivileged: true for port 80/443Use cap_add: [NET_BIND_SERVICE] instead
Download clientsNeed host networkUse bridge + explicit port mapping where possible
MonitoringMount Docker socketUse read-only mount: /var/run/docker.sock:/var/run/docker.sock:ro and consider socket proxy

Docker Socket Security

If a service requires the Docker socket (monitoring tools, Portainer, Traefik):

  • Never mount the socket without understanding the implications — socket access = root access to the host.
  • Mount read-only: /var/run/docker.sock:/var/run/docker.sock:ro
  • Prefer a socket proxy (e.g., Tecnativa/docker-socket-proxy) that filters API calls:
services:
  docker-proxy:
    image: tecnativa/docker-socket-proxy:0.2
    environment:
      CONTAINERS: 1
      NETWORKS: 0
      VOLUMES: 0
      IMAGES: 0
      EXEC: 0
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks: [backend]
    cap_drop: [ALL]
    security_opt: [no-new-privileges:true]
    read_only: true

  traefik:
    environment:
      DOCKER_HOST: tcp://docker-proxy:2375
    networks: [backend, frontend]
    # no docker socket mount 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.