Cachelagring av pipeline
Azure DevOps Services
Cachelagring av pipeline kan minska byggtiden genom att tillåta att utdata eller nedladdade beroenden från en körning återanvänds i senare körningar, vilket minskar eller undviker kostnaden för att återskapa eller ladda ned samma filer igen. Cachelagring är särskilt användbart i scenarier där samma beroenden laddas ned om och om för varje körning. Det här är ofta en tidskrävande process som omfattar hundratals eller tusentals nätverksanrop.
Cachelagring kan vara effektivt för att förbättra byggtiden, förutsatt att tiden för att återställa och spara cachen är mindre än den tid då utdata skapas igen från grunden. På grund av detta kanske cachelagring inte är effektivt i alla scenarier och kan faktiskt ha en negativ inverkan på byggtiden.
Kommentar
Cachelagring av pipeline stöds i agentpooljobb för både YAML- och klassiska pipelines. Det stöds dock inte i klassiska versionspipelines.
När artefakter ska användas jämfört med cachelagring
Cachelagring av pipeline och pipelineartefakter utför liknande funktioner men är utformade för olika scenarier och bör inte användas på ett utbytbart sätt.
Använd pipelineartefakter när du behöver ta specifika filer som skapats i ett jobb och dela dem med andra jobb (och dessa andra jobb misslyckas förmodligen utan dem).
Använd pipelinecachelagring när du vill förbättra byggtiden genom att återanvända filer från tidigare körningar (och om du inte har dessa filer påverkas inte jobbets möjlighet att köras).
Kommentar
Cachelagring av pipeline och pipelineartefakter är kostnadsfria för alla nivåer (kostnadsfri och betald). Mer information finns i Lagringsförbrukning för artefakter.
Cacheuppgift: så här fungerar den
Cachelagring läggs till i en pipeline med hjälp av cacheaktiviteten. Den här uppgiften fungerar som alla andra aktiviteter och läggs till i steps
avsnittet i ett jobb.
När ett cachesteg påträffas under en körning återställer uppgiften cachen baserat på de angivna indata. Om ingen cache hittas slutförs steget och nästa steg i jobbet körs.
När alla steg i jobbet har körts och ett lyckat jobb har status, läggs ett särskilt "Post-job: Cache" -steg automatiskt till och utlöses för varje "återställningscache" -steg som inte hoppades över. Det här steget ansvarar för att spara cacheminnet.
Kommentar
Cacheminnen är oföränderliga, vilket innebär att när ett cacheminne har skapats kan dess innehåll inte ändras.
Konfigurera cacheaktiviteten
Cacheaktiviteten har två obligatoriska argument: nyckel och sökväg:
- path: sökvägen till mappen som ska cachelagrats. Kan vara en absolut eller relativ sökväg. Relativa sökvägar matchas mot
$(System.DefaultWorkingDirectory)
.
Kommentar
Du kan använda fördefinierade variabler för att lagra sökvägen till den mapp som du vill cachelagrar, men jokertecken stöds inte.
- nyckel: ska anges till identifieraren för cacheminnet som du vill återställa eller spara. Nycklarna består av en kombination av strängvärden, filsökvägar eller filmönster, där varje segment avgränsas med ett
|
tecken.
Strängar:
Fast värde (till exempel namnet på cachen eller ett verktygsnamn) eller hämtat från en miljövariabel (till exempel det aktuella operativsystemet eller det aktuella jobbnamnet)Filsökvägar:
Sökväg till en specifik fil vars innehåll ska hashas. Den här filen måste finnas när aktiviteten körs. Tänk på att alla nyckelsegment som "ser ut som en filsökväg" behandlas som en filsökväg. I synnerhet omfattar detta segment som innehåller en.
. Detta kan leda till att aktiviteten misslyckas när den här "filen" inte finns.Dricks
Om du vill undvika att ett sökvägsliknande strängsegment behandlas som en filsökväg, omsluter du det med dubbla citattecken, till exempel:
"my.key" | $(Agent.OS) | key.file
Filmönster:
Kommaavgränsad lista över jokerteckenmönster i globformat som måste matcha minst en fil. Till exempel:**/yarn.lock
: alla yarn.lock-filer under källkatalogen*/asset.json, !bin/**
: alla asset.json filer som finns i en katalog under källkatalogen, förutom under bin-katalogen
Innehållet i en fil som identifieras av en filsökväg eller ett filmönster hashas för att skapa en dynamisk cachenyckel. Detta är användbart när projektet har filer som unikt identifierar vad som cachelagras. Till exempel refereras filer som package-lock.json
, yarn.lock
, Gemfile.lock
eller Pipfile.lock
ofta i en cachenyckel eftersom de alla representerar en unik uppsättning beroenden.
Relativa filsökvägar eller filmönster matchas mot $(System.DefaultWorkingDirectory)
.
Exempel:
Här är ett exempel som visar hur du cachelagrar beroenden som installerats av 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
I det här exemplet innehåller cachenyckeln tre delar: en statisk sträng ("yarn"), operativsystemet som jobbet körs på eftersom cacheminnet är unikt per operativsystem och hashen för yarn.lock
filen som unikt identifierar uppsättningen beroenden i cacheminnet.
Vid den första körningen efter att aktiviteten har lagts till rapporterar cachesteget en "cachemiss" eftersom cacheminnet som identifieras av den här nyckeln inte finns. Efter det sista steget skapas en cache från filerna i $(Pipeline.Workspace)/s/.yarn
och laddas upp. Vid nästa körning rapporterar cachesteget en "cacheträff" och innehållet i cachen laddas ned och återställs.
När du använder checkout: self
checkas lagringsplatsen ut till $(Pipeline.Workspace)/s
och mappen .yarn
finns vanligtvis på själva lagringsplatsen.
Kommentar
Pipeline.Workspace
är den lokala sökvägen på agenten som kör din pipeline där alla kataloger skapas. Den här variabeln har samma värde som Agent.BuildDirectory
.
Se till att du uppdaterar variabeln YARN_CACHE_FOLDER
om du använder något annat än checkout: self
detta bör peka på lagringsplatsen där .yarn
den finns.
Återställa nycklar
restoreKeys
kan användas om man vill köra frågor mot flera exakta nycklar eller nyckelprefix. Detta används för att återgå till en annan nyckel om en key
inte ger en träff. En återställningsnyckel söker efter en nyckel efter prefix och ger därför den senaste skapade cacheposten. Detta är användbart om pipelinen inte kan hitta en exakt matchning men vill använda en partiell cacheträff i stället. Om du vill infoga flera återställningsnycklar avgränsar du dem med hjälp av en ny rad för att ange återställningsnyckeln (se exemplet för mer information). Ordningen som återställningsnycklarna ska provas mot kommer att vara uppifrån och ned.
Nödvändig programvara på en lokalt installerad agent
Arkivera programvara/plattform | Windows | Linux | Mac |
---|---|---|---|
GNU Tar | Obligatoriskt | Obligatoriskt | Nej |
BSD-tjära | Nej | Nej | Obligatoriskt |
7-Zip | Rekommenderat | Nej | Nej |
Ovanstående körbara filer måste finnas i en mapp som anges i PATH-miljövariabeln. Tänk på att de värdbaserade agenterna kommer med den programvara som ingår, detta gäller endast för lokalt installerade agenter.
Exempel:
Här är ett exempel på hur du använder återställningsnycklar av 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
I det här exemplet försöker cacheuppgiften ta reda på om nyckeln finns i cacheminnet. Om nyckeln inte finns i cacheminnet försöker den använda den första återställningsnyckeln yarn | $(Agent.OS)
.
Detta försöker söka efter alla nycklar som antingen exakt matchar den nyckeln eller har den nyckeln som ett prefix. En prefixträff kan inträffa om det fanns ett annat yarn.lock
hash-segment.
Om följande nyckel yarn | $(Agent.OS) | old-yarn.lock
till exempel fanns i cachen där den old-yarn.lock
gav en annan hash än yarn.lock
ger återställningsnyckeln en partiell träff.
Om det finns en miss på den första återställningsnyckeln använder den sedan nästa återställningsnyckel yarn
som försöker hitta alla nycklar som börjar med yarn
. För prefixträffar ger resultatet den senast skapade cachenyckeln som resultat.
Kommentar
En pipeline kan ha en eller flera cachelagringsaktiviteter. Det finns ingen gräns för cachelagringskapaciteten, och jobb och uppgifter från samma pipeline kan komma åt och dela samma cache.
Cacheisolering och säkerhet
För att säkerställa isolering mellan cacheminnen från olika pipelines och olika grenar tillhör varje cache en logisk container som kallas för ett omfång. Omfång ger en säkerhetsgräns som säkerställer att ett jobb från en pipeline inte kan komma åt cacheminnena från en annan pipeline, och ett jobb som skapar en PR har läsåtkomst till cacheminnena för PR:s målgren (för samma pipeline), men kan inte skriva (skapa) cacheminnen i målgrenens omfång.
När ett cachesteg påträffas under en körning begärs cachen som identifieras av nyckeln från servern. Servern letar sedan efter en cache med den här nyckeln från de omfång som är synliga för jobbet och returnerar cacheminnet (om tillgängligt). Vid cachesparning (i slutet av jobbet) skrivs en cache till omfånget som representerar pipelinen och grenen. Se nedan för mer information.
CI, manuella och schemalagda körningar
Omfattning | Lästa | Skriv |
---|---|---|
Källgren | Ja | Ja |
main gren |
Ja | Nej |
master gren |
Ja | Nej |
Pull-begäranden körs
Omfattning | Lästa | Skriv |
---|---|---|
Källgren | Ja | Nej |
Målgren | Ja | Nej |
Mellanliggande gren (till exempel refs/pull/1/merge ) |
Ja | Ja |
main gren |
Ja | Nej |
master gren |
Ja | Nej |
Pull-begärandeförgreningskörningar
Filial | Lästa | Skriv |
---|---|---|
Målgren | Ja | Nej |
Mellanliggande gren (till exempel refs/pull/1/merge ) |
Ja | Ja |
main gren |
Ja | Nej |
master gren |
Ja | Nej |
Dricks
Eftersom cacheminnen redan är begränsade till ett projekt, en pipeline och en gren behöver du inte inkludera några projekt-, pipeline- eller grenidentifierare i cachenyckeln.
Konditionering vid cacheåterställning
I vissa scenarier bör en lyckad återställning av cachen leda till att en annan uppsättning steg körs. Ett steg som installerar beroenden kan till exempel hoppas över om cacheminnet återställdes. Detta är möjligt med hjälp av uppgiftsindata cacheHitVar
. Om du anger den här indatan till namnet på en miljövariabel blir variabeln inställd true
på när det finns en cacheträff, inexact
vid en återställningsnyckelcacheträff, annars är den inställd på false
. Den här variabeln kan sedan refereras i ett stegvillkor eller inifrån ett skript.
I följande exempel install-deps.sh
hoppas steget över när cacheminnet återställs:
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
Bundler
För Ruby-projekt som använder Bundler åsidosätter du miljövariabeln BUNDLE_PATH
som används av Bundler för att ange sökvägen Bundler söker efter Gems i.
Exempel:
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 är en kompilatorcache för C/C++. Om du vill använda Ccache i pipelinen kontrollerar du att Ccache
den är installerad och eventuellt tillagd i dina PATH
(se Ccache-körningslägen). CCACHE_DIR
Ange miljövariabeln till en sökväg under $(Pipeline.Workspace)
och cachelagras i den här katalogen.
Exempel:
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)"
Mer information finns i Konfigurationsinställningar för Ccache.
Docker-avbildningar
Cachelagring av Docker-avbildningar minskar avsevärt den tid det tar att köra pipelinen.
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'))
- nyckel: (krävs) – en unik identifierare för cacheminnet.
- path: (krävs) – sökvägen till den mapp eller fil som du vill cachelagras.
Golang
För Golang-projekt kan du ange vilka paket som ska laddas ned i go.mod-filen . Om variabeln GOCACHE
inte redan har angetts anger du den till den där du vill att cachen ska laddas ned.
Exempel:
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
Att använda Gradles inbyggda cachelagringsstöd kan ha en betydande inverkan på byggtiden. Om du vill aktivera byggcachen anger du GRADLE_USER_HOME
miljövariabeln till en sökväg under $(Pipeline.Workspace)
och kör antingen din version med --build-cache
eller lägger till org.gradle.caching=true
i gradle.properties
filen.
Exempel:
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: Återställningsnycklarna om den primära nyckeln misslyckas (valfritt)
Kommentar
Cacheminnen är oföränderliga när en cache med en viss nyckel har skapats för ett specifikt omfång (gren) och cacheminnet inte kan uppdateras. Det innebär att om nyckeln är ett fast värde kommer alla efterföljande versioner för samma gren inte att kunna uppdatera cacheminnet även om cachens innehåll har ändrats. Om du vill använda ett fast nyckelvärde måste du använda restoreKeys
argumentet som reservalternativ.
Maven
Maven har en lokal lagringsplats där den lagrar nedladdningar och skapade artefakter. Om du vill aktivera anger du maven.repo.local
alternativet till en sökväg under $(Pipeline.Workspace)
och cachelagr den här mappen.
Exempel:
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
Om du använder en Maven-uppgift ser du till att även skicka variabeln eftersom den MAVEN_OPTS
skrivs över annars:
- task: Maven@4
inputs:
mavenPomFile: 'pom.xml'
mavenOptions: '-Xmx3072m $(MAVEN_OPTS)'
.NET/NuGet
Om du använder PackageReferences
för att hantera NuGet-beroenden direkt i projektfilen och har en packages.lock.json
fil kan du aktivera cachelagring genom att ange NUGET_PACKAGES
miljövariabeln till en sökväg under $(UserProfile)
och cachelagra den här katalogen. Mer information om hur du låser beroenden finns i Paketreferens i projektfiler .
Om du vill använda flera packages.lock.json kan du fortfarande använda följande exempel utan att göra några ändringar. Innehållet i alla packages.lock.json filer hashas och om en av filerna ändras genereras en ny cachenyckel.
Exempel:
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
Det finns olika sätt att aktivera cachelagring i ett Node.js projekt, men det rekommenderade sättet är att cachelagra npm:s delade cachekatalog. Den här katalogen hanteras av npm och innehåller en cachelagrad version av alla nedladdade moduler. Under installationen kontrollerar npm den här katalogen först (som standard) efter moduler som kan minska eller eliminera nätverksanrop till det offentliga npm-registret eller till ett privat register.
Eftersom standardsökvägen till npm:s delade cachekatalog inte är densamma på alla plattformar rekommenderar vi att du åsidosätter npm_config_cache
miljövariabeln till en sökväg under $(Pipeline.Workspace)
. Detta säkerställer också att cachen är tillgänglig från container- och icke-behållarjobb.
Exempel:
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
Om projektet inte har någon package-lock.json
fil refererar du till package.json
filen i cachenyckelns indata i stället.
Dricks
Eftersom npm ci
tar bort node_modules
mappen för att säkerställa att en konsekvent, repeterbar uppsättning moduler används bör du undvika cachelagring node_modules
när du anropar npm ci
.
Node.js/Yarn
Precis som med npm finns det olika sätt att cachelagrat paket som installerats med Yarn. Det rekommenderade sättet är att cachelagrat Yarns delade cachemapp. Den här katalogen hanteras av Yarn och innehåller en cachelagrad version av alla nedladdade paket. Under installationen kontrollerar Yarn den här katalogen först (som standard) för moduler, vilket kan minska eller eliminera nätverksanrop till offentliga eller privata register.
Exempel:
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
Konfigurera din pipelinecachelagring med Anaconda-miljöer:
Exempel
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
För PHP-projekt som använder Composer åsidosätter du miljövariabeln COMPOSER_CACHE_DIR
som används av Composer.
Exempel:
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
Kända problem och feedback
Om du har problem med att konfigurera cachelagring för din pipeline kontrollerar du listan över öppna problem på lagringsplatsen microsoft/azure-pipelines-tasks . Om du inte ser problemet i listan skapar du ett nytt ärende och anger nödvändig information om ditt scenario.
Frågor och svar
F: Kan jag rensa en cache?
S: Det finns för närvarande inte stöd för att rensa en cache. Du kan dock lägga till en strängliteral (till exempel version2
) i din befintliga cachenyckel för att ändra nyckeln på ett sätt som undviker träffar på befintliga cacheminnen. Ändra till exempel följande cachenyckel från detta:
key: 'yarn | "$(Agent.OS)" | yarn.lock'
Så här gör du:
key: 'version2 | yarn | "$(Agent.OS)" | yarn.lock'
F: När upphör en cache att gälla?
S: Cacheminnen upphör att gälla efter sju dagar utan aktivitet.
F: När laddas cachen upp?
S: Efter det sista steget i pipelinen skapas en cache från cacheminnet path
och laddas upp. Mer information finns i exemplet.
F: Finns det en gräns för storleken på en cache?
S: Det finns ingen framtvingad gräns för storleken på enskilda cacheminnen eller den totala storleken på alla cacheminnen i en organisation.