codeforge-dev 1.4.0
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/.devcontainer/.env +22 -0
- package/.devcontainer/CHANGELOG.md +197 -0
- package/.devcontainer/CLAUDE.md +117 -0
- package/.devcontainer/README.md +222 -0
- package/.devcontainer/config/main-system-prompt.md +502 -0
- package/.devcontainer/config/settings.json +47 -0
- package/.devcontainer/devcontainer.json +94 -0
- package/.devcontainer/features/README.md +113 -0
- package/.devcontainer/features/agent-browser/README.md +65 -0
- package/.devcontainer/features/agent-browser/devcontainer-feature.json +23 -0
- package/.devcontainer/features/agent-browser/install.sh +79 -0
- package/.devcontainer/features/ast-grep/README.md +24 -0
- package/.devcontainer/features/ast-grep/devcontainer-feature.json +24 -0
- package/.devcontainer/features/ast-grep/install.sh +51 -0
- package/.devcontainer/features/ccstatusline/README.md +296 -0
- package/.devcontainer/features/ccstatusline/devcontainer-feature.json +19 -0
- package/.devcontainer/features/ccstatusline/install.sh +290 -0
- package/.devcontainer/features/ccusage/README.md +205 -0
- package/.devcontainer/features/ccusage/devcontainer-feature.json +38 -0
- package/.devcontainer/features/ccusage/install.sh +132 -0
- package/.devcontainer/features/claude-code/README.md +498 -0
- package/.devcontainer/features/claude-code/config/settings.json +36 -0
- package/.devcontainer/features/claude-code/config/system-prompt.md +118 -0
- package/.devcontainer/features/claude-code/config/world-building-sp.md +1432 -0
- package/.devcontainer/features/claude-code/devcontainer-feature.json +42 -0
- package/.devcontainer/features/claude-code/install.sh +466 -0
- package/.devcontainer/features/claude-monitor/README.md +74 -0
- package/.devcontainer/features/claude-monitor/devcontainer-feature.json +38 -0
- package/.devcontainer/features/claude-monitor/install.sh +99 -0
- package/.devcontainer/features/lsp-servers/README.md +85 -0
- package/.devcontainer/features/lsp-servers/devcontainer-feature.json +40 -0
- package/.devcontainer/features/lsp-servers/install.sh +116 -0
- package/.devcontainer/features/mcp-qdrant/CHANGES.md +399 -0
- package/.devcontainer/features/mcp-qdrant/README.md +474 -0
- package/.devcontainer/features/mcp-qdrant/devcontainer-feature.json +57 -0
- package/.devcontainer/features/mcp-qdrant/install.sh +295 -0
- package/.devcontainer/features/mcp-qdrant/poststart-hook.sh +129 -0
- package/.devcontainer/features/mcp-reasoner/README.md +177 -0
- package/.devcontainer/features/mcp-reasoner/devcontainer-feature.json +20 -0
- package/.devcontainer/features/mcp-reasoner/install.sh +177 -0
- package/.devcontainer/features/mcp-reasoner/poststart-hook.sh +67 -0
- package/.devcontainer/features/notify-hook/README.md +86 -0
- package/.devcontainer/features/notify-hook/devcontainer-feature.json +23 -0
- package/.devcontainer/features/notify-hook/install.sh +38 -0
- package/.devcontainer/features/splitrail/README.md +140 -0
- package/.devcontainer/features/splitrail/devcontainer-feature.json +34 -0
- package/.devcontainer/features/splitrail/install.sh +129 -0
- package/.devcontainer/features/tree-sitter/README.md +138 -0
- package/.devcontainer/features/tree-sitter/devcontainer-feature.json +52 -0
- package/.devcontainer/features/tree-sitter/install.sh +173 -0
- package/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json +106 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/hooks/hooks.json +17 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-file.py +101 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/hooks/hooks.json +17 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/lint-file.py +137 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/.claude-plugin/plugin.json +8 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/claude-code-headless/SKILL.md +387 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/claude-code-headless/references/cli-flags-and-output.md +312 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/claude-code-headless/references/sdk-and-mcp.md +569 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker/SKILL.md +309 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker/references/compose-services.md +438 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker/references/dockerfile-patterns.md +340 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker-py/SKILL.md +412 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker-py/references/container-lifecycle.md +388 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/docker-py/references/resources-and-security.md +444 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/SKILL.md +344 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/middleware-and-lifespan.md +254 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/pydantic-models.md +245 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/routing-and-dependencies.md +255 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/fastapi/references/sse-and-streaming.md +318 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/pydantic-ai/SKILL.md +345 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/pydantic-ai/references/agents-and-tools.md +271 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/pydantic-ai/references/models-and-streaming.md +422 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/SKILL.md +220 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/references/cross-vendor-principles.md +139 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/references/patterns-and-antipatterns.md +376 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/skill-building/references/skill-authoring-patterns.md +356 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/SKILL.md +329 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/advanced-queries.md +314 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/javascript-patterns.md +323 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/python-patterns.md +354 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/sqlite/references/schema-and-pragmas.md +326 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/SKILL.md +356 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/ai-sdk-svelte.md +128 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/component-patterns.md +332 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/layercake.md +203 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/migration-guide.md +350 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/runes-and-reactivity.md +328 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/spa-and-routing.md +262 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/svelte5/references/svelte-dnd-action.md +181 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/testing/SKILL.md +414 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/testing/references/fastapi-testing.md +411 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codedirective-skills/skills/testing/references/svelte-testing.md +538 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/codeforge-lsp/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/hooks/hooks.json +17 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/block-dangerous.py +110 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/hooks/hooks.json +17 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/hooks/hooks.json +17 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/hooks/hooks.json +17 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/guard-protected.py +108 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272create-pr.md +337 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272new.md +166 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272review-commit.md +290 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/commands/ticket/357/200/272work.md +257 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/plugin.json +8 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/ticket-workflow/.claude-plugin/system-prompt.md +184 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/.claude-plugin/plugin.json +6 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/config/planning-instructions.md +14 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/functional-conjuring-map.md +989 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/hooks/hooks.json +33 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/__pycache__/post-enhance-task.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhance-planning.py +71 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-plan.sh +68 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-task.sh +120 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-plan.py +133 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-task.py +253 -0
- package/.devcontainer/scripts/setup-aliases.sh +80 -0
- package/.devcontainer/scripts/setup-config.sh +28 -0
- package/.devcontainer/scripts/setup-irie-claude.sh +32 -0
- package/.devcontainer/scripts/setup-plugins.sh +80 -0
- package/.devcontainer/scripts/setup.sh +58 -0
- package/LICENSE.txt +674 -0
- package/README.md +267 -0
- package/package.json +44 -0
- package/setup.js +83 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# Dockerfile Patterns — Deep Dive
|
|
2
|
+
|
|
3
|
+
## 1. Multi-Stage Build Strategies
|
|
4
|
+
|
|
5
|
+
### Shared Base Stage
|
|
6
|
+
|
|
7
|
+
Multiple stages can inherit from a common base to avoid repeating setup:
|
|
8
|
+
|
|
9
|
+
```dockerfile
|
|
10
|
+
FROM node:22-alpine AS base
|
|
11
|
+
WORKDIR /app
|
|
12
|
+
RUN apk add --no-cache tini
|
|
13
|
+
|
|
14
|
+
FROM base AS deps
|
|
15
|
+
COPY package.json package-lock.json ./
|
|
16
|
+
RUN npm ci
|
|
17
|
+
|
|
18
|
+
FROM base AS dev-deps
|
|
19
|
+
COPY package.json package-lock.json ./
|
|
20
|
+
RUN npm ci --include=dev
|
|
21
|
+
|
|
22
|
+
FROM dev-deps AS builder
|
|
23
|
+
COPY . .
|
|
24
|
+
RUN npm run build
|
|
25
|
+
|
|
26
|
+
FROM dev-deps AS test
|
|
27
|
+
COPY . .
|
|
28
|
+
RUN npm run test
|
|
29
|
+
|
|
30
|
+
FROM base AS runtime
|
|
31
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
32
|
+
COPY --from=builder /app/dist ./dist
|
|
33
|
+
USER node
|
|
34
|
+
ENTRYPOINT ["/sbin/tini", "--"]
|
|
35
|
+
CMD ["node", "dist/server.js"]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Build a specific stage with `docker build --target test .` to run tests without producing the runtime image. The final stage (runtime) only includes production dependencies and build output.
|
|
39
|
+
|
|
40
|
+
### BuildKit Cache Mounts
|
|
41
|
+
|
|
42
|
+
Cache mounts persist package manager caches across builds, eliminating redundant downloads:
|
|
43
|
+
|
|
44
|
+
```dockerfile
|
|
45
|
+
# Node.js — cache npm
|
|
46
|
+
RUN --mount=type=cache,target=/root/.npm \
|
|
47
|
+
npm ci --production
|
|
48
|
+
|
|
49
|
+
# Python — cache pip
|
|
50
|
+
RUN --mount=type=cache,target=/root/.cache/pip \
|
|
51
|
+
pip install --no-compile -r requirements.txt
|
|
52
|
+
|
|
53
|
+
# Go — cache modules and build
|
|
54
|
+
RUN --mount=type=cache,target=/go/pkg/mod \
|
|
55
|
+
--mount=type=cache,target=/root/.cache/go-build \
|
|
56
|
+
go build -o /app .
|
|
57
|
+
|
|
58
|
+
# Apt — cache package lists and archives
|
|
59
|
+
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
|
|
60
|
+
--mount=type=cache,target=/var/lib/apt,sharing=locked \
|
|
61
|
+
apt-get update && apt-get install -y --no-install-recommends gcc
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The `sharing=locked` option serializes access when parallel builds target the same cache, preventing corruption of package manager lock files.
|
|
65
|
+
|
|
66
|
+
Cache mounts are BuildKit-only. Enable with `DOCKER_BUILDKIT=1` or use `docker buildx build`. Cache mounts are performance optimizations — builds must produce correct results even when the cache is empty.
|
|
67
|
+
|
|
68
|
+
### Secret Mounts
|
|
69
|
+
|
|
70
|
+
Inject secrets at build time without baking them into image layers:
|
|
71
|
+
|
|
72
|
+
```dockerfile
|
|
73
|
+
# As a file mount
|
|
74
|
+
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
|
|
75
|
+
npm ci --production
|
|
76
|
+
|
|
77
|
+
# As an environment variable
|
|
78
|
+
RUN --mount=type=secret,id=GITHUB_TOKEN,env=GITHUB_TOKEN \
|
|
79
|
+
go install private.example.com/tool@latest
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Pass secrets at build time:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
docker buildx build --secret id=npmrc,src=$HOME/.npmrc .
|
|
86
|
+
docker buildx build --secret id=GITHUB_TOKEN,env=GITHUB_TOKEN .
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Secret mounts are never included in the image layer cache. The `required` option (default `false`) controls whether the build fails if the secret is not provided.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 2. Layer Ordering Strategy
|
|
94
|
+
|
|
95
|
+
Order Dockerfile instructions from least-frequently-changed to most-frequently-changed. Each instruction creates a layer; Docker caches layers until it encounters a change, then rebuilds all subsequent layers.
|
|
96
|
+
|
|
97
|
+
**Optimal order:**
|
|
98
|
+
|
|
99
|
+
```dockerfile
|
|
100
|
+
# 1. Base image (changes rarely)
|
|
101
|
+
FROM python:3.13-slim
|
|
102
|
+
|
|
103
|
+
# 2. System dependencies (changes occasionally)
|
|
104
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
105
|
+
libpq-dev \
|
|
106
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
107
|
+
|
|
108
|
+
# 3. Working directory
|
|
109
|
+
WORKDIR /app
|
|
110
|
+
|
|
111
|
+
# 4. Dependency manifests (changes when deps change)
|
|
112
|
+
COPY pyproject.toml uv.lock ./
|
|
113
|
+
|
|
114
|
+
# 5. Install dependencies (rebuilds only when manifests change)
|
|
115
|
+
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
116
|
+
uv sync --frozen --no-dev
|
|
117
|
+
|
|
118
|
+
# 6. Application source (changes most frequently)
|
|
119
|
+
COPY . .
|
|
120
|
+
|
|
121
|
+
# 7. Runtime configuration (changes rarely)
|
|
122
|
+
USER nobody
|
|
123
|
+
EXPOSE 8000
|
|
124
|
+
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0"]
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Common mistakes:**
|
|
128
|
+
- Copying the entire source tree before installing dependencies — any source change invalidates the dependency cache
|
|
129
|
+
- Running `apt-get update` and `apt-get install` in separate `RUN` instructions — the update layer gets cached, leading to stale package lists
|
|
130
|
+
- Installing build tools in the runtime stage — use a separate build stage
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 3. ENTRYPOINT and CMD Interaction
|
|
135
|
+
|
|
136
|
+
### Exec Form vs Shell Form
|
|
137
|
+
|
|
138
|
+
| Form | Syntax | PID 1 | Signal handling | Variable expansion |
|
|
139
|
+
|------|--------|-------|-----------------|-------------------|
|
|
140
|
+
| Exec | `["executable", "arg1"]` | The executable | Direct (receives SIGTERM) | None |
|
|
141
|
+
| Shell | `executable arg1` | `/bin/sh -c` | Shell receives signals, not the process | Yes (`$VAR` works) |
|
|
142
|
+
|
|
143
|
+
Always prefer exec form for `ENTRYPOINT`. Shell form wraps the process in `/bin/sh`, preventing proper signal propagation for graceful shutdown.
|
|
144
|
+
|
|
145
|
+
### Interaction Matrix
|
|
146
|
+
|
|
147
|
+
| | No ENTRYPOINT | ENTRYPOINT (shell) `cmd` | ENTRYPOINT (exec) `["exec"]` |
|
|
148
|
+
|---|---|---|---|
|
|
149
|
+
| **No CMD** | Error | `/bin/sh -c cmd` | `exec` |
|
|
150
|
+
| **CMD (exec)** `["c1", "c2"]` | `c1 c2` | `/bin/sh -c cmd` | `exec c1 c2` |
|
|
151
|
+
| **CMD (shell)** `c1 c2` | `/bin/sh -c c1 c2` | `/bin/sh -c cmd` | `exec /bin/sh -c c1 c2` |
|
|
152
|
+
|
|
153
|
+
Key rules:
|
|
154
|
+
- `docker run <image> arg1 arg2` replaces CMD but preserves ENTRYPOINT
|
|
155
|
+
- Setting ENTRYPOINT resets any inherited CMD to empty
|
|
156
|
+
- Only the last ENTRYPOINT and last CMD in a Dockerfile take effect
|
|
157
|
+
|
|
158
|
+
### Common Patterns
|
|
159
|
+
|
|
160
|
+
**Init process wrapper** — handles zombie processes and signal forwarding:
|
|
161
|
+
|
|
162
|
+
```dockerfile
|
|
163
|
+
RUN apk add --no-cache tini
|
|
164
|
+
ENTRYPOINT ["/sbin/tini", "--"]
|
|
165
|
+
CMD ["node", "server.js"]
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Script entrypoint** — performs setup then execs the main process:
|
|
169
|
+
|
|
170
|
+
```dockerfile
|
|
171
|
+
COPY docker-entrypoint.sh /usr/local/bin/
|
|
172
|
+
ENTRYPOINT ["docker-entrypoint.sh"]
|
|
173
|
+
CMD ["postgres"]
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
#!/bin/sh
|
|
178
|
+
set -e
|
|
179
|
+
# Run migrations, set permissions, etc.
|
|
180
|
+
exec "$@"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The `exec "$@"` pattern replaces the shell with the CMD arguments, ensuring the application becomes PID 1.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 4. Security Hardening
|
|
188
|
+
|
|
189
|
+
### Non-Root User
|
|
190
|
+
|
|
191
|
+
```dockerfile
|
|
192
|
+
# Alpine
|
|
193
|
+
RUN addgroup -S app && adduser -S -G app app
|
|
194
|
+
USER app
|
|
195
|
+
|
|
196
|
+
# Debian/Ubuntu
|
|
197
|
+
RUN groupadd --system app && useradd --system --gid app --no-create-home app
|
|
198
|
+
USER app
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Set `USER` after copying files and before `ENTRYPOINT`/`CMD`. Files copied before `USER` are owned by root; use `COPY --chown=app:app` to set ownership at copy time.
|
|
202
|
+
|
|
203
|
+
### Read-Only Filesystem
|
|
204
|
+
|
|
205
|
+
Run containers with `--read-only` and provide writable tmpfs mounts for required paths:
|
|
206
|
+
|
|
207
|
+
```yaml
|
|
208
|
+
# compose.yaml
|
|
209
|
+
services:
|
|
210
|
+
app:
|
|
211
|
+
read_only: true
|
|
212
|
+
tmpfs:
|
|
213
|
+
- /tmp
|
|
214
|
+
- /var/run
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Minimal Base Images
|
|
218
|
+
|
|
219
|
+
| Base | Size | Use Case |
|
|
220
|
+
|------|------|----------|
|
|
221
|
+
| `alpine:3.21` | ~7 MB | Static binaries, Go, Rust |
|
|
222
|
+
| `node:22-alpine` | ~130 MB | Node.js applications |
|
|
223
|
+
| `python:3.13-slim` | ~140 MB | Python (when C extensions needed) |
|
|
224
|
+
| `python:3.13-alpine` | ~50 MB | Python (pure Python or prebuilt wheels) |
|
|
225
|
+
| `gcr.io/distroless/static` | ~2 MB | Static binaries, no shell |
|
|
226
|
+
| `gcr.io/distroless/cc` | ~20 MB | C/C++ with glibc |
|
|
227
|
+
| `ubuntu:24.04` | ~75 MB | When Alpine compatibility is an issue |
|
|
228
|
+
|
|
229
|
+
Distroless images contain no shell, package manager, or unnecessary utilities — reducing attack surface. Debug variants (`distroless/static:debug`) include a busybox shell for troubleshooting.
|
|
230
|
+
|
|
231
|
+
### No Secrets in Build Args
|
|
232
|
+
|
|
233
|
+
Build args are visible in the image metadata (`docker history`). Use `--mount=type=secret` instead of `ARG` for sensitive values:
|
|
234
|
+
|
|
235
|
+
```dockerfile
|
|
236
|
+
# WRONG — secret visible in image history
|
|
237
|
+
ARG DATABASE_PASSWORD
|
|
238
|
+
RUN echo $DATABASE_PASSWORD > /app/config
|
|
239
|
+
|
|
240
|
+
# CORRECT — secret available only during build step
|
|
241
|
+
RUN --mount=type=secret,id=db_pass,target=/run/secrets/db_pass \
|
|
242
|
+
cat /run/secrets/db_pass > /app/config
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 5. .dockerignore Patterns
|
|
248
|
+
|
|
249
|
+
Place `.dockerignore` in the build context root. Patterns follow `.gitignore` syntax:
|
|
250
|
+
|
|
251
|
+
```gitignore
|
|
252
|
+
# Version control
|
|
253
|
+
.git
|
|
254
|
+
.gitignore
|
|
255
|
+
|
|
256
|
+
# Dependencies (rebuilt in container)
|
|
257
|
+
node_modules
|
|
258
|
+
__pycache__
|
|
259
|
+
*.pyc
|
|
260
|
+
.venv
|
|
261
|
+
vendor/
|
|
262
|
+
|
|
263
|
+
# Build output
|
|
264
|
+
dist
|
|
265
|
+
build
|
|
266
|
+
*.egg-info
|
|
267
|
+
|
|
268
|
+
# IDE and editor files
|
|
269
|
+
.vscode
|
|
270
|
+
.idea
|
|
271
|
+
*.swp
|
|
272
|
+
*.swo
|
|
273
|
+
|
|
274
|
+
# Docker files (prevent recursive context)
|
|
275
|
+
Dockerfile*
|
|
276
|
+
compose*.yaml
|
|
277
|
+
.dockerignore
|
|
278
|
+
|
|
279
|
+
# Secrets and environment
|
|
280
|
+
.env
|
|
281
|
+
.env.*
|
|
282
|
+
*.pem
|
|
283
|
+
*.key
|
|
284
|
+
secrets/
|
|
285
|
+
|
|
286
|
+
# Documentation and CI
|
|
287
|
+
README.md
|
|
288
|
+
LICENSE
|
|
289
|
+
.github/
|
|
290
|
+
docs/
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
A well-maintained `.dockerignore` reduces build context size (faster builds) and prevents accidentally including secrets or unnecessary files in the image.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## 6. HEALTHCHECK in Dockerfile
|
|
298
|
+
|
|
299
|
+
Define health checks directly in the Dockerfile when the check is intrinsic to the application:
|
|
300
|
+
|
|
301
|
+
```dockerfile
|
|
302
|
+
# HTTP service
|
|
303
|
+
HEALTHCHECK --interval=30s --timeout=5s --retries=3 --start-period=10s \
|
|
304
|
+
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
|
|
305
|
+
|
|
306
|
+
# TCP service (no curl/wget needed)
|
|
307
|
+
HEALTHCHECK --interval=10s --timeout=3s --retries=3 \
|
|
308
|
+
CMD ["pg_isready", "-U", "postgres"]
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
| Parameter | Default | Description |
|
|
312
|
+
|-----------|---------|-------------|
|
|
313
|
+
| `--interval` | `30s` | Time between probes |
|
|
314
|
+
| `--timeout` | `30s` | Maximum time for a single probe |
|
|
315
|
+
| `--retries` | `3` | Consecutive failures before `unhealthy` |
|
|
316
|
+
| `--start-period` | `0s` | Grace period — failures do not count |
|
|
317
|
+
| `--start-interval` | `5s` | Probe frequency during start period |
|
|
318
|
+
|
|
319
|
+
Exit codes: `0` = healthy, `1` = unhealthy. Only the last `HEALTHCHECK` instruction takes effect. Disable an inherited health check with `HEALTHCHECK NONE`.
|
|
320
|
+
|
|
321
|
+
Prefer lightweight probes. Use `wget --spider` over `curl` in Alpine images (wget is included by default; curl requires installation). For non-HTTP services, use the service's native readiness tool (`pg_isready`, `redis-cli ping`, `mysqladmin ping`).
|
|
322
|
+
|
|
323
|
+
Health checks defined in the Dockerfile serve as defaults. Compose health checks override them when specified.
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## 7. Security Audit Checklist
|
|
328
|
+
|
|
329
|
+
A systematic checklist for auditing Dockerfile and Compose security. Work through each item in order — earlier items address higher-impact risks:
|
|
330
|
+
|
|
331
|
+
1. **Base image currency** — Pin base images to a specific digest or version tag. Scan with `docker scout cves` or Trivy. Verify the image is updated within the last 90 days.
|
|
332
|
+
2. **Non-root user** — Confirm a dedicated user/group is created and `USER` is set before `ENTRYPOINT`/`CMD`. Verify no `chmod 777` or overly permissive ownership.
|
|
333
|
+
3. **Read-only root filesystem** — Enable `read_only: true` in Compose. Provide `tmpfs` mounts only for paths that require writes (`/tmp`, `/var/run`, application-specific caches).
|
|
334
|
+
4. **No secrets in build args or ENV** — Search for `ARG` and `ENV` containing passwords, tokens, or keys. Replace with `--mount=type=secret` for build-time secrets and `/run/secrets/` for runtime secrets.
|
|
335
|
+
5. **`.dockerignore` coverage** — Confirm `.env`, `*.pem`, `*.key`, credentials files, and `.git` are excluded from the build context.
|
|
336
|
+
6. **Minimal exposed ports** — Verify each `EXPOSE` and Compose `ports` entry is required. Internal-only services should not publish ports to the host.
|
|
337
|
+
7. **Capabilities dropped** — Set `cap_drop: [ALL]` in Compose, then add back only required capabilities with `cap_add`. Common additions: `NET_BIND_SERVICE` (bind ports < 1024), `SYS_PTRACE` (debugging only).
|
|
338
|
+
8. **Volume mounts reviewed** — Confirm no mount exposes the host root filesystem or Docker socket (`/var/run/docker.sock`) unless explicitly required and documented.
|
|
339
|
+
9. **Network isolation** — Backend services (databases, caches, internal APIs) should use networks with `internal: true`. Only edge services belong on externally reachable networks.
|
|
340
|
+
10. **Image scanning in CI** — Run `docker scout cves`, `trivy image`, or equivalent in the build pipeline. Fail the build on critical/high CVEs with no available fix excluded.
|