26、CI/CD集成:GitHub Actions、Jenkins、GitLab CI配置
说实话,Gradle Kotlin DSL 写起来再爽,如果每次构建都要手动敲命令,那跟骑自行车送外卖有什么区别?
我这些年带过的团队,几乎每个项目都会踩一遍 CI 配置的坑。有的同学把 Jenkins 配成了“手动触发器”,有的在 GitHub Actions 里把 Gradle 缓存搞丢了,构建一次要 20 分钟……
今天我们就来聊聊,怎么把 Gradle Kotlin DSL 的构建脚本,优雅地接入主流的 CI/CD 平台。
核心要点:CI/CD 配置的核心不是“跑通”,而是“跑得快 + 跑得稳”。Gradle 守护进程、构建缓存、并行任务,这三个东西缺一不可。
26.1 通用配置原则
不管用哪个 CI 平台,有几个原则是通用的。我个人习惯先把这些基础打好,再去看平台特有的配置。
- 使用 Gradle Wrapper:永远不要直接装 Gradle 版本。用
gradlew可以锁定版本,避免“在我机器上能跑”的尴尬。 - 开启构建缓存:
--build-cache参数能省掉大量重复编译。我在项目中遇到过,没开缓存时全量构建要 8 分钟,开了之后增量构建只要 40 秒。 - 并行执行:
--parallel参数让多模块项目并行编译,效果立竿见影。 - 守护进程策略:CI 环境里建议用
--no-daemon,避免守护进程残留导致资源泄漏。
小技巧:可以在 gradle.properties 里统一设置这些参数,这样 CI 脚本里就不用重复写了。
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.daemon=false
26.2 GitHub Actions 配置
GitHub Actions 是我用得最多的 CI 平台。它的 YAML 语法很直观,而且社区有现成的 Gradle Action,省了不少事。
先看一个完整的配置示例:
# .github/workflows/build.yml
name: Build with Gradle Kotlin DSL
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
- name: Build with Gradle
run: ./gradlew build --build-cache --parallel
- name: Upload build reports
if: always()
uses: actions/upload-artifact@v4
with:
name: test-reports
path: build/reports/tests/
这里有几个关键点:
gradle/actions/setup-gradle这个 Action 会自动处理 Gradle 缓存,包括依赖缓存和构建缓存。我曾经手写过缓存配置,结果经常缓存失效,后来直接用官方 Action 就稳了。if: always()确保即使构建失败,测试报告也能上传。这个细节我踩过坑——有一次测试挂了,但报告没上传,排查问题全靠猜。- JDK 版本要和你的
build.gradle.kts里配置的 Java 版本一致,否则会出现奇怪的编译错误。
注意:GitHub Actions 的免费额度有限,如果项目比较大,建议把 on.push 限制在主要分支,不要每个分支都触发全量构建。
26.3 Jenkins 配置
Jenkins 虽然老,但在企业里还是主流。它的配置方式比较灵活,可以用 Pipeline 脚本,也可以用 Freestyle 项目。
我个人推荐用 Pipeline,因为脚本可以版本化管理。下面是一个声明式 Pipeline 的例子:
// Jenkinsfile
pipeline {
agent any
tools {
jdk 'JDK17'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh './gradlew build --build-cache --parallel --no-daemon'
}
}
stage('Test') {
steps {
sh './gradlew test --build-cache --parallel --no-daemon'
}
post {
always {
junit 'build/test-results/**/*.xml'
publishHTML(target: [
reportName: 'Test Report',
reportDir: 'build/reports/tests/test',
reportFiles: 'index.html'
])
}
}
}
stage('Publish') {
when {
branch 'main'
}
steps {
sh './gradlew publish --build-cache --no-daemon'
}
}
}
post {
failure {
emailext(
subject: "Build Failed: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
body: "请查看构建日志:${env.BUILD_URL}",
to: 'team@example.com'
)
}
}
}
Jenkins 里有个容易忽略的点:Gradle 用户目录的持久化。默认情况下,每次构建都会重新下载依赖,非常慢。我建议在 Jenkins 全局配置里设置 GRADLE_USER_HOME 到一个持久化目录,比如 /var/jenkins_home/.gradle。
避坑指南:我曾经在 Jenkins 里遇到过 Gradle 守护进程残留的问题。多个构建同时跑,守护进程互相抢占资源,导致构建失败。解决方案就是在 gradlew 命令后面加上 --no-daemon,一劳永逸。
26.4 GitLab CI 配置
GitLab CI 的配置文件和 GitHub Actions 类似,也是 YAML 格式。但它有一个独特的优势:内置的制品管理和环境管理。
来看一个典型的 .gitlab-ci.yml:
# .gitlab-ci.yml
image: gradle:8.5-jdk17
variables:
GRADLE_OPTS: "-Dorg.gradle.daemon=false"
GRADLE_USER_HOME: "$CI_PROJECT_DIR/.gradle"
cache:
key: "$CI_COMMIT_REF_SLUG"
paths:
- .gradle/wrapper
- .gradle/caches
stages:
- build
- test
- deploy
build:
stage: build
script:
- ./gradlew assemble --build-cache --parallel
artifacts:
paths:
- build/libs/
expire_in: 1 week
test:
stage: test
script:
- ./gradlew test --build-cache --parallel
artifacts:
reports:
junit: build/test-results/**/TEST-*.xml
deploy:
stage: deploy
script:
- ./gradlew publish --build-cache
only:
- main
GitLab CI 的缓存机制做得不错。上面配置里,我把 .gradle/caches 和 .gradle/wrapper 都缓存了,这样每次构建不用重新下载依赖。不过要注意,缓存 key 用 $CI_COMMIT_REF_SLUG 可以按分支隔离,避免不同分支的缓存冲突。
还有一个细节:artifacts 的过期时间。我建议设置 expire_in,否则 GitLab 会一直保留所有构建产物,磁盘很快就满了。1 周是比较合理的值。
对比总结:
| 特性 | GitHub Actions | Jenkins | GitLab CI |
|---|---|---|---|
| 配置格式 | YAML | Groovy / 声明式 | YAML |
| 缓存管理 | 官方 Action 自动处理 | 需手动配置持久化目录 | 内置 cache 关键字 |
| 制品管理 | upload-artifact Action | Archive Artifacts 插件 | 内置 artifacts 关键字 |
| 并行构建 | 矩阵策略 | Declarative Parallel | parallel 关键字 |
| 适合场景 | 开源项目、小团队 | 企业级、复杂流水线 | DevOps 一体化 |
26.5 核心流程示意图
下面这张图展示了 Gradle Kotlin DSL 项目在 CI/CD 中的完整流程。从代码提交到最终部署,每一步都离不开 Gradle 的构建能力。
26.6 一些实战建议
最后分享几个我在实际项目中总结的经验:
- 不要迷信“一键配置”:每个 CI 平台的 Gradle 缓存策略都不一样。GitHub Actions 的缓存是自动的,但 Jenkins 需要手动配。花点时间理解缓存机制,比抄别人的配置要靠谱得多。
- 测试报告一定要保留:不管是 JUnit XML 还是 HTML 报告,都建议作为构建产物保存。我曾经因为没保留测试报告,线上出了问题还得重新跑一遍构建,浪费时间。
- CI 脚本也要版本化:把
.github/workflows/、Jenkinsfile、.gitlab-ci.yml都放在代码仓库里。这样改配置的时候可以走 PR 流程,避免直接在 CI 平台上改导致“配置漂移”。 - 善用 Gradle 的
--scan参数:如果构建速度突然变慢,加上--scan生成构建扫描报告,能直观看到每个任务的耗时。我在排查构建性能问题时,这个功能帮了大忙。
一句话总结:CI/CD 配置的核心不是“跑通”,而是“跑得快 + 跑得稳”。把 Gradle 的缓存、并行、守护进程这三个点吃透,不管换哪个 CI 平台,你都能快速上手。