Ripristinare una distribuzione non riuscita dell'app con piano Flex Consumption

Quando una distribuzione introduce un bug, è necessario un modo per eseguire rapidamente il ripristino. Questo articolo illustra come ripristinare una distribuzione non riuscita di un'app per le funzioni Flex Consumption utilizzando un processo di integrazione continua e distribuzione continua (CI/CD). Questo processo include questi metodi di ripristino:

Metodo di recupero Velocità Quando utilizzare Description
Rieseguire l'ultima esecuzione completata con successo (rollback) Il più veloce Esiste una versione nota come valida oppure non vi sono dati né modifiche dello stato tra le versioni Selezionare un'esecuzione precedente ed eseguirla di nuovo, quindi attendere la compilazione e la distribuzione.
git revert e quindi git push (roll forward) Moderate La correzione è semplice, altrimenti non è possibile eseguire il rollback dello stato esterno Identificare il commit che ha causato l'errore, annullarlo e fare il push. Attendere quindi lo stesso tempo di compilazione e distribuzione.
git commit un hotfix e poi git push (roll forward) Più lento La causa radice è nota e richiede una correzione mirata Identificare la causa radice; creare, esaminare, testare e unire una correzione; e quindi attendere il completamento della compilazione e della distribuzione.

Queste strategie ripristinano sia il codice dell'app per le funzioni che le impostazioni dell'app, in modo che le modifiche alla configurazione siano recuperabili con le modifiche al codice.

Perché è necessario il CI/CD per ripristinare un deployment

Quando distribuisci il codice nell'app del piano Flex Consumption:

  • Il codice viene distribuito come pacchetto ZIP in un contenitore di archiviazione BLOB, montato all'avvio.
  • Ogni distribuzione sovrascrive il pacchetto corrente.
  • La piattaforma non mantiene alcuna cronologia delle revisioni predefinita per conservare le versioni precedenti.
  • La funzionalità degli slot di distribuzione non è attualmente supportata.
  • Le impostazioni dell'app vengono applicate separatamente tramite il portale di Azure, l'interfaccia della riga di comando o l'infrastruttura come codice (IaC) e la piattaforma non può ripristinarle in uno stato precedente.

Questi comportamenti di distribuzione limitano le opzioni per ripristinare l'app del piano a consumo Flex da una distribuzione non valida.

La cronologia Git e il processo CI/CD forniscono l'unico modo per tenere traccia delle distribuzioni di codice in un determinato momento. La compilazione di una distribuzione che include codice e configurazione consente di eseguire il ripristino da una versione non valida puntando l'esecuzione successiva a un commit valido noto.

Per ulteriori informazioni sul modello di distribuzione Flex Consumption, vedere Flex Consumption plan e Site updates in the Flex Consumption plan.

Prerequisiti

  • Un'app funzione esistente distribuita nel piano Flex Consumption di Azure.

  • Codice sorgente in un repository Git. Usare tag Git o registrare gli SHA di commit per ogni versione in modo da identificare rapidamente gli elementi a cui eseguire il rollback.

  • Una distribuzione configurata per l'app per funzioni:

    Un flusso di lavoro configurato con l'autenticazione OIDC come descritto in Distribuzione continua tramite GitHub Actions. Il flusso di lavoro deve usare azure/login. L'autenticazione tramite profilo di pubblicazione non supporta i comandi az cli usati in questa guida.

Preparare la distribuzione per gestire le impostazioni dell'app

Prima di poter eseguire un rollback completo, devi inserire le impostazioni dell'app nel controllo del codice sorgente e applicarle come parte della distribuzione. Anche se questo approccio consente di ripristinare sia il codice che la configurazione in un'unica riesecuzione, richiede passaggi aggiuntivi, ad esempio l'applicazione delle impostazioni, l'attesa dei riavvii e la pulizia dei valori non dichiarati.

Tip

Quando la distribuzione non include impostazioni, è possibile eseguire solo il rollback del codice distribuito ma non la configurazione.

Questa sezione descrive in dettaglio due approcci per la gestione delle impostazioni dell'app come parte della distribuzione:

Avvicinarsi Nel flusso di lavoro (interfaccia della riga di comando di Azure) Nella definizione del servizio (Bicep)
Funzionamento I passaggi di distribuzione applicano le impostazioni da un file JSON usando az functionapp config appsettings, quindi rimuovere le impostazioni non dichiarate Il modello Bicep dichiara le impostazioni in siteConfig.appSettings; ARM sostituisce l'intero insieme durante la distribuzione
Complessità Moderato. file JSON più passaggi CLI aggiuntivi nel tuo flusso di lavoro Superiore. Richiede conoscenza di Bicep
Rilevamento della deriva No Sì (what-if)
Migliore per Per iniziare, piccoli team Infrastruttura complessa multi-ambiente, pronta per la produzione

