Distribuzione continua stile GitOps con Cloud Build


Questa pagina spiega come creare una pipeline di integrazione e distribuzione continue (CI/CD) su Google Cloud utilizzando solo prodotti in hosting e la popolare metodologia GitOps.

Gli ingegneri di Google archiviano i file di configurazione e di deployment nel nostro repository del codice sorgente principale da molto tempo. Questa metodologia è описана в книге Site Reliability Engineering, Chapter 8 (Beyer et. al., 2016), e è stata dimostrata da Kelsey Hightower durante il suo keynote di Google Cloud Next '17.

Un aspetto fondamentale di GitOps è l'idea di "environments-as-code": descrivere i deployment in modo dichiarativo utilizzando file (ad esempio manifest di Kubernetes) archiviati in un repository Git.

In questo tutorial, crei una pipeline CI/CD che genera automaticamente un'immagine container dal codice dopo il commit, archivia l'immagine in Artifact Registry, aggiorna un manifest Kubernetes in un repository Git ed esegue il deployment dell'applicazione in Google Kubernetes Engine (GKE) utilizzando il manifest.

Architettura della pipeline CI/CD

Questo tutorial utilizza due repository Git:

  • Repository app: contiene il codice sorgente dell'applicazione stessa
  • Repository env: contiene i manifest per il deployment Kubernetes

Quando esegui il push di una modifica nel repository app, la pipeline Cloud Build esegue i test, crea un'immagine container e la invia ad Artifact Registry. Dopo aver eseguito il push dell'immagine, Cloud Build aggiorna il manifest del deployment e lo invia al repository env. Questo attiva un'altra pipeline di Cloud Build che applica il manifest al cluster GKE e, se l'operazione ha esito positivo, lo archivia in un altro ramo del repository env.

Manteniamo separati i repository app ed env perché hanno cicli di vita e utilizzi diversi. Gli utenti principali del repository app sono persone reali e questo repository è dedicato a un'applicazione specifica. Gli utenti principali del repository env sono sistemi automatici (come Cloud Build) e questo repository potrebbe essere condiviso da diverse applicazioni. Il repository env può avere vari rami, ciascuno con mappatura su un ambiente specifico (in questo tutorial utilizzi solo l'ambiente di produzione) e con riferimento a una specifica immagine container, al contrario del repository app.

Al termine di questo tutorial, avrai un sistema in cui è facile:

  • Distinguere i deployment non riusciti e quelli riusciti esaminando la cronologia di Cloud Build.
  • Accedere al manifest attualmente in uso esaminando il ramo production del repository env.
  • Effettuare il rollback a qualsiasi versione precedente mediante una nuova esecuzione della corrispondente build di Cloud Build.

Flusso della pipeline CI/CD

Informazioni su questo tutorial

Questo tutorial utilizza Cloud Source Repositories per ospitare repository Git, ma puoi ottenere gli stessi risultati con altri prodotti di terze parti come GitHub, Bitbucket o GitLab.

Questa pipeline non implementa un meccanismo di convalida prima del deployment. Se utilizzi GitHub, Bitbucket o GitLab, puoi modificare la pipeline per utilizzare una richiesta di pull a questo scopo.

Sebbene consigliamo Spinnaker ai team che vogliono implementare pattern di deployment avanzati (blu/verde, analisi canary, multi-cloud e così via), il suo set di funzionalità potrebbe non essere necessario per una strategia CI/CD efficace per organizzazioni e progetti più piccoli. In questo tutorial, imparerai a creare una pipeline CI/CD adatta per le applicazioni ospitate su GKE con gli strumenti.

Per semplicità, questo tutorial utilizza un singolo ambiente, "production", nel repository env, ma puoi estenderlo per eseguire il deployment in più ambienti, se necessario.

Obiettivi

  • Crea i repository Git in Cloud Source Repositories.
  • Crea un'immagine container con Cloud Build e archiviala in Artifact Registry.
  • Crea una pipeline CI.
  • Crea una pipeline CD.
  • Testa la pipeline CI/CD.

