#azure-devops #azure-pipelines #azure-pipelines-yaml
Вопрос:
Обзор
Я использую артефакты для сохранения некоторых файлов и сборок на разных этапах. В одном случае он работает, а в другом-нет, несмотря на то, что он может видеть, что артефакт опубликован.
Что Работает
Например, это загружает мои 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 }}
What Doesn’t Work
However, now what I’m trying to do is build a service in the application, run unit tests, and take the exact same build that was tested and use it for building the Docker image.
I’m trying to do this with the following:
# 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 }} amp;amp;
python -m pip install --upgrade pip amp;amp;
pip install -r requirements.txt
displayName: Install requirements for ${{ parameters.pathName }}...
- script: cd ${{ parameters.pathName }} amp;amp; coverage run --omit='manage.py,config/*,.venv*,*/*__init__.py,*/tests.py,*/admin.py' manage.py test amp;amp; 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
, что артефакт был опубликован:
Но потом, когда дело доходит до того, чтобы на самом деле вытащить его для создания образа Докера, я просто получаю:
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
Вопрос
Так что же я здесь делаю не так, что ссылка на артефакт работает в одном случае, а не в другом?
Ответ №1:
Задание развертывания в первом случае автоматически загружает все опубликованные артефакты.
Во втором случае вы используете обычную работу, которая не загружает ее. Вы должны сделать это неявно, добавив шаг загрузки перед запуском шага настройки..