ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

13-自动化CI/CD流水线:代码提交→编译→打包→镜像构建自动流程

13-自动化CI/CD流水线:代码提交→编译→打包→镜像构建自动流程

13-自动化CI/CD流水线:代码提交→编译→打包→镜像构建自动流程

一、什么是CI/CD?先搞懂概念再动手

很多新手一上来就配流水线,配了半天不知道自己在配啥。咱们先把概念捋清楚。

  • CI(Continuous Integration,持续集成):开发人员把代码推送到仓库后,自动触发编译、单元测试、代码质量检查。核心目的是——尽早发现问题,别等到上线前一天才发现代码跑不起来。
  • CD(Continuous Delivery/Deployment,持续交付/部署):在CI的基础上,把编译好的产物自动打包、构建镜像、推送到仓库,甚至自动部署到测试/生产环境。

一句话总结:CI管编译测试,CD管打包部署。两者串联起来,就是一条从代码提交到上线的自动化流水线。

二、为什么我们需要CI/CD?

在智慧农业和无人售货柜的项目中,后端有十几个微服务(Java SpringBoot),设备端有嵌入式固件(瑞芯微/STM32),前端有安卓APP。如果没有CI/CD:

  • 程序员手动mvn package,手动docker build,手动docker push——十个服务能搞一下午
  • 某个同事忘了推镜像,测试环境跑的还是上周的代码,排查半天
  • 上线时手忙脚乱,人为操作出错率极高

上了CI/CD之后:git push 一敲,剩下的事交给机器。这就是工程化的魅力。

三、GitLab CI流水线实战

我们以GitLab CI为例(GitHub Actions原理类似),搭建一条完整的流水线。

3.1 核心概念速览

概念说明
Runner执行流水线的机器(物理机/容器),需要注册到GitLab
Pipeline一条完整的流水线,包含多个Stage
Stage流水线的阶段,如 build → test → package → deploy
JobStage中的具体任务,同一Stage的Job并行执行

3.2 .gitlab-ci.yml 完整配置示例

在项目根目录创建.gitlab-ci.yml文件:

# 定义阶段顺序,前一个阶段全部成功才会执行下一个stages:-build-test-package-deploy# 全局变量variables:MAVEN_OPTS:"-Dmaven.repo.local=.m2/repository"IMAGE_REGISTRY:"registry.cn-shenzhen.aliyuncs.com"IMAGE_NAMESPACE:"alspd/smart-agri"# === 编译阶段 ===build-job:stage:buildimage:maven:3.8-openjdk-8script:-echo "===== 开始编译 $CI_PROJECT_NAME ====="-mvn clean compile-DskipTests-echo "编译完成,产物路径:target/"artifacts:paths:-target/*.jarexpire_in:1 hourrules:-if:$CI_COMMIT_BRANCH == "develop"||$CI_COMMIT_BRANCH == "main"# === 单元测试阶段 ===test-job:stage:testimage:maven:3.8-openjdk-8script:-echo "===== 执行单元测试 ====="-mvn test-echo "测试通过率统计:"-cat target/site/jacoco/index.html|grep-oP 'Total.*?([0-9]+%)'|tail-1rules:-if:$CI_COMMIT_BRANCH == "develop"# === Docker镜像构建与推送 ===package-job:stage:packageimage:docker:20.10services:-docker:20.10-dindscript:-echo "===== 构建Docker镜像 ====="# 登录镜像仓库-docker login-u "$CI_REGISTRY_USER"-p "$CI_REGISTRY_PASSWORD" $IMAGE_REGISTRY# 构建镜像,标签包含分支名+commit短hash+时间戳-IMAGE_TAG="$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-$(date +%Y%m%d%H%M)"-docker build-t $IMAGE_REGISTRY/$IMAGE_NAMESPACE/$CI_PROJECT_NAME:$IMAGE_TAG .-docker push $IMAGE_REGISTRY/$IMAGE_NAMESPACE/$CI_PROJECT_NAME:$IMAGE_TAG-echo "镜像推送成功:$IMAGE_REGISTRY/$IMAGE_NAMESPACE/$CI_PROJECT_NAME:$IMAGE_TAG"# 把镜像tag写入文件,供下游阶段使用-echo "$IMAGE_TAG">image-tag.txtartifacts:paths:-image-tag.txtexpire_in:1 dayrules:-if:$CI_COMMIT_BRANCH == "develop"||$CI_COMMIT_BRANCH == "main"# === 部署到测试环境 ===deploy-test-job:stage:deployimage:alpine:latestbefore_script:-apk add--no-cache openssh-clientscript:-echo "===== 部署到测试环境 ====="-IMAGE_TAG=$(cat image-tag.txt)# 通过SSH远程执行部署脚本-ssh-o StrictHostKeyChecking=no deploy@192.168.1.100 " docker pull $IMAGE_REGISTRY/$IMAGE_NAMESPACE/$CI_PROJECT_NAME:$IMAGE_TAG&&docker stop $CI_PROJECT_NAME||true&&docker rm $CI_PROJECT_NAME||true&&docker run-d--name $CI_PROJECT_NAME--network agri-net-p 8080:8080-e SPRING_PROFILES_ACTIVE=test $IMAGE_REGISTRY/$IMAGE_NAMESPACE/$CI_PROJECT_NAME:$IMAGE_TAG"-echo "部署完成"rules:-if:$CI_COMMIT_BRANCH == "develop"

