Кэширование конвейера

Azure DevOps Services

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

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

Примечание.

Кэширование конвейера поддерживается в заданиях пула агентов как для YAML, так и для классических конвейеров. Однако он не поддерживается в конвейерах классических выпусков.

Использование артефактов и кэширования

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

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

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

Примечание.

Кэширование конвейера и артефакты конвейера бесплатны для всех уровней (бесплатные и платные). Дополнительные сведения см. в разделе " Использование хранилища артефактов".

Задача кэша: как она работает

Кэширование добавляется в конвейер с помощью задачи "Кэш". Эта задача работает как любая другая задача и добавляется в steps раздел задания.

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

После выполнения всех шагов задания и при условии успешного состояния задания специальный шаг "Post-job: Cache" автоматически добавляется и активируется для каждого шага восстановления кэша, который не был пропущен. Этот шаг отвечает за сохранение кэша.

Примечание.

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

Настройка задачи кэша

Задача кэша имеет два обязательных аргумента: ключ и путь:

  • путь: путь к папке для кэширования. Может быть абсолютным или относительным путем. Относительные пути разрешаются против $(System.DefaultWorkingDirectory).

Примечание.

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

  • ключ: необходимо задать идентификатор для кэша, который требуется восстановить или сохранить. Ключи состоят из сочетания строковых значений, путей к файлам или шаблонов файлов, где каждый сегмент отделен символом | .
  • Строки:
    Фиксированное значение (например, имя кэша или имени средства) или взятое из переменной среды (например, текущее имя ОС или текущего задания).

  • Пути к файлам:
    Путь к определенному файлу, содержимое которого будет хэшировано. Этот файл должен существовать во время выполнения задачи. Помните, что любой сегмент ключа, который будет рассматриваться как путь к файлу, будет рассматриваться как путь к файлу. В частности, это включает сегменты, содержащие объект .. Это может привести к сбою задачи, если этот файл не существует.

    Совет

    Чтобы избежать обращения к сегменту строки типа пути, как путь к файлу, обтекайте его двойными кавычками, например: "my.key" | $(Agent.OS) | key.file

  • Шаблоны файлов:
    Разделенный запятыми список шаблонов подстановочных знаков в стиле с запятыми, который должен соответствовать по крайней мере одному файлу. Например:

    • **/yarn.lock: все файлы yarn.lock в каталоге источников
    • */asset.json, !bin/**: все asset.json файлы, расположенные в каталоге источников, за исключением каталога bin

Содержимое любого файла, определяемого путем к файлу или шаблоном файла, хэшируется для создания ключа динамического кэша. Это полезно, если в проекте есть файлы, которые однозначно определяют, что кэшируется. Например, такие файлы, как package-lock.json, Gemfile.lockyarn.lockили Pipfile.lock обычно ссылаются на ключ кэша, так как все они представляют уникальный набор зависимостей.

Относительные пути к файлам или шаблоны файлов разрешаются для $(System.DefaultWorkingDirectory).

Пример:

Ниже приведен пример кэширования зависимостей, установленных Yarn:

variables:
  YARN_CACHE_FOLDER: $(Pipeline.Workspace)/s/.yarn

steps:
- task: Cache@2
  inputs:
    key: '"yarn" | "$(Agent.OS)" | yarn.lock'
    restoreKeys: |
       "yarn" | "$(Agent.OS)"
       "yarn"
    path: $(YARN_CACHE_FOLDER)
  displayName: Cache Yarn packages

- script: yarn --frozen-lockfile

В этом примере ключ кэша содержит три части: статическую строку (yarn), на которую выполняется задание, так как этот кэш является уникальным для каждой операционной системы, а хэш yarn.lock файла, который однозначно определяет набор зависимостей в кэше.

При первом запуске после добавления задачи шаг кэша сообщит о "промахе кэша", так как кэш, определенный этим ключом, не существует. После последнего шага кэш будет создан из файлов $(Pipeline.Workspace)/s/.yarn и отправлен. На следующем этапе кэша будет сообщаться о "попадании в кэш", а содержимое кэша будет загружено и восстановлено.

При использовании checkout: selfрепозиторий извлекается $(Pipeline.Workspace)/sи папка .yarn обычно находится в самом репозитории.

Примечание.

Pipeline.Workspace — это локальный путь к агенту, на котором выполняются конвейер, где создаются все каталоги. Эта переменная имеет то же значение, что Agent.BuildDirectoryи .

Убедитесь, что переменная YARN_CACHE_FOLDER обновляется, если используется что-либо, отличное от checkout: self этого, в репозитории, где .yarn находится.

Восстановление ключей

restoreKeys можно использовать, если требуется запросить несколько точных ключей или префиксов ключей. Это используется для возврата к другому ключу в случае, если не key дает удара. Ключ восстановления выполняет поиск ключа по префиксу и дает последнюю созданную запись кэша в результате. Это полезно, если конвейер не может найти точное совпадение, но хочет использовать частичное попадание кэша. Чтобы вставить несколько ключей восстановления, разделите их с помощью новой строки, чтобы указать ключ восстановления (см. пример для получения дополнительных сведений). Порядок, в котором будут пытаться выполнить восстановление ключей, будут выполняться сверху вниз.

Обязательное программное обеспечение для локального агента

Архивное программное обеспечение / платформа Windows Linux Mac
GNU Tar Обязательное поле Обязательное поле No
BSD Tar No Нет Обязательное поле
7-Zip Рекомендуемая конфигурация No No

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

Пример:

Ниже приведен пример использования ключей восстановления Yarn:

variables:
  YARN_CACHE_FOLDER: $(Pipeline.Workspace)/.yarn

steps:
- task: Cache@2
  inputs:
    key: '"yarn" | "$(Agent.OS)" | yarn.lock'
    restoreKeys: |
       yarn | "$(Agent.OS)"
       yarn
    path: $(YARN_CACHE_FOLDER)
  displayName: Cache Yarn packages

- script: yarn --frozen-lockfile

В этом примере задача кэша пытается найти, существует ли ключ в кэше. Если ключ не существует в кэше, он пытается использовать первый ключ yarn | $(Agent.OS)восстановления. При этом выполняется поиск всех ключей, которые точно соответствуют этому ключу или имеют этот ключ в качестве префикса. При наличии другого yarn.lock хэш-сегмента может произойти попадание префикса. Например, если следующий ключ был в кэше, где old-yarn.lock получен хэш, отличный от хэшаyarn.lock, ключ yarn | $(Agent.OS) | old-yarn.lock восстановления даст частичный удар. Если на первом ключе восстановления отсутствует, он будет использовать следующий ключ восстановления, который попытается найти любой ключ yarn , который начинается с yarn. В случае попаданий префикса результат возвращает последний созданный ключ кэша в результате.

Примечание.

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

Изоляция кэша и безопасность

Чтобы обеспечить изоляцию между кэшами из разных конвейеров и разных ветвей, каждый кэш принадлежит логическому контейнеру, называемому областью. Области предоставляют границу безопасности, которая гарантирует, что задание из одного конвейера не может получить доступ к кэшам из другого конвейера, а задание, создающее PR, имеет доступ на чтение к кэшам целевой ветви PR (для одного конвейера), но не может записывать (создать) кэши в области целевой ветви.

При обнаружении шага кэша во время выполнения кэш, кэш, определенный ключом, запрашивается с сервера. Затем сервер ищет кэш с этим ключом из областей, видимых для задания, и возвращает кэш (если он доступен). При сохранении кэша (в конце задания) кэш записывается в область, представляющую конвейер и ветвь. Дополнительные сведения см. ниже.

CI, вручную и запланированные запуски

Область Читать Запись
Исходная ветвь Да Да
main ветка Да Нет
master ветка Да Нет

Запуски запроса на вытягивание

Область Читать Запись
Исходная ветвь Да Нет
Целевая ветвь Да Нет
Промежуточная ветвь (например refs/pull/1/merge) Да Да
main ветка Да Нет
master ветка Да Нет

Запуски запросов на вытягивание

Ветвь Читать Запись
Целевая ветвь Да Нет
Промежуточная ветвь (например refs/pull/1/merge) Да Да
main ветка Да Нет
master ветка Да Нет

Совет

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

Кондиционирование при восстановлении кэша

В некоторых сценариях успешное восстановление кэша должно привести к выполнению другого набора шагов. Например, шаг установки зависимостей можно пропустить, если кэш был восстановлен. Это возможно с помощью входных cacheHitVar данных задачи. Установка этого входного значения в имя переменной среды приводит к тому, что true переменная будет задана при попадании в кэш кэша восстановления, inexact в противном случае оно имеет значение false. Затем эту переменную можно ссылаться в условии шага или из скрипта.

В следующем примере install-deps.sh шаг пропускается при восстановлении кэша:

steps:
- task: Cache@2
  inputs:
    key: mykey | mylockfile
    restoreKeys: mykey
    path: $(Pipeline.Workspace)/mycache
    cacheHitVar: CACHE_RESTORED

- script: install-deps.sh
  condition: ne(variables.CACHE_RESTORED, 'true')

- script: build.sh

Средство увязки программ в пакеты

Для проектов Ruby с помощью Bundler переопределите BUNDLE_PATH переменную среды, используемую Пакетировщиком, чтобы задать путь Для поиска драгоценных камней.

Пример:

variables:
  BUNDLE_PATH: $(Pipeline.Workspace)/.bundle

steps:
- task: Cache@2
  displayName: Bundler caching
  inputs:
    key: 'gems | "$(Agent.OS)" | Gemfile.lock'
    path: $(BUNDLE_PATH)
    restoreKeys: | 
      gems | "$(Agent.OS)"
      gems   

Ccache (C/C++)

Ccache — это кэш компилятора для C/C++. Чтобы использовать Ccache в конвейере, убедитесь, что Ccache установлен и дополнительно добавлен в ваш PATH (см . режимы выполнения Ccache). Задайте для переменной CCACHE_DIR среды путь и $(Pipeline.Workspace) кэшируйте этот каталог.

Пример:

variables:
  CCACHE_DIR: $(Pipeline.Workspace)/ccache

steps:
- bash: |
    sudo apt-get install ccache -y    
    echo "##vso[task.prependpath]/usr/lib/ccache"
  displayName: Install ccache and update PATH to use linked versions of gcc, cc, etc

- task: Cache@2
  displayName: Ccache caching
  inputs:
    key: 'ccache | "$(Agent.OS)" | $(Build.SourceVersion)'
    path: $(CCACHE_DIR)
    restoreKeys: | 
      ccache | "$(Agent.OS)"

Дополнительные сведения см . в параметрах конфигурации Ccache.

Образы Docker

Кэширование образов Docker значительно сокращает время, необходимое для запуска конвейера.

variables:
  repository: 'myDockerImage'
  dockerfilePath: '$(Build.SourcesDirectory)/app/Dockerfile'
  tag: '$(Build.BuildId)'

pool:
  vmImage: 'ubuntu-latest'
steps:
  - task: Cache@2
    displayName: Cache task
    inputs:
      key: 'docker | "$(Agent.OS)" | cache'
      path: $(Pipeline.Workspace)/docker
      cacheHitVar: CACHE_RESTORED                #Variable to set to 'true' when the cache is restored
    
  - script: |
      docker load -i $(Pipeline.Workspace)/docker/cache.tar
    displayName: Docker restore
    condition: and(not(canceled()), eq(variables.CACHE_RESTORED, 'true'))

  - task: Docker@2
    displayName: 'Build Docker'
    inputs:
      command: 'build'
      repository: '$(repository)'
      dockerfile: '$(dockerfilePath)'
      tags: |
        '$(tag)'

  - script: |
      mkdir -p $(Pipeline.Workspace)/docker
      docker save -o $(Pipeline.Workspace)/docker/cache.tar $(repository):$(tag)
    displayName: Docker save
    condition: and(not(canceled()), not(failed()), ne(variables.CACHE_RESTORED, 'true'))
  • key: (обязательно) — уникальный идентификатор кэша.
  • path: (обязательно) — путь к папке или файлу, который требуется кэшировать.

Golang

Для проектов Golang можно указать пакеты, которые нужно скачать в файле go.mod . GOCACHE Если переменная еще не задана, задайте для нее место загрузки кэша.

Пример:

variables:
  GO_CACHE_DIR: $(Pipeline.Workspace)/.cache/go-build/

steps:
- task: Cache@2
  inputs:
    key: 'go | "$(Agent.OS)" | go.mod'
    restoreKeys: | 
      go | "$(Agent.OS)"
    path: $(GO_CACHE_DIR)
  displayName: Cache GO packages

Gradle

Использование встроенной поддержки кэширования Gradle может оказать значительное влияние на время сборки. Чтобы включить кэш сборки, установите GRADLE_USER_HOME переменную среды в путь $(Pipeline.Workspace) и запустите сборку или --build-cache добавьте org.gradle.caching=true в gradle.properties файл.

Пример:

variables:
  GRADLE_USER_HOME: $(Pipeline.Workspace)/.gradle

steps:
- task: Cache@2
  inputs:
    key: 'gradle | "$(Agent.OS)" | **/build.gradle.kts' # Swap build.gradle.kts for build.gradle when using Groovy
    restoreKeys: |
      gradle | "$(Agent.OS)"
      gradle
    path: $(GRADLE_USER_HOME)
  displayName: Configure gradle caching

