Использование двух автономных агентов конвейера Azure для публикации артефактов в параллельном режиме

У меня есть конвейер сборки в Azure Pipelines, состоящий из нескольких этапов. Язык - C #, .Net Core 3.1 / .Net Framework 4.7 На первом этапе конвейера создается все решение и запускаются модульные и интеграционные тесты. На следующих этапах различные микросервисы и отдельные части API публикуются и загружаются в Azure как отдельные артефакты. Все это запускается на собственном агенте сборки.

После тестирования пытался распараллелить этапы. Логика заключалась в том, что на этих этапах сборка не производится, выполняется только простое копирование и архивирование файлов. Для этого я запустил два разных агента сборки из одного пула на одном компьютере. Агенты использовали ту же локальную папку, что и их рабочие папки. Но когда я попытался запустить конвейер сборки, агенты начали конкурировать за ресурсы. Проблема с папкой для артефактов сборки решена, но не единственная. Например, оба агента пытались создать / удалить одинаковые временные файлы в папке _temp. В этом случае одна задача завершилась сбоем со следующей ошибкой:

[error]Unhandled: ENOENT: no such file or directory, open 'e:\_build\_temp\.taskkey'

Также стали возникать странные ошибки другого типа. Текст ошибок был примерно таким, как на скриншоте ниже: Странный текст ошибки

Я предполагаю, что причиной этих ошибок были конфликты между двумя агентами.

Использование двух разных рабочих папок для агентов кажется не лучшим решением, потому что в этом случае один агент не будет иметь доступа к файлам, созданным на первом этапе.

Есть ли у кого-нибудь успешный опыт запуска двух агентов Azure Pipelines на одном компьютере для обработки одного конвейера?


person Oleksii Serik    schedule 24.03.2020    source источник


Ответы (2)


Как упоминал Дэниел выше, вы не должны использовать ту же локальную папку, что и рабочие папки для ваших локальных агентов.

Существуют обходные пути для обмена файлами между различными этапами на локальных машинных агентах.

Например, вы можете использовать задача публикации артефактов сборки на этапе A для публикации файлов, необходимых на других этапах, на сервере azure DevOps. Затем вы можете использовать загрузить задачу артефактов сборки на этапе B, чтобы загрузить файлы в его рабочий каталог.

Обновление:

Другой обходной путь - добавить задачу сценария в определите переменную и установите ее значение в рабочий каталог этапа A. И добавьте зависимость для этапа A на этапе B.

Затем вы можете использовать выражение dependencies.<Previous stage name>.outputs['<name of the job which execute the task.setvariable >.TaskName.VariableName'], чтобы получить значение переменной, определенной на этапе A, который является рабочим каталогом этапа A.

Пожалуйста, проверьте пример ниже: Этап B может получить доступ к рабочему каталогу этапа A и скопировать свои файлы в c:\test\copyfromoriginalfolder

stages: 
- stage: A
  jobs:
  - job: a
    pool: Default
    steps:
    - task: PowerShell@2
      inputs:
        targetType: inline
        script: |
          echo "##vso[task.setvariable variable=PathA]$(system.defaultworkingdirectory)"
      name: power1

- stage: B
  dependsOn: A
  variables:
    PathInA: $[dependencies.A.outputs['a.power1.PathA']]
  jobs:
  - job: b
    pool: Default
    steps:
    - powershell: |
        cd $(PathInA)
        ls
    - task: CopyFiles@2
      inputs:
        SourceFolder: $(PathInA)
        contents: '**'
        TargetFolder: 'c:\test\copyfromoriginalfolder'
        CleanTargetFolder: true

Надеюсь на помощь!

person Levi Lu-MSFT    schedule 25.03.2020
comment
Спасибо за предложения, @ Levi-Lu-MSFT. Проблема в том, что решение довольно велико и имеет сложную структуру внутренних зависимостей. Он содержит более 60 проектов, а его общий размер после компиляции всех проектов составляет около 2 ГБ. Таким образом, любая попытка скопировать все решение станет трудоемкой задачей, а копирование различных частей скомпилированного решения эквивалентно dotnet publish --no-build, поэтому фактически задача публикации будет выполняться дважды. - person Oleksii Serik; 25.03.2020
comment
Привет, @OleksiiSerik. Я тестировал на своем локальном компьютере и обнаружил, что агент может получить доступ к файлам, созданным на первом этапе. Вам нужно только сообщить другим этапам путь к файлам / папкам. Я обновил ответ выше. Пожалуйста, проверьте это. - person Levi Lu-MSFT; 25.03.2020
comment
@LeviLuMSFT Может быть, я что-то не так сделал, но пример кода из вашего поста мне не подходит. Просто попробуйте установить для выходной переменной любую другую предопределенную переменную или настраиваемый путь, например c: \ temp или $ (Build.ArtifactStagingDirectory). Вы увидите, что ls по-прежнему выводит содержимое каталога $ (system.defaultworkingdirectory). Кажется, проблема в том, что пользователи могут передавать переменные только между заданиями и задачами, а не этапами. Но в любом случае ваша идея разделить путь между двумя этапами прекрасна. Я постараюсь двигаться в этом направлении! - person Oleksii Serik; 25.03.2020
comment
Я нашел способ разделить пользовательское значение между двумя этапами. Вот статья . А вот Учебник по MS, где MS ссылается на статью. - person Oleksii Serik; 25.03.2020
comment
Замечательно, что ты с этим справился. Вы можете опубликовать это как ответ. - person Levi Lu-MSFT; 26.03.2020
comment
ОБНОВЛЕНИЕ: в начале мая 2020 года Microsoft добавила возможность совместного использования выходных переменных между этапами конвейеров YAML: docs.microsoft.com/en-us/azure/devops/release-notes/2020/ Я еще не пробовал эту функцию, но все равно звучит отлично, ИМХО - person Oleksii Serik; 19.05.2020

Вы не можете и не должны делать то, что пытаетесь сделать. Агенты намеренно запускают задания в изолированных, независимых рабочих папках. Попытка запустить несколько агентов в одной и той же рабочей папке вызовет условия гонки и ошибки, точно такие же, как вы видите.

person Daniel Mann    schedule 24.03.2020