SuperAPI AI Directory

docker

Deployment & operations

View repository

Updated 10-15 20:31

About this skill

Docker

One image, one process. Multi-service, shared networks and volumes: skill docker-compose. Detect the runtime (package.json, Gemfile, mix.exs, go.mod, Cargo.toml, pyproject.toml) and adapt — don't copy a Node Dockerfile into an Elixir app.

Non-negotiable rules

  • Tags pinned (node:22-alpine, digest when the risk requires it). Avoid latest in production.
  • Multi-stage: build tools stay in the build stage; minimal runtime at the end.
  • .dockerignore before the first COPY . . — otherwise node_modules, .git and secrets enter the context.
  • Secrets only at runtime (ENV injected, files, orchestrator). Never COPY .env nor ENV API_KEY=... in the Dockerfile.
  • Process as non-root USER.
  • One concern per container (app or db or worker).
  • HEALTHCHECK in images that start a long-running service.

.dockerignore

.git
.gitignore
**/.env
**/.env.*
**/node_modules
**/dist
**/target
**/_build
**/deps
**/.venv
**/coverage
**/*.md
Dockerfile*
compose*.yml
compose*.yaml

Adjust to the stack. Don't ignore what the build needs (package-lock.json, mix.lock, Gemfile.lock).

Multi-stage (default)

# syntax=docker/dockerfile:1

FROM node:22-bookworm-slim AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM deps AS build
COPY . .
RUN npm run build && npm prune --omit=dev

FROM node:22-bookworm-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN useradd --system --uid 1001 --create-home app
COPY --from=build --chown=app:app /app/package.json ./
COPY --from=build --chown=app:app /app/node_modules ./node_modules
COPY --from=build --chown=app:app /app/dist ./dist
USER app
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD node -e "fetch('http://127.0.0.1:3000/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
CMD ["node", "dist/server.js"]

Adapt:

Stack Build Runtime
Node npm ci / pnpm node in the artifact
Rails bundle deploy, assets rails server / Puma
Phoenix mix deps.get + assets + mix release OTP release
Go CGO_ENABLED=0 go build scratch/distroless + binary
Rust cargo build --release slim + binary
  • WORKDIR explicit; COPY from the most stable (lockfile) to the most volatile (source) — layer cache.
  • RUN combined sensibly (fewer layers), but readable.
  • Alpine: great if native deps compile; glibc (Debian slim) when musl breaks gems/N-API.

Security and runtime

  • USER numeric or named after installing packages (apt needs root).
  • Don't install a compiler in the final stage.
  • --chown in the COPY --from for the final user.
  • Filesystem: assume read-only root in orchestrators; write only to /tmp or a volume.
  • Drop capabilities and read-only stay in compose/k8s — document if the image requires it.
  • EXPOSE is documentation; the real bind is in run/compose.

Tags, build, and CI

docker build -t myapp:$(git rev-parse --short HEAD) .
docker build --target build .   # validar stage
  • Immutable tag (git sha) + myapp:prod movable if the flow requires it.
  • --platform explicit in CI (linux/amd64) when the host is ARM.
  • BuildKit (DOCKER_BUILDKIT=1 / syntax directive) for conscious cache mounts:
RUN --mount=type=cache,target=/root/.npm npm ci

Don't cache secrets.

Anti-patterns

  • FROM ubuntu:latest + apt-get of toolchain in the same stage that runs prod
  • COPY . . without .dockerignore
  • Root as PID 1 without tini/dumb-init when the app doesn't respond to SIGTERM
  • latest in production
  • Two processes (nginx + app) in the same container without a requested supervisor
  • Healthcheck that pings the internet
  • Committing .dockerignore which ignores the lockfile

Integration with other skills

  • Multiple services, DB, networks: docker-compose
  • Go-live: production-readiness
  • Rails/Phoenix/Nuxt: use the language skill and this one for the image

Completion criteria

  • Multi-stage Dockerfile aligned with the detected runtime
  • .dockerignore covering git, deps, and env
  • Non-root user; secrets outside the image
  • Pinned tag; HEALTHCHECK if it is a service
  • Image starts and responds locally (docker build + docker run)