看不出为什么已发布的工件在一种情况下有效,而在另一种情况下不适用于 Azure DevOps Pipelines

Not seeing why published artifacts are working in one case and not another for Azure DevOps Pipelines

概览

我正在使用工件来跨阶段保存一些文件和构建。在一种情况下,它正在工作,而在另一种情况下,尽管能够看到工件已发布,但它却没有。

什么有效

例如,这会将我的 k8s 清单上传到一个工件中,这样它们就可以在 deployment 阶段访问到 AKS 并且它完美地工作:

# publishStage.yaml
stages:
- stage: Publish
  displayName: Publish artifacts
  dependsOn: 
  - SeleniumTests
  - Changed
  condition: succeeded()
  variables:
    anyServicesChanged: $[ stageDependencies.Changed.Changes.outputs['detectChanges.anyServicesChanged'] ]
    anyConfigsChanged: $[ stageDependencies.Changed.Changes.outputs['detectChanges.anyConfigsChanged'] ]
  jobs:
  - job: Publish
    condition: or(eq(variables.anyServicesChanged, true), eq(variables.anyConfigsChanged, true), eq(variables['Build.Reason'], 'Manual'))
    displayName: Publishing artifacts...
    steps:
    - upload: k8s
      artifact: k8s
# deployStage.yaml
parameters:
- name: tag
  default: ''
- name: tagVersion
  default: ''

stages:
- stage: Deploy
  displayName: Deployment stage...
  dependsOn: 
  - Publish
  - Changed
  condition: succeeded()
  variables:
    anyServicesChanged: $[ stageDependencies.Changed.Changes.outputs['detectChanges.anyServicesChanged'] ]
    anyConfigsChanged: $[ stageDependencies.Changed.Changes.outputs['detectChanges.anyConfigsChanged'] ]
    servicesChanged: $[ stageDependencies.Changed.Changes.outputs['detectChanges.servicesChanged'] ]
  jobs:
  - deployment: Deploy
    condition: or(eq(variables.anyServicesChanged, true), eq(variables.anyConfigsChanged, true), eq(variables['Build.Reason'], 'Manual'))
    displayName: Deploying services...
    environment: 'App Production AKS'
    strategy:
      runOnce:
        deploy:
          steps:
          - task: KubernetesManifest@0
            displayName: Create imagePullSecret
            inputs:
              action: createSecret
              secretName: $(imagePullSecret)
              kubernetesServiceConnection: 'App Production AKS'
              dockerRegistryEndpoint: $(dockerRegistryServiceConnection)
          - template: deployStep.yaml
            parameters: 
              tag: ${{ parameters.tag }}
              tagVersion: ${{ parameters.tagVersion }}
              serviceName: api-v1
              pathName: api
# deployStep.yaml
parameters:
- name: tag
  default: ''
- name: tagVersion
  default: ''
- name: serviceName
  default: ''
- name: pathName
  default: ''

steps:
- task: KubernetesManifest@0
  condition: contains(variables['servicesChanged'], '${{ parameters.serviceName }}')
  displayName: Deploy to ${{ parameters.pathName }} Kubernetes cluster...
  inputs:
    action: deploy
    kubernetesServiceConnection: 'App Production AKS'
    manifests: |
      $(Pipeline.Workspace)/k8s/aks/${{ parameters.pathName }}.yaml
    imagePullSecrets: |
      $(imagePullSecret)
    containers: |
      $(containerRegistry)/$(imageRepository)-${{ parameters.pathName }}:${{ parameters.tag }}-${{ parameters.tagVersion }}

什么不起作用

但是,现在我要做的是在应用程序中构建服务,运行 单元测试,并采用与测试完全相同的构建并将其用于构建 Docker 图片。

我正在尝试使用以下方法执行此操作:

# unitTestsStage.yaml
stages:
- stage: UnitTests
  displayName: Run unit tests for services...
  dependsOn: Changed
  condition: succeeded()
  jobs:
  - template: ../secretsJob.yaml
  - template: pythonJob.yaml
    parameters:
      serviceName: api-v1
      pathName: api
# pythonJob.yaml
parameters:
- name: serviceName
  type: string
  default: ''
- name: pathName
  type: string
  default: ''