Costi

In questo documento utilizzi i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi basata sull'utilizzo previsto, utilizza il Calcolatore prezzi. I nuovi utenti di Google Cloud potrebbero essere idonei per una prova gratuita.

Al termine delle attività descritte in questo documento, puoi evitare la fatturazione continua eliminando le risorse che hai creato. Per ulteriori informazioni, consulta la sezione Pulizia.

Prima di iniziare

  1. Seleziona o crea un progetto Google Cloud.

    Vai a Gestisci risorse

  2. Abilita la fatturazione per il tuo progetto.

    Attiva la fatturazione

  3. Apri Cloud Shell per eseguire i comandi elencati in questo tutorial. Cloud Shell è un ambiente shell interattivo per Google Cloud che ti consente di gestire i tuoi progetti e le tue risorse dal browser web.

    Vai a Cloud Shell

  4. Se il comando gcloud config get-value project non restituisce l'ID del progetto selezionato, configura Cloud Shell in modo da utilizzare il progetto.

    gcloud config set project [PROJECT_ID]
    
  5. In Cloud Shell, abilita le API richieste.

    gcloud services enable container.googleapis.com \
        cloudbuild.googleapis.com \
        sourcerepo.googleapis.com \
        artifactregistry.googleapis.com
    
  6. Crea un repository Docker in Artifact Registry denominato my-repository nella regione us-central1 per archiviare le tue immagini container.

    gcloud artifacts repositories create my-repository \
      --repository-format=docker \
      --location=us-central1
    
  7. In Cloud Shell, crea un cluster GKE che utilizzerai per eseguire il deployment dell'applicazione di esempio di questo tutorial.

    Autopilot

    Crea un cluster Autopilot denominato hello-cloudbuild:

    gcloud container clusters create-auto hello-cloudbuild \
        --region us-central1
    

    Standard

    Crea un cluster standard a un nodo denominato hello-cloudbuild:

    gcloud container clusters create hello-cloudbuild \
        --num-nodes 1 --region us-central1
    
  8. Se non hai mai utilizzato Git in Cloud Shell, configuralo con il tuo nome e indirizzo email. Git li utilizzerà per identificarti come autore dei commit che creerai in Cloud Shell.

    git config --global user.email "YOUR_EMAIL_ADDRESS"
    git config --global user.name "YOUR_NAME"
    

Al termine di questo tutorial, puoi evitare la fatturazione continua eliminando le risorse che hai creato. Per ulteriori dettagli, consulta la sezione Pulizia.

Creazione dei repository Git in Cloud Source Repositories

In questa sezione creerai i due repository Git (app ed env) utilizzati in questo tutorial e inizilizzerai quello app con del codice campione.

  1. In Cloud Shell, crea i due repository Git.

    gcloud source repos create hello-cloudbuild-app
    gcloud source repos create hello-cloudbuild-env
    
  2. Clona il codice campione da GitHub.

    cd ~
    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    cd ~/kubernetes-engine-samples/management/gitops-style-delivery/
    
  3. Configura Cloud Source Repositories come repository remoto.

    PROJECT_ID=$(gcloud config get-value project)
    git remote add google \
        "https://source.developers.google.com/p/${PROJECT_ID}/r/hello-cloudbuild-app"
    

Il codice che hai clonato contiene un'applicazione "Hello World".

from flask import Flask
app = Flask('hello-cloudbuild')

@app.route('/')
def hello():
  return "Hello World!\n"

if __name__ == '__main__':
  app.run(host = '0.0.0.0', port = 8080)

Creazione di un'immagine container con Cloud Build

Il codice clonato contiene il seguente Dockerfile.

FROM python:3.13-slim
RUN pip install flask
WORKDIR /app
COPY app.py /app/app.py
ENTRYPOINT ["python"]
CMD ["/app/app.py"]

