看不出为什么已发布的工件在一种情况下有效,而在另一种情况下不适用于 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 来明确地做到这一点..
概览
我正在使用工件来跨阶段保存一些文件和构建。在一种情况下,它正在工作,而在另一种情况下,尽管能够看到工件已发布,但它却没有。
什么有效
例如,这会将我的 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 来明确地做到这一点..