CI/CD 规范
本页定义 AgileLabs Framework 项目在前后端混合仓库中的默认 CI/CD 规则,包括前端依赖安装、后端发布、镜像构建、部署边界和多应用产物汇总约定。接口契约请继续阅读 前端对接规范 与 WebAPI 规范;Drone 的 runner、结构模板和示例请继续阅读 Drone CI 配置专题。
适用场景
- 使用 Drone 作为持续集成与持续部署平台的项目。
- 同一仓库中同时存在一个或多个前端应用、WebAPI、后台任务或需要统一发布目录的项目。
- 需要把前端构建、后端发布、镜像和部署边界稳定写成团队默认规则的项目。
必须遵守
- 前端 CI 默认使用
pnpm,不再以npm ci作为新项目和新流水线的默认方案。 - 使用
pnpm的前端项目必须提交pnpm-lock.yaml,不得与package-lock.json长期混用为同一套默认锁文件。 - 前端依赖安装默认使用
pnpm install --frozen-lockfile,确保 CI 可复现。 - 当项目使用
node:latest或其他会漂移的 Node 构建镜像,且依赖链包含需要 install/build script 的包时,项目级必须显式提交pnpm-workspace.yaml或等价 pnpm 策略配置,声明允许执行的依赖构建脚本。 - 多前端仓库中,每个前端应用必须独立成一个构建步骤,不把多个应用串进同一个长命令步骤。
- 前端构建步骤只负责安装依赖和生成
dist/等构建产物,产物同步必须放到独立汇总步骤。 - 后端 CI 必须把
restore、test、publish视为清晰边界;至少dotnet publish必须独立成正式步骤。 - 后端
dotnet publish只负责生成最终发布目录,不与镜像构建、推送或部署命令混写成一个大步骤。 - 前端构建镜像、后端 SDK 发布镜像、后端运行时镜像必须分别记录镜像族与版本 tag,不能只写“用 Docker 构建”。
- 后端 SDK 发布镜像只用于
dotnet restore、dotnet test、dotnet publish等构建阶段;应用 Dockerfile 中的运行时镜像必须单独维护。 - 镜像构建步骤只能消费已经准备好的
publish目录或其他最终制品目录,不得在镜像步骤里重新编译源码。 - 部署步骤只能消费镜像或最终制品,不得在部署步骤中再次执行源码构建。
- 多步骤之间的依赖必须显式写出,不能依赖 YAML 书写顺序猜测执行边界。
- 部署规则只定义步骤边界和制品来源,不在通用规范中写真实仓库地址、命名空间、凭据或内网环境细节。
推荐做法
- 将复杂构建逻辑收敛到
scripts/ci/*,让.drone.yml主要表达步骤边界和依赖关系。 - 为每个前端应用单独维护
package.json和pnpm-lock.yaml,在没有 workspace 需求时保持独立 importer 即可。 - 在前端步骤中统一使用团队认可的 Node 构建镜像,并固定安装命令、锁文件策略和产物目录约定。
- 当依赖链包含原生模块、文件监听器或其他需要 install/build script 的包时,优先使用项目级 allow 配置显式声明允许列表,而不是关闭 pnpm 的整套安全检查。
- 在后端步骤中先执行测试或必要检查,再执行
dotnet publish,把最终发布目录作为镜像步骤唯一输入,并记录实际使用的 SDK 镜像 tag。 - 用单独的汇总步骤将多个前端
dist/、后端publish/和附加静态资源同步到最终发布目录。 - 在镜像推送成功后再进入部署步骤,并将版本写入、部署命令和回滚点信息视为部署阶段的一部分,而不是构建阶段的副作用。
运作机制
- 本页负责定义正式默认规则,Drone CI 配置专题 负责说明 runner、模板和组织方式,两者不要混写成一页。
- 前端依赖安装统一收敛到
pnpm和pnpm-lock.yaml,目的是让本地开发、CI 构建和文档口径建立在同一套可复现前提上。 pnpm install --frozen-lockfile只能保证锁文件解析一致,不能覆盖包管理器新版本引入的安全策略变化;当 pnpm 升级后,CI 是否可复现还取决于项目是否显式声明构建脚本策略。node:latest会隐式带来 Node、corepack 和 pnpm 行为漂移,因此前端 CI 的可复现性不只依赖 lockfile,也依赖项目级 pnpm 配置是否完整。- 多前端仓库将每个应用拆成独立步骤,是为了并行执行、缩小失败定位范围,并避免多个应用共享同一发布目录时互相覆盖。
- 后端
dotnet publish是源码编译边界,镜像构建是制品打包边界,部署步骤是环境变更边界;三者分开后,问题定位、缓存复用和重试策略都更清晰。 - 构建镜像和运行时镜像不是同一件事:前者决定 CI 中能否完成依赖安装和源码发布,后者决定容器启动后的系统库、时区、端口和运行时版本。
- 多前端 + WebAPI 仓库的推荐顺序固定为:前端各自构建、后端发布、统一汇总静态资源、构建镜像、推送镜像、执行部署。
- 部署动作可以是 Kubernetes 更新、版本写入、脚本发布或其他环境发布方式,但它们都必须消费已经完成的最终制品,而不是继续回头处理源码。
标准 CI 镜像记录
项目级 CI 文档或 .drone.yml 附近应能快速查到以下信息:
| 类别 | 典型示例 | 记录位置 | 说明 |
|---|---|---|---|
| 前端构建镜像 | hub.feinian.net/build/node:latest、hub.feinian.net/library/node:25-alpine、hub.feinian.net/feinian/node:20-alpine |
.drone.yml 的前端构建步骤、前端 package.json、pnpm-lock.yaml |
记录 Node 镜像族和 tag,避免 latest 漂移后无法追踪构建环境。 |
| 后端发布镜像 | hub.feinian.net/dotnet/sdk:10.0、hub.feinian.net/dotnet/sdk:8.0 |
.drone.yml 的 dotnet publish 步骤 |
只负责 restore、test、publish,不应出现在应用运行时 Dockerfile 中。 |
| 后端运行时镜像 | hub.feinian.net/build/dotnet/aspnet:10.0、hub.feinian.net/dotnet/aspnet:10.0、hub.feinian.net/dotnet/aspnet:8.0 |
WebAPI、WebHost、JobHost 等项目 Dockerfile | 决定容器运行环境,应与发布目标框架和端口、时区等运行配置一起检查。 |
| 发布与部署配置 | Dockerfile、version.txt、kubectl set image 或部署脚本 |
镜像打包步骤和部署步骤 | 只消费最终发布目录与镜像 tag,不回头编译源码。 |
多后端制品项目可以分别发布 WebAPI、JobHost 等目录,再分别构建镜像;如果这些制品属于同一次发布,应共享同一份版本号来源,并分别把 version.txt 写入各自最终发布目录。
pnpm 11 build-script 审核的默认处理方式
- 当 Drone 或其他 CI 在安装阶段报
ERR_PNPM_IGNORED_BUILDS时,先确认是否因为node:latest或镜像升级引入了新的 pnpm 行为。 - 如果项目目录本身就是独立前端入口,即使仓库根没有 workspace,也可以在该目录放置
pnpm-workspace.yaml。 - 默认修复方式是显式声明允许执行的依赖构建脚本,不把“关闭整套 pnpm 安全检查”作为团队默认规则。
- 最小示例:
allowBuilds:
"@parcel/watcher": true
常见问题
- “现有项目还在用
npm ci,必须立刻切掉吗?” 不要求一次性重写全部存量流水线,但不得继续把npm ci当作新前端项目的默认 CI 方案。存量兼容应写明偏差范围和迁移计划。 - “用了
pnpm以后,还能顺手保留package-lock.json吗?” 不建议。这样会让本地与 CI 可能解析出两套依赖树,破坏可复现性。 - “后端镜像里顺便执行
dotnet publish不是更省步骤吗?” 不建议作为默认规则。这样会把源码编译、发布目录和镜像打包边界混在一起,难以复用制品,也不利于排查失败点。 - “部署步骤里顺便再跑一遍构建,能保证最新吗?” 不能作为默认规则。部署应消费已经验证过的最终制品,否则会让部署结果与前面通过的构建产物脱节。
- “项目没有根
pnpm-workspace.yaml,是不是就不适合多个前端应用?” 不是。多个前端应用可以保持独立包目录和独立锁文件,只要 CI 步骤边界、产物目录和汇总顺序写清楚即可。 - “
pnpm install --frozen-lockfile本地能过,为什么 Drone 里会报ERR_PNPM_IGNORED_BUILDS?” 先看 CI 镜像是否切到了新的 Node / pnpm 版本,尤其是node:latest。这类问题通常不是 lockfile 损坏,而是新 pnpm 开始要求项目显式声明允许执行的依赖构建脚本。 - “没有根
pnpm-workspace.yaml的独立前端目录,也可以放项目级pnpm-workspace.yaml吗?” 可以。只要该目录本身是独立前端入口,就可以在该目录放置项目级pnpm-workspace.yaml,不要求仓库根一定存在 workspace。 - “遇到被忽略的 build scripts,默认做法是关闭限制还是显式 allow?” 默认做法是显式 allow。优先把允许列表收敛到项目级配置,而不是直接关闭整套 pnpm 安全检查。
- “本地复现 pnpm 11 的 CI 行为时,为什么有时还会看到无 TTY 或
CI=true相关提示?” 这是本地模拟 CI 时的排查细节,不是团队正式规则。正式规范关注的是显式声明 pnpm build-script 策略,而不是要求所有项目在文档里固定写本地调试技巧。
相关检查
示例项目对照
- Linux amd64 WebAPI + 多 ClientApp 的 Drone 示例:适合对照多前端、后端发布、镜像与部署顺序。
- Drone 配置参考索引:适合快速核对字段和
depends_on写法。 - 前端项目规范:适合同时核对前端默认技术栈、包源和构建口径。
- WebAPI 规范:适合同时核对接口规则与后端交付边界。