- task: Gradle@2
  inputs:
    gradleWrapperFile: 'gradlew'
    tasks: 'build'
    options: '--build-cache'
  displayName: Build

- script: |   
    # stop the Gradle daemon to ensure no files are left open (impacting the save cache operation later)
    ./gradlew --stop    
  displayName: Gradlew stop
  • restoreKeys: резервные ключи, если первичный ключ завершается сбоем (необязательно)

Примечание.

Кэши неизменяемы, когда кэш с определенным ключом создается для определенной области (ветви), кэш нельзя обновить. Это означает, что если ключ является фиксированным значением, все последующие сборки для одной ветви не смогут обновить кэш, даже если содержимое кэша изменилось. Если вы хотите использовать фиксированное значение ключа, необходимо использовать restoreKeys аргумент в качестве резервного варианта.

Maven

Maven имеет локальный репозиторий, в котором хранятся скачивающие и созданные артефакты. Чтобы включить, задайте maven.repo.local для параметра путь в $(Pipeline.Workspace) папку и кэшируйте эту папку.

Пример:

variables:
  MAVEN_CACHE_FOLDER: $(Pipeline.Workspace)/.m2/repository
  MAVEN_OPTS: '-Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'

steps:
- task: Cache@2
  inputs:
    key: 'maven | "$(Agent.OS)" | **/pom.xml'
    restoreKeys: |
      maven | "$(Agent.OS)"
      maven
    path: $(MAVEN_CACHE_FOLDER)
  displayName: Cache Maven local repo

