化CI/CD流水線:代碼提交→編譯→打包→鏡像構(gòu)建自動(dòng)流程)
13-自動(dòng)化CI/CD流水線代碼提交→編譯→打包→鏡像構(gòu)建自動(dòng)流程一、什么是CI/CD先搞懂概念再動(dòng)手很多新手一上來就配流水線配了半天不知道自己在配啥。咱們先把概念捋清楚。CIContinuous Integration持續(xù)集成開發(fā)人員把代碼推送到倉庫后自動(dòng)觸發(fā)編譯、單元測(cè)試、代碼質(zhì)量檢查。核心目的是——盡早發(fā)現(xiàn)問題別等到上線前一天才發(fā)現(xiàn)代碼跑不起來。CDContinuous Delivery/Deployment持續(xù)交付/部署在CI的基礎(chǔ)上把編譯好的產(chǎn)物自動(dòng)打包、構(gòu)建鏡像、推送到倉庫甚至自動(dòng)部署到測(cè)試/生產(chǎn)環(huán)境。一句話總結(jié)CI管編譯測(cè)試CD管打包部署。兩者串聯(lián)起來就是一條從代碼提交到上線的自動(dòng)化流水線。二、為什么我們需要CI/CD在智慧農(nóng)業(yè)和無人售貨柜的項(xiàng)目中后端有十幾個(gè)微服務(wù)Java SpringBoot設(shè)備端有嵌入式固件瑞芯微/STM32前端有安卓APP。如果沒有CI/CD程序員手動(dòng)mvn package手動(dòng)docker build手動(dòng)docker push——十個(gè)服務(wù)能搞一下午某個(gè)同事忘了推鏡像測(cè)試環(huán)境跑的還是上周的代碼排查半天上線時(shí)手忙腳亂人為操作出錯(cuò)率極高上了CI/CD之后git push 一敲剩下的事交給機(jī)器。這就是工程化的魅力。三、GitLab CI流水線實(shí)戰(zhàn)我們以GitLab CI為例GitHub Actions原理類似搭建一條完整的流水線。3.1 核心概念速覽概念說明Runner執(zhí)行流水線的機(jī)器物理機(jī)/容器需要注冊(cè)到GitLabPipeline一條完整的流水線包含多個(gè)StageStage流水線的階段如 build → test → package → deployJobStage中的具體任務(wù)同一Stage的Job并行執(zhí)行3.2 .gitlab-ci.yml 完整配置示例在項(xiàng)目根目錄創(chuàng)建.gitlab-ci.yml文件# 定義階段順序前一個(gè)階段全部成功才會(huì)執(zhí)行下一個(gè)stages:-build-test-package-deploy# 全局變量variables:MAVEN_OPTS:-Dmaven.repo.local.m2/repositoryIMAGE_REGISTRY:registry.cn-shenzhen.aliyuncs.comIMAGE_NAMESPACE:alspd/smart-agri# 編譯階段 build-job:stage:buildimage:maven:3.8-openjdk-8script:-echo 開始編譯 $CI_PROJECT_NAME -mvn clean compile-DskipTests-echo 編譯完成產(chǎn)物路徑target/artifacts:paths:-target/*.jarexpire_in:1 hourrules:-if:$CI_COMMIT_BRANCH develop||$CI_COMMIT_BRANCH main# 單元測(cè)試階段 test-job:stage:testimage:maven:3.8-openjdk-8script:-echo 執(zhí)行單元測(cè)試 -mvn test-echo 測(cè)試通過率統(tǒng)計(jì)-cat target/site/jacoco/index.html|grep-oP Total.*?([0-9]%)|tail-1rules:-if:$CI_COMMIT_BRANCH develop# Docker鏡像構(gòu)建與推送 package-job:stage:packageimage:docker:20.10services:-docker:20.10-dindscript:-echo 構(gòu)建Docker鏡像 # 登錄鏡像倉庫-docker login-u $CI_REGISTRY_USER-p $CI_REGISTRY_PASSWORD $IMAGE_REGISTRY# 構(gòu)建鏡像標(biāo)簽包含分支名commit短hash時(shí)間戳-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_TAGimage-tag.txtartifacts:paths:-image-tag.txtexpire_in:1 dayrules:-if:$CI_COMMIT_BRANCH develop||$CI_COMMIT_BRANCH main# 部署到測(cè)試環(huán)境 deploy-test-job:stage:deployimage:alpine:latestbefore_script:-apk add--no-cache openssh-clientscript:-echo 部署到測(cè)試環(huán)境 -IMAGE_TAG$(cat image-tag.txt)# 通過SSH遠(yuǎn)程執(zhí)行部署腳本-ssh-o StrictHostKeyCheckingno deploy192.168.1.100 docker pull $IMAGE_REGISTRY/$IMAGE_NAMESPACE/$CI_PROJECT_NAME:$IMAGE_TAGdocker stop $CI_PROJECT_NAME||truedocker rm $CI_PROJECT_NAME||truedocker run-d--name $CI_PROJECT_NAME--network agri-net-p 8080:8080-e SPRING_PROFILES_ACTIVEtest $IMAGE_REGISTRY/$IMAGE_NAMESPACE/$CI_PROJECT_NAME:$IMAGE_TAG-echo 部署完成rules:-if:$CI_COMMIT_BRANCH develop3.3 關(guān)鍵配置解讀1artifacts產(chǎn)物傳遞build-job編譯出來的 jar 包通過artifacts傳遞給下游Job。如果不配每個(gè)Job都是獨(dú)立容器編譯產(chǎn)物拿不到。2rules條件觸發(fā)rules:-if:$CI_COMMIT_BRANCH develop只有推送到develop分支才觸發(fā)完整流水線。推到feature/xxx分支只編譯不部署避免每個(gè)功能分支都污染測(cè)試環(huán)境。3鏡像標(biāo)簽策略IMAGE_TAG$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA-$(date%Y%m%d%H%M)# 示例develop-a3f5c2e1-202608071430分支名 commit短hash 時(shí)間戳既能追溯代碼版本又能區(qū)分構(gòu)建時(shí)間。這個(gè)標(biāo)簽規(guī)范在下一篇會(huì)詳細(xì)展開。四、Dockerfile 配套寫法流水線里調(diào)了docker build對(duì)應(yīng)的 Dockerfile 也得跟上# 多階段構(gòu)建減小最終鏡像體積 FROM maven:3.8-openjdk-8 AS builder WORKDIR /build COPY pom.xml . RUN mvn dependency:go-offline # 先下依賴?yán)肈ocker緩存層 COPY src/ ./src/ RUN mvn clean package -DskipTests FROM openjdk:8-jre-slim WORKDIR /app COPY --frombuilder /build/target/*.jar app.jar # 健康檢查K8s就緒探針會(huì)用到 HEALTHCHECK --interval30s --timeout3s \ CMD curl -f http://localhost:8080/actuator/health || exit 1 EXPOSE 8080 ENTRYPOINT [java, -jar, app.jar]多階段構(gòu)建的好處最終鏡像只包含JRE和jar包不含Maven和源碼體積從800MB降到180MB左右。在工控設(shè)備上部署時(shí)小鏡像就是快速度。五、GitHub Actions 簡(jiǎn)版對(duì)照如果你用的是GitHub Actions邏輯完全一樣換套語法name:CI/CD Pipelineon:push:branches:[develop,main]jobs:build:runs-on:ubuntu-lateststeps:-uses:actions/checkoutv3-uses:actions/setup-javav3with:java-version:8distribution: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 }}六、流水線提速技巧實(shí)際項(xiàng)目中流水線跑10分鐘以上很常見這里列幾個(gè)優(yōu)化點(diǎn)Maven依賴緩存把.m2/repository緩存到Runner第二次構(gòu)建省去下載依賴的時(shí)間Docker層緩存Dockerfile中先COPY pom.xml再RUN mvn dependency:go-offline依賴不變時(shí)這層直接命中緩存并行Job把單元測(cè)試和代碼質(zhì)量掃描SonarQube放到同一個(gè)Stage并行執(zhí)行按需觸發(fā)只有src/目錄變更時(shí)才觸發(fā)編譯文檔改動(dòng)不浪費(fèi)CI資源# 只在源碼變更時(shí)觸發(fā)編譯rules:-if:$CI_COMMIT_BRANCH developchanges:-src/**-pom.xml七、小結(jié)CI/CD的本質(zhì)是把人的重復(fù)勞動(dòng)交給機(jī)器。代碼提交后自動(dòng)編譯、測(cè)試、打包、構(gòu)建鏡像、推送倉庫、部署——一氣呵成。配置好之后開發(fā)人員只需要關(guān)心寫代碼部署的事全自動(dòng)。下一篇我們會(huì)深入Docker鏡像版本管理講清楚標(biāo)簽規(guī)范、版本留存策略和鏡像清理——?jiǎng)e讓鏡像倉庫變成垃圾場(chǎng)。