Gestire le analogie tra ambienti usando flussi di lavoro riutilizzabili

Completato

Quando si distribuiscono le modifiche in più ambienti, i passaggi necessari per la distribuzione in ogni ambiente sono simili o addirittura identici. In questa unità si apprenderà come progettare i flussi di lavoro per evitare ripetizioni e consentire il riutilizzo del codice del flusso di lavoro.

Distribuzione in più ambienti

Dopo aver parlato con i colleghi del team del sito Web, si decide il flusso di lavoro seguente per il sito Web dell'azienda di giocattoli:

Diagramma che mostra una serie di processi del flusso di lavoro e include le distribuzioni di test e produzione.

  1. Il flusso di lavoro esegue il linter Bicep per verificare che il codice Bicep sia valido e segua le procedure consigliate.

    Il linting avviene nel codice Bicep senza doversi connettere ad Azure, quindi non importa il numero di ambienti in cui si esegue la distribuzione. Viene eseguito una volta sola.

  2. Il flusso di lavoro viene distribuito nell'ambiente di test e richiede:

    1. Esecuzione della convalida preliminare di Azure Resource Manager.
    2. Distribuzione del codice Bicep.
    3. Esecuzione di alcuni test sull'ambiente di test.
  3. Se una parte del flusso di lavoro ha esito negativo, l'intero flusso di lavoro viene arrestato in modo da poter analizzare e risolvere il problema. Tuttavia, se tutto ha esito positivo, il flusso di lavoro continua a essere distribuito nell'ambiente di produzione:

    1. Il flusso di lavoro include un passaggio di anteprima, che esegue l'operazione di simulazione nell'ambiente di produzione per elencare le modifiche che verranno apportate alle risorse di Azure di produzione. L'operazione di simulazione convalida anche la distribuzione, quindi non è necessario eseguire un passaggio di convalida separato per l'ambiente di produzione.
    2. Il flusso di lavoro viene sospeso per la convalida manuale.
    3. Se viene ricevuta l'approvazione, il flusso di lavoro esegue i test di distribuzione e smoke test sull'ambiente di produzione.

Alcune di queste attività vengono ripetute tra gli ambienti di test e di produzione e alcune vengono eseguite solo per ambienti specifici:

Attività Ambienti
Linting Nessuno dei due: il linting non funziona su un ambiente
Convalida Solo test
Anteprima Solo produzione
Distribuzione Entrambi gli ambienti
Smoke test Entrambi gli ambienti

Quando è necessario ripetere i passaggi nel flusso di lavoro, copiare e incollare le definizioni dei passaggi non è una procedura consigliata. È facile commettere accidentalmente piccoli errori o che si verifichino errori di sincronizzazione quando si duplica il codice del flusso di lavoro. E in futuro, quando sarà necessario apportare una modifica ai passaggi, si dovrà ricordare di applicare la modifica in più posizioni. Una procedura migliore consiste nell'usare flussi di lavoro riutilizzabili.

Flussi di lavoro riutilizzabili

GitHub Actions consente di creare sezioni riutilizzabili di definizioni del flusso di lavoro creando un file YAML del flusso di lavoro separato che definisce passaggi o processi. È possibile creare file YAML per riutilizzare più volte parti di un flusso di lavoro all'interno di un singolo flusso di lavoro o anche in più flussi di lavoro. Il flusso di lavoro riutilizzato è un flusso di lavoro chiamato e il flusso di lavoro che lo include è un flusso di lavoro chiamante. Concettualmente, si possono considerare simili ai moduli Bicep.

Quando si crea un flusso di lavoro riutilizzabile, si usa il trigger workflow_call per indicare a GitHub Actions che il flusso di lavoro può essere chiamato da altri flussi di lavoro. Ecco un esempio di base di un flusso di lavoro riutilizzabile, salvato in un file denominato script.yml:

on:
  workflow_call:

jobs:
  say-hello:
    runs-on: ubuntu-latest
    steps:
    - run: |
        echo Hello world!

Nel flusso di lavoro chiamante si fa riferimento al flusso di lavoro chiamato includendo la parola chiave uses: e specificando il percorso del flusso di lavoro chiamato all'interno del repository corrente:

on: 
  workflow_dispatch:

jobs:
  job:
    uses: ./.github/workflows/script.yml

È anche possibile fare riferimento a un file di definizione del flusso di lavoro in un altro repository.

Input e segreti del flusso di lavoro chiamato

È possibile usare input e segreti per semplificare il riutilizzo dei flussi di lavoro chiamati, perché è possibile consentire piccole differenze nei flussi di lavoro ogni volta che vengono usati.

Quando si crea un flusso di lavoro chiamato, è possibile indicare i relativi input e segreti all'inizio del file:

on:
  workflow_call:
    inputs:
      environmentType:
        required: true
        type: string
    secrets:
      AZURE_CLIENT_ID:
        required: true
      AZURE_TENANT_ID:
        required: true
      AZURE_SUBSCRIPTION_ID:
        required: true

È possibile definire tutti gli input e i segreti necessari. Ma proprio come i parametri Bicep, è meglio non usare gli input del flusso di lavoro. È consigliabile semplificare il riutilizzo del flusso di lavoro da parte di un altro utente senza dover specificare troppe impostazioni.

Gli input possono avere diverse proprietà, tra cui:

  • Il nome di input usato per fare riferimento all'input nelle definizioni del flusso di lavoro.
  • Il tipo di input. Gli input supportano valori stringa, numero e booleani.
  • Il valore predefinito dell'input, che è facoltativo. Se non si specifica un valore predefinito, è necessario specificare un valore quando il flusso di lavoro viene usato in un flusso di lavoro chiamante.

I segreti hanno nomi, ma non hanno tipi o valori predefiniti.

Nell'esempio il flusso di lavoro definisce un input stringa obbligatorio denominato environmentType e tre segreti obbligatori denominati AZURE_CLIENT_ID, AZURE_TENANT_ID e AZURE_SUBSCRIPTION_ID.

Nel flusso di lavoro si usa una sintassi speciale per fare riferimento al valore del parametro, come in questo esempio:

jobs:
  say-hello:
    runs-on: ubuntu-latest
    steps:
    - run: |
        echo Hello ${{ inputs.environmentType }}!

Il valore per gli input viene passato a un flusso di lavoro chiamato usando la parola chiave with. È necessario definire i valori per ogni input all'interno della sezione with. Non è possibile usare la parola chiave env per fare riferimento alle variabili di ambiente di un flusso di lavoro. I valori dei segreti vengono passati a un flusso di lavoro chiamato usando la parola chiave secrets.

on: 
  workflow_dispatch:

permissions:
  id-token: write
  contents: read

jobs:
  job-test:
    uses: ./.github/workflows/script.yml
    with:
      environmentType: Test
    secrets:
      AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID_TEST }}
      AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
      AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

  job-production:
    uses: ./.github/workflows/script.yml
    with:
      environmentType: Production
    secrets:
      AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID_PRODUCTION }}
      AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
      AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

Usare le identità dei carichi di lavoro dei flussi di lavoro chiamati

Quando si usano i flussi di lavoro chiamati, spesso si definiscono alcune azioni di distribuzione in più file di definizione del flusso di lavoro. È necessario concedere l'autorizzazione al flusso di lavoro chiamante, il che garantisce che ogni flusso di lavoro chiamato sia in grado di accedere all'identità del flusso di lavoro e di eseguire l'autenticazione in Azure:

on: 
  workflow_dispatch:

permissions:
  id-token: write
  contents: read

jobs:
  job-test:
    uses: ./.github/workflows/script.yml
    with:
      environmentType: Test
    secrets:
      AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID_TEST }}
      AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
      AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

  job-production:
    uses: ./.github/workflows/script.yml
    with:
      environmentType: Production
    secrets:
      AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID_PRODUCTION }}
      AZURE_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
      AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

Condizioni

È possibile usare le condizioni del flusso di lavoro per specificare se un passaggio o un processo deve essere eseguito in base a una regola specificata. È possibile combinare input e condizioni del flusso di lavoro per personalizzare il processo di distribuzione per più situazioni.

Si supponga, ad esempio, di definire un flusso di lavoro che esegue i passaggi di script. Si prevede di riutilizzare il modello per ogni ambiente. Quando si distribuisce l'ambiente di produzione, si vuole eseguire un altro passaggio. Ecco come ottenere questo risultato usando la condizione if nel passaggio:

jobs:
  say-hello:
    runs-on: ubuntu-latest
    steps:
    - run: |
        echo Hello ${{ inputs.environmentType }}!

    - run: |
        echo This step only runs for production deployments.
      if: inputs.environmentType == 'Production'

La condizione in questo caso si traduce in: se il valore del parametro environmentType è uguale a "Production", eseguire il passaggio .

Anche se le condizioni aggiungono flessibilità al flusso di lavoro, se sono troppe possono complicare il flusso di lavoro e rendere più difficile la comprensione. Se si hanno molte condizioni in un flusso di lavoro chiamato, è consigliabile riprogettare il flusso di lavoro.

Usare anche commenti YAML per spiegare le condizioni usate e qualsiasi altro aspetto del flusso di lavoro che potrebbe richiedere una spiegazione più approfondita. I commenti semplificano la comprensione e l'uso del flusso di lavoro in futuro. In tutti gli esercizi di questo modulo sono presenti alcuni commenti YAML di esempio.