You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Monorepo目录变更触发对应Dockerfile构建工作流

Monorepo按需构建Docker镜像的实现方案

核心思路

通过Git的文件变更对比能力,识别本次提交(push或PR)中包含Dockerfile的改动文件夹,仅针对这些文件夹执行镜像构建流程,避免无意义的全量构建。

GitHub Actions实现

  1. 拉取完整代码历史
    使用actions/checkout时设置fetch-depth: 0,确保能获取完整提交记录用于对比:

    - uses: actions/checkout@v4
      with:
        fetch-depth: 0
    
  2. 检测变更文件夹
    根据事件类型(PR/push)执行不同的Git diff命令,筛选出包含Dockerfile的改动文件夹:

    if [ "${{ github.event_name }}" = "pull_request" ]; then
      DIFF_CMD="git diff --name-only ${{ github.base_ref }} ${{ github.head_ref }}"
    else
      DIFF_CMD="git diff --name-only HEAD^ HEAD"
    fi
    # 提取Dockerfile所在文件夹并去重
    CHANGED_DIRS=$($DIFF_CMD | grep -E 'Dockerfile$' | xargs dirname | sort | uniq | jq -R . | jq -s .)
    echo "changed_dirs=$CHANGED_DIRS" >> $GITHUB_OUTPUT
    
  3. 动态生成构建任务
    将变更文件夹列表转为JSON数组,作为矩阵参数触发多任务并行构建:

    jobs:
      detect-changes:
        runs-on: ubuntu-latest
        outputs:
          changed_dirs: ${{ steps.set-dirs.outputs.changed_dirs }}
        steps:
          - uses: actions/checkout@v4
            with:
              fetch-depth: 0
          - id: set-dirs
            run: |
              # 上面的检测命令
      build-images:
        needs: detect-changes
        if: ${{ needs.detect-changes.outputs.changed_dirs != '[]' }}
        runs-on: ubuntu-latest
        strategy:
          matrix:
            dir: ${{ fromJSON(needs.detect-changes.outputs.changed_dirs) }}
        steps:
          - uses: actions/checkout@v4
          - name: Build image for ${{ matrix.dir }}
            run: |
              cd ${{ matrix.dir }}
              docker build -t my-image-${{ matrix.dir }} .
              # 可选:添加镜像推送步骤
    

GitLab CI实现

  1. 获取变更文件列表
    根据CI环境变量判断是PR还是push场景,执行Git diff筛选目标文件夹:

    if [ -n "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
      DIFF_CMD="git diff --name-only $CI_MERGE_REQUEST_TARGET_BRANCH_NAME...$CI_COMMIT_BRANCH"
    else
      DIFF_CMD="git diff --name-only HEAD^ HEAD"
    fi
    CHANGED_DIRS=$($DIFF_CMD | grep -E 'Dockerfile$' | xargs dirname | sort | uniq)
    echo "CHANGED_DIRS=$CHANGED_DIRS" > changed_dirs.env
    
  2. 传递变量并执行构建
    通过dotenv制品传递变更列表,在构建阶段循环处理每个文件夹:

    stages:
      - detect-changes
      - build
    
    detect-changes:
      stage: detect-changes
      script:
        # 上面的检测命令
      artifacts:
        reports:
          dotenv: changed_dirs.env
    
    build:
      stage: build
      script:
        - |
          for dir in $CHANGED_DIRS; do
            echo "Building image for $dir"
            cd $dir
            docker build -t my-image-$dir .
            # 可选:添加镜像推送步骤
          done
      only:
        variables:
          - $CHANGED_DIRS != ""
    

Jenkins实现

  1. 检测变更文件夹
    在流水线中通过Groovy脚本处理Git变更,筛选出目标文件夹:
    pipeline {
      agent any
      stages {
        stage('Detect Changes') {
          steps {
            script {
              def changedFiles
              if (env.CHANGE_ID) {
                // PR场景对比分支
                changedFiles = sh(script: "git diff --name-only origin/${env.CHANGE_TARGET} origin/${env.CHANGE_BRANCH}", returnStdout: true).trim()
              } else {
                // push场景对比提交
                changedFiles = sh(script: "git diff --name-only HEAD^ HEAD", returnStdout: true).trim()
              }
              def changedDirs = changedFiles.split('\n').findAll { it.endsWith('Dockerfile') }.collect { new File(it).parent }.unique()
              env.CHANGED_DIRS = changedDirs.join(' ')
            }
          }
        }
        stage('Build Images') {
          when {
            expression { env.CHANGED_DIRS != '' }
          }
          steps {
            script {
              env.CHANGED_DIRS.split(' ').each { dir ->
                echo "Building image for ${dir}"
                dir(dir) {
                  sh "docker build -t my-image-${dir} ."
                  // 可选:添加镜像推送步骤
                }
              }
            }
          }
        }
      }
    }
    

通用注意事项

  • 确保Git仓库能获取完整提交历史,否则diff命令无法正确对比变更;
  • 若需要文件夹内任何文件变更都触发构建,可修改筛选规则,比如用grep -E '^services/api/'匹配整个文件夹的变更;
  • 对于嵌套目录结构,dirname命令会自动获取Dockerfile所在的直接父目录,无需额外处理。

内容的提问来源于stack exchange,提问作者Memphis Meng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 15:01:53