Memorizzazione nella cache della pipeline
Servizi di Azure DevOps
La memorizzazione nella cache della pipeline consente di ridurre il tempo di compilazione consentendo di riutilizzare gli output o le dipendenze scaricate da un'esecuzione successiva, riducendo o evitando così il costo di ricreare o scaricare nuovamente gli stessi file. La memorizzazione nella cache è particolarmente utile negli scenari in cui le stesse dipendenze vengono scaricate oltre e oltre all'inizio di ogni esecuzione. Si tratta spesso di un processo dispendioso in termini di tempo che coinvolge centinaia o migliaia di chiamate di rete.
La memorizzazione nella cache può essere efficace per migliorare il tempo di compilazione fornito il tempo necessario per ripristinare e salvare la cache è inferiore al tempo necessario per produrre nuovamente l'output da zero. Per questo motivo, la memorizzazione nella cache potrebbe non essere efficace in tutti gli scenari e potrebbe effettivamente avere un impatto negativo sul tempo di compilazione.
Nota
La memorizzazione nella cache della pipeline è supportata nei processi del pool di agenti sia per le pipeline YAML che per le pipeline classiche. Tuttavia, non è supportato nelle pipeline di versione classica.
La memorizzazione nella cache delle pipeline e gli artefatti della pipeline eseguono funzioni simili, ma sono progettate per scenari diversi e non devono essere usate in modo intercambiabile.
Usare gli artefatti della pipeline quando è necessario acquisire file specifici prodotti in un processo e condividerli con altri processi e questi altri processi avranno probabilmente esito negativo senza di essi.
Usare la memorizzazione nella cache della pipeline quando si vuole migliorare il tempo di compilazione riutilizzando i file delle esecuzioni precedenti e non avendo questi file non influiscono sulla capacità di esecuzione del processo.
Nota
La memorizzazione nella cache della pipeline e gli artefatti della pipeline sono gratuiti per tutti i livelli (gratuiti e a pagamento). Per altri dettagli, vedere Utilizzo dell'archiviazione degli artefatti.
La memorizzazione nella cache viene aggiunta a una pipeline usando l'attività Cache. Questa attività funziona come qualsiasi altra attività e viene aggiunta alla steps
sezione di un processo.
Quando viene rilevato un passaggio della cache durante un'esecuzione, l'attività ripristina la cache in base agli input forniti. Se non viene trovata alcuna cache, il passaggio viene completato e viene eseguito il passaggio successivo del processo.
Dopo che tutti i passaggi del processo sono stati eseguiti e presupponendo che lo stato di un processo abbia esito positivo , viene aggiunto automaticamente un passaggio speciale "Post-processo: cache" e attivato per ogni passaggio "ripristina cache" che non è stato ignorato. Questo passaggio è responsabile del salvataggio della cache.
Nota
Le cache non sono modificabili, ovvero una volta creata una cache, il relativo contenuto non può essere modificato.
L'attività Cache ha due argomenti obbligatori: chiave e percorso:
- path: percorso della cartella da memorizzare nella cache. Può essere un percorso assoluto o relativo. I percorsi relativi vengono risolti in
$(System.DefaultWorkingDirectory)
.
Nota
È possibile usare variabili predefinite per archiviare il percorso della cartella da memorizzare nella cache, ma i caratteri jolly non sono supportati.
- key: deve essere impostato sull'identificatore per la cache da ripristinare o salvare. Le chiavi sono costituite da una combinazione di valori stringa, percorsi di file o modelli di file, in cui ogni segmento è separato da un
|
carattere.
Stringhe:
Valore fisso (ad esempio il nome della cache o un nome dello strumento) o tratto da una variabile di ambiente (ad esempio il sistema operativo corrente o il nome del processo corrente)Percorsi di file:
Percorso di un file specifico il cui contenuto verrà sottoposto a hashing. Questo file deve esistere al momento dell'esecuzione dell'attività. Tenere presente che qualsiasi segmento chiave "simile a un percorso di file" verrà considerato come un percorso di file. In particolare, sono inclusi i segmenti contenenti un oggetto.
. Ciò potrebbe causare un errore dell'attività quando questo "file" non esiste.Suggerimento
Per evitare che un segmento di stringa simile al percorso venga trattato come un percorso di file, eseguire il wrapping con virgolette doppie, ad esempio:
"my.key" | $(Agent.OS) | key.file
Modelli di file:
Elenco delimitato da virgole di criteri jolly di tipo glob che devono corrispondere ad almeno un file. Ad esempio:**/yarn.lock
: tutti i file yarn.lock nella directory sources*/asset.json, !bin/**
: tutti i file asset.json che si trovano in una directory nella directory sources, ad eccezione della directory bin
Il contenuto di qualsiasi file identificato da un percorso di file o da un modello di file viene sottoposto a hashing per produrre una chiave della cache dinamica. Ciò è utile quando il progetto include file che identificano in modo univoco ciò che viene memorizzato nella cache. Ad esempio, i file come package-lock.json
, yarn.lock
, Gemfile.lock
o Pipfile.lock
vengono comunemente a cui viene fatto riferimento in una chiave della cache perché rappresentano tutti un set univoco di dipendenze.
I percorsi di file relativi o i modelli di file vengono risolti in $(System.DefaultWorkingDirectory)
.
Esempio:
Ecco un esempio che illustra come memorizzare nella cache le dipendenze installate da 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
In questo esempio, la chiave della cache contiene tre parti: una stringa statica ("yarn"), il sistema operativo su cui è in esecuzione il processo poiché questa cache è univoca per ogni sistema operativo e l'hash del yarn.lock
file che identifica in modo univoco il set di dipendenze nella cache.
Al primo esecuzione dopo l'aggiunta dell'attività, il passaggio della cache segnala un "mancato riscontro nella cache" perché la cache identificata da questa chiave non esiste. Dopo l'ultimo passaggio, verrà creata una cache dai file in $(Pipeline.Workspace)/s/.yarn
e caricati. All'esecuzione successiva, il passaggio della cache segnala un "riscontri nella cache" e il contenuto della cache verrà scaricato e ripristinato.
Quando si usa checkout: self
, il repository viene estratto in $(Pipeline.Workspace)/s
e la .yarn
cartella si trova in genere nel repository stesso.
Nota
Pipeline.Workspace
è il percorso locale dell'agente che esegue la pipeline in cui vengono create tutte le directory. Questa variabile ha lo stesso valore di Agent.BuildDirectory
.
Assicurarsi di aggiornare la variabile YARN_CACHE_FOLDER
se si usa qualcosa di diverso checkout: self
da come dovrebbe puntare al repository in cui .yarn
risiede.
restoreKeys
può essere usato se si desidera eseguire una query su più chiavi esatte o prefissi di chiave. Viene usato per eseguire il fallback a un'altra chiave nel caso in cui un key
oggetto non restituisca un riscontro. Una chiave di ripristino cerca una chiave per prefisso e restituisce la voce della cache creata più recente come risultato. Ciò è utile se la pipeline non riesce a trovare una corrispondenza esatta, ma vuole usare invece un hit parziale della cache. Per inserire più chiavi di ripristino, delimitarle usando una nuova riga per indicare la chiave di ripristino (vedere l'esempio per altri dettagli). L'ordine in cui verranno tentate le chiavi di ripristino sarà dall'alto verso il basso.
Archivio software/piattaforma | Windows | Linux | Mac |
---|---|---|---|
GNU Tar | Richiesto | Richiesto | No |
BSD Tar | No | No | Richiesto |
7-Zip | Consigliato | No | No |
I file eseguibili precedenti devono trovarsi in una cartella elencata nella variabile di ambiente PATH. Tenere presente che gli agenti ospitati sono dotati del software incluso, questo è applicabile solo per gli agenti self-hosted.
Esempio:
Ecco un esempio di come usare le chiavi di ripristino da 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
In questo esempio l'attività della cache tenta di trovare se la chiave esiste nella cache. Se la chiave non esiste nella cache, prova a usare la prima chiave yarn | $(Agent.OS)
di ripristino.
In questo modo si tenta di cercare tutte le chiavi che corrispondono esattamente a tale chiave o a quella chiave come prefisso. Un hit di prefisso può verificarsi se è presente un segmento hash diverso yarn.lock
.
Ad esempio, se la chiave yarn | $(Agent.OS) | old-yarn.lock
seguente si trovava nella cache in cui l'oggetto old-yarn.lock
ha restituito un hash diverso da yarn.lock
, la chiave di ripristino genererà un riscontro parziale.
Se si verifica un errore nella prima chiave di ripristino, verrà usata la chiave yarn
di ripristino successiva che tenterà di trovare qualsiasi chiave che inizia con yarn
. Per i riscontri del prefisso, il risultato restituisce la chiave della cache creata più di recente come risultato.
Nota
Una pipeline può avere una o più attività di memorizzazione nella cache. Non esiste alcun limite per la capacità di archiviazione nella cache e i processi e le attività della stessa pipeline possono accedere e condividere la stessa cache.
Per garantire l'isolamento tra cache da pipeline diverse e rami diversi, ogni cache appartiene a un contenitore logico denominato ambito. Gli ambiti forniscono un limite di sicurezza che garantisce che un processo da una pipeline non possa accedere alle cache da una pipeline diversa e che un processo che crea una richiesta pull abbia accesso in lettura alle cache per il ramo di destinazione della richiesta pull (per la stessa pipeline), ma non può scrivere (creare) cache nell'ambito del ramo di destinazione.
Quando viene rilevato un passaggio della cache durante un'esecuzione, la cache identificata dalla chiave viene richiesta dal server. Il server cerca quindi una cache con questa chiave dagli ambiti visibili al processo e restituisce la cache (se disponibile). Al salvataggio della cache (alla fine del processo), viene scritta una cache nell'ambito che rappresenta la pipeline e il ramo. Per ulteriori dettagli, vedi la sezione seguente.
Ambito | Lettura | Scrittura |
---|---|---|
Ramo di origine | Sì | Sì |
main ramo |
Sì | No |
master ramo |
Sì | No |
Ambito | Lettura | Scrittura |
---|---|---|
Ramo di origine | Sì | No |
Ramo di destinazione | Sì | No |
Ramo intermedio (ad esempio refs/pull/1/merge ) |
Sì | Sì |
main ramo |
Sì | No |
master ramo |
Sì | No |
Ramo | Lettura | Scrittura |
---|---|---|
Ramo di destinazione | Sì | No |
Ramo intermedio (ad esempio refs/pull/1/merge ) |
Sì | Sì |
main ramo |
Sì | No |
master ramo |
Sì | No |
Suggerimento
Poiché le cache hanno già come ambito un progetto, una pipeline e un ramo, non è necessario includere alcun progetto, pipeline o identificatori di ramo nella chiave della cache.
In alcuni scenari, il ripristino corretto della cache deve causare l'esecuzione di un set diverso di passaggi. Ad esempio, un passaggio che installa le dipendenze può essere ignorato se la cache è stata ripristinata. Ciò è possibile usando l'input dell'attività cacheHitVar
. Se si imposta questo input sul nome di una variabile di ambiente, la variabile viene impostata true
su quando si verifica un riscontro nella cache, inexact
in caso contrario viene impostata su false
. È quindi possibile fare riferimento a questa variabile in una condizione di passaggio o dall'interno di uno script.
Nell'esempio seguente il install-deps.sh
passaggio viene ignorato quando viene ripristinata la cache:
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
Per i progetti Ruby che usano Bundler, eseguire l'override della BUNDLE_PATH
variabile di ambiente usata da Bundler per impostare il percorso in cui bundler cerca gemme.
Esempio:
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 è una cache del compilatore per C/C++. Per usare Ccache nella pipeline, assicurarsi che Ccache
sia installato e, facoltativamente, aggiunto all'oggetto PATH
(vedere Modalità di esecuzione di Ccache). Impostare la CCACHE_DIR
variabile di ambiente su un percorso in $(Pipeline.Workspace)
e memorizzare nella cache questa directory.
Esempio:
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)"
Per altri dettagli, vedere Impostazioni di configurazione di Ccache.
La memorizzazione nella cache delle immagini Docker riduce notevolmente il tempo necessario per eseguire la pipeline.
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: (obbligatorio): identificatore univoco per la cache.
- path: (obbligatorio): percorso della cartella o del file da memorizzare nella cache.
Per i progetti Golang, è possibile specificare i pacchetti da scaricare nel file go.mod . Se la GOCACHE
variabile non è già impostata, impostarla su dove si vuole scaricare la cache.
Esempio:
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
L'uso del supporto predefinito per la memorizzazione nella cache di Gradle può avere un impatto significativo sul tempo di compilazione. Per abilitare la cache di compilazione, impostare la GRADLE_USER_HOME
variabile di ambiente su un percorso in $(Pipeline.Workspace)
ed eseguire la compilazione con --build-cache
o aggiungere org.gradle.caching=true
al gradle.properties
file.
Esempio:
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: chiavi di fallback se la chiave primaria ha esito negativo (facoltativo)
Nota
Le cache non sono modificabili, una volta creata una cache con una chiave specifica per un ambito specifico (ramo), non è possibile aggiornare la cache. Ciò significa che se la chiave è un valore fisso, tutte le compilazioni successive per lo stesso ramo non saranno in grado di aggiornare la cache anche se il contenuto della cache è stato modificato. Se si vuole usare un valore di chiave fissa, è necessario usare l'argomento restoreKeys
come opzione di fallback.
Maven ha un repository locale in cui archivia i download e gli artefatti compilati. Per abilitare, impostare l'opzione maven.repo.local
su un percorso in $(Pipeline.Workspace)
e memorizzare nella cache questa cartella.
Esempio:
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
Se si usa un'attività Maven, assicurarsi di passare anche la MAVEN_OPTS
variabile perché viene sovrascritta in caso contrario:
- task: Maven@4
inputs:
mavenPomFile: 'pom.xml'
mavenOptions: '-Xmx3072m $(MAVEN_OPTS)'
Se si usano PackageReferences
per gestire le dipendenze NuGet direttamente all'interno del file di progetto e si dispone di un packages.lock.json
file, è possibile abilitare la memorizzazione nella cache impostando la variabile di ambiente su un percorso in $(UserProfile)
e memorizzando nella NUGET_PACKAGES
cache questa directory. Per altre informazioni su come bloccare le dipendenze, vedere Informazioni di riferimento sui pacchetti nei file di progetto.
Se si desidera usare più packages.lock.json, è comunque possibile usare l'esempio seguente senza apportare modifiche. Il contenuto di tutti i file packages.lock.json verrà sottoposto a hashing e, se uno dei file viene modificato, viene generata una nuova chiave della cache.
Esempio:
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
Esistono diversi modi per abilitare la memorizzazione nella cache in un progetto Node.js, ma è consigliabile memorizzare nella cache la directory cache condivisa di npm. Questa directory è gestita da npm e contiene una versione memorizzata nella cache di tutti i moduli scaricati. Durante l'installazione, npm controlla prima questa directory (per impostazione predefinita) per i moduli che possono ridurre o eliminare le chiamate di rete al registro npm pubblico o a un registro privato.
Poiché il percorso predefinito della directory cache condivisa di npm non è uguale in tutte le piattaforme, è consigliabile eseguire l'override della npm_config_cache
variabile di ambiente in un percorso in $(Pipeline.Workspace)
. Ciò garantisce anche che la cache sia accessibile dai processi contenitore e non contenitore.
Esempio:
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
Se il progetto non ha un package-lock.json
file, fare riferimento al package.json
file nell'input della chiave della cache.
Suggerimento
Poiché npm ci
elimina la node_modules
cartella per garantire che venga usato un set coerente e ripetibile di moduli, è consigliabile evitare la memorizzazione nella cache node_modules
quando si chiama npm ci
.
Analogamente a npm, esistono diversi modi per memorizzare nella cache i pacchetti installati con Yarn. Il modo consigliato consiste nel memorizzare nella cache la cartella cache condivisa di Yarn. Questa directory è gestita da Yarn e contiene una versione memorizzata nella cache di tutti i pacchetti scaricati. Durante l'installazione, Yarn controlla prima questa directory (per impostazione predefinita) per i moduli, che possono ridurre o eliminare le chiamate di rete ai registri pubblici o privati.
Esempio:
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
Configurare la memorizzazione nella cache della pipeline con gli ambienti 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')
Per i progetti PHP che usano Composer, eseguire l'override della COMPOSER_CACHE_DIR
variabile di ambiente usata da Composer.
Esempio:
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
Se si verificano problemi durante la configurazione della memorizzazione nella cache per la pipeline, controllare l'elenco dei problemi aperti nel microsoft/azure-pipelines-tasks repository. Se il problema riscontrato non è incluso nell'elenco, crearne uno nuovo e fornire le informazioni necessarie sullo scenario.
R: La cancellazione di una cache non è attualmente supportata. È tuttavia possibile aggiungere un valore letterale stringa (ad esempio version2
) alla chiave della cache esistente per modificare la chiave in modo da evitare riscontri nelle cache esistenti. Ad esempio, modificare la chiave della cache seguente da questo:
key: 'yarn | "$(Agent.OS)" | yarn.lock'
A questo scopo:
key: 'version2 | yarn | "$(Agent.OS)" | yarn.lock'
R: Le cache scadono dopo sette giorni di assenza di attività.
R: Dopo l'ultimo passaggio della pipeline, verrà creata una cache dalla cache path
e caricata. Per altri dettagli, vedere l'esempio.
R: Non esiste alcun limite applicato alle dimensioni delle singole cache o alle dimensioni totali di tutte le cache in un'organizzazione.