Per informazioni più generali sulle impostazioni dell'app, vedi Informazioni di riferimento sulle impostazioni dell'app per Funzioni di Azure.

Considerazioni sulle impostazioni dell'app

Prestare attenzione a queste considerazioni quando si lavora con la configurazione a livello di codice delle impostazioni dell'app.

Important

L'impossibilità di includere tutte le impostazioni necessarie usando uno dei due approcci può interrompere l'app distribuita.

  • Entrambi gli approcci in questa sezione considerano il file di impostazioni come lo stato desiderato completo. Rimuovono dall'app, a ogni distribuzione, tutte le impostazioni dell'app non dichiarate nel file. Includi sempre tutte le impostazioni necessarie per evitare l'interruzione dell'app.

  • Tratta app-settings.json e le modifiche ai modelli di file Bicep con lo stesso livello di attenzione riservato alle modifiche al codice. Esaminare le modifiche alle impostazioni nelle richieste pull per rilevare gli errori di configurazione prima di raggiungere l'ambiente di produzione.

  • Per una sicurezza ottimale, seguire queste linee guida per le connessioni:

    • Usare le connessioni di identità gestite laddove possibile. Configurare connessioni basate sull'identità per l'archiviazione host (AzureWebJobsStorage), l'archiviazione della distribuzione e le connessioni trigger/binding. Per altre informazioni, vedere Configurare le impostazioni di distribuzione.

      • Usare i riferimenti a Key Vault quando i segreti sono inevitabili. Key Vault archivia in modo sicuro i segreti. Anziché archiviare direttamente i segreti, è possibile usare un riferimento per accedere in modo sicuro al segreto richiesto in fase di esecuzione. Per altre informazioni, vedi Usare i riferimenti di Key Vault.
  • Quando si usa CI/CD, ogni modifica alle impostazioni dell'app o al codice attiva un aggiornamento del sito separato. Per impostazione predefinita, questo processo di distribuzione produce almeno due aggiornamenti del sito: prima quando vengono applicate le impostazioni e poi quando viene distribuito il codice. Per le distribuzioni senza tempi di inattività, usare invece una strategia di aggiornamento in sequenza , in cui le istanze vengono svuotate e sostituite in batch. Per altre informazioni, vedere Aggiornamenti del sito nel piano a consumo Flex.

Configurare le impostazioni dell'app nel flusso di lavoro

Usare questi passaggi di base per aggiungere un file di configurazione delle impostazioni dell'app alla distribuzione del progetto:

  1. Creare un file JSON nel repository, ad esempio in infra/app-settings.json. Questo file deve includere tutte le impostazioni dell'app necessarie in un formato JSON simile all'esempio seguente:

    [
      {
        "name": "FUNCTIONS_EXTENSION_VERSION",
        "value": "~4"
      },
      {
        "name": "FUNCTIONS_WORKER_RUNTIME",
        "value": "dotnet-isolated"
      },
      {
        "name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
        "value": "InstrumentationKey=00000000-..."
      },
      {
        "name": "AzureWebJobsStorage__blobServiceUri",
        "value": "https://mystorageaccount.blob.core.windows.net"
      },
      {
        "name": "AzureWebJobsStorage__queueServiceUri",
        "value": "https://mystorageaccount.queue.core.windows.net"
      },
      {
        "name": "AzureWebJobsStorage__tableServiceUri",
        "value": "https://mystorageaccount.table.core.windows.net"
      },
      {
        "name": "MyFeatureFlag",
        "value": "true"
      },
      {
        "name": "ServiceBus__fullyQualifiedNamespace",
        "value": "my-namespace.servicebus.windows.net"
      }
    ]
    
  2. Nella definizione di distribuzione specifica aggiungere i passaggi che applicano le impostazioni prima che si verifichi la distribuzione del codice, con una pausa di 30 secondi tra di esse.

Le sezioni seguenti forniscono esempi di distribuzione specifici che usano entrambi gli approcci.

Esempio: distribuzione del file app-settings.json

Questo esempio di distribuzione illustra come configurare la distribuzione per includere la configurazione. Scegliere la scheda corrispondente al metodo CI/CD.

