Awesome-omni-skill scaffold-docker
Generate production-grade Docker configuration with multi-stage builds and health check module
git clone https://github.com/diegosouzapw/awesome-omni-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/devops/scaffold-docker" ~/.claude/skills/diegosouzapw-awesome-omni-skill-scaffold-docker && rm -rf "$T"
skills/devops/scaffold-docker/SKILL.mdScaffold Docker & Health Checks
You are setting up production-grade containerization for a mission-critical TypeScript project. This skill generates a hardened Dockerfile, health check module, and Docker Compose configuration.
Available Components
| Key | Component | Description |
|---|---|---|
| Dockerfile + .dockerignore | Multi-stage build with security hardening |
| Health Check Module | module with liveness, readiness, and startup probes |
| Docker Compose | Development and production compose files |
Instructions
1. Determine components
If
$ARGUMENTS is provided, parse it as a comma-separated list. Otherwise, ask the user which components to set up. Default: all.
2. Load context
- Read
for project name, main entry point, scriptspackage.json - Read
fortsconfig.json
(default:outDir
)dist/ - Check if
orsrc/index.ts
exists (application entry point)src/main.ts - Check for existing
,Dockerfile
,docker-compose.ymlsrc/health/
Component: dockerfile
— Dockerfile + .dockerignore
dockerfileAsk the user which base image they prefer for the production stage:
(recommended for most cases) — smaller than full image, includes shell for debuggingnode:22-slim
— no shell, no package manager, minimal attack surface (best for production)gcr.io/distroless/nodejs22-debian12
Generate Dockerfile
:
Dockerfile# ============================================================================= # Build Stage # ============================================================================= FROM node:22-slim AS builder WORKDIR /app # Copy dependency files first for layer caching COPY package.json package-lock.json ./ # Use npm ci for reproducible installs (Rule 3.4) RUN npm ci # Copy source and build COPY tsconfig.json ./ COPY src/ ./src/ RUN npm run build # Prune dev dependencies RUN npm ci --omit=dev # ============================================================================= # Production Stage # ============================================================================= FROM <chosen-base-image> AS production # Security: run as non-root user USER node WORKDIR /app # Copy only production artifacts COPY --from=builder --chown=node:node /app/dist ./dist COPY --from=builder --chown=node:node /app/node_modules ./node_modules COPY --from=builder --chown=node:node /app/package.json ./ # Environment ENV NODE_ENV=production # Health check (adjust port and path as needed) HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD ["node", "-e", "fetch('http://localhost:3000/healthz').then(r => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))"] EXPOSE 3000 # Use node directly (not npm start) for proper signal handling CMD ["node", "dist/index.js"]
If the user chose distroless:
- Remove
(no shell available; rely on Kubernetes probes)HEALTHCHECK
uses JSON array format onlyCMD- No
directive needed (distroless defaults to non-root)USER
If the user chose slim:
- Add
for PID 1 signal handling:dumb-initRUN apt-get update && apt-get install -y --no-install-recommends dumb-init && rm -rf /var/lib/apt/lists/* ENTRYPOINT ["dumb-init", "--"]
Generate .dockerignore
:
.dockerignore# Source and tests (built artifacts are in dist/) src/ tests/ **/*.test.ts **/*.spec.ts # Documentation docs/ *.md !README.md # Development .git/ .github/ .claude/ .vscode/ .idea/ coverage/ .stryker-tmp/ reports/ # Environment and secrets .env .env.* *.pem *.key # Build tools stryker.config.* vitest.config.* tsconfig.json .eslintrc* eslint.config.* commitlint.config.* .husky/ # OS files .DS_Store Thumbs.db # Dependencies (rebuilt in Docker) node_modules/
Add npm scripts:
{ "docker:build": "docker build -t <project-name> .", "docker:run": "docker run -p 3000:3000 <project-name>" }
Suggest Trivy scanning:
# Scan the built image for vulnerabilities trivy image --severity HIGH,CRITICAL --exit-code 1 <project-name>
Component: health-checks
— Health Check Module
health-checksGenerate a health check module under
src/health/ following the project's coding standard (Result pattern, Zod schemas, branded types, readonly, TSDoc).
src/health/schema.ts
:
src/health/schema.ts- Zod schema for health check responses
- Status type using
object (not enum — Rule 3.5):as constconst HealthStatus = { HEALTHY: 'HEALTHY', DEGRADED: 'DEGRADED', UNHEALTHY: 'UNHEALTHY', } as const; type HealthStatusValue = typeof HealthStatus[keyof typeof HealthStatus]; - Response types for liveness, readiness (with per-component status), and startup
- All properties
(Rule 7.1)readonly - Exhaustive switch with
(Rule 8.3)assertUnreachable
src/health/health.ts
:
src/health/health.ts-
: ReturnscheckLiveness()
. Checks:Result<LivenessResponse>- Process is running
- Event loop is responsive (measure event loop lag)
- Does NOT check downstream dependencies (liveness should not trigger restarts due to external failures)
-
: ReturnscheckReadiness(options)
. Checks each dependency:Promise<Result<ReadinessResponse>>- Accept a
(dependency name + check function)ReadonlyArray<HealthDependency> - Each check has an individual timeout using
+AbortController
(Rule 4.2)Promise.race - Default timeout: 5 seconds per dependency
- Returns per-component status with overall status
- Bounded parallelism: check dependencies concurrently but with a limit (Rule 4.3)
- Accept a
-
: ReturnscheckStartup()
. Validates initialization prerequisites.Result<StartupResponse> -
All functions <= 40 lines (Rule 8.4), use Result pattern (Rule 6.2), have TSDoc (Rule 10.1)
src/health/health.test.ts
:
src/health/health.test.ts- Unit tests for all three health check functions
- Tests for: all healthy, one degraded, one unhealthy, timeout scenario, all down
- Property-based test with fast-check for dependency check arrays
- No
in testsany
src/health/index.ts
:
src/health/index.ts- Barrel export of public types and functions
Kubernetes probe configuration:
Generate a
docs/kubernetes-probes.yaml reference:
livenessProbe: httpGet: path: /livez port: 3000 initialDelaySeconds: 30 periodSeconds: 15 failureThreshold: 3 timeoutSeconds: 5 readinessProbe: httpGet: path: /readyz port: 3000 initialDelaySeconds: 10 periodSeconds: 10 failureThreshold: 3 timeoutSeconds: 5 startupProbe: httpGet: path: /healthz port: 3000 initialDelaySeconds: 5 periodSeconds: 5 failureThreshold: 30 timeoutSeconds: 5
Integration guidance:
Show how to wire the health module into common frameworks:
- Plain
: route handler examplehttp.createServer - Express:
exampleapp.get('/healthz', ...) - Fastify: route example
Component: compose
— Docker Compose
composeGenerate docker-compose.yml
for development:
docker-compose.ymlservices: app: build: context: . target: builder # Use build stage for development ports: - "3000:3000" - "9229:9229" # Node.js debugger volumes: - ./src:/app/src - ./dist:/app/dist environment: - NODE_ENV=development - LOG_LEVEL=debug command: npm run dev # Add dependencies as needed: # depends_on: # - postgres # - redis
If the user has databases or caches:
Ask which services to include and add them:
- PostgreSQL: with health check, volume for persistence
- Redis: with health check, memory limits
- MongoDB: with health check, volume
Generate docker-compose.prod.yml
(production overrides):
docker-compose.prod.ymlservices: app: build: context: . target: production restart: unless-stopped environment: - NODE_ENV=production deploy: resources: limits: memory: 512M
Summary
After generating all selected components:
- List all created files
- Note the Kubernetes probe configuration if health checks were generated
- Remind the user to:
- Run
to verify the Dockerfile worksdocker build - Run Trivy scan on the built image
- Wire health check endpoints into their HTTP server
- Add
to the parent barrel export if applicablesrc/health/
- Run