在与已发布的 Artifact 不同的阶段使用 $(Build.ArtifactStagingDirectory) 感到困惑

Confused by the use of $(Build.ArtifactStagingDirectory) in separate stage from published Artifact

问题:

$(Build.ArtifactStagingDirectory) 为空,尽管能够在 Azure DevOps 管道 UI 中查看已发布的工件,这会导致管道失败。

我想做什么:

  1. 构建微服务(例如,/api)。
  2. 运行 单元测试。
  3. 如果单元测试通过,将构建发布为工件。
  4. Docker使用 buildContext 调整构建工件。

这是基于建议here, here, and

发布阶段配置

单元测试通过后我的发布配置如下:

- publish: $(System.DefaultWorkingDirectory)/${{ parameters.pathName }} 
  artifact: ${{ parameters.pathName }}
  condition: succeeded()

Docker buildAndPush 舞台配置

我获取神器并在 Docker buildAndPush 配置中使用它的配置如下:

- task: Docker@2
  condition: contains(variables['servicesChanged'], '${{ parameters.serviceName }}')
  displayName: Build and Push ${{ parameters.pathName }} Docker image
  inputs:
    command: buildAndPush
    repository: $(imageRepository)-${{ parameters.pathName }}
    dockerfile: $(dockerfilePath)/${{ parameters.pathName }}/Dockerfile
    buildContext: $(Build.ArtifactStagingDirectory)
    containerRegistry: $(dockerRegistryServiceConnection)
    tags: |
      ${{ parameters.tag }}-${{ parameters.tagVersion }}

Dockerfile 配置

信息,但这是 Dockerfile 包含的内容:

FROM python:3.8-slim

WORKDIR /app
EXPOSE 5000
COPY . .
RUN pip install -r requirements.txt
CMD ["gunicorn", "-b", ":5000", "--log-level", "info", "config.wsgi:application", "-t", "150"]

项目结构

/project-root
  /admin
    package.json
    Dockerfile
  /api
    requirements.txt
    Dockerfile
  /client
    package.json
    Dockerfile

我试过的

dockerfile: $(dockerfilePath)/${{ parameters.pathName }}/Dockerfile
buildContext: $(Build.ArtifactStagingDirectory)


Step 5/17 : RUN pip install -r requirements.txt
 ---> Running in 277ce44b61cf
ERROR: Could not open requirements file: [Errno 2] No such file or directory: 'requirements.txt'
The command '/bin/sh -c pip install -r requirements.txt' returned a non-zero code: 1
##[error]The command '/bin/sh -c pip install -r requirements.txt' returned a non-zero code: 1
##[error]The process '/usr/bin/docker' failed with exit code 1

dockerfile: $(dockerfilePath)/${{ parameters.pathName }}/Dockerfile
buildContext: $(Build.ArtifactStagingDirectory)/${{ parameters.pathName }}


unable to prepare context: path "/home/vsts/work/1/a/api" not found
##[error]unable to prepare context: path "/home/vsts/work/1/a/api" not found
##[error]The process '/usr/bin/docker' failed with exit code 1
dockerfile: $(Build.ArtifactStagingDirectory)/${{ parameters.pathName }}/Dockerfile
buildContext: $(Build.ArtifactStagingDirectory)


##[error]Unhandled: No Dockerfile matching  /home/vsts/work/1/a/api/Dockerfile  was found.

dockerfile: $(Build.ArtifactStagingDirectory)/Dockerfile
buildContext: $(Build.ArtifactStagingDirectory)

##[error]Unhandled: No Dockerfile matching  /home/vsts/work/1/a/Dockerfile  was found.

什么有效

dockerfile: $(System.DefaultWorkingDirectory)/${{ parameters.pathName }}/Dockerfile
buildContext: $(System.DefaultWorkingDirectory)/${{ parameters.pathName }}

但这样做似乎否定了 publish 作为神器的必要性。也许这是“正确”的方式,我不知道。它似乎正在做我想通过 COPY 为单元测试构建到 Docker 图像而不是使用不同版本的东西。

我很确定这不是我想要的,因为它看起来只是在这个阶段开始时再次将回购克隆到 /home/vsts/work/1/a/

问题

当您使用时:

- publish: $(System.DefaultWorkingDirectory)/${{ parameters.pathName }} 
  artifact: ${{ parameters.pathName }}
  condition: succeeded()

在后台它使用 Publish Pipeline Artifact task 默认下载

downloads files to $(Pipeline.Workspace). This is the default and recommended path for all types of artifacts.

所以请尝试

buildContext: $(Pipeline.Workspace)

buildContext: $(Pipeline.Workspace)/${{ parameters.pathName }}

但是,当您拥有多级管道时(我不确定,因为您没有发布整个管道),这很有意义。请检查 here

For build artifacts, it's common to copy files to $(Build.ArtifactStagingDirectory) and then use the Publish Build Artifacts task to publish this folder. With the Publish Pipeline Artifact task, you can just publish directly from the path containing the files.

所以这里没有必要在发布文件之前将文件移动到$(Build.ArtifactStagingDirectory)。因此,对于更新和推荐的任务,此 foler 可能始终为空。