Aggiungi i passaggi seguenti al job deploy nel tuo flusso di lavoro. Aggiungi actions/checkout@v4 al job deploy in modo che infra/app-settings.json sia disponibile e aggiungi RESOURCE_GROUP al blocco env a livello di flusso di lavoro. I passaggi applicano prima le impostazioni, attendere il riavvio, distribuire il codice, quindi pulire le impostazioni non dichiarate.

  deploy:
    needs: build
    steps:
      - name: 'Checkout repository'
        uses: actions/checkout@v4

      - name: 'Download artifact from build job'
        uses: actions/download-artifact@v4
        with:
          name: ${{ env.BUILD_ARTIFACT_NAME }}
          path: ./downloaded-artifact

      - name: 'Log in to Azure'
        uses: azure/login@v2
        with:
          client-id: ${{ vars.AZURE_CLIENT_ID }}
          tenant-id: ${{ vars.AZURE_TENANT_ID }}
          subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }}

      - name: 'Apply app settings'
        run: |
          az functionapp config appsettings set \
            --name ${{ env.AZURE_FUNCTIONAPP_NAME }} \
            --resource-group ${{ env.RESOURCE_GROUP }} \
            --settings @infra/app-settings.json

      - name: 'Wait for settings restart'
        run: sleep 30

      - name: 'Deploy code'
        uses: Azure/functions-action@v1
        with:
          app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }}
          package: ./downloaded-artifact

      - name: 'Remove undeclared app settings'
        run: |
          DESIRED=$(jq -r '.[].name' infra/app-settings.json)
          CURRENT=$(az functionapp config appsettings list \
            --name ${{ env.AZURE_FUNCTIONAPP_NAME }} \
            --resource-group ${{ env.RESOURCE_GROUP }} \
            --query "[].name" -o tsv)
          TO_DELETE=""
          for setting in $CURRENT; do
            if ! echo "$DESIRED" | grep -qx "$setting"; then
              TO_DELETE="$TO_DELETE $setting"
            fi
          done
          if [ -n "$TO_DELETE" ]; then
            az functionapp config appsettings delete \
              --name ${{ env.AZURE_FUNCTIONAPP_NAME }} \
              --resource-group ${{ env.RESOURCE_GROUP }} \
              --setting-names $TO_DELETE
          fi

Il azure/login@v2 passaggio nel flusso di lavoro basato su OIDC fornisce l'autenticazione necessaria per i az cli comandi.

Definire le impostazioni per una distribuzione Bicep

Per le distribuzioni IaC, gestire le impostazioni dell'app direttamente nel modello di Bicep. Bicep sostituisce nativamente l'intera collezione siteConfig.appSettings a ogni distribuzione senza richiedere un passaggio di pulizia separato. Supporta anche il rilevamento della deriva usando what-if.

Quando si aggiorna solo la sezione delle impostazioni dell'app del file Bicep, tutte le altre risorse Azure rimangono invariate durante la distribuzione. Questo articolo non tratta la creazione di file Bicep dall'inizio alla fine. Per i modelli completi di Flex Consumption, vedi Infrastruttura come codice di Funzioni di Azure.

Ecco il frammento rilevante del template Bicep (solo la parte appSettings):

siteConfig: {
  appSettings: [
    {
      name: 'MyFeatureFlag'
      value: 'true'
    }
    {
      name: 'ServiceBus__Connection'
      value: '@Microsoft.KeyVault(SecretUri=https://my-vault.vault.azure.net/secrets/sb-conn)'
    }
  ]
}

Aggiungere i passaggi per distribuire il modello Bicep prima della distribuzione del codice, con un'attesa di 30 secondi tra l'una e l'altra. L'aggiornamento delle impostazioni dell'app tramite Bicep è asincrono. L'app viene riavviata per raccogliere i nuovi valori e la distribuzione del codice durante il riavvio può non riuscire.

      - name: 'Deploy infrastructure'
        run: |
          az deployment group create \
            --resource-group ${{ env.RESOURCE_GROUP }} \
            --template-file infra/main.bicep \
            --parameters appName=${{ env.AZURE_FUNCTIONAPP_NAME }}

      - name: 'Wait for settings restart'
        run: sleep 30

      - name: 'Deploy code'
        uses: Azure/functions-action@v1
        with:
          app-name: ${{ env.AZURE_FUNCTIONAPP_NAME }}
          package: ./downloaded-artifact

Eseguire il rollback di una distribuzione

Rollback significa eseguire nuovamente un'esecuzione precedente completata con successo. Un'esecuzione di nuovo esegue il check-out dello SHA di commit originale che ha attivato l'esecuzione (non il ramo corrente HEAD), quindi ricompila e distribuisce il codice e il file di impostazioni da quel momento. Non hai bisogno di nuovi commit.

Per ripristinare una distribuzione rieseguendo una precedente esecuzione completata con successo:

  1. Passare alla scheda Azioni nel repository GitHub.
  2. Trovare l'ultima esecuzione corretta del flusso di lavoro prima della distribuzione non valida.
  3. Selezionare Esegui di nuovo tutti i processi.
  4. Il flusso di lavoro recupera il commit di quell'esecuzione, ricompila, distribuisce il codice e sincronizza le impostazioni dell'app dal app-settings.json commit di quell'esecuzione.

Cosa ricostruisce una nuova esecuzione

