@slamb2k/mad-skills 2.0.13 → 2.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,348 @@
1
+ ---
2
+ name: dock
3
+ description: >-
4
+ Generate container-based release pipelines that build once and promote immutable
5
+ artifacts through environments (dev → staging → prod). Detects your stack, interviews
6
+ for infrastructure choices, then outputs deterministic CI/CD files (Dockerfile,
7
+ workflows, deployment manifests) that run without an LLM. Use when setting up
8
+ deployment pipelines, containerizing an app, creating release workflows, or
9
+ connecting CI to container-friendly infrastructure (Azure Container Apps, AWS Fargate,
10
+ Google Cloud Run, Kubernetes, Dokku, Coolify, CapRover, etc.).
11
+ argument-hint: "--registry-only, --skip-interview, --dry-run"
12
+ allowed-tools: Bash, Read, Write, Edit, Glob, Grep, AskUserQuestion, Agent
13
+ ---
14
+
15
+ # Dock - Container Release Pipelines
16
+
17
+ When this skill is invoked, IMMEDIATELY output the banner below before doing anything else.
18
+ Pick ONE tagline at random — vary your choice each time.
19
+ CRITICAL: Reproduce the banner EXACTLY character-for-character. The first line of the art has 4 leading spaces — you MUST preserve them.
20
+
21
+ ```
22
+ {tagline}
23
+
24
+ ⠀ ██╗██████╗ ██████╗ ██████╗██╗ ██╗
25
+ ██╔╝██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝
26
+ ██╔╝ ██║ ██║██║ ██║██║ █████╔╝
27
+ ██╔╝ ██║ ██║██║ ██║██║ ██╔═██╗
28
+ ██╔╝ ██████╔╝╚██████╔╝╚██████╗██║ ██╗
29
+ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝
30
+ ```
31
+
32
+ Taglines:
33
+ - 🐳 Containerize all the things!
34
+ - 📦 Build once, deploy everywhere!
35
+ - 🚀 From code to container in one shot!
36
+ - ⚓ Anchoring your release pipeline!
37
+ - 🏗️ Immutable artifacts, mutable environments!
38
+ - 🔒 Same image, every stage, every time!
39
+ - 🌊 Shipping containers since... just now!
40
+ - 🎯 One build to rule them all!
41
+
42
+ ---
43
+
44
+ Generate container-based release pipelines following the **build-once, promote-everywhere**
45
+ philosophy. Every artifact is built exactly once, tested, tagged with git SHA + semver,
46
+ pushed to a registry, and promoted through environments without rebuilding.
47
+
48
+ All generated files are deterministic — no LLM required at runtime.
49
+
50
+ ## Flags
51
+
52
+ Parse optional flags from the request:
53
+ - `--registry-only`: Only generate Dockerfile, .dockerignore, and registry config (skip deployment)
54
+ - `--skip-interview`: Use detected defaults without interactive prompts
55
+ - `--dry-run`: Show what would be generated without writing files
56
+
57
+ ---
58
+
59
+ ## Pre-flight
60
+
61
+ Before starting, check dependencies:
62
+
63
+ | Dependency | Type | Check | Required | Resolution | Detail |
64
+ |-----------|------|-------|----------|------------|--------|
65
+ | docker | cli | `docker --version` | no | ask | Needed for local build verification; skip verify phase if absent |
66
+ | git | cli | `git --version` | yes | stop | Install from https://git-scm.com |
67
+
68
+ For each row:
69
+ 1. Run the Check command
70
+ 2. If found: continue silently
71
+ 3. If missing: apply Resolution strategy
72
+ 4. After all checks: summarize availability
73
+
74
+ ---
75
+
76
+ ## Phase 1: Detection
77
+
78
+ Launch an **Explore subagent** to scan the codebase and produce a DETECTION_REPORT.
79
+
80
+ ```
81
+ Task(
82
+ subagent_type: "Explore",
83
+ description: "Detect stack and existing infrastructure",
84
+ prompt: <read from references/interview-guide.md#detection-prompt>
85
+ )
86
+ ```
87
+
88
+ The detection prompt scans for:
89
+ - **Language & framework**: package.json, requirements.txt, go.mod, Cargo.toml, Gemfile, pom.xml, etc.
90
+ - **Existing Dockerfile**: Dockerfile, Dockerfile.*, docker-compose.yml
91
+ - **Existing CI**: .github/workflows/, azure-pipelines.yml, .gitlab-ci.yml
92
+ - **Existing deploy config**: Helm charts, Kubernetes manifests, Procfile, app.json, fly.toml, dokku config
93
+ - **Package manager**: npm/yarn/pnpm/bun, pip/uv/poetry, go modules, cargo, bundler, maven/gradle
94
+ - **Entry point**: main file, start scripts, Procfile commands
95
+ - **Port**: exposed ports in existing config or framework defaults
96
+ - **Environment files**: .env, .env.example, .env.* patterns
97
+
98
+ Parse DETECTION_REPORT. This feeds into the interview phase.
99
+
100
+ ---
101
+
102
+ ## Phase 2: Interview
103
+
104
+ Present the detection results to the user and fill in gaps through guided questions.
105
+ Read the full interview flow from `references/interview-guide.md#interview-questions`.
106
+
107
+ The interview covers these topics in order. Skip questions where detection already
108
+ provided a confident answer (but confirm with the user).
109
+
110
+ ### 2.1 — Stack Confirmation
111
+
112
+ Confirm detected language, framework, and entry point. Ask only if detection was
113
+ ambiguous (e.g., monorepo with multiple stacks).
114
+
115
+ ### 2.2 — Container Registry
116
+
117
+ Detect from existing CI config or ask:
118
+ - GitHub Container Registry (ghcr.io) — default for GitHub repos
119
+ - Azure Container Registry
120
+ - AWS ECR
121
+ - Google Artifact Registry
122
+ - Docker Hub
123
+ - Self-hosted registry
124
+
125
+ ### 2.3 — Environment Topology
126
+
127
+ Ask how many deployment stages and the promotion model:
128
+ - **Simple**: dev → prod (2-stage)
129
+ - **Standard**: dev → staging → prod (3-stage, default)
130
+ - **Custom**: user-defined stages
131
+
132
+ For each environment, ask the deployment target:
133
+ - Azure App Service for Containers
134
+ - Azure Container Apps
135
+ - AWS Fargate
136
+ - Google Cloud Run
137
+ - Kubernetes (any distribution)
138
+ - Dokku
139
+ - Coolify
140
+ - CapRover
141
+ - Other (user-specified)
142
+
143
+ Different environments can use different targets (e.g., dev=Dokku, prod=Azure Container Apps).
144
+
145
+ ### 2.4 — Testing Gates
146
+
147
+ For each environment promotion, ask what tests gate the promotion:
148
+ - **Build gate** (before registry push): unit tests, linting, type checks
149
+ - **Dev gate**: smoke tests, health check verification
150
+ - **Staging gate**: integration tests, e2e tests
151
+ - **Prod gate**: final smoke test post-deploy
152
+
153
+ ### 2.5 — Secrets & Configuration
154
+
155
+ How environment-specific config is managed:
156
+ - GitHub Secrets / Variables (default for GitHub Actions)
157
+ - Azure Key Vault
158
+ - AWS Secrets Manager
159
+ - Environment variables in deployment platform
160
+ - Doppler / 1Password / Vault
161
+
162
+ ### 2.6 — Networking & Domains
163
+
164
+ Optional — ask only if deploying to platforms that need this:
165
+ - Custom domain per environment?
166
+ - TLS certificate management (auto via platform, Let's Encrypt, manual)
167
+ - Load balancer or ingress configuration
168
+
169
+ ### 2.7 — Rollback Strategy
170
+
171
+ - **Simple rollback** (default): redeploy previous image tag on failure
172
+ - **Blue-green**: maintain two environments, swap traffic
173
+ - **Canary**: gradual traffic shift with automatic rollback on error thresholds
174
+
175
+ **If `--skip-interview` flag**: Use detected defaults + sensible defaults for
176
+ everything else (ghcr.io, 3-stage, GitHub Secrets, simple rollback).
177
+
178
+ Compile all answers into a DOCK_CONFIG object for Phase 3.
179
+
180
+ ---
181
+
182
+ ## Phase 3: Generate Artifacts
183
+
184
+ Based on DETECTION_REPORT and DOCK_CONFIG, generate all pipeline files.
185
+ Use templates from `references/` as starting points and customize for the
186
+ detected stack and chosen platforms.
187
+
188
+ ### 3.1 — Dockerfile & .dockerignore
189
+
190
+ Read `references/dockerfile-templates.md` for the detected stack.
191
+
192
+ Generate a multi-stage Dockerfile:
193
+ - **Stage 1 — deps**: Install dependencies only (maximizes cache hits)
194
+ - **Stage 2 — build**: Copy source, run build step
195
+ - **Stage 3 — test**: Run unit tests against the build
196
+ - **Stage 4 — production**: Minimal runtime image with built artifacts only
197
+
198
+ Generate `.dockerignore` excluding: `.git`, `node_modules`, `__pycache__`, `.env*`,
199
+ test fixtures, documentation, IDE config.
200
+
201
+ ### 3.2 — docker-compose.yml
202
+
203
+ Generate a local development compose file that mirrors the production image
204
+ with development overrides (volume mounts, hot reload, debug ports).
205
+
206
+ ### 3.3 — CI/CD Workflow
207
+
208
+ Detect CI system from Phase 1 (GitHub Actions / Azure Pipelines / GitLab CI).
209
+ Read the appropriate template from `references/pipeline-templates.md`.
210
+
211
+ Generate a workflow that implements:
212
+
213
+ **On pull request:**
214
+ 1. Build image tagged with `pr-{number}-{sha:7}`
215
+ 2. Run test stage inside the image
216
+ 3. Push to registry (optional — configurable)
217
+ 4. Comment build status on PR
218
+
219
+ **On merge to main (or default branch):**
220
+ 1. Build image tagged with `{sha:7}` and `latest`
221
+ 2. Run full test suite inside the image
222
+ 3. Push to registry
223
+ 4. Deploy to dev environment
224
+ 5. Run dev-gate tests (smoke tests)
225
+
226
+ **On release tag (vX.Y.Z):**
227
+ 1. Retag the existing `{sha:7}` image as `vX.Y.Z` — **do NOT rebuild**
228
+ 2. Deploy to staging
229
+ 3. Run staging-gate tests
230
+ 4. On success: deploy to prod
231
+ 5. Run prod-gate tests (post-deploy smoke)
232
+
233
+ Key principle: the release workflow **never rebuilds**. It promotes the exact
234
+ image that was tested on main.
235
+
236
+ ### 3.4 — Deployment Manifests
237
+
238
+ Based on the chosen platforms per environment, read the appropriate section
239
+ from `references/platform-deploy-guides.md` and generate:
240
+
241
+ - **Kubernetes**: Helm chart or kustomize overlays with per-environment values
242
+ - **Azure Container Apps**: Bicep/ARM template or `az containerapp` commands in workflow
243
+ - **Azure App Service**: App Service deployment slots config
244
+ - **AWS Fargate**: ECS task definition + service config
245
+ - **Google Cloud Run**: Cloud Run service YAML or `gcloud run deploy` commands
246
+ - **Dokku**: Procfile + dokku git push deployment step
247
+ - **Coolify**: API-based deployment step or docker-compose based
248
+ - **CapRover**: captain-definition file + deploy step
249
+
250
+ ### 3.5 — Environment Matrix
251
+
252
+ Generate an environment matrix config file (`deploy/environments.json` or
253
+ `deploy/environments.yml`) defining per-environment settings:
254
+
255
+ ```yaml
256
+ environments:
257
+ dev:
258
+ target: <platform>
259
+ registry_tag_pattern: "{sha:7}"
260
+ auto_deploy: true
261
+ tests: [smoke]
262
+ staging:
263
+ target: <platform>
264
+ registry_tag_pattern: "v{version}"
265
+ auto_deploy: false # requires manual approval or tag
266
+ tests: [integration, e2e]
267
+ prod:
268
+ target: <platform>
269
+ registry_tag_pattern: "v{version}"
270
+ auto_deploy: false
271
+ tests: [smoke-post-deploy]
272
+ ```
273
+
274
+ ### 3.6 — Health Check Endpoint Guidance
275
+
276
+ If the detected framework doesn't already have a health endpoint, add a comment
277
+ in the generated workflow noting that a `/healthz` or `/health` endpoint is
278
+ recommended for deployment readiness probes.
279
+
280
+ ---
281
+
282
+ ## Phase 4: Verify
283
+
284
+ If Docker is available, run a verification step:
285
+
286
+ ```bash
287
+ docker build --target production -t dock-verify:test .
288
+ ```
289
+
290
+ If the build succeeds, report success. If it fails, diagnose and fix the
291
+ Dockerfile. Skip this phase if Docker is not installed (noted in pre-flight).
292
+
293
+ Also validate generated workflow files:
294
+ - GitHub Actions: check YAML syntax
295
+ - Azure Pipelines: check YAML syntax
296
+ - GitLab CI: check YAML syntax
297
+
298
+ Present the user with a summary of all generated files before writing.
299
+
300
+ **If `--dry-run` flag**: Show the file list and content previews without writing.
301
+
302
+ ---
303
+
304
+ ## Final Report
305
+
306
+ After all files are generated and verified, present:
307
+
308
+ ```
309
+ Dock complete
310
+
311
+ Stack: {language} / {framework}
312
+ Registry: {registry}
313
+ Stages: {env1} → {env2} → {env3}
314
+
315
+ Generated files:
316
+ {file list with brief descriptions}
317
+
318
+ Pipeline flow:
319
+ PR → build + test → [push to registry]
320
+ Merge → build + test → push → deploy dev → smoke tests
321
+ Tag → retag (no rebuild) → deploy staging → e2e → deploy prod → smoke
322
+
323
+ Next steps:
324
+ 1. Review generated files
325
+ 2. Configure secrets: {list of required secrets}
326
+ 3. Push to trigger first pipeline run
327
+ ```
328
+
329
+ ---
330
+
331
+ ## Idempotency
332
+
333
+ If /dock detects it has been run before (existing `deploy/` directory, existing
334
+ deployment workflow), it should:
335
+ - **Dockerfile**: Update if stack detection shows changes; preserve custom stages
336
+ - **Workflow**: Merge new steps; never overwrite user customizations without confirmation
337
+ - **Manifests**: Update image references; preserve environment-specific overrides
338
+ - **Always ask** before overwriting existing files
339
+
340
+ ---
341
+
342
+ ## Integration with /rig and /ship
343
+
344
+ - **/rig integration**: When /rig runs after /dock, it should detect `deploy/`
345
+ artifacts and wire the CI workflow to trigger deployment on merge to main.
346
+ - **/ship integration**: /ship's merge step naturally triggers the deployment
347
+ workflow created by /dock. No special coupling needed — the CI/CD workflow
348
+ handles the handoff via branch/tag triggers.
@@ -0,0 +1,358 @@
1
+ # Dockerfile Templates
2
+
3
+ Multi-stage Dockerfile templates by detected stack. Each template follows the
4
+ four-stage pattern: deps → build → test → production.
5
+
6
+ Customize based on DETECTION_REPORT values. These are starting points, not
7
+ rigid templates — adapt to the specific project.
8
+
9
+ ---
10
+
11
+ ## Node.js
12
+
13
+ ### With npm/yarn/pnpm
14
+
15
+ ```dockerfile
16
+ # Stage 1: Dependencies
17
+ FROM node:22-alpine AS deps
18
+ WORKDIR /app
19
+ COPY package.json package-lock.json ./
20
+ RUN npm ci --production=false
21
+
22
+ # Stage 2: Build
23
+ FROM deps AS build
24
+ COPY . .
25
+ RUN npm run build
26
+
27
+ # Stage 3: Test (used in CI, not in final image)
28
+ FROM build AS test
29
+ RUN npm test
30
+
31
+ # Stage 4: Production
32
+ FROM node:22-alpine AS production
33
+ WORKDIR /app
34
+ ENV NODE_ENV=production
35
+ RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001 -G appgroup
36
+ COPY --from=deps /app/node_modules ./node_modules
37
+ COPY --from=build /app/dist ./dist
38
+ COPY --from=build /app/package.json ./
39
+ USER appuser
40
+ EXPOSE {PORT}
41
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
42
+ CMD wget --no-verbose --tries=1 --spider http://localhost:{PORT}/healthz || exit 1
43
+ CMD ["node", "dist/index.js"]
44
+ ```
45
+
46
+ ### With bun
47
+
48
+ ```dockerfile
49
+ FROM oven/bun:1-alpine AS deps
50
+ WORKDIR /app
51
+ COPY package.json bun.lockb ./
52
+ RUN bun install --frozen-lockfile
53
+
54
+ FROM deps AS build
55
+ COPY . .
56
+ RUN bun run build
57
+
58
+ FROM build AS test
59
+ RUN bun test
60
+
61
+ FROM oven/bun:1-alpine AS production
62
+ WORKDIR /app
63
+ ENV NODE_ENV=production
64
+ RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001 -G appgroup
65
+ COPY --from=deps /app/node_modules ./node_modules
66
+ COPY --from=build /app/dist ./dist
67
+ COPY --from=build /app/package.json ./
68
+ USER appuser
69
+ EXPOSE {PORT}
70
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
71
+ CMD bun --eval "fetch('http://localhost:{PORT}/healthz').then(r => process.exit(r.ok ? 0 : 1))" || exit 1
72
+ CMD ["bun", "run", "dist/index.js"]
73
+ ```
74
+
75
+ ### Next.js (standalone output)
76
+
77
+ ```dockerfile
78
+ FROM node:22-alpine AS deps
79
+ WORKDIR /app
80
+ COPY package.json package-lock.json ./
81
+ RUN npm ci
82
+
83
+ FROM deps AS build
84
+ COPY . .
85
+ ENV NEXT_TELEMETRY_DISABLED=1
86
+ RUN npm run build
87
+
88
+ FROM build AS test
89
+ RUN npm test
90
+
91
+ FROM node:22-alpine AS production
92
+ WORKDIR /app
93
+ ENV NODE_ENV=production NEXT_TELEMETRY_DISABLED=1
94
+ RUN addgroup -g 1001 -S appgroup && adduser -S appuser -u 1001 -G appgroup
95
+ COPY --from=build /app/.next/standalone ./
96
+ COPY --from=build /app/.next/static ./.next/static
97
+ COPY --from=build /app/public ./public
98
+ USER appuser
99
+ EXPOSE 3000
100
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=15s \
101
+ CMD wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1
102
+ CMD ["node", "server.js"]
103
+ ```
104
+
105
+ Note: Requires `output: 'standalone'` in next.config.js.
106
+
107
+ ---
108
+
109
+ ## Python
110
+
111
+ ### With pip/uv
112
+
113
+ ```dockerfile
114
+ FROM python:3.12-slim AS deps
115
+ WORKDIR /app
116
+ COPY requirements.txt ./
117
+ RUN pip install --no-cache-dir -r requirements.txt
118
+
119
+ FROM deps AS build
120
+ COPY . .
121
+
122
+ FROM build AS test
123
+ RUN python -m pytest
124
+
125
+ FROM python:3.12-slim AS production
126
+ WORKDIR /app
127
+ RUN groupadd -r appgroup && useradd -r -g appgroup appuser
128
+ COPY --from=deps /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
129
+ COPY --from=deps /usr/local/bin /usr/local/bin
130
+ COPY --from=build /app .
131
+ USER appuser
132
+ EXPOSE {PORT}
133
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
134
+ CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:{PORT}/healthz')" || exit 1
135
+ CMD ["gunicorn", "--bind", "0.0.0.0:{PORT}", "--workers", "4", "app:app"]
136
+ ```
137
+
138
+ ### With uv (faster installs)
139
+
140
+ ```dockerfile
141
+ FROM python:3.12-slim AS deps
142
+ WORKDIR /app
143
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
144
+ COPY pyproject.toml uv.lock ./
145
+ RUN uv sync --frozen --no-dev --no-install-project
146
+
147
+ FROM deps AS build
148
+ COPY . .
149
+ RUN uv sync --frozen --no-install-project
150
+
151
+ FROM build AS test
152
+ RUN uv run pytest
153
+
154
+ FROM python:3.12-slim AS production
155
+ WORKDIR /app
156
+ RUN groupadd -r appgroup && useradd -r -g appgroup appuser
157
+ COPY --from=deps /app/.venv /app/.venv
158
+ COPY --from=build /app .
159
+ ENV PATH="/app/.venv/bin:$PATH"
160
+ USER appuser
161
+ EXPOSE {PORT}
162
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
163
+ CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:{PORT}/healthz')" || exit 1
164
+ CMD ["gunicorn", "--bind", "0.0.0.0:{PORT}", "--workers", "4", "app:app"]
165
+ ```
166
+
167
+ ### Django
168
+
169
+ Replace CMD with:
170
+ ```dockerfile
171
+ CMD ["gunicorn", "--bind", "0.0.0.0:{PORT}", "--workers", "4", "{PROJECT_NAME}.wsgi:application"]
172
+ ```
173
+
174
+ Add collectstatic to build stage:
175
+ ```dockerfile
176
+ RUN python manage.py collectstatic --noinput
177
+ ```
178
+
179
+ ### FastAPI
180
+
181
+ Replace CMD with:
182
+ ```dockerfile
183
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "{PORT}", "--workers", "4"]
184
+ ```
185
+
186
+ ---
187
+
188
+ ## Go
189
+
190
+ ```dockerfile
191
+ FROM golang:1.23-alpine AS deps
192
+ WORKDIR /app
193
+ COPY go.mod go.sum ./
194
+ RUN go mod download
195
+
196
+ FROM deps AS build
197
+ COPY . .
198
+ RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/server ./cmd/server
199
+
200
+ FROM build AS test
201
+ RUN go test ./...
202
+
203
+ FROM gcr.io/distroless/static-debian12 AS production
204
+ COPY --from=build /app/server /server
205
+ EXPOSE {PORT}
206
+ USER nonroot:nonroot
207
+ CMD ["/server"]
208
+ ```
209
+
210
+ ---
211
+
212
+ ## Rust
213
+
214
+ ```dockerfile
215
+ FROM rust:1.83-slim AS deps
216
+ WORKDIR /app
217
+ COPY Cargo.toml Cargo.lock ./
218
+ RUN mkdir src && echo "fn main() {}" > src/main.rs
219
+ RUN cargo build --release && rm -rf src
220
+
221
+ FROM deps AS build
222
+ COPY . .
223
+ RUN cargo build --release
224
+
225
+ FROM build AS test
226
+ RUN cargo test --release
227
+
228
+ FROM debian:bookworm-slim AS production
229
+ RUN groupadd -r appgroup && useradd -r -g appgroup appuser
230
+ COPY --from=build /app/target/release/{BINARY_NAME} /usr/local/bin/app
231
+ USER appuser
232
+ EXPOSE {PORT}
233
+ CMD ["app"]
234
+ ```
235
+
236
+ ---
237
+
238
+ ## Ruby / Rails
239
+
240
+ ```dockerfile
241
+ FROM ruby:3.3-slim AS deps
242
+ WORKDIR /app
243
+ RUN apt-get update && apt-get install -y build-essential libpq-dev && rm -rf /var/lib/apt/lists/*
244
+ COPY Gemfile Gemfile.lock ./
245
+ RUN bundle config set --local deployment true && bundle install
246
+
247
+ FROM deps AS build
248
+ COPY . .
249
+ RUN SECRET_KEY_BASE=placeholder bundle exec rails assets:precompile
250
+
251
+ FROM build AS test
252
+ RUN bundle exec rspec
253
+
254
+ FROM ruby:3.3-slim AS production
255
+ WORKDIR /app
256
+ RUN apt-get update && apt-get install -y libpq5 && rm -rf /var/lib/apt/lists/*
257
+ RUN groupadd -r appgroup && useradd -r -g appgroup appuser
258
+ COPY --from=deps /app/vendor/bundle ./vendor/bundle
259
+ COPY --from=build /app .
260
+ ENV RAILS_ENV=production RAILS_SERVE_STATIC_FILES=true
261
+ USER appuser
262
+ EXPOSE {PORT}
263
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=15s \
264
+ CMD ruby -e "require 'net/http'; Net::HTTP.get(URI('http://localhost:{PORT}/up'))" || exit 1
265
+ CMD ["bundle", "exec", "rails", "server", "-b", "0.0.0.0", "-p", "{PORT}"]
266
+ ```
267
+
268
+ ---
269
+
270
+ ## .NET
271
+
272
+ ```dockerfile
273
+ FROM mcr.microsoft.com/dotnet/sdk:9.0 AS deps
274
+ WORKDIR /app
275
+ COPY *.csproj ./
276
+ RUN dotnet restore
277
+
278
+ FROM deps AS build
279
+ COPY . .
280
+ RUN dotnet publish -c Release -o /app/publish --no-restore
281
+
282
+ FROM build AS test
283
+ RUN dotnet test --no-restore
284
+
285
+ FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS production
286
+ WORKDIR /app
287
+ RUN groupadd -r appgroup && useradd -r -g appgroup appuser
288
+ COPY --from=build /app/publish .
289
+ USER appuser
290
+ EXPOSE {PORT}
291
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \
292
+ CMD curl -f http://localhost:{PORT}/healthz || exit 1
293
+ CMD ["dotnet", "{ASSEMBLY_NAME}.dll"]
294
+ ```
295
+
296
+ ---
297
+
298
+ ## Java / Spring Boot
299
+
300
+ ```dockerfile
301
+ FROM eclipse-temurin:21-jdk AS deps
302
+ WORKDIR /app
303
+ COPY pom.xml mvnw .mvn ./
304
+ RUN ./mvnw dependency:resolve
305
+
306
+ FROM deps AS build
307
+ COPY . .
308
+ RUN ./mvnw package -DskipTests
309
+
310
+ FROM build AS test
311
+ RUN ./mvnw test
312
+
313
+ FROM eclipse-temurin:21-jre AS production
314
+ WORKDIR /app
315
+ RUN groupadd -r appgroup && useradd -r -g appgroup appuser
316
+ COPY --from=build /app/target/*.jar app.jar
317
+ USER appuser
318
+ EXPOSE {PORT}
319
+ HEALTHCHECK --interval=30s --timeout=3s --start-period=30s \
320
+ CMD curl -f http://localhost:{PORT}/actuator/health || exit 1
321
+ CMD ["java", "-jar", "app.jar"]
322
+ ```
323
+
324
+ ---
325
+
326
+ ## Generic .dockerignore
327
+
328
+ Adapt based on detected stack. Always include:
329
+
330
+ ```
331
+ .git
332
+ .github
333
+ .gitlab
334
+ .env
335
+ .env.*
336
+ *.md
337
+ LICENSE
338
+ docs/
339
+ tests/
340
+ test/
341
+ __tests__/
342
+ *.test.*
343
+ *.spec.*
344
+ .vscode
345
+ .idea
346
+ .editorconfig
347
+ .eslintrc*
348
+ .prettierrc*
349
+ Makefile
350
+ docker-compose*.yml
351
+ ```
352
+
353
+ Stack-specific additions:
354
+ - Node: `node_modules/`
355
+ - Python: `__pycache__/`, `*.pyc`, `.venv/`, `.mypy_cache/`
356
+ - Go: no additions needed (Go copies only what's needed)
357
+ - Rust: `target/`
358
+ - Ruby: `.bundle/`, `tmp/`, `log/`