azure - 如何在包含许多 Dockerfile 的单一存储库中构建一个特定的 Docker 镜像

标签 azure docker azure-devops pipeline

我有一个包含 8 个不同 Dockerfile 的存储库,用于构建不同的镜像。它们都在同一个存储库中,因为它们共享 80% 的相同代码。每个 Dockerfile 对应一个单独的产品。我目前有一个 azure-pipeline.yaml 文件来将 8 个 Dockerfile 构建到镜像中。在制作 PR 或合并到我的主分支时,我通常只更新 8 个产品之一的功能。因此更新所有 8 张图像是没有意义的。

我想知道我可以选择哪些选项来触发我更改的产品的构建。但偶尔会触发所有 8 个构建(如果更新了共享方法)。例如,是否有一个标志功能可以用来表示当识别出该标志时,仅运行管道的这一部分?

旁注:我知道我可以将我的单一存储库拆分为许多不同的存储库,并创建一个允许共享公共(public)代码的包。然而,这需要大量的时间投入,想知道是否有更简单的方法。

最佳答案

您可以在 yaml 文件中结合使用路径过滤器和条件,根据拉取请求或提交中的更改有选择地运行构建。

1。路径过滤器

您可以使用路径过滤器来指定哪些路径应触发管道。例如,如果每个 Dockerfile 都位于单独的目录中,则可能有如下内容:

trigger:
  paths:
    include:
      - 'productA/*'

仅当 productA 目录发生更改时才会触发构建。

2。条件步骤

您可以向步骤或作业添加条件来决定它们是否应该运行。例如,您可以定义变量并使用它们有条件地运行步骤:

variables:
  isFullBuild: $[eq(variables['Build.Reason'], 'Manual')]

steps:
- script: echo Building ProductA...
  condition: or(eq(variables.isFullBuild, true), changesContain('productA/*'))

您可以将两者结合起来添加触发器并调节您的管道,如下所示。

trigger:
  branches:
    include:
    - main
  paths:
    include:
    - 'productA/*'
    - 'productB/*'
    - 'common/*'

- job: BuildProductA
  condition: or(eq(variables.isFullBuild, true), changesContain('productA/*', 'common/*'))
  steps:
  - script: echo Building ProductA...

- job: BuildProductB
  condition: or(eq(variables.isFullBuild, true), changesContain('productB/*', 'common/*'))
  steps:
  - script: echo Building ProductB...

更多信息:changeContains 不是 Azure Pipelines 中的表达式(它只是添加类似条件的占位符)。在使用作业条件之前,您应该添加一个运行脚本并生成将保存更改的文件夹的输出的作业。用于比较工作条件是否存在变化。下面的例子:

CheckChanges.ps1

$folders = @("productA", "productB", "productC") # specify your folder names
$changedFolders = @()

foreach ($folder in $folders) {
    $changes = git diff --name-only HEAD HEAD~1 -- $folder
    if ($changes) {
        $changedFolders += $folder
    }
}

# Join the changed folders into a comma-separated string
$changedFoldersString = $changedFolders -join ','

# Set the pipeline variable
Write-Output "##vso[task.setvariable variable=changedFolders;isOutput=true]$changedFoldersString"

您更新后的管道可能如下所示:

trigger:
  branches:
    include:
    - main
  paths:
    include:
    - 'productA/*'
    - 'productB/*'
    - 'common/*'


- job: CheckChanges
  pool:
    vmImage: 'windows-latest'
  steps:
  - powershell: |
      .\CheckChanges.ps1
    name: checkChangesStep

- job: BuildProductA
  dependsOn: CheckChanges
  variables:
    changes: $[ dependencies.CheckChanges.outputs['checkChangesStep.changedFolders'] ]
 
  condition: or(eq(variables.isFullBuild, true), contains(variables['changes'], 'productA'))
  steps:
  - script: echo Building ProductA...

- job: BuildProductB
  dependsOn: CheckChanges
  variables:
    changes: $[ dependencies.CheckChanges.outputs['checkChangesStep.changedFolders'] ]
 
  condition: or(eq(variables.isFullBuild, true), contains(variables['changes'], 'productB'))
  steps:
  - script: echo Building ProductB...

注意:我尚未通过运行来验证上述管道,并且可能包含一些语法/其他问题,并且仅作为通用方法提供。

关于azure - 如何在包含许多 Dockerfile 的单一存储库中构建一个特定的 Docker 镜像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/77181559/

相关文章:

azure - 列出 Azure AD 组所需的权限

docker - phpstorm Xdebug无法与ddev一起使用

azure - 根据 Azure DevOps Pipelines YAML 中的条件隐藏/显示参数

sql - 从 Azure SQL InlineSqlTask​​ 任务创建输出变量 azure devops

azure - 我可以使用具有动态架构的 Azure 数据工厂创建 SQL 表吗

Azure虚拟机: SQL servers on machines should have vulnerability findings resolved

azure - 如何检查二头肌文件中是否已存在 KeyVault secret

mysql - 带有自定义主题+ mysql的Docker-compose wordpress

Docker 端口未映射

azure - 通过 REST API 从 Azure Devops 构建获取已使用的管道工件