如何在Git单体仓库中仅部署发生变更的微服务?
仅部署Git单体仓库中变更的Gradle微服务的CI/CD配置方案
一、核心思路:先检测变更,再定向构建部署
要实现只部署变更的微服务,核心是两步:精准识别哪些子模块有代码变更,然后只对这些模块执行构建和部署任务。以下是具体落地方案:
二、Git变更检测(基础环节)
首先需要通过Git命令筛选出本次提交中发生变更的微服务模块,同时要兼顾根项目核心配置变更的情况(这类变更会影响所有子模块,需全量部署)。
常用检测命令
假设你的微服务都放在services/目录下,每个子目录对应一个服务(如services/user-service、services/order-service):
# 检测根目录核心配置是否变更(build.gradle、settings.gradle等) ROOT_CHANGED=$(git diff --name-only HEAD^ HEAD | grep -E '^(build.gradle|settings.gradle|gradle.properties|gradle/wrapper/)' | wc -l) # 若根配置无变更,提取变更的服务列表 if [ $ROOT_CHANGED -eq 0 ]; then CHANGED_SERVICES=$(git diff --name-only HEAD^ HEAD | grep -E 'services/[^/]+/' | cut -d'/' -f2 | uniq) fi
- 命令说明:通过
git diff对比当前提交与上一次提交的差异,筛选出变更的服务目录名并去重;若根项目核心配置有变更,则标记为全量部署。
三、Gradle层面适配
确保Gradle支持单独构建指定子模块,避免全量构建浪费资源:
- 直接指定模块路径执行构建/部署任务:
# 构建并发布user-service ./gradlew :services:user-service:build :services:user-service:publish - 每个微服务模块的
build.gradle需定义独立的部署任务(如publish到镜像仓库、deploy到K8s),避免依赖无关模块的任务。 - 若服务间存在依赖(如A依赖B的API模块),需额外编写脚本分析依赖关系,当B的API变更时,自动将A加入部署列表。
四、主流CI/CD平台配置示例
1. GitHub Actions
name: Deploy Changed Services on: push: branches: [ main ] jobs: detect-changes: runs-on: ubuntu-latest outputs: changed-services: ${{ steps.filter.outputs.changed-services }} root-changed: ${{ steps.filter.outputs.root-changed }} steps: - uses: actions/checkout@v4 with: fetch-depth: 2 - id: filter run: | ROOT_CHANGED=$(git diff --name-only HEAD^ HEAD | grep -E '^(build.gradle|settings.gradle|gradle.properties|gradle/wrapper/)' | wc -l) if [ $ROOT_CHANGED -gt 0 ]; then echo "root-changed=true" >> $GITHUB_OUTPUT echo "changed-services=all" >> $GITHUB_OUTPUT else echo "root-changed=false" >> $GITHUB_OUTPUT CHANGED_SERVICES=$(git diff --name-only HEAD^ HEAD | grep -E 'services/[^/]+/' | cut -d'/' -f2 | uniq | tr '\n' ',') CHANGED_SERVICES=${CHANGED_SERVICES%,} echo "changed-services=$CHANGED_SERVICES" >> $GITHUB_OUTPUT fi deploy-services: needs: detect-changes runs-on: ubuntu-latest if: ${{ needs.detect-changes.outputs.changed-services != '' }} strategy: matrix: service: ${{ fromJson('["' + replace(needs.detect-changes.outputs.changed-services, ',', '","') + '"]') }} steps: - uses: actions/checkout@v4 - name: Set up JDK 17 uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' - name: Grant execute permission for gradlew run: chmod +x gradlew - name: Build and deploy ${{ matrix.service }} run: | ./gradlew :services:${{ matrix.service }}:build :services:${{ matrix.service }}:publish # 此处添加具体部署命令,如kubectl apply、云厂商部署API调用等
2. GitLab CI
stages: - detect-changes - deploy detect-changes: stage: detect-changes image: alpine/git:latest script: - | ROOT_CHANGED=$(git diff --name-only HEAD^ HEAD | grep -E '^(build.gradle|settings.gradle|gradle.properties|gradle/wrapper/)' | wc -l) if [ $ROOT_CHANGED -gt 0 ]; then echo "CHANGED_SERVICES=all" > variables.env else CHANGED_SERVICES=$(git diff --name-only HEAD^ HEAD | grep -E 'services/[^/]+/' | cut -d'/' -f2 | uniq | tr '\n' ',') CHANGED_SERVICES=${CHANGED_SERVICES%,} echo "CHANGED_SERVICES=$CHANGED_SERVICES" > variables.env fi artifacts: reports: dotenv: variables.env deploy-services: stage: deploy image: gradle:jdk17-alpine needs: [detect-changes] parallel: matrix: - SERVICE: $[[ split(CHANGED_SERVICES, ',') ]] script: - chmod +x gradlew - ./gradlew :services:$SERVICE:build :services:$SERVICE:publish # 添加具体部署命令,如kubectl apply等 only: - main
五、关键注意事项
- 依赖关联处理:若服务A依赖服务B的API模块,需在变更检测脚本中加入依赖分析逻辑,当B的API变更时自动触发A的部署。
- 缓存优化:在CI/CD中配置Gradle缓存(如缓存
~/.gradle/caches和~/.gradle/wrapper),减少依赖下载时间。 - 版本管理:建议给每个服务配置独立版本号,或用Git提交哈希作为版本后缀,确保变更服务的版本唯一可追溯。
- 定向测试:构建前仅运行变更服务的测试用例,如
./gradlew :services:user-service:test,缩短测试周期。
内容的提问来源于stack exchange,提问作者KMV
相关产品推荐
相关产品推荐