Con questo Dockerfile puoi creare un'immagine container con Cloud Build e archiviarla in Artifact Registry.

  1. In Cloud Shell, crea una build di Cloud Build basata sull'ultimo commit con il comando seguente.

    cd ~/kubernetes-engine-samples/management/gitops-style-delivery/
    COMMIT_ID="$(git rev-parse --short=7 HEAD)"
    gcloud builds submit --tag="us-central1-docker.pkg.dev/${PROJECT_ID}/my-repository/hello-cloudbuild:${COMMIT_ID}" .
    

    Quando esegui questo comando, Cloud Build trasmette il flusso dei log generati dalla creazione dell'immagine container al tuo terminale.

  2. Al termine della build, verifica che la nuova immagine container sia disponibile in Artifact Registry.

    Vai ad Artifact Registry

    Immagine hello-cloudbuild in Artifact Registry

Creazione della pipeline di integrazione continua

In questa sezione configurerai Cloud Build in modo che esegua automaticamente un piccolo test delle unità, crei l'immagine container e quindi esegua il push in Artifact Registry. Il push di un nuovo commit in Cloud Source Repositories attiva automaticamente questa pipeline. Il file cloudbuild.yaml incluso nel codice è la configurazione della pipeline.

steps:
# This step runs the unit tests on the app
- name: 'python:3.13-slim'
  id: Test
  entrypoint: /bin/sh
  args:
  - -c
  - 'pip install flask && python test_app.py -v'

# This step builds the container image.
- name: 'gcr.io/cloud-builders/docker'
  id: Build
  args:
  - 'build'
  - '-t'
  - 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repository/hello-cloudbuild:$SHORT_SHA'
  - '.'

# This step pushes the image to Artifact Registry
# The PROJECT_ID and SHORT_SHA variables are automatically
# replaced by Cloud Build.
- name: 'gcr.io/cloud-builders/docker'
  id: Push
  args:
  - 'push'
  - 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repository/hello-cloudbuild:$SHORT_SHA'
  1. Apri la pagina Trigger di Cloud Build.

    Vai ai trigger

  2. Fai clic su Crea trigger.

  3. Compila le seguenti opzioni:

    • Nel campo Nome, digita hello-cloudbuild.
    • In Evento, seleziona Push al ramo.
    • In Origine, seleziona hello-cloudbuild-app come Repository e ^master$ come Ramo.
    • In Configurazione build, seleziona File di configurazione di Cloud Build.
    • Nel campo Posizione file di configurazione Cloud Build, digita cloudbuild.yaml dopo /.
  4. Fai clic su Crea per salvare il trigger di build.

    Suggerimento: se devi creare trigger di compilazione per molti progetti, puoi utilizzare l'API Build Triggers.

  5. In Cloud Shell, esegui il push del codice dell'applicazione in Cloud Source Repositories per attivare la pipeline CI in Cloud Build.

    cd ~/kubernetes-engine-samples/management/gitops-style-delivery/
    git push google master
    
  6. Apri la console Cloud Build.

    Vai a Cloud Build

    Vengono visualizzate le build eseguite e completate di recente. Puoi fare clic su una build per seguirne l'esecuzione ed esaminare i relativi log.

Creazione della pipeline di distribuzione continua

Cloud Build viene utilizzato anche per la pipeline di distribuzione continua. La pipeline viene eseguita per ogni push di un commit al ramo candidate del repository hello-cloudbuild-env. La pipeline applica la nuova versione del manifest al cluster Kubernetes e, in caso di esito positivo, copia il manifest nel ramo production. Questo processo prevede le seguenti proprietà:

  • Il ramo candidate rappresenta una cronologia dei tentativi di deployment.
  • Il ramo production rappresenta una cronologia dei deployment riusciti.
  • Puoi visualizzare i deployment riusciti e non riusciti in Cloud Build.
  • Puoi eseguire il rollback a qualsiasi deployment precedente eseguendo di nuovo la build corrispondente in Cloud Build. Un rollback aggiorna anche il ramo production in modo da riflettere in modo veritiero la cronologia dei deployment.

Dovrai modificare la pipeline di integrazione continua per aggiornare il ramo candidate del repository hello-cloudbuild-env e attivare così la pipeline di distribuzione continua.