- script: mvn install -B -e

Если вы используете задачу Maven, обязательно передайте MAVEN_OPTS переменную, так как она перезаписывается в противном случае:

- task: Maven@4
  inputs:
    mavenPomFile: 'pom.xml'
    mavenOptions: '-Xmx3072m $(MAVEN_OPTS)'

.NET/NuGet

Если вы используете PackageReferences для управления зависимостями NuGet непосредственно в файле проекта и имеете packages.lock.json файл, можно включить кэширование, задав NUGET_PACKAGES переменную среды в путь $(UserProfile) и кэширование этого каталога. Дополнительные сведения о блокировке зависимостей см . в справочнике по пакетам в файлах проекта. Если вы хотите использовать несколько packages.lock.json, вы по-прежнему можете использовать следующий пример без внесения изменений. Содержимое всех файлов packages.lock.json будет хэшировано и при изменении одного из файлов создается новый ключ кэша.

Пример:

variables:
  NUGET_PACKAGES: $(Pipeline.Workspace)/.nuget/packages

steps:
- task: Cache@2
  inputs:
    key: 'nuget | "$(Agent.OS)" | $(Build.SourcesDirectory)/**/packages.lock.json'
    restoreKeys: |
       nuget | "$(Agent.OS)"
       nuget
    path: $(NUGET_PACKAGES)
  displayName: Cache NuGet packages

