2.2 自动化构建与依赖


2.2 自动化构建与依赖

本节摘要:自动化构建将源码经编译、依赖解析、打包变为可部署制品(JAR、Docker 镜像等)。本节以 Maven -B 非交互构建、npm ci 锁定依赖、Docker 多阶段构建为主线,并说明 Nexus 制品入库策略。

核心问题

阅读完本节,你应当能够:

  1. 编写 Maven/Gradle/npm 的 CI 构建命令
  2. 解释 npm cinpm install 在 CI 中的差异
  3. 使用 Docker 多阶段构建缩小生产镜像
  4. 配置制品库的版本 tag 规则

一、五分钟 Maven 构建流水线

Java 团队最简 Jenkins stage:

stage('Build') { steps { sh 'mvn -B clean package -DskipTests' } }

-B(batch mode)禁止 Maven 等待人工输入——CI 无人值守必加。完整 verify 含测试:

mvn -B clean verify -Dmaven.test.failure.ignore=false

构建产物默认在 target/*.jar。Archive 到 Jenkins 或 push Nexus:

stage('Publish') { steps { sh ''' mvn deploy -DskipTests \ -DaltDeploymentRepository=nexus::default::https://nexus.corp/repository/maven-releases/ ''' } }

构建流水线阶段图

构建流水线阶段图

二、Node.js 与 Python 构建要点

npm ci + 缓存

- uses: actions/setup-node@v4 with: { node-version: '20', cache: 'npm' } - run: npm ci - run: npm run build
命令 CI 适用 说明
npm ci ✅ 推荐 严格按 package-lock.json,先删 node_modules
npm install 可能更新 lock,不可复现
pnpm i --frozen-lockfile monorepo 友好

Python Poetry

poetry install --no-interaction --no-root poetry build

wheel 输出在 dist/,推 PyPI 私有库或作为 Docker COPY 源。

三、Docker 多阶段构建

FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html

CI 中 build & push:

- run: docker build -t registry.corp/myapp:${{ github.sha }} . - run: docker push registry.corp/myapp:${{ github.sha }}

tag 用 commit SHA,不用 latest——回滚与审计需要 immutable 标识。

构建工具选型

语言 工具 制品
Java Maven, Gradle JAR/WAR
.NET dotnet CLI DLL/nupkg
Node npm, webpack dist/
Python poetry, setuptools wheel
Go go build 静态二进制
通用 Docker 镜像

⚠️ 常见坑:CI 用 SNAPSHOT 覆盖同版本 JAR——无法追溯哪次 commit 上了生产。

💡 关键直觉:构建脚本本身进 Git(Maven pom、Dockerfile)——「在我机器上能编」= CI 也能编,环境差异交给容器。

Gradle 缓存加速

- uses: gradle/actions/setup-gradle@v3 - run: ./gradlew build --no-daemon

GitHub Actions 的 Gradle build action 缓存 ~/.gradle/caches,大型项目可省 5–10 分钟。

构件管理 Nexus 策略

仓库类型 存放 保留策略
maven-snapshots 开发分支构建 30 天
maven-releases tag 发布 永久
docker-hosted 镜像 按 digest

四、Gradle、缓存与 reproducible build

Gradle 与 Maven 并行

// build.gradle.kts plugins { java } tasks.test { useJUnitPlatform() } tasks.withType<Test> { maxParallelForks = Runtime.runtime.availableProcessors() / 2 }

Gradle build cache 跨 CI job 复用编译输出——企业 Nexus 托管 remote build cache。

Reproducible Builds

相同源码 + 相同 lock 文件 → 相同制品 hash。Go 1.20+ 默认 reproducible;Docker 用 --build-arg SOURCE_DATE_EPOCH 固定时间戳。供应链安全 SBOM(Syft、CycloneDX)在 build 后生成,随制品入库。

私有依赖与凭证

Maven settings.xml 在 CI 用 secret 注入,不进 Git:

<server> <id>nexus</id> <username>${env.NEXUS_USER}</username> <password>${env.NEXUS_PASS}</password> </server>

npm 用 .npmrc 指向私有 registry,token 来自 NPM_TOKEN 环境变量。

构建失败常见原因

现象 原因 修复
依赖下载 403 IP 未加 Nexus 白名单 加 runner egress
编译 OOM 默认 heap 太小 MAVEN_OPTS=-Xmx2g
时区测试失败 runner UTC vs 本地 CST 测试用固定 ZoneId
并发 test 竞态 共享 /tmp 隔离 temp dir

本章回顾

  • mvn -B 非交互,CI 必备
  • npm ci / frozen-lockfile 保证依赖可复现
  • Docker 多阶段 分离构建与运行环境
  • 制品 tag 用 SHA 不用 latest
  • Nexus deploy 分离 snapshots 与 releases
  • Gradle/npm 缓存 缩短反馈时间
  • 构建脚本版本化 消除「本地能编」问题

下一节 2.3 在构建之后设测试与静态分析门禁。

构建策略的工程取舍

构建阶段的目标是「可复现、可追踪、可加速」,三个目标有时互相冲突。可复现依赖 lock 文件与干净环境,可追踪依赖制品 tag 与构建日志,可加速依赖缓存与并行——缓存往往会引入「脏状态」,需要与可复现做权衡。推荐的折中是:CI runner 的缓存只用于依赖下载(Maven Central、npm registry 的 HTTP 缓存),不缓存编译产物;制品库(Nexus/Harbor)负责跨构建共享,用 immutable tag 保证可追踪。

构建时还要注意环境隔离:同一份源码在开发机、CI runner、Docker 容器里构建的结果应当一致。把构建工具链版本(JDK、Node、Python)写进版本控制,用 mise/asdf 或容器镜像固定版本,能消除「在我机器上能编」的经典问题。对多语言 monorepo,建议给每个服务独立构建 job,避免一个语言的构建失败拖慢全仓。

构建产物的可追溯性

可追溯性是制品管理的底线:每次构建要能回答「这份制品对应哪个 commit、由哪次构建产出」。实现方式是给制品打上不可变标识——Maven 用版本号加 build number,容器镜像用 commit SHA,npm 包用 version 加 pre-release 标签。制品库的保留策略要区分快照与正式发布:快照可过期清理,正式发布永久保留,否则磁盘很快被占满且无法审计。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U