jobs:
- job: UnitTests
  displayName: Running unit tests for ${{ parameters.serviceName }}...
  variables:
    servicesChanged: $[ stageDependencies.Changed.Changes.outputs['detectChanges.servicesChanged'] ]
  condition: or(contains(variables['servicesChanged'], '${{ parameters.serviceName }}'), eq(variables['Build.Reason'], 'Manual'))
  dependsOn: Secrets
  steps:
  - task: UsePythonVersion@0
    inputs:
      versionSpec: '3.8'
  - script: |
      cd ${{ parameters.pathName }} && 
      python -m pip install --upgrade pip && 
      pip install -r requirements.txt
    displayName: Install requirements for ${{ parameters.pathName }}...
  - script: cd ${{ parameters.pathName }} &&  coverage run --omit='manage.py,config/*,.venv*,*/*__init__.py,*/tests.py,*/admin.py' manage.py test && coverage report
    displayName: Run unit tests and coverage for ${{ parameters.pathName }}...
    env:
      DJANGO_SECRET_KEY: $(PROD-DJANGOSECRETKEY)
      DJANGO_DEBUG: $(PROD-DJANGODEBUG)
      DOMAIN: $(PROD-DOMAIN)
      PGDATABASE: $(PROD-PGDATABASE)
      PGDATABASEV2: $(PROD-PGDATABASEV2)
      PGUSER: $(PROD-PGUSER)
      PGPASSWORD: $(PROD-PGPASSWORD)
      PGHOST: $(PROD-PGHOST)
      PGPORT: $(PROD-PGPORT)
  - upload: ${{ parameters.pathName }}
    artifact: ${{ parameters.pathName }}
    condition: succeeded()

# buildStage.yaml
parameters:
- name: tag
  default: ''
- name: tagVersion
  default: ''
#
stages:
- stage: BuildAndPush
  displayName: Build and Push Docker images of services...
  dependsOn: 
  - UnitTests
  - Changed
  condition: succeeded()
  variables:
    anyServicesChanged: $[ stageDependencies.Changed.Changes.outputs['detectChanges.anyServicesChanged'] ]
    servicesChanged: $[ stageDependencies.Changed.Changes.outputs['detectChanges.servicesChanged'] ]
  jobs:
  - job: BuildAndPush
    condition: or(eq(variables.anyServicesChanged, true), eq(variables['Build.Reason'], 'Manual'))
    displayName: Building and Push Docker images of services...
    steps:
    - template: buildStep.yaml
      parameters: 
        tag: ${{ parameters.tag }}
        tagVersion: ${{ parameters.tagVersion }}
        serviceName: api-v1
        pathName: api
# buildStep.yaml
parameters:
- name: tag
  default: ''
- name: tagVersion
  default: ''
- name: serviceName
  default: ''
- name: pathName
  default: ''

steps: 
- 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: $(Pipeline.Workspace)/${{ parameters.pathName }}/Dockerfile
    buildContext: $(Pipeline.Workspace)/${{ parameters.pathName }}
    containerRegistry: $(dockerRegistryServiceConnection)
    tags: |
      ${{ parameters.tag }}-${{ parameters.tagVersion }}

我可以看到 api 工件已发布:

但是当它实际拉动它来构建 Docker 图像时,我得到:

Starting: Build and Push api Docker image
==============================================================================
Task         : Docker
Description  : Build or push Docker images, login or logout, start or stop containers, or run a Docker command
Version      : 2.187.0
Author       : Microsoft Corporation
Help         : https://aka.ms/azpipes-docker-tsg
==============================================================================
##[error]Unhandled: No Dockerfile matching  /home/vsts/work/1/api/Dockerfile  was found.
Finishing: Build and Push api Docker image

如果我有一个脚本任务到 ls -la $(Pipeline.Workspace) 我得到:

drwxr-xr-x  6 vsts docker 4096 Jul  9 16:19 .
drwxr-xr-x  7 vsts root   4096 Jul  9 16:19 ..
drwxr-xr-x  2 vsts docker 4096 Jul  9 16:19 TestResults
drwxr-xr-x  2 vsts docker 4096 Jul  9 16:19 a
drwxr-xr-x  2 vsts docker 4096 Jul  9 16:19 b
drwxr-xr-x 12 vsts docker 4096 Jul  9 16:19 s

问题

那么我在这里做错了什么,引用工件在一种情况下有效,而在另一种情况下无效?

第一种情况下的部署作业会自动下载所有已发布的工件。

在你的第二种情况下,你使用的是不下载它的常规作业。您必须通过在 运行 您的 docker 步骤之前添加 download step 来明确地做到这一点..