Node.js/npm

Существуют различные способы включения кэширования в проекте Node.js, но рекомендуется кэшировать общий каталог кэша npm. Этот каталог управляется npm и содержит кэшированную версию всех загруженных модулей. Во время установки npm сначала проверяет этот каталог (по умолчанию) для модулей, которые могут уменьшить или устранить сетевые вызовы к общедоступному реестру npm или к частному реестру.

Так как путь по умолчанию к каталогу общего кэша npm не совпадает на всех платформах, рекомендуется переопределить npm_config_cache переменную среды на путь.$(Pipeline.Workspace) Это также гарантирует, что кэш доступен из заданий контейнера и неконтейнеров.

Пример:

variables:
  npm_config_cache: $(Pipeline.Workspace)/.npm

steps:
- task: Cache@2
  inputs:
    key: 'npm | "$(Agent.OS)" | package-lock.json'
    restoreKeys: |
       npm | "$(Agent.OS)"
    path: $(npm_config_cache)
  displayName: Cache npm

- script: npm ci

Если в проекте нет package-lock.json файла, обратитесь package.json к файлу в входных данных ключа кэша.

Совет

Так как npm ci удаляет node_modules папку, чтобы обеспечить согласованное использование повторяемого набора модулей, следует избегать кэширования node_modules при вызове npm ci.

