@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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +390 -15
- package/package.json +1 -1
- package/skills/dock/SKILL.md +348 -0
- package/skills/dock/references/dockerfile-templates.md +358 -0
- package/skills/dock/references/interview-guide.md +209 -0
- package/skills/dock/references/pipeline-templates.md +398 -0
- package/skills/dock/references/platform-deploy-guides.md +457 -0
- package/skills/dock/tests/evals.json +36 -0
- package/skills/keel/SKILL.md +494 -0
- package/skills/keel/references/bicep-templates.md +359 -0
- package/skills/keel/references/iac-pipeline-templates.md +519 -0
- package/skills/keel/references/interview-guide.md +257 -0
- package/skills/keel/references/terraform-templates.md +474 -0
- package/skills/keel/tests/evals.json +35 -0
- package/skills/manifest.json +22 -2
|
@@ -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/`
|