Docker
Overview
Containerization, Dockerfile architecture, security best practices, and container orchestration for production workloads.
When to Use
Activate when creating or optimizing Dockerfiles, docker-compose configurations, container security audits, or CI/CD container builds.
Rules & Patterns
Negative Constraints (What NOT to Do)
- NEVER run containers as
rootin production: Always create and switch to an unprivileged non-root user (e.g.USER nodeorUSER nonroot). - NEVER use the
latesttag: Always pin base images to specific immutable version digests or explicit minor tags (e.g.node:20.12.2-alpine3.19). - NEVER copy source code before
package.json: Always copy lockfiles and install dependencies first to leverage Docker's layer caching. - NEVER bake secrets, API keys, or
.envfiles into image layers: Pass secrets via build-time secret mounts (--mount=type=secret) or runtime environment variables. - NEVER include build tools or devDependencies in the final runner image: Always use multi-stage builds to discard compilers and package managers from production images.
Multi-Stage Standard Pattern
FROM node:20.12.2-alpine3.19 AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --production
FROM node:20.12.2-alpine3.19 AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup -S -g 1001 appgroup && adduser -S -u 1001 appuser -G appgroup
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
USER appuser
CMD ["node", "dist/index.js"]
Code Examples
See EXAMPLES.md for production Dockerfiles and dockerignore patterns.
Validation Checklist
- Multi-stage build separates build tools from runtime
- Non-root
USERdirective active in final stage - Base images pinned to exact versions
-
.dockerignorefile prevents leaking node_modules or secrets
Common Mistakes
- Copying entire workspace before
npm ci, breaking Docker cache. SeeTROUBLESHOOTING.md.
Integration Notes
Interacts with security (container hardening) and node / nextjs / fastapi.
Docker Examples — Anti-patterns vs ContextOS Standard
Example 1: Multi-Stage Build & Layer Caching
Anti-pattern: Anti-pattern (Fat single-stage image running as root)
# BAD: 1.2GB image, runs as root, breaks caching on every file edit
FROM node:latest
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
Best practice: ContextOS Standard (Slim multi-stage build with non-root user)
# GOOD: 95MB image, non-root user, optimized layer caching
FROM node:20.12.2-alpine3.19 AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --production
FROM node:20.12.2-alpine3.19 AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup -S -g 1001 appgroup && adduser -S -u 1001 appuser -G appgroup
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
USER appuser
CMD ["node", "dist/main.js"]
Example 2: Docker Ignore File (.dockerignore)
Best practice: ContextOS Standard .dockerignore
node_modules
npm-debug.log
.git
.gitignore
.env
.env.*
dist
coverage
.DS_Store
*.md
Docker Troubleshooting Guide
Common Issues & Fixes
1. Slow Docker builds rebuilding node_modules every time
- Cause: Copying the entire directory (
COPY . .) before runningnpm ci. - Fix: Copy
package.jsonandpackage-lock.jsonseparately first, runnpm ci, and only then copy application source code.
2. Permission Denied Errors with Non-Root Users
- Cause: Files copied from builder without changing ownership.
- Fix: Always use
--chown=appuser:appgroupwhen copying files in Dockerfile.
3. Missing native build dependencies on Alpine Linux
- Cause: Packages requiring C bindings (e.g.
sharp,bcrypt) fail on musl libc. - Fix: Add
RUN apk add --no-cache libc6-compat python3 make g++in the builder stage.