Node.js/Yarn

Как и в npm, существуют различные способы кэширования пакетов, установленных с помощью Yarn. Рекомендуется кэшировать общую папку кэша Yarn. Этот каталог управляется Yarn и содержит кэшированную версию всех загруженных пакетов. Во время установки Yarn сначала проверяет этот каталог (по умолчанию) для модулей, что может уменьшить или исключить сетевые вызовы к общедоступным или частным реестрам.

Пример:

variables:
  YARN_CACHE_FOLDER: $(Pipeline.Workspace)/.yarn

steps:
- task: Cache@2
  inputs:
    key: 'yarn | "$(Agent.OS)" | yarn.lock'
    restoreKeys: |
       yarn | "$(Agent.OS)"
       yarn
    path: $(YARN_CACHE_FOLDER)
  displayName: Cache Yarn packages

- script: yarn --frozen-lockfile

Python/Anaconda

Настройте кэширование конвейера с помощью сред Anaconda:

Пример

variables:
  CONDA_CACHE_DIR: /usr/share/miniconda/envs

# Add conda to system path
steps:
- script: echo "##vso[task.prependpath]$CONDA/bin"
  displayName: Add conda to PATH

- bash: |
    sudo chown -R $(whoami):$(id -ng) $(CONDA_CACHE_DIR)
  displayName: Fix CONDA_CACHE_DIR directory permissions

- task: Cache@2
  displayName: Use cached Anaconda environment
  inputs:
    key: 'conda | "$(Agent.OS)" | environment.yml'
    restoreKeys: | 
      python | "$(Agent.OS)"
      python
    path: $(CONDA_CACHE_DIR)
    cacheHitVar: CONDA_CACHE_RESTORED

- script: conda env create --quiet --file environment.yml
  displayName: Create Anaconda environment
  condition: eq(variables.CONDA_CACHE_RESTORED, 'false')
  • Windows

    - task: Cache@2
      displayName: Cache Anaconda
      inputs:
        key: 'conda | "$(Agent.OS)" | environment.yml'
        restoreKeys: | 
          python | "$(Agent.OS)"
          python
        path: $(CONDA)/envs
        cacheHitVar: CONDA_CACHE_RESTORED
    
    - script: conda env create --quiet --file environment.yml
      displayName: Create environment
      condition: eq(variables.CONDA_CACHE_RESTORED, 'false')
    

PHP/Composer

Для проектов PHP с помощью Composer переопределите переменную среды, используемую COMPOSER_CACHE_DIR composer.

Пример:

variables:
  COMPOSER_CACHE_DIR: $(Pipeline.Workspace)/.composer

steps:
- task: Cache@2
  inputs:
    key: 'composer | "$(Agent.OS)" | composer.lock'
    restoreKeys: |
      composer | "$(Agent.OS)"
      composer
    path: $(COMPOSER_CACHE_DIR)
  displayName: Cache composer

- script: composer install

Известные проблемы и отзывы

Если у вас возникли проблемы с настройкой кэширования для конвейера, проверьте список открытых проблем в репозитории microsoft/azure-pipelines-tasks . Если вашей проблемы нет в списке, создайте новую проблему и предоставьте необходимые сведения о сценарии.

Q&A

Вопрос. Можно ли очистить кэш?

Ответ. Очистка кэша в настоящее время не поддерживается. Однако можно добавить строковый литерал (например version2) в существующий ключ кэша, чтобы изменить ключ таким образом, чтобы избежать попаданий в существующие кэши. Например, измените следующий ключ кэша из этого:

key: 'yarn | "$(Agent.OS)" | yarn.lock'

На эту:

key: 'version2 | yarn | "$(Agent.OS)" | yarn.lock'

Вопрос. Когда истекает срок действия кэша?

Ответ. Срок действия кэша истекает через семь дней без действия.

Вопрос. Когда кэш отправляется?

Ответ. После последнего шага конвейера кэш будет создан из кэша path и отправлен. Дополнительные сведения см. в примере .

Вопрос. Существует ли ограничение на размер кэша?

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