Concedere a Cloud Build l'accesso a GKE

Per eseguire il deployment dell'applicazione nel cluster Kubernetes, Cloud Build richiede il ruolo Identity and Access Management sviluppatore Kubernetes Engine.

Shell

In Cloud Shell, esegui questo comando:

PROJECT_NUMBER="$(gcloud projects describe ${PROJECT_ID} --format='get(projectNumber)')"
gcloud projects add-iam-policy-binding ${PROJECT_NUMBER} \
    --member=serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
    --role=roles/container.developer

Console

  1. Nella console Google Cloud, apri la pagina Impostazioni Cloud Build:

    Apri le impostazioni di Cloud Build

    Viene visualizzata la pagina Autorizzazioni account di servizio:

    Screenshot della pagina Autorizzazioni account di servizio

  2. Imposta lo stato del ruolo Sviluppatore Kubernetes Engine su Attiva.

Inizializzazione del repository hello-cloudbuild-env

Devi inizializzare il repository hello-cloudbuild-env con due rami (production e candidate) e un file di configurazione di Cloud Build che descrive il processo di deployment.

  1. In Cloud Shell, clona il repository hello-cloudbuild-env e crea il ramo production.

    cd ~
    gcloud source repos clone hello-cloudbuild-env
    cd ~/kubernetes-engine-samples/management/gitops-style-delivery/
    git checkout -b production
    
  2. Copia il file cloudbuild-delivery.yaml disponibile nel repository hello-cloudbuild-app ed esegui il commit della modifica.

    cd ~/kubernetes-engine-samples/management/gitops-style-delivery/
    cp ~/hello-cloudbuild-app/cloudbuild-delivery.yaml ~/kubernetes-engine-samples/management/gitops-style-delivery/cloudbuild.yaml
    git add .
    git commit -m "Create cloudbuild.yaml for deployment"
    

    Il file cloudbuild-delivery.yaml descrive il processo di deployment da eseguire in Cloud Build. che prevede due passaggi:

    1. Cloud Build applica il manifest al cluster GKE.

    2. In caso di esito positivo, Cloud Build copia il manifest nel ramo production.

    steps:
    # This step deploys the new version of our container image
    # in the hello-cloudbuild Kubernetes Engine cluster.
    - name: 'gcr.io/cloud-builders/kubectl'
      id: Deploy
      args:
      - 'apply'
      - '-f'
      - 'kubernetes.yaml'
      env:
      - 'CLOUDSDK_COMPUTE_REGION=us-central1'
      - 'CLOUDSDK_CONTAINER_CLUSTER=hello-cloudbuild'
    
    # This step copies the applied manifest to the production branch
    # The COMMIT_SHA variable is automatically
    # replaced by Cloud Build.
    - name: 'gcr.io/cloud-builders/git'
      id: Copy to production branch
      entrypoint: /bin/sh
      args:
      - '-c'
      - |
        set -x && \
        # Configure Git to create commits with Cloud Build's service account
        git config user.email $(gcloud auth list --filter=status:ACTIVE --format='value(account)') && \
        # Switch to the production branch and copy the kubernetes.yaml file from the candidate branch
        git fetch origin production && git checkout production && \
        git checkout $COMMIT_SHA kubernetes.yaml && \
        # Commit the kubernetes.yaml file with a descriptive commit message
        git commit -m "Manifest from commit $COMMIT_SHA
        $(git log --format=%B -n 1 $COMMIT_SHA)" && \
        # Push the changes back to Cloud Source Repository
        git push origin production
  3. Crea un ramo candidate ed esegui il push di entrambi i rami per renderli disponibili in Cloud Source Repositories.

    git checkout -b candidate
    git push origin production
    git push origin candidate
    
  4. Concedi il ruolo IAM Writer repository di codice sorgente all'account di servizio Cloud Build per il repository hello-cloudbuild-env.

    PROJECT_NUMBER="$(gcloud projects describe ${PROJECT_ID} \
        --format='get(projectNumber)')"
    cat >/tmp/hello-cloudbuild-env-policy.yaml <<EOF
    bindings:
    - members:
      - serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com
      role: roles/source.writer
    EOF
    gcloud source repos set-iam-policy \
        hello-cloudbuild-env /tmp/hello-cloudbuild-env-policy.yaml
    

