Кэширование конвейера
Azure DevOps Services
Кэширование конвейера может помочь сократить время сборки, позволяя выходным данным или скачанным зависимостям из одного запуска повторно использоваться в последующих запусках, тем самым уменьшая или избегая затрат повторного создания или повторной загрузки одних и таких же файлов. Кэширование особенно полезно в сценариях, когда одни и те же зависимости скачиваются снова и снова в начале каждого запуска. Это часто занимает много времени, включая сотни или тысячи сетевых вызовов.
Кэширование может быть эффективным при улучшении времени сборки, если время восстановления и сохранения кэша меньше времени для повторного создания выходных данных с нуля. Из-за этого кэширование может оказаться не эффективным во всех сценариях и на самом деле может оказать негативное влияние на время сборки.
Заметка
Кэширование конвейеров не поддерживается в классических конвейерах выпуска.
Когда использовать артефакты или кэширование
Кэширование конвейера и артефакты конвейера выполнять аналогичные функции, но предназначены для различных сценариев и не должны использоваться взаимозаменяемо.
Используйте артефакты конвейера, когда необходимо взять определенные файлы, созданные в одном задании, и предоставить их для других заданий (и эти другие задания, скорее всего, могут завершиться сбоем без них).
Используйте кэширование конвейера, если требуется улучшить время сборки, повторно используя файлы из предыдущих запусков (и отсутствие этих файлов не повлияет на возможность выполнения задания).
Заметка
Кэширование конвейера и артефакты конвейера бесплатны для всех уровней (бесплатные и платные). Дополнительные сведения см. в разделе потребления хранилища артефактов.
Задача кэша: как она работает
Кэширование добавляется в конвейер с помощью задачи кэша . Эта задача работает как любая другая задача и добавляется в раздел steps
задания.
При обнаружении шага кэша во время выполнения задача восстанавливает кэш на основе предоставленных входных данных. Если кэш не найден, шаг завершается и выполняется следующий шаг задания.
После выполнения всех шагов задания и при условии успешного состояния задания специальный "Post-job: Cache" шаг автоматически добавляется и активируется для каждого "кэш восстановления" шаг, который не был пропущен. Этот шаг отвечает за сохранение кэша.
Заметка
Кэши неизменяемы, то есть после создания кэша его содержимое неизменяемо.
Настройка задачи кэша
Задача кэша имеет два обязательных аргумента: ключ и путь :
-
путь: путь папки для кэширования. Может быть абсолютным или относительным путем. Относительные пути разрешаются относительно
$(System.DefaultWorkingDirectory)
.
Заметка
Можно использовать предопределенные переменные для хранения пути к папке, которую вы хотите кэшировать, однако подстановочные знаки не поддерживаются.
-
ключ: необходимо задать идентификатор кэша, который требуется восстановить или сохранить. Ключи состоят из сочетания строковых значений, путей к файлам или шаблонов файлов, где каждый сегмент разделен символом
|
.
строки:
Фиксированное значение (например, имя кэша или имени средства) или взятое из переменной среды (например, текущее имя ОС или текущего задания).пути к файлам:
Путь к определенному файлу, содержимое которого будет хэшировано. Этот файл должен существовать во время выполнения задачи. Помните, что любой ключевой сегмент, который будет рассматриваться как путь к файлу. В частности, это включает сегменты, содержащие.
. Это может привести к сбою задачи, если этот файл не существует.Совет
Чтобы избежать обработки сегмента строки типа пути, как путь к файлу, обтекайте его двойными кавычками, например:
"my.key" | $(Agent.OS) | key.file
Шаблоны файлов:
Список шаблонов подстановочных знаков в стиле glob, разделенный запятыми, который должен соответствовать по крайней мере одному файлу. Например:-
**/yarn.lock
: все файлы yarn.lock в каталоге источников -
*/asset.json, !bin/**
: все файлы asset.json, расположенные в каталоге источников, за исключением каталога bin
-
Содержимое любого файла, определяемого путем к файлу или шаблоном файла, хэшируется для создания ключа динамического кэша. Это полезно, если в проекте есть файлы, которые однозначно определяют, что кэшируется. Например, файлы, такие как package-lock.json
, yarn.lock
, Gemfile.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
не дает результата. Ключ восстановления выполняет поиск ключа по префиксу и дает последнюю созданную запись кэша в результате. Это полезно, если конвейер не может найти точное совпадение, но предпочитает использовать частичное совпадение кэша. Чтобы вставить несколько ключей восстановления, разделите их с помощью новой строки, чтобы указать ключ восстановления (см. пример для получения дополнительных сведений). Порядок, в котором будут пытаться восстановить ключи, будет сверху вниз.
Обязательное программное обеспечение для локального агента
Архивное программное обеспечение / платформа | Виндоус | Линукс | Mac |
---|---|---|---|
GNU Tar | Обязательно | Обязательно | Нет |
BSD Tar | Нет | Нет | Обязательно |
7-Zip | Рекомендуется | Нет | Нет |
Приведенные выше исполняемые файлы должны находиться в папке, указанной в переменной среды 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
.
Например, если следующий ключ yarn | $(Agent.OS) | old-yarn.lock
был в кэше, где old-yarn.lock
дал другой хэш, чем yarn.lock
, ключ восстановления даст частичный удар.
Если первый ключ восстановления не срабатывает, будет использован следующий ключ восстановления yarn
, который может обнаружить любой ключ, начинающийся с yarn
. При совпадении префикса результатом является последний созданный ключ кэша.
Заметка
Конвейер может иметь одну или несколько задач кэширования. Нет ограничений на емкость хранилища кэширования, а задания и задачи из одного конвейера могут получить доступ к одному и тому же кэшу.
Изоляция кэша и безопасность
Чтобы обеспечить изоляцию между кэшами из разных конвейеров и разных ветвей, каждый кэш принадлежит логическому контейнеру, называемому областью. Области создают границу безопасности, которая обеспечивает:
- Задание из одного потока не может обратиться к кэшам из другого потока.
- Задание на создание ПР имеет право на чтение кешей целевой ветви ПР (для того же конвейера), но не может записывать кэши в её области.
При обнаружении шага кэша во время выполнения, кэш, определенный ключом, запрашивается с сервера. Затем сервер ищет кэш с этим ключом из областей, видимых для задания, и возвращает кэш (если он доступен). При сохранении кэша (в конце работы) кэш записывается в область, обозначающую конвейер и ветку. Дополнительные сведения см. ниже.
Непрерывная интеграция (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
, которую Bundler использует для задания пути , по которому Bundler ищет Gems.
пример:
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)"
Дополнительные сведения см. в
Образы 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'))
- ключ: (обязательно) — уникальный идентификатор для кэша.
- путь: (обязательно) — путь к папке или файлу, который нужно кэшировать.
Голанг
Для проектов 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
Этот подход также действителен для проектов .NET Core, если проект использует packages.lock.json для блокировки версий пакетов. Это можно включить, задав RestorePackagesWithLockFile
True
в файле csproj или выполнив следующую команду: dotnet restore --use-lock-file
.
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/Пряжа
Как и в 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
и отправлен. Дополнительные сведения см. в примере .
Вопрос. Существует ли ограничение на размер кэша?
Ответ. Нет принудительного ограничения на размер отдельных кэшей или общий размер всех кэшей в организации.