Dela via


Cachelagring av pipeline

Azure DevOps Services

Pipeline-cachelagring 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 att behöva betala för att återskapa alternativt ladda ner samma filer igen. Cachelagring är särskilt användbart i scenarier där samma beroenden laddas ned upprepade gånger vid 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.

Obs

Cachelagring av rörledning stöds inte i klassiska utgivningsrörledningar.

När artefakter ska användas jämfört med cachelagring

Pipelincaching och pipelineartefakter utför liknande funktioner, men de är utformade för olika scenarier och bör inte användas växelvis.

  • 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 cachelagring av pipelinen 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).

Anteckning

Pipeline-cache och pipelineartefakter är gratis för alla nivåer (gratis och för betalversioner). Mer information finns i Artifakternas lagringsförbrukning.

Cacheuppgift: så här fungerar den

Caching läggs till i en pipeline med hjälp av Cache-aktiviteten. Den här uppgiften fungerar som alla andra aktiviteter och läggs till i steps delen av 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 förutsatt att ett lyckades jobbstatus 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 har ansvar för att spara cacheminnet .

Anteckning

Cacheminnen är oföränderliga, vilket innebär att när en cache har skapats är dess innehåll oföränderligt.

Konfigurera cachningsuppgiften

Uppgiften Cache har två obligatoriska argument: nyckel och sökväg:

  • sökväg: sökvägen till mappen som ska cachelagrats. Kan vara en absolut eller relativ sökväg. Relativa sökvägar löses upp mot $(System.DefaultWorkingDirectory).

Not

Du kan använda fördefinierade variabler för att lagra sökvägen till den mapp du vill cacha, 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.

    Tips

    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.lockeller Pipfile.lock ofta i en cachenyckel eftersom de alla representerar en unik uppsättning beroenden.

Relativa filsökvägar eller filmönster avgörs 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 den yarn.lock fil som unikt identifierar uppsättningen beroenden i cacheminnet.

Vid den första körningen efter att aktiviteten har lagts till rapporterar cachesteget en "cache miss" eftersom det cacheminne som identifieras av denna nyckel inte existerar. 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: selfcheckas lagringsplatsen ut till $(Pipeline.Workspace)/soch din .yarn-mapp finns vanligtvis i lagringsplatsen.

Anteckning

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 uppdatera variabeln YARN_CACHE_FOLDER om du använder något annat än checkout: self eftersom detta bör peka på lagringsplatsen där .yarn 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 Krävs Krävs Nej
BSD Tar Nej Nej Krävs
7-Zip Rekommenderad 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 old-yarn.lock gav en annan hash än yarn.lock, skulle återställningsnyckeln ge 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.

Not

En pipeline kan ha en eller flera cachelagringsuppgifter. Det finns ingen gräns för lagringskapaciteten för cachelagring, 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. Scopes ger en säkerhetsgräns som säkerställer:

  1. Ett jobb från en pipeline kan inte komma åt cacheminnena från en annan pipeline och
  2. 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 den av nyckeln identifierade cachen 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). När cachen sparas (i slutet av jobbet) skrivs den till det område som representerar pipelinen och grenen. Mer information finns nedan.

CI, manuella och schemalagda körningar

Omfattning Läsa Skriva
Källgren Ja Ja
main gren Ja Nej
master gren Ja Nej

Pull-begäranden genomförs

Omfattning Läsa Skriva
Källkodsförgrening Ja Nej
Målfilial Ja Nej
Mellanliggande gren (till exempel refs/pull/1/merge) Ja Ja
main gren Ja Nej
master avdelning Ja Nej

Körningar av förgrenade pull-begäranden

Gren Läsa Skriva
Målgenerering Ja Nej
Mellanliggande gren (till exempel refs/pull/1/merge) Ja Ja
main gren Ja Nej
master gren Ja Nej

Tips

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.

Förberedelse för cacheåterställning

I vissa scenarier bör en lyckad återställning av cachen leda till att en annan uppsättning steg körs. Om cacheminnet har återställts kan ett steg som installerar beroenden till exempel hoppas över. Detta är möjligt med hjälp av cacheHitVar uppgiftsindata. Om du anger den här indatan till namnet på en miljövariabel blir variabeln inställd på true när det finns en cacheträff, inexact på 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 hoppas steget install-deps.sh ö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 BUNDLE_PATH miljövariabeln som används av Bundler för att ange den 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 har installerats och eventuellt läggs till i din PATH (se Ccache-körningslägen). Ange miljövariabeln CCACHE_DIR till en sökväg under $(Pipeline.Workspace) och cachelagra denna katalog.

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 cachen.
  • sökväg: (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 filen go.mod. Om din GOCACHE variabel 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 cachestöd kan ha en betydande inverkan på byggtiden. Om du vill aktivera byggcachen anger du miljövariabeln GRADLE_USER_HOME till en sökväg under $(Pipeline.Workspace) och kör antingen bygget 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)

Obs

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 argumentet restoreKeys som reserv.

Maven

Maven har en lokal lagringsplats där den lagrar nedladdningar och skapade artefakter. Om du vill aktivera, ange alternativet maven.repo.local till en sökväg under $(Pipeline.Workspace) och cachelagra 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-aktivitetska du även skicka variabeln MAVEN_OPTS eftersom den 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.jsonkan 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

Den här metoden är också giltig för .NET Core-projekt om projektet använder packages.lock.json för att låsa paketversioner. Du kan aktivera detta genom att ställa in RestorePackagesWithLockFile till True i din Csproj--fil eller med hjälp av följande kommando: dotnet restore --use-lock-file.

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 cachekatalogen. 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 är inte samma på alla plattformarrekommenderar vi att du åsidosätter miljövariabeln npm_config_cache till en sökväg under $(Pipeline.Workspace). Detta säkerställer också att cachen är tillgänglig från container- och icke-containerjobb.

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 den package.json-filen i cache-nyckelns indata istället.

Tips

Eftersom npm ci tar bort mappen node_modules 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 cachelagra 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 cachelagring för din pipeline 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, kontrollera listan över öppna ärenden i microsoft/azure-pipelines-tasks förrådet. Om du inte ser ditt problem i listan skapa en ny och ange nödvändig information om ditt scenario.

Q&A

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?

Cacher går ut efter sju dagar utan aktivitet.

F: När laddas cachen upp?

S: Efter det sista steget i pipelinen skapas en cache från din cache path och laddas upp. Mer information finns i exempel.

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.