agilelabs-fx-docs main reference/drone-ci-cd-abcred-ai.md

Linux amd64 WebAPI + 多 ClientApp 的 Drone 示例

本页基于一个真实 Linux pipeline 的结构进行脱敏拆解,重点帮助读者理解:同一仓库里有 WebAPI、多个前端应用、统一发布目录、Docker 镜像和 Kubernetes 部署时,Drone 步骤应该如何分层。页面保留原路径,方便历史链接继续使用。

正式规范请先看 Drone CI 配置专题;Windows / Mac 示例请看 Windows / Mac Runner 的 Drone 示例

这份示例适合看什么

  • type: exec 的 Linux runner 如何承接 Docker、Kubernetes 和共享缓存目录。
  • 多个前端应用如何并行构建,再统一同步到后端发布目录。
  • dotnet publish、镜像打包和 kubectl set image 如何串成一条交付链。
  • Docker 发布的 ASP.NET WebAPI / Web 宿主项目,怎样把运行时版本号一起带进镜像。
  • 哪些字段是结构性做法,哪些字段只是项目示例值,必须替换。

流水线总览

  • pipeline 类型:exec
  • pipeline 名称:build-pipeline
  • runner 节点:cn-build-02
  • 平台:linux / amd64
  • 触发条件:push 到指定分支

这条流水线先准备 Docker 和 Kubernetes 运行环境,再并行构建多个前端应用与后端发布目录,随后把前端产物同步到后端发布目录,最后构建并推送镜像,再执行滚动更新。

脱敏后的结构示例

---
kind: pipeline
name: build-pipeline
type: exec

platform:
  os: linux
  arch: amd64

node:
  runner_name: cn-build-02

trigger:
  branch:
    - main
  event:
    - push

steps:
  - name: docker-config
    commands:
      - bash scripts/ci/linux-prepare.sh

  - name: build-portal
    depends_on:
      - docker-config
    commands:
      - bash scripts/ci/build-portal.sh

  - name: build-admin
    depends_on:
      - docker-config
    commands:
      - bash scripts/ci/build-admin.sh

  - name: publish-backend
    depends_on:
      - docker-config
    commands:
      - bash scripts/ci/publish-backend.sh

  - name: sync-clientapp
    depends_on:
      - build-portal
      - build-admin
      - publish-backend
    commands:
      - bash scripts/ci/sync-clientapp.sh

  - name: package-image
    depends_on:
      - sync-clientapp
    commands:
      - bash scripts/ci/package-image.sh

  - name: deploy
    depends_on:
      - package-image
    commands:
      - bash scripts/ci/deploy.sh

这个版本刻意把真实仓库地址、镜像名、命名空间、deployment 名称和长命令收敛到脚本中,方便读者先理解结构。

步骤拆解

docker-config

这一层通常负责:

  • 准备 ~/.docker 或 runner 上的 Docker 登录态
  • 准备 ~/.kube 或部署脚本需要的集群上下文
  • 验证 docker loginkubectl get nodes 等基础可用性
  • 检查共享缓存目录是否存在

它本质上是 runner 环境预热。后续大多数步骤都依赖它,因为一旦 Docker 或 Kubernetes 凭据有问题,越早失败越容易定位。

前端构建步骤

典型前端步骤包括:

  • build portal assets
  • build chatweb
  • build dashboardweb
  • build adminweb
  • build statusweb
  • build toolsweb

这些步骤通常都依赖 docker-config,并统一通过某个 Node 构建镜像执行:

  • 把当前仓库挂载到工作目录
  • 把共享 pnpm store 挂载到固定缓存目录
  • 在各自应用目录执行 pnpm install
  • 继续执行 testtypecheckbuild

可复用的思路:

  • Node 构建镜像版本统一,减少不同前端应用之间的环境漂移。
  • pnpm store 用共享目录缓存,减少重复下载。
  • 前端步骤只生成 dist,不直接写最终发布目录。

publish-backend

