第九章:基于 Docker 的持续集成:代码检查、单元测试、镜像构建 将应用容器化之后CI 流水线的核心任务也随之升级不仅要编译代码、运行测试还要构建出可部署的 Docker 镜像。本章深入讲解基于 Docker 的持续集成流水线中的三个关键环节——代码质量检查、单元测试与Docker 镜像构建涵盖 SonarQube 集成、测试容器化、多阶段构建与构建缓存优化等实战技巧。一、基于 Docker 的 CI 流水线概览在容器化时代CI 流水线的典型结构如下text代码提交 → 拉取代码 → 依赖安装 → 代码质量检查 → 单元测试 → 构建 Docker 镜像 → 推送镜像仓库与传统 CI 相比基于 Docker 的 CI 有两个显著变化构建环境容器化CI Runner 在 Docker 容器中执行所有任务环境一致性得到保障。产出物是镜像而非 JAR/WAR最终制品是可运行的 Docker 镜像而非传统的应用包。二、代码质量检查SonarQube 集成代码质量检查是 CI 流水线的第一道质量门禁。SonarQube 是最主流的静态代码分析平台支持 30 种语言能够检测代码中的 Bug、漏洞、坏味道和重复代码。2.1 在 CI 流水线中集成 SonarQube以 GitLab CI 为例集成 SonarQube 的步骤如下# .gitlab-ci.ymlstages:-build-quality-scan-deployvariables:SONAR_HOST_URL:https://sonarqube.example.comSONAR_TOKEN:$SONAR_TOKEN# 在 CI/CD 变量中配置# 构建阶段build:stage:buildimage:openjdk:11-jdk-slimscript:-mvn clean compile-Dmaven.test.skiptrue# 代码质量扫描阶段quality-scan:stage:quality-scanimage:sonarsource/sonar-scanner-cli:latestscript:-sonar-scanner-Dsonar.projectKeymy-project-Dsonar.sources.-Dsonar.java.binariestarget/classes-Dsonar.coverage.jacoco.xmlReportPathstarget/site/jacoco/jacoco.xml-Dsonar.qualitygate.waittrue# 等待质量门禁结果失败则阻断流水线only:-main-merge_requests2.2 质量门禁Quality GateSonarQube 的质量门禁是 CI 流水线的关键控制点。当扫描结果不满足预设阈值时如新增 Bug 数量 0、代码覆盖率 80%流水线会失败并阻断后续环节。配置建议为 main 分支设置严格的质量门禁所有指标必须达标为 feature 分支设置较宽松的门禁允许一定比例的技术债务将质量门禁结果作为合并请求的必检项2.3 在 GitHub Actions 中集成 SonarQube# .github/workflows/ci.yml-name:SonarQube Scanuses:SonarSource/sonarqube-scan-actionv4env:SONAR_TOKEN:${{secrets.SONAR_TOKEN}}SONAR_HOST_URL:${{vars.SONAR_HOST_URL}}with:args:-Dsonar.projectKeymy-project -Dsonar.sourcessrc -Dsonar.java.binariestarget/classes -Dsonar.coverage.jacoco.xmlReportPathstarget/site/jacoco/jacoco.xml三、单元测试在容器中运行单元测试是 CI 流水线的第二道质量门禁。在容器化 CI 中单元测试也在 Docker 容器中执行确保测试环境的可复现性。3.1 在 GitLab CI 中运行测试test:unit:stage:testimage:maven:3.8.4-openjdk-17script:-mvn testartifacts:reports:junit:target/surefire-reports/*.xmlpaths:-target/surefire-reports/coverage:/Coverage: \d\.\d%/3.2 测试容器化的高级实践并行测试对大型项目可在多个 Docker 容器中并行运行不同测试套件显著缩短测试时间。test:unit:stage:testparallel:4script:-mvn test-Dgroupsgroup$CI_NODE_INDEX测试容器共享缓存使用 Docker volume 在测试容器之间共享 Maven 依赖缓存variables:MAVEN_OPTS:-Dmaven.repo.local$CI_PROJECT_DIR/.m2/repositorycache:paths:-.m2/repository/3.3 测试报告与覆盖率将测试报告作为 CI 的 Artifact 保存便于开发人员下载查看artifacts:paths:-target/surefire-reports/reports:junit:target/surefire-reports/*.xmlexpire_in:30 days四、Docker 镜像构建镜像构建是容器化 CI 流水线的核心产出环节。4.1 多阶段构建Multi-stage Builds多阶段构建是 Docker 镜像优化的核心技巧它允许在一个 Dockerfile 中使用多个 FROM 指令最终只将运行时需要的文件复制到最终镜像中。dockerfile阶段1构建阶段使用完整 JDKFROM maven:3.8.4-openjdk-17 AS builderWORKDIR /appCOPY pom.xml .RUN mvn dependency:go-offlineCOPY src ./srcRUN mvn package -DskipTests阶段2运行阶段使用精简 JREFROM openjdk:17-jre-slimCOPY --frombuilder /app/target/*.jar /app/app.jarEXPOSE 8080ENTRYPOINT [“java”, “-jar”, “/app/app.jar”]多阶段构建的收益最终镜像只包含 JRE 和 JAR 包不包含 Maven、JDK 等构建工具镜像体积可从数百 MB 降至数十 MB4.2 构建缓存优化合理利用 Docker 缓存可以显著加速镜像构建原则将变化频率低的指令放在 Dockerfile 前面变化频率高的指令放在后面。dockerfile✅ 正确先复制 pom.xml变化少安装依赖利用缓存COPY pom.xml .RUN mvn dependency:go-offline # 这一层会被缓存除非 pom.xml 变化后复制源码变化频繁COPY src ./srcRUN mvn package使用 BuildKit 加速Docker BuildKit 支持并行执行构建步骤进一步提升构建速度。DOCKER_BUILDKIT1dockerbuild-tmyapp.4.3 在 GitLab CI 中构建镜像GitLab CI 支持两种 Docker 构建方式方式一Docker-in-Dockerdindbuild-image:stage:packageimage:docker:latestservices:-docker:dindvariables:DOCKER_HOST:tcp://docker:2375DOCKER_DRIVER:overlay2script:-docker build-t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .-docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA方式二使用 BuildKit推荐build-image:stage:packageimage:docker:latestservices:-docker:dindvariables:DOCKER_BUILDKIT:1script:-docker build--cache-from $CI_REGISTRY_IMAGE:latest-t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .-docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA4.4 在 GitHub Actions 中构建镜像使用 docker/build-push-action 是 GitHub Actions 中最推荐的镜像构建方式-name:Build and push Docker imageuses:docker/build-push-actionv5with:context:.push:truetags:ghcr.io/${{github.repository}}:${{github.sha}}cache-from:typeghacache-to:typegha,modemaxcache-from: typegha 利用 GitHub Actions 的共享缓存大幅加速后续构建。五、CI 流水线完整示例将以上三个环节组合成一条完整的 GitLab CI 流水线stages:-build-quality-scan-test-packagevariables:MAVEN_OPTS:-Dmaven.repo.local.m2/repositorySONAR_HOST_URL:https://sonarqube.example.comcache:paths:-.m2/repository/# 1. 编译build:stage:buildimage:maven:3.8.4-openjdk-17script:-mvn clean compileartifacts:paths:-target/classes/# 2. 代码质量扫描quality-scan:stage:quality-scanimage:sonarsource/sonar-scanner-cli:latestscript:-sonar-scanner-Dsonar.projectKeymyapp-Dsonar.qualitygate.waittruedependencies:-buildonly:-main-merge_requests# 3. 单元测试test:unit:stage:testimage:maven:3.8.4-openjdk-17script:-mvn testartifacts:reports:junit:target/surefire-reports/*.xmldependencies:-build# 4. 构建并推送镜像package:stage:packageimage:docker:latestservices:-docker:dindvariables:DOCKER_BUILDKIT:1script:-docker build-t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA .-docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHAdependencies:-buildonly:-main六、小结基于 Docker 的持续集成将传统 CI 的“编译→测试→打包”升级为“编译→测试→构建镜像→推送仓库”。三个核心环节各有侧重代码质量检查SonarQube 质量门禁确保代码健康度单元测试容器化执行 并行策略保证功能正确性镜像构建多阶段构建 缓存优化产出轻量、安全的镜像