Creazione dell'attivatore per la pipeline di distribuzione continua

In questa sezione configurerai Cloud Build in modo che venga attivato da un push al ramo candidate del repository hello-cloudbuild-env.

  1. Apri la pagina Trigger di Cloud Build.

    Vai ai trigger

  2. Fai clic su Crea trigger.

  3. Compila le seguenti opzioni:

    • Nel campo Nome, digita hello-cloudbuild-deploy.
    • In Evento, seleziona Push al ramo.
    • In Origine, seleziona hello-cloudbuild-env come Repository e ^candidate$ come Ramo.
    • In Configurazione, seleziona File di configurazione di Cloud Build (yaml o json).
    • Nel campo Posizione file di configurazione Cloud Build, digita cloudbuild.yaml dopo /.
  4. Fai clic su Crea.

Modifica della pipeline di integrazione continua per attivare la pipeline di distribuzione continua

In questa sezione aggiungerai alcuni passaggi alla pipeline di integrazione continua che genereranno una nuova versione del manifest Kubernetes e ne eseguiranno il push al repository hello-cloudbuild-env per attivare la pipeline di distribuzione continua.

  1. Sostituisci il file cloudbuild.yaml con l'esempio esteso nel file cloudbuild-trigger-cd.yaml.

    cd ~/kubernetes-engine-samples/management/gitops-style-delivery/
    cp cloudbuild-trigger-cd.yaml cloudbuild.yaml
    

    cloudbuild-trigger-cd.yaml è una versione estesa del file cloudbuild.yaml. Aggiunge i passaggi per generare il nuovo manifest Kubernetes e attivare la pipeline di distribuzione continua.

    # This step clones the hello-cloudbuild-env repository
    - name: 'gcr.io/cloud-builders/gcloud'
      id: Clone env repository
      entrypoint: /bin/sh
      args:
      - '-c'
      - |
        gcloud source repos clone hello-cloudbuild-env && \
        cd hello-cloudbuild-env && \
        git checkout candidate && \
        git config user.email $(gcloud auth list --filter=status:ACTIVE --format='value(account)')
    
    # This step generates the new manifest
    - name: 'gcr.io/cloud-builders/gcloud'
      id: Generate manifest
      entrypoint: /bin/sh
      args:
      - '-c'
      - |
         sed "s/GOOGLE_CLOUD_PROJECT/${PROJECT_ID}/g" kubernetes.yaml.tpl | \
         sed "s/COMMIT_SHA/${SHORT_SHA}/g" > hello-cloudbuild-env/kubernetes.yaml
    
    # This step pushes the manifest back to hello-cloudbuild-env
    - name: 'gcr.io/cloud-builders/gcloud'
      id: Push manifest
      entrypoint: /bin/sh
      args:
      - '-c'
      - |
        set -x && \
        cd hello-cloudbuild-env && \
        git add kubernetes.yaml && \
        git commit -m "Deploying image us-central1-docker.pkg.dev/$PROJECT_ID/my-repository/hello-cloudbuild:${SHORT_SHA}
        Built from commit ${COMMIT_SHA} of repository hello-cloudbuild-app
        Author: $(git log --format='%an <%ae>' -n 1 HEAD)" && \
        git push origin candidate
    
  2. Esegui il commit delle modifiche e inviale a Cloud Source Repositories.

    cd ~/kubernetes-engine-samples/management/gitops-style-delivery/
    git add cloudbuild.yaml
    git commit -m "Trigger CD pipeline"
    git push google master
    

    In questo modo viene attivata la pipeline di integrazione continua in Cloud Build.

  3. Esamina la compilazione dell'integrazione continua.

    Vai a Cloud Build

    Vengono visualizzate le build eseguite e completate di recente per il repository hello-cloudbuild-app. Puoi fare clic su una build per seguirne l'esecuzione ed esaminare i relativi log. L'ultimo passaggio di questa pipeline esegue il push del nuovo manifest al repository hello-cloudbuild-env, attivando la pipeline di distribuzione continua.

  4. Esamina la build di distribuzione continua.

    Vai a Cloud Build

    Vengono visualizzate le build eseguite e completate di recente per il repository hello-cloudbuild-env. Puoi fare clic su una build per seguirne l'esecuzione ed esaminare i relativi log.