这一层只做后端发布:

  • 执行 dotnet publish
  • 输出到固定发布目录
  • 生成一次构建版本号
  • 将版本号写入发布目录中的 version.txt,供后续步骤复用

推荐原因:

  • 把“后端发布”和“镜像构建”拆开,更容易单独排查 dotnet publish 失败。
  • 版本号写到发布目录后,镜像构建与部署都可以消费同一份结果。
  • 运行中的应用可以通过 AppContext.BaseDirectory/version.txt 读取当前发布版本,再由 /fwdiag/v 暴露出来。

一个脱敏后的最小示意可以是:

dotnet publish src/Your.WebHost/Your.WebHost.csproj -c Release -o ./artifacts/publish
echo "$BUILD_VERSION" > ./artifacts/publish/version.txt

sync-clientapp

这是整个 Linux 多应用示例里最关键的汇总步骤:

  • 等待后端发布完成
  • 等待所有前端构建完成
  • 把各前端产物同步到最终发布目录中的 ClientApp/...
  • 不再承担编译职责,只做产物收敛

如果你的项目托管多个前端入口,这一步强烈建议放到脚本里,例如 scripts/frontend/sync-all-apps-to-publish.sh。这样后续新增一个前端入口时,只需要调整脚本或映射表,不需要在 YAML 里复制很多段 cprsync

package-image

这一层负责:

  • 从发布目录读取版本号
  • 基于最终发布目录构建镜像
  • 推送镜像到仓库

关键点是:镜像步骤应该只消费最终发布目录,而不是回头重新跑一遍 dotnet publish 或前端构建。对于 Docker 发布项目来说,version.txt 也必须跟随最终发布目录一起进入镜像,否则镜像 tag 虽然带了版本,应用运行时仍然无法通过 /fwdiag/v 读取当前发布版本。

脱敏示意:

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY artifacts/publish/ ./
ENTRYPOINT ["dotnet", "Your.WebHost.dll"]

在这种写法里,只要 artifacts/publish/version.txt 已经存在,容器启动后的 AppContext.BaseDirectory/version.txt 就会是同一份文件。

deploy

这一层负责:

  • 基于上一步生成的镜像标签执行部署
  • 使用 kubectl set image 或项目自己的部署脚本完成滚动更新

部署步骤与构建步骤要共享同一套版本来源,避免“打出来的是 A,部署出去的是 B”。

依赖链说明

  • docker-config 是大多数步骤的共同前置。
  • 多个前端应用在 docker-config 完成后并行构建。
  • publish-backend 可以与部分前端构建并行,只要它依赖的前置已经满足。
  • sync-clientapp 是完整汇总点,等待所有必要构建完成。
  • package-imagedeploy 只消费汇总好的最终产物。
  • 版本文件、镜像 tag 和部署动作都应共享同一份版本来源。

这种组织方式的优点是:

  • 并行度高
  • 问题边界清晰
  • 产物流向稳定
  • 后续增加前端应用时不需要重写整条流水线

哪些字段必须替换

下面这些值即使在真实项目中存在,也只能当示例值看,迁移到别的项目时必须替换:

  • 镜像仓库地址
  • 镜像命名空间
  • 镜像名称
  • Kubernetes namespace
  • deployment 名称
  • kubectl 资源名
  • 共享缓存目录路径
  • 具体 Node / .NET 构建镜像名
  • 仓库内部的项目路径

runner_name: cn-build-02 是否替换,要看它是不是你们团队约定的 Linux runner。如果这正是团队固定 runner,可以保留;如果不是,就必须改成目标环境的 runner 名称。

这份示例最值得复用的点

  • 用单独步骤准备 Docker、Kubernetes 和认证上下文。
  • 用共享目录缓存 pnpm、NuGet 和 .NET SDK。
  • 将前端构建拆成独立步骤并行执行。
  • 用脚本统一同步前端产物到后端发布目录。
  • 在发布目录里写入 version.txt,并让它随最终发布目录一起进入镜像。
  • 让版本文件、镜像标签、部署版本统一来源,避免“镜像版本”和“应用自报版本”不一致。

相关页面