La riesecuzione ricostruisce il codice da un commit precedente. Non riutilizza l'artefatto binario originale. Questo comportamento significa:

  • Con i file di blocco delle dipendenze aggiunti (package-lock.json, requirements.txte così via), l'output è funzionalmente identico.
  • Il tempo di compilazione è uguale a quello di una distribuzione normale. Non è istantaneo.
  • Le dipendenze esterne recuperate in fase di compilazione (NuGet, npm, pip) devono essere ancora disponibili.

Considerazioni sul rollback

  • Inserisci nel controllo del codice sorgente i file di blocco delle dipendenze (package-lock.json, requirements.txt o le versioni bloccate di .csproj). I file di blocco aggiunti assicurano che la ripetizione dell'esecuzione di una distribuzione produchi una compilazione funzionalmente identica indipendentemente dal momento in cui si verifica la ripetizione dell'esecuzione.

  • La riesecuzione usa il file YAML del flusso di lavoro o della pipeline del commit originale. Tuttavia, i segreti e le variabili della pipeline vengono risolti nei valori correnti al momento in cui vengono eseguiti di nuovo. Quando si ruotano i segreti tra l'esecuzione originale e una riesecuzione, viene utilizzato il nuovo valore del segreto.

  • Una riesezione ripristina l'app distribuita in uno stato valido noto, ma non modifica la cronologia git. Il tuo branch HEAD punta ancora al commit danneggiato.

  • Cosa non viene ripristinato ripetendo l’operazione:

    • Configurazione delle risorse di Azure gestita al di fuori della distribuzione, inclusi piani di hosting, rete e assegnazioni di identità.
    • Modifiche ai dati o allo schema nei servizi downstream, come database, code di messaggi e sistemi di archiviazione.
    • Valori dei segreti di Key Vault Nel controllo del codice sorgente vengono mantenuti solo i riferimenti a Key Vault. La rotazione dei segreti è un'operazione di Key Vault.
  • Verificate regolarmente il processo di rollback. Non aspettare che si verifichi un incidente in produzione per scoprire che non funziona.

Correggi il ramo dopo un rollback

Poiché la successiva esecuzione attivata tramite push ridistribuisce il commit interrotto, altri sviluppatori che eseguono il pull del ramo visualizzano ancora il codice interrotto. È necessario risolvere questa situazione con una di queste azioni:

  • Crea un commit di hotfix per risolvere il problema, che è in sostanza un'operazione di roll forward.
  • Eseguire un git revert per annullare il commit problematico creando un nuovo commit, che costituisce anche un'azione di roll forward.
  • Criteri di ramo che impediscono l'unione fino a quando non si risolve il problema.

Fino a quando non si completa una di queste azioni, evitare di attivare una nuova esecuzione in tale ramo. Per indicazioni sulla convalida, vedere Convalidare prima dell'unione.

Eseguire l'avanzamento di una distribuzione

Roll forward significa eseguire il push di un nuovo commit per risolvere il problema. La distribuzione interrotta rimane attiva fino alla distribuzione della correzione, quindi questa strategia funziona meglio quando l'app può tollerare un comportamento degradato durante tale periodo.

  1. Crea un commit di correzione sul tuo ramo. Questa correzione può essere:

    • Un hotfix che affronta direttamente il problema.
    • Un git revert <bad-commit-sha> che crea un nuovo commit che annulla le modifiche errate. Anche se git revert inverte il codice, si tratta di un roll forward perché produce un nuovo commit e attiva una nuova distribuzione.
  2. Se la correzione richiede anche modifiche alla configurazione, aggiorna le impostazioni dell'app (in app-settings.json oppure nel tuo template Bicep) nello stesso commit.

  3. Esegui il push del commit. La tua distribuzione compila e distribuisce automaticamente la correzione.

Convalida prima dell'unione

Indipendentemente dalla strategia di ripristino, convalida e correggi i commit prima di fonderli nel ramo di produzione per evitare di aggravare il problema.

Queste raccomandazioni si applicano sia che si proceda in modo proattivo con un roll forward, sia che si corregga il ramo dopo un rollback:

  • Usa un ambiente di staging: poiché il piano Flex Consumption attualmente non supporta gli slot di distribuzione, valuta invece di distribuire in un'app separata del piano Flex Consumption per convalidare la correzione prima di unire le modifiche al ramo di produzione.

  • Automatizzare i controlli di integrità: aggiungere un passaggio post-distribuzione che chiama un endpoint di controllo integrità nell'app e verifica una risposta positiva. In caso di errore, valutare la possibilità di attivare una riesecuzione dell'esecuzione riuscita precedente per eseguire automaticamente il rollback.

  • Monitorare dopo la distribuzione: configurare gli avvisi di Application Insights per il rilevamento della regressione. Il rilevamento anticipato riduce l'impatto di una distribuzione non valida.