feat(dev-cicd): add Docker context analysis + .dockerignore check
从实际 CI 失败中学到的经验: - 缺 .dockerignore 导致 768MB context 传入(node_modules) - ACR push denied 因镜像路径缺 namespace - /cicd analyze 增加 .dockerignore + 凭据硬编码 + 镜像命名扫描 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -224,6 +224,43 @@ if: github.ref == 'refs/heads/develop'
|
|||||||
docker build -f docker/gateway.prebuilt.Dockerfile -t $IMAGE .
|
docker build -f docker/gateway.prebuilt.Dockerfile -t $IMAGE .
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 2.6 Docker Context 瘦身
|
||||||
|
|
||||||
|
**问题**:`docker build` 会将整个 context 目录发送到 daemon。缺少 `.dockerignore` 时,`node_modules`(数百 MB)、`.next/`、`.git/` 等全部传入,导致 `transferring context: 768MB` 耗时 30s+。
|
||||||
|
|
||||||
|
**诊断**:
|
||||||
|
```bash
|
||||||
|
# 检查 context 大小(模拟 docker build 发送量)
|
||||||
|
du -sh --exclude=.git <project-dir>
|
||||||
|
|
||||||
|
# 检查是否有 .dockerignore
|
||||||
|
cat <project-dir>/.dockerignore 2>/dev/null || echo "缺少 .dockerignore!"
|
||||||
|
```
|
||||||
|
|
||||||
|
**`/cicd analyze` 必查项**:对每个有 Dockerfile 的目录检查 `.dockerignore` 是否存在。缺失则告警。
|
||||||
|
|
||||||
|
**标准 .dockerignore 模板**:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Node.js
|
||||||
|
node_modules
|
||||||
|
.next
|
||||||
|
.turbo
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# Common
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.env*
|
||||||
|
*.md
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
```
|
||||||
|
|
||||||
|
**效果**:Web 项目 context 从 768MB → ~10MB,Docker build 加速 10x。
|
||||||
|
|
||||||
|
**经验教训**:`.gitignore` 不等于 `.dockerignore`。Git 忽略的文件可能在 runner workspace 中存在(如 self-hosted runner 保留的 `node_modules` 缓存),docker build 会把它们全部打包传入。每个有 Dockerfile 的子目录**必须有 `.dockerignore`**。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. 故障排查
|
## 3. 故障排查
|
||||||
@@ -256,10 +293,12 @@ Pipeline 失败
|
|||||||
│ ├── "Redundant Binary Upload" → 递增 CURRENT_PROJECT_VERSION
|
│ ├── "Redundant Binary Upload" → 递增 CURRENT_PROJECT_VERSION
|
||||||
│ └── "Missing required icon" → Assets.xcassets 缺 1024x1024 icon
|
│ └── "Missing required icon" → Assets.xcassets 缺 1024x1024 icon
|
||||||
│
|
│
|
||||||
├── Docker 构建失败
|
├── Docker 构建失败/慢
|
||||||
│ ├── "Cannot connect to daemon" → Docker Desktop 未启动
|
│ ├── "Cannot connect to daemon" → Docker Desktop 未启动
|
||||||
│ ├── "unauthorized" → docker login 凭据过期
|
│ ├── "unauthorized" / "denied" → docker login 凭据过期 或 ACR namespace 缺失
|
||||||
│ └── "no space left" → docker system prune
|
│ ├── "no space left" → docker system prune
|
||||||
|
│ ├── "transferring context: XXX MB" 很慢 → 缺少 .dockerignore(node_modules 被传入)
|
||||||
|
│ └── build 成功但 push denied → 镜像路径缺 namespace(registry/namespace/image)
|
||||||
│
|
│
|
||||||
└── 部署失败
|
└── 部署失败
|
||||||
├── "Connection refused" (SSH) → 目标服务器 SSH 端口/密钥
|
├── "Connection refused" (SSH) → 目标服务器 SSH 端口/密钥
|
||||||
@@ -278,6 +317,8 @@ Pipeline 失败
|
|||||||
| `Cloud signing permission error` | API Key 权限不足或 Issuer ID 错误 | 用手动签名 + 本地 profile |
|
| `Cloud signing permission error` | API Key 权限不足或 Issuer ID 错误 | 用手动签名 + 本地 profile |
|
||||||
| `HTTP 401 Unauthorized` (ASC API) | JWT 缺少 `kid` header | `headers={"kid": KEY_ID}` |
|
| `HTTP 401 Unauthorized` (ASC API) | JWT 缺少 `kid` header | `headers={"kid": KEY_ID}` |
|
||||||
| `No profiles for bundle id` | 无 distribution profile | 在 Apple Developer 创建并安装 |
|
| `No profiles for bundle id` | 无 distribution profile | 在 Apple Developer 创建并安装 |
|
||||||
|
| `transferring context: 768MB` | 缺 .dockerignore | 创建 .dockerignore 排除 node_modules/.next/.git |
|
||||||
|
| `denied: requested access` (push) | ACR 镜像路径缺 namespace | registry/**namespace**/image |
|
||||||
| `missing icon file 120x120` | 无 App Icon asset | 创建 Assets.xcassets + AppIcon |
|
| `missing icon file 120x120` | 无 App Icon asset | 创建 Assets.xcassets + AppIcon |
|
||||||
| `UIInterfaceOrientation` iPad | 缺 iPad 方向声明 | 四方向 + `UIRequiresFullScreen` |
|
| `UIInterfaceOrientation` iPad | 缺 iPad 方向声明 | 四方向 + `UIRequiresFullScreen` |
|
||||||
|
|
||||||
@@ -453,6 +494,26 @@ curl -s -H "Authorization: token <TOKEN>" \
|
|||||||
|
|
||||||
## 7. Workflow 模板生成
|
## 7. Workflow 模板生成
|
||||||
|
|
||||||
|
### `/cicd analyze` 检查清单
|
||||||
|
|
||||||
|
执行时自动扫描以下项目:
|
||||||
|
|
||||||
|
1. **Workflow YAML** — 语法检查、路径过滤、并发取消、[skip ci]
|
||||||
|
2. **Docker context** — 每个有 Dockerfile 的目录是否有 `.dockerignore`(**必查**)
|
||||||
|
3. **Secrets** — workflow 中是否有硬编码凭据、路径
|
||||||
|
4. **缓存** — 是否利用了依赖缓存(npm/Go/SPM)
|
||||||
|
5. **浅克隆** — checkout 是否用了 `--depth 1`
|
||||||
|
6. **镜像命名** — ACR/registry 路径是否包含 namespace
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 快速扫描命令
|
||||||
|
echo "=== .dockerignore 检查 ==="
|
||||||
|
find . -name Dockerfile -exec sh -c 'DIR=$(dirname "{}"); [ -f "$DIR/.dockerignore" ] && echo "✅ $DIR" || echo "❌ $DIR 缺少 .dockerignore"' \;
|
||||||
|
|
||||||
|
echo "=== 硬编码凭据检查 ==="
|
||||||
|
grep -rn 'password\|secret\|token' .gitea/workflows/ | grep -v 'secrets\.' | grep -v '#'
|
||||||
|
```
|
||||||
|
|
||||||
### `/cicd template go`
|
### `/cicd template go`
|
||||||
|
|
||||||
生成 Go 后端 CI workflow,含 vet → test → build → docker → deploy。
|
生成 Go 后端 CI workflow,含 vet → test → build → docker → deploy。
|
||||||
|
|||||||
Reference in New Issue
Block a user