Test della pipeline completa

La pipeline CI/CD completa è ora configurata. In questa sezione, dovrai eseguire il test dall'inizio alla fine.

  1. Vai alla pagina Servizi GKE.

    Vai a Servizi Google Kubernetes Engine

    L'elenco contiene un singolo servizio chiamato hello-cloudbuild creato dalla build di distribuzione continua completata di recente.

  2. Fai clic sull'endpoint per il servizio hello-cloudbuild. Viene visualizzato il messaggio "Hello World!". In assenza di un endpoint o se visualizzi un errore del bilanciatore del carico, potresti dover attendere qualche minuto per l'inizializzazione completa del bilanciatore del carico. Se necessario, fai clic su Aggiorna per aggiornare la pagina.

  3. In Cloud Shell, sostituisci "Hello World" con "Hello Cloud Build", sia nell'applicazione sia nel test delle unità.

    cd ~/kubernetes-engine-samples/management/gitops-style-delivery/
    sed -i 's/Hello World/Hello Cloud Build/g' app.py
    sed -i 's/Hello World/Hello Cloud Build/g' test_app.py
    
  4. Esegui il commit e il push della modifica in Cloud Source Repositories.

    git add app.py test_app.py
    git commit -m "Hello Cloud Build"
    git push google master
    

    Questo attiva la pipeline CI/CD completa.

  5. Dopo qualche minuto, ricarica l'applicazione nel browser. Viene visualizzato il messaggio "Hello Cloud Build!".

Testare il rollback

In questa sezione esegui il rollback alla versione dell'applicazione che visualizzava "Hello World!".

  1. Apri la console Cloud Build per il repository hello-cloudbuild-env.

    Vai a Cloud Build

  2. Fai clic sulla seconda build più recente disponibile.

  3. Fai clic su Ricostruisci.

  4. Al termine dell'esecuzione della build, ricarica l'applicazione nel browser. Viene visualizzato di nuovo "Hello World!".

Esegui la pulizia

Per evitare che al tuo account Google Cloud vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto che contiene le risorse oppure mantieni il progetto ed elimina le singole risorse.

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Eliminazione delle risorse

Se vuoi mantenere il progetto Google Cloud utilizzato in questo tutorial, elimina le singole risorse:

  1. Elimina i repository Git locali.

    cd ~
    rm -rf ~/hello-cloudbuild-app
    rm -rf ~/hello-cloudbuild-env
    
  2. Elimina i repository Git in Cloud Source Repositories.

    gcloud source repos delete hello-cloudbuild-app --quiet
    gcloud source repos delete hello-cloudbuild-env --quiet
    
  3. Elimina gli trigger di Cloud Build.

    1. Apri la pagina Trigger di Cloud Build.

      Vai ai trigger

    2. Per ogni attivatore, fai clic su Altro e poi su Elimina.

  4. Elimina il repository Docker in Artifact Registry.

    gcloud artifacts repositories delete my-repository \
        --location=us-central1
    
  5. Rimuovi l'autorizzazione concessa a Cloud Build per connettersi a GKE.

    PROJECT_NUMBER="$(gcloud projects describe ${PROJECT_ID} \
        --format='get(projectNumber)')"
    gcloud projects remove-iam-policy-binding ${PROJECT_NUMBER} \
        --member=serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
        --role=roles/container.developer
    
  6. Elimina il cluster GKE.

    gcloud container clusters delete hello-cloudbuild \
       --region us-central1
    

Passaggi successivi