3.3 关键配置解读

1)artifacts(产物传递)

build-job编译出来的 jar 包通过artifacts传递给下游Job。如果不配,每个Job都是独立容器,编译产物拿不到。

2)rules(条件触发)

rules:-if:$CI_COMMIT_BRANCH == "develop"

只有推送到develop分支才触发完整流水线。推到feature/xxx分支只编译不部署,避免每个功能分支都污染测试环境。

3)镜像标签策略

IMAGE_TAG="$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-$(date+%Y%m%d%H%M)"# 示例:develop-a3f5c2e1-202608071430

分支名 + commit短hash + 时间戳,既能追溯代码版本,又能区分构建时间。这个标签规范在下一篇会详细展开。

四、Dockerfile 配套写法

流水线里调了docker build,对应的 Dockerfile 也得跟上:

# 多阶段构建,减小最终镜像体积 FROM maven:3.8-openjdk-8 AS builder WORKDIR /build COPY pom.xml . RUN mvn dependency:go-offline # 先下依赖,利用Docker缓存层 COPY src/ ./src/ RUN mvn clean package -DskipTests FROM openjdk:8-jre-slim WORKDIR /app COPY --from=builder /build/target/*.jar app.jar # 健康检查,K8s就绪探针会用到 HEALTHCHECK --interval=30s --timeout=3s \ CMD curl -f http://localhost:8080/actuator/health || exit 1 EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]

多阶段构建的好处:最终镜像只包含JRE和jar包,不含Maven和源码,体积从800MB降到180MB左右。在工控设备上部署时,小镜像就是快速度。

五、GitHub Actions 简版对照

如果你用的是GitHub Actions,逻辑完全一样,换套语法:

name:CI/CD Pipelineon:push:branches:[develop,main]jobs:build:runs-on:ubuntu-lateststeps:-uses:actions/checkout@v3-uses:actions/setup-java@v3with:java-version:'8'distribution:'temurin'-name:Maven Buildrun:mvn clean package-DskipTests-name:Build & Push Docker Imagerun:|docker login -u ${{ secrets.REGISTRY_USER }} -p ${{ secrets.REGISTRY_PASS }} registry.cn-shenzhen.aliyuncs.com docker build -t registry.cn-shenzhen.aliyuncs.com/alspd/smart-agri/${{ github.event.repository.name }}:${{ github.sha }} . docker push registry.cn-shenzhen.aliyuncs.com/alspd/smart-agri/${{ github.event.repository.name }}:${{ github.sha }}

六、流水线提速技巧

实际项目中流水线跑10分钟以上很常见,这里列几个优化点:

  1. Maven依赖缓存:把.m2/repository缓存到Runner,第二次构建省去下载依赖的时间
  2. Docker层缓存:Dockerfile中先COPY pom.xmlRUN mvn dependency:go-offline,依赖不变时这层直接命中缓存
  3. 并行Job:把单元测试和代码质量扫描(SonarQube)放到同一个Stage,并行执行
  4. 按需触发:只有src/目录变更时才触发编译,文档改动不浪费CI资源
# 只在源码变更时触发编译rules:-if:$CI_COMMIT_BRANCH == "develop"changes:-src/**-pom.xml

七、小结

CI/CD的本质是:把人的重复劳动交给机器。代码提交后自动编译、测试、打包、构建镜像、推送仓库、部署——一气呵成。配置好之后,开发人员只需要关心写代码,部署的事全自动。

下一篇我们会深入Docker镜像版本管理,讲清楚标签规范、版本留存策略和镜像清理——别让镜像仓库变成垃圾场。

返回列表