packwise-skills 1.0.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/.cursorrules +23 -0
- package/CLAUDE.md +25 -0
- package/README.md +295 -0
- package/audit.md +224 -0
- package/bin/packwise.js +155 -0
- package/package.json +31 -0
- package/skill.md +719 -0
- package/sub-skills/ai/local-llm.md +183 -0
- package/sub-skills/ai/python-ml.md +164 -0
- package/sub-skills/backend/go-server.md +184 -0
- package/sub-skills/backend/java-spring.md +241 -0
- package/sub-skills/backend/node-server.md +164 -0
- package/sub-skills/backend/php-laravel.md +175 -0
- package/sub-skills/backend/python-server.md +164 -0
- package/sub-skills/backend/rust-backend.md +118 -0
- package/sub-skills/cli/python-cli.md +236 -0
- package/sub-skills/cli/sdk-library.md +497 -0
- package/sub-skills/cloud/ci-cd-pipelines.md +350 -0
- package/sub-skills/cloud/docker.md +191 -0
- package/sub-skills/cloud/kubernetes.md +277 -0
- package/sub-skills/cloud/payment-integration.md +307 -0
- package/sub-skills/cross-platform/multiplatform.md +252 -0
- package/sub-skills/desktop/electron.md +783 -0
- package/sub-skills/desktop/game-dev.md +443 -0
- package/sub-skills/desktop/native-app.md +123 -0
- package/sub-skills/desktop/scenarios.md +443 -0
- package/sub-skills/desktop/smart-platforms.md +324 -0
- package/sub-skills/desktop/tauri.md +428 -0
- package/sub-skills/desktop/vr-ar.md +252 -0
- package/sub-skills/desktop/web-to-desktop.md +153 -0
- package/sub-skills/embedded/car-infotainment.md +129 -0
- package/sub-skills/embedded/esp32.md +184 -0
- package/sub-skills/embedded/ros.md +150 -0
- package/sub-skills/embedded/stm32.md +160 -0
- package/sub-skills/mobile/android.md +322 -0
- package/sub-skills/mobile/capacitor.md +232 -0
- package/sub-skills/mobile/flutter-mobile.md +138 -0
- package/sub-skills/mobile/harmonyos.md +150 -0
- package/sub-skills/mobile/ios.md +245 -0
- package/sub-skills/mobile/react-native.md +443 -0
- package/sub-skills/mobile/wearables.md +230 -0
- package/sub-skills/plugins/browser-extension.md +308 -0
- package/sub-skills/plugins/jetbrains-plugin.md +226 -0
- package/sub-skills/plugins/vscode-extension.md +204 -0
- package/sub-skills/security/security-tools.md +174 -0
- package/sub-skills/web/monorepo.md +274 -0
- package/sub-skills/web/pwa.md +220 -0
- package/sub-skills/web/serverless-edge.md +295 -0
- package/sub-skills/web/spa.md +266 -0
- package/sub-skills/web/ssr.md +228 -0
- package/sub-skills/web/wasm.md +243 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# CI/CD Pipeline Build Sub-Skill
|
|
2
|
+
|
|
3
|
+
Set up continuous integration and continuous deployment pipelines for building, testing, and publishing software packages.
|
|
4
|
+
|
|
5
|
+
**Current versions**: GitHub Actions / GitLab CI / Jenkins (2025-2026)
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
- Automated build on every push/tag
|
|
10
|
+
- Automated testing before merge
|
|
11
|
+
- Automated publishing to package registries
|
|
12
|
+
- Multi-platform build (build on Linux/macOS/Windows)
|
|
13
|
+
- Release automation (tag → build → publish → notify)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## GitHub Actions (Recommended for GitHub-hosted projects)
|
|
18
|
+
|
|
19
|
+
### Basic Build + Test
|
|
20
|
+
|
|
21
|
+
```yaml
|
|
22
|
+
# .github/workflows/ci.yml
|
|
23
|
+
name: CI
|
|
24
|
+
on:
|
|
25
|
+
push:
|
|
26
|
+
branches: [main]
|
|
27
|
+
pull_request:
|
|
28
|
+
branches: [main]
|
|
29
|
+
|
|
30
|
+
jobs:
|
|
31
|
+
build:
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
- uses: actions/setup-node@v4
|
|
36
|
+
with:
|
|
37
|
+
node-version: '22'
|
|
38
|
+
cache: 'npm'
|
|
39
|
+
- run: npm ci
|
|
40
|
+
- run: npm run lint
|
|
41
|
+
- run: npm test
|
|
42
|
+
- run: npm run build
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Multi-Platform Build
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
# .github/workflows/release.yml
|
|
49
|
+
name: Release
|
|
50
|
+
on:
|
|
51
|
+
push:
|
|
52
|
+
tags: ['v*']
|
|
53
|
+
|
|
54
|
+
jobs:
|
|
55
|
+
build:
|
|
56
|
+
strategy:
|
|
57
|
+
matrix:
|
|
58
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
59
|
+
runs-on: ${{ matrix.os }}
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/checkout@v4
|
|
62
|
+
- uses: actions/setup-node@v4
|
|
63
|
+
with:
|
|
64
|
+
node-version: '22'
|
|
65
|
+
- run: npm ci
|
|
66
|
+
- run: npm run build
|
|
67
|
+
- run: npm run package # electron-builder, tauri, etc.
|
|
68
|
+
- uses: actions/upload-artifact@v4
|
|
69
|
+
with:
|
|
70
|
+
name: build-${{ matrix.os }}
|
|
71
|
+
path: release/
|
|
72
|
+
|
|
73
|
+
publish:
|
|
74
|
+
needs: build
|
|
75
|
+
runs-on: ubuntu-latest
|
|
76
|
+
permissions:
|
|
77
|
+
contents: write
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/download-artifact@v4
|
|
80
|
+
with:
|
|
81
|
+
path: artifacts/
|
|
82
|
+
- uses: softprops/action-gh-release@v2
|
|
83
|
+
with:
|
|
84
|
+
files: artifacts/**/*
|
|
85
|
+
generate_release_notes: true
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Container Build + Push
|
|
89
|
+
|
|
90
|
+
```yaml
|
|
91
|
+
# .github/workflows/docker.yml
|
|
92
|
+
name: Docker
|
|
93
|
+
on:
|
|
94
|
+
push:
|
|
95
|
+
tags: ['v*']
|
|
96
|
+
|
|
97
|
+
jobs:
|
|
98
|
+
docker:
|
|
99
|
+
runs-on: ubuntu-latest
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/checkout@v4
|
|
102
|
+
- uses: docker/setup-buildx-action@v3
|
|
103
|
+
- uses: docker/login-action@v3
|
|
104
|
+
with:
|
|
105
|
+
registry: ghcr.io
|
|
106
|
+
username: ${{ github.actor }}
|
|
107
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
108
|
+
- uses: docker/build-push-action@v6
|
|
109
|
+
with:
|
|
110
|
+
push: true
|
|
111
|
+
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
|
|
112
|
+
cache-from: type=gha
|
|
113
|
+
cache-to: type=gha,mode=max
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Release to Package Registries
|
|
117
|
+
|
|
118
|
+
```yaml
|
|
119
|
+
# npm publish
|
|
120
|
+
- run: npm publish --provenance --access public
|
|
121
|
+
env:
|
|
122
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
123
|
+
|
|
124
|
+
# PyPI publish
|
|
125
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
126
|
+
with:
|
|
127
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
128
|
+
|
|
129
|
+
# crates.io publish
|
|
130
|
+
- run: cargo publish
|
|
131
|
+
env:
|
|
132
|
+
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_TOKEN }}
|
|
133
|
+
|
|
134
|
+
# Docker Hub
|
|
135
|
+
- uses: docker/login-action@v3
|
|
136
|
+
with:
|
|
137
|
+
username: ${{ secrets.DOCKER_USERNAME }}
|
|
138
|
+
password: ${{ secrets.DOCKER_TOKEN }}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## GitLab CI
|
|
144
|
+
|
|
145
|
+
### Basic Pipeline
|
|
146
|
+
|
|
147
|
+
```yaml
|
|
148
|
+
# .gitlab-ci.yml
|
|
149
|
+
stages:
|
|
150
|
+
- build
|
|
151
|
+
- test
|
|
152
|
+
- package
|
|
153
|
+
- publish
|
|
154
|
+
|
|
155
|
+
variables:
|
|
156
|
+
NODE_VERSION: "22"
|
|
157
|
+
|
|
158
|
+
build:
|
|
159
|
+
stage: build
|
|
160
|
+
image: node:${NODE_VERSION}-alpine
|
|
161
|
+
script:
|
|
162
|
+
- npm ci
|
|
163
|
+
- npm run build
|
|
164
|
+
artifacts:
|
|
165
|
+
paths:
|
|
166
|
+
- dist/
|
|
167
|
+
|
|
168
|
+
test:
|
|
169
|
+
stage: test
|
|
170
|
+
image: node:${NODE_VERSION}-alpine
|
|
171
|
+
script:
|
|
172
|
+
- npm ci
|
|
173
|
+
- npm test
|
|
174
|
+
coverage: '/Lines\s*:\s*(\d+\.?\d*)%/'
|
|
175
|
+
|
|
176
|
+
package:
|
|
177
|
+
stage: package
|
|
178
|
+
image: node:${NODE_VERSION}-alpine
|
|
179
|
+
script:
|
|
180
|
+
- npm ci
|
|
181
|
+
- npm run package
|
|
182
|
+
artifacts:
|
|
183
|
+
paths:
|
|
184
|
+
- release/
|
|
185
|
+
only:
|
|
186
|
+
- tags
|
|
187
|
+
|
|
188
|
+
publish:
|
|
189
|
+
stage: publish
|
|
190
|
+
image: node:${NODE_VERSION}-alpine
|
|
191
|
+
script:
|
|
192
|
+
- npm ci
|
|
193
|
+
- npm publish
|
|
194
|
+
only:
|
|
195
|
+
- tags
|
|
196
|
+
environment: production
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Multi-Platform (GitLab)
|
|
200
|
+
|
|
201
|
+
```yaml
|
|
202
|
+
# Using GitLab CI with Docker-in-Docker for multi-arch
|
|
203
|
+
build-multiarch:
|
|
204
|
+
stage: package
|
|
205
|
+
image: docker:latest
|
|
206
|
+
services:
|
|
207
|
+
- docker:dind
|
|
208
|
+
script:
|
|
209
|
+
- docker buildx create --use
|
|
210
|
+
- docker buildx build --platform linux/amd64,linux/arm64 -t $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG --push .
|
|
211
|
+
only:
|
|
212
|
+
- tags
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Jenkins
|
|
218
|
+
|
|
219
|
+
### Jenkinsfile (Declarative Pipeline)
|
|
220
|
+
|
|
221
|
+
```groovy
|
|
222
|
+
// Jenkinsfile
|
|
223
|
+
pipeline {
|
|
224
|
+
agent any
|
|
225
|
+
environment {
|
|
226
|
+
NODE_VERSION = '22'
|
|
227
|
+
}
|
|
228
|
+
stages {
|
|
229
|
+
stage('Build') {
|
|
230
|
+
steps {
|
|
231
|
+
sh 'npm ci'
|
|
232
|
+
sh 'npm run build'
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
stage('Test') {
|
|
236
|
+
steps {
|
|
237
|
+
sh 'npm test'
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
stage('Package') {
|
|
241
|
+
when { tag pattern: "v\\d+\\.\\d+\\.\\d+", comparator: "REGEXP" }
|
|
242
|
+
steps {
|
|
243
|
+
sh 'npm run package'
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
stage('Publish') {
|
|
247
|
+
when { tag pattern: "v\\d+\\.\\d+\\.\\d+", comparator: "REGEXP" }
|
|
248
|
+
steps {
|
|
249
|
+
withCredentials([string(credentialsId: 'npm-token', variable: 'NPM_TOKEN')]) {
|
|
250
|
+
sh 'npm publish'
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
post {
|
|
256
|
+
always {
|
|
257
|
+
cleanWs()
|
|
258
|
+
}
|
|
259
|
+
success {
|
|
260
|
+
slackSend(channel: '#builds', message: "Build succeeded: ${env.JOB_NAME} #${env.BUILD_NUMBER}")
|
|
261
|
+
}
|
|
262
|
+
failure {
|
|
263
|
+
slackSend(channel: '#builds', message: "Build failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}")
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Common CI/CD Patterns
|
|
272
|
+
|
|
273
|
+
### Pattern: Tag-Based Release
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
# Developer workflow:
|
|
277
|
+
git tag v1.2.3
|
|
278
|
+
git push origin v1.2.3
|
|
279
|
+
# CI automatically: build → test → package → publish → create release
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Pattern: Monorepo CI
|
|
283
|
+
|
|
284
|
+
```yaml
|
|
285
|
+
# Only run jobs for changed packages
|
|
286
|
+
on:
|
|
287
|
+
push:
|
|
288
|
+
paths:
|
|
289
|
+
- 'packages/web/**'
|
|
290
|
+
- 'packages/shared/**'
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Pattern: Matrix Build
|
|
294
|
+
|
|
295
|
+
```yaml
|
|
296
|
+
strategy:
|
|
297
|
+
matrix:
|
|
298
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
299
|
+
node: [20, 22]
|
|
300
|
+
exclude:
|
|
301
|
+
- os: macos-latest
|
|
302
|
+
node: 20 # Save macOS runner minutes
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Pattern: Caching
|
|
306
|
+
|
|
307
|
+
```yaml
|
|
308
|
+
# npm
|
|
309
|
+
- uses: actions/cache@v4
|
|
310
|
+
with:
|
|
311
|
+
path: ~/.npm
|
|
312
|
+
key: npm-${{ hashFiles('package-lock.json') }}
|
|
313
|
+
|
|
314
|
+
# Gradle
|
|
315
|
+
- uses: actions/cache@v4
|
|
316
|
+
with:
|
|
317
|
+
path: |
|
|
318
|
+
~/.gradle/caches
|
|
319
|
+
~/.gradle/wrapper
|
|
320
|
+
key: gradle-${{ hashFiles('**/*.gradle*') }}
|
|
321
|
+
|
|
322
|
+
# Docker layers
|
|
323
|
+
cache-from: type=gha
|
|
324
|
+
cache-to: type=gha,mode=max
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## Platform Comparison
|
|
330
|
+
|
|
331
|
+
| Feature | GitHub Actions | GitLab CI | Jenkins |
|
|
332
|
+
|---------|---------------|-----------|---------|
|
|
333
|
+
| Hosting | GitHub Cloud | GitLab Cloud / Self-hosted | Self-hosted |
|
|
334
|
+
| Free tier | 2000 min/month | 400 min/month | Unlimited (self-hosted) |
|
|
335
|
+
| Config format | YAML | YAML | Groovy (Jenkinsfile) |
|
|
336
|
+
| Marketplace | Large (actions) | Smaller | Huge (plugins) |
|
|
337
|
+
| Matrix builds | Yes | Yes | Yes |
|
|
338
|
+
| Best for | GitHub repos | GitLab repos | On-premise, complex workflows |
|
|
339
|
+
|
|
340
|
+
## Common Pitfalls
|
|
341
|
+
|
|
342
|
+
| Issue | Fix |
|
|
343
|
+
|-------|-----|
|
|
344
|
+
| Secrets not available in PRs | PRs from forks don't have secrets; use `pull_request_target` carefully |
|
|
345
|
+
| Build timeout | Increase timeout; optimize build (caching, parallel jobs) |
|
|
346
|
+
| macOS runner expensive | Use Linux for testing; macOS only for packaging |
|
|
347
|
+
| Artifact size limit | GitHub: 500MB per artifact; use release assets for large files |
|
|
348
|
+
| Tag triggers not working | Ensure tag pattern matches: `tags: ['v*']` |
|
|
349
|
+
| Docker build slow | Use BuildKit caching; multi-stage builds; smaller base images |
|
|
350
|
+
| Node_modules cache not working | Check `cache` option in `setup-node`; verify lockfile hash |
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Docker Containerization Sub-Skill
|
|
2
|
+
|
|
3
|
+
Containerize any project for deployment using Docker.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
- Backend service containerization
|
|
8
|
+
- Frontend static resource containerization
|
|
9
|
+
- Full-stack application containerization
|
|
10
|
+
- Microservice architecture
|
|
11
|
+
- Development environment standardization
|
|
12
|
+
|
|
13
|
+
## Dockerfile Templates
|
|
14
|
+
|
|
15
|
+
### Node.js Application
|
|
16
|
+
|
|
17
|
+
```dockerfile
|
|
18
|
+
FROM node:22-alpine AS builder
|
|
19
|
+
WORKDIR /app
|
|
20
|
+
COPY package*.json ./
|
|
21
|
+
RUN npm ci
|
|
22
|
+
COPY . .
|
|
23
|
+
RUN npm run build
|
|
24
|
+
|
|
25
|
+
FROM node:22-alpine
|
|
26
|
+
WORKDIR /app
|
|
27
|
+
COPY --from=builder /app/dist ./dist
|
|
28
|
+
COPY --from=builder /app/node_modules ./node_modules
|
|
29
|
+
COPY --from=builder /app/package.json ./
|
|
30
|
+
RUN apk add --no-cache tini && \
|
|
31
|
+
addgroup -S appgroup && adduser -S appuser -G appgroup && \
|
|
32
|
+
chown -R appuser:appgroup /app
|
|
33
|
+
USER appuser
|
|
34
|
+
EXPOSE 3000
|
|
35
|
+
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:3000/health || exit 1
|
|
36
|
+
ENTRYPOINT ["/sbin/tini", "--"]
|
|
37
|
+
CMD ["node", "dist/server.js"]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Python Application
|
|
41
|
+
|
|
42
|
+
```dockerfile
|
|
43
|
+
FROM python:3.13-slim AS builder
|
|
44
|
+
WORKDIR /app
|
|
45
|
+
COPY requirements.txt .
|
|
46
|
+
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
|
|
47
|
+
|
|
48
|
+
FROM python:3.13-slim
|
|
49
|
+
WORKDIR /app
|
|
50
|
+
COPY --from=builder /install /usr/local
|
|
51
|
+
COPY . .
|
|
52
|
+
RUN groupadd -r appuser && useradd -r -g appuser appuser && \
|
|
53
|
+
chown -R appuser:appuser /app
|
|
54
|
+
USER appuser
|
|
55
|
+
EXPOSE 8000
|
|
56
|
+
HEALTHCHECK --interval=30s --timeout=3s CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1
|
|
57
|
+
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "app:app"]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Go Application
|
|
61
|
+
|
|
62
|
+
```dockerfile
|
|
63
|
+
FROM golang:1.23-alpine AS builder
|
|
64
|
+
WORKDIR /app
|
|
65
|
+
COPY go.* ./
|
|
66
|
+
RUN go mod download
|
|
67
|
+
COPY . .
|
|
68
|
+
RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o myapp .
|
|
69
|
+
|
|
70
|
+
FROM alpine:latest
|
|
71
|
+
RUN apk add --no-cache ca-certificates tzdata && \
|
|
72
|
+
addgroup -S appgroup && adduser -S appuser -G appgroup
|
|
73
|
+
COPY --from=builder /app/myapp /myapp
|
|
74
|
+
USER appuser
|
|
75
|
+
EXPOSE 8080
|
|
76
|
+
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:8080/health || exit 1
|
|
77
|
+
CMD ["/myapp"]
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Static Frontend
|
|
81
|
+
|
|
82
|
+
```dockerfile
|
|
83
|
+
FROM nginx:alpine
|
|
84
|
+
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
|
85
|
+
COPY dist/ /usr/share/nginx/html
|
|
86
|
+
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
|
87
|
+
RUN chown -R appuser:appgroup /usr/share/nginx/html
|
|
88
|
+
USER appuser
|
|
89
|
+
EXPOSE 80
|
|
90
|
+
HEALTHCHECK --interval=30s --timeout=3s CMD wget -qO- http://localhost:80/ || exit 1
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Docker Compose
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
services:
|
|
97
|
+
app:
|
|
98
|
+
build: .
|
|
99
|
+
ports: ["3000:3000"]
|
|
100
|
+
environment:
|
|
101
|
+
- DATABASE_URL=postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
|
|
102
|
+
depends_on:
|
|
103
|
+
db:
|
|
104
|
+
condition: service_healthy
|
|
105
|
+
restart: unless-stopped
|
|
106
|
+
db:
|
|
107
|
+
image: postgres:16
|
|
108
|
+
environment:
|
|
109
|
+
POSTGRES_USER: ${POSTGRES_USER}
|
|
110
|
+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
111
|
+
POSTGRES_DB: ${POSTGRES_DB}
|
|
112
|
+
volumes: ["pgdata:/var/lib/postgresql/data"]
|
|
113
|
+
healthcheck:
|
|
114
|
+
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
|
|
115
|
+
interval: 10s
|
|
116
|
+
timeout: 5s
|
|
117
|
+
retries: 5
|
|
118
|
+
restart: unless-stopped
|
|
119
|
+
volumes:
|
|
120
|
+
pgdata:
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
> **Security**: Never hardcode passwords in docker-compose.yml. Use `.env` file (add to `.gitignore`) or Docker secrets.
|
|
124
|
+
|
|
125
|
+
> **Best practice**: Commit a `.env.example` file (without real values) to version control so other developers know which environment variables are required. The actual `.env` file must remain in `.gitignore`.
|
|
126
|
+
>
|
|
127
|
+
> ```text
|
|
128
|
+
> # .env.example (commit this — no real values)
|
|
129
|
+
> POSTGRES_USER=your_user
|
|
130
|
+
> POSTGRES_PASSWORD=
|
|
131
|
+
> POSTGRES_DB=your_db
|
|
132
|
+
> ```
|
|
133
|
+
|
|
134
|
+
## .dockerignore (Required)
|
|
135
|
+
|
|
136
|
+
```text
|
|
137
|
+
# .dockerignore — must be in the same directory as Dockerfile
|
|
138
|
+
node_modules
|
|
139
|
+
.git
|
|
140
|
+
.gitignore
|
|
141
|
+
.env
|
|
142
|
+
.env.*
|
|
143
|
+
*.md
|
|
144
|
+
.dockerignore
|
|
145
|
+
Dockerfile
|
|
146
|
+
docker-compose*.yml
|
|
147
|
+
.vscode
|
|
148
|
+
.idea
|
|
149
|
+
coverage
|
|
150
|
+
test
|
|
151
|
+
tests
|
|
152
|
+
*.log
|
|
153
|
+
dist
|
|
154
|
+
build
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Image Security Scanning
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Scan for vulnerabilities before pushing
|
|
161
|
+
docker scout cves myapp:latest # Docker Scout (built-in)
|
|
162
|
+
trivy image myapp:latest # Trivy (open-source)
|
|
163
|
+
grype myapp:latest # Anchore Grype
|
|
164
|
+
|
|
165
|
+
# Scan in CI
|
|
166
|
+
docker scout cves --only-severity critical,high myapp:latest
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Best Practices
|
|
170
|
+
|
|
171
|
+
| Practice | Description |
|
|
172
|
+
|----------|-------------|
|
|
173
|
+
| Multi-stage build | Reduce image size by separating build and runtime |
|
|
174
|
+
| Alpine base image | Smaller images (5MB vs 100MB+ for Debian) |
|
|
175
|
+
| .dockerignore | Exclude node_modules, .git, .env, tests |
|
|
176
|
+
| Non-root user | Run as non-root in production (`USER appuser`) |
|
|
177
|
+
| Health check | `HEALTHCHECK` instruction for container orchestration |
|
|
178
|
+
| Pinned versions | Avoid `latest` tag; use specific versions (`node:22.3.1-alpine`) |
|
|
179
|
+
| No secrets in image | Use env vars, Docker secrets, or mounted volumes |
|
|
180
|
+
| Image scanning | Scan for CVEs before pushing (`docker scout cves`) |
|
|
181
|
+
| Read-only filesystem | `--read-only` flag prevents runtime file modifications |
|
|
182
|
+
| No `ADD` when `COPY` suffices | `ADD` can fetch URLs and extract archives (security risk) |
|
|
183
|
+
|
|
184
|
+
## Common Pitfalls
|
|
185
|
+
|
|
186
|
+
| Issue | Fix |
|
|
187
|
+
|-------|-----|
|
|
188
|
+
| Large image | Multi-stage build + Alpine |
|
|
189
|
+
| Slow build | Leverage Docker layer caching |
|
|
190
|
+
| Permission issues | Use non-root user |
|
|
191
|
+
| Timezone | Set `TZ` environment variable |
|