Diffusion continue de type GitOps avec Cloud Build

Cette page explique comment créer un pipeline d'intégration et de diffusion continues (CI/CD) sur Google Cloud Platform en utilisant uniquement des produits hébergés et la méthodologie bien connue GitOps.

Les ingénieurs Google stockent les fichiers de configuration et de déploiement dans notre dépôt de code source principal depuis très longtemps. Cette méthodologie est décrite dans le chapitre 8 du livre Site Reliability Engineering (Beyer et. al., 2016). Kelsey Hightower en a fait la démonstration lors de la keynote Google Cloud Next '17. Le terme "Gitops" lui-même a été inventé par Weaveworks. L'un des éléments clés de GitOps est le concept des "Environnements en tant que code" : cette approche permet de décrire les déploiements de manière déclarative à l'aide de fichiers (par exemple, des manifestes Kubernetes) stockés dans un dépôt Git.

Dans ce tutoriel, vous allez créer un pipeline CI/CD qui compile automatiquement une image de conteneur à partir d'un code validé, stocke l'image dans Container Registry, met à jour un manifeste Kubernetes dans un dépôt Git, puis déploie l'application sur Google Kubernetes Engine à l'aide de ce manifeste.

Architecture du pipeline CI/CD

Ce tutoriel utilise deux dépôts Git :

  • dépôt de l'application (app) : contient le code source de l'application
  • dépôt de l'environnement (env) : contient les manifestes pour le déploiement Kubernetes

Lorsque vous déployez une modification dans le dépôt app, le pipeline Cloud Build exécute des tests, compile une image de conteneur, puis déploie cette image sur Container Registry. Après avoir déployé l'image, Cloud Build met à jour le manifeste de déploiement et le transfère vers le dépôt env. Cette opération déclenche un autre pipeline Cloud Build qui applique le manifeste au cluster GKE et, en cas de succès, le stocke dans une autre branche du dépôt env.

Nous gardons les dépôts app et env séparés, car leur utilisation et leur cycle de vie diffèrent. Les principaux utilisateurs du dépôt app sont des humains et ce dépôt est dédié à une application spécifique. Les principaux utilisateurs du dépôt env sont des systèmes automatisés (comme Cloud Build), et ce dépôt peut être partagé par plusieurs applications. Le dépôt env peut contenir plusieurs branches, chacune d'entre elles correspondant à un environnement spécifique (vous n'utiliserez que l'environnement de production dans ce tutoriel) et faisant référence à une image de conteneur spécifique, ce qui n'est pas le cas avec le dépôt app.

Une fois ce tutoriel terminé, vous disposerez d’un système dans lequel vous pourrez facilement :

  • distinguer les déploiements en échec des déploiements réussis en consultant l'historique de Cloud Build ;
  • accéder au manifeste actuellement utilisé en consultant la branche production du dépôt env ;
  • revenir à n'importe quelle version précédente en exécutant une nouvelle fois la compilation Cloud Build correspondante.

Flux du pipeline CI/CD

À propos de ce tutoriel

Ce tutoriel utilise Cloud Source Repositories pour héberger des dépôts Git, mais vous pouvez obtenir les mêmes résultats avec des produits tiers, tels que GitHub, Bitbucket ou GitLab.

Ce pipeline ne met pas en œuvre de mécanisme de validation avant le déploiement. Si vous utilisez GitHub, Bitbucket ou GitLab, vous pouvez le modifier pour qu'il utilise une requête d'extraction à cette fin.

Bien que nous recommandions Spinnaker aux équipes souhaitant mettre en œuvre des schémas de déploiement avancés (bleu-vert, analyse Canary, multicloud, etc.), ses fonctionnalités ne sont pas vraiment indispensables au succès d'une stratégie CI/CD pour les petites entreprises et les projets de moindre envergure. Dans ce tutoriel, vous découvrirez comment créer un pipeline CI/CD adapté à des applications hébergées sur GKE avec des outils simples.

Pour des raisons de simplicité, ce tutoriel utilise un seul environnement (production) dans le dépôt env, mais vous pouvez étendre le déploiement sur plusieurs environnements si nécessaire.

Coûts

Avant de commencer

  1. Sélectionnez ou créez un projet GCP.

    ACCÉDER À LA PAGE "GÉRER LES RESSOURCES"

  2. Activez la facturation pour votre projet.

    ACTIVER LA FACTURATION

  3. Ouvrez Cloud Shell pour exécuter les commandes répertoriées dans ce tutoriel.

    ACCÉDER À CLOUD SHELL

  4. Si la commande gcloud config get-value project ne renvoie pas l'ID du projet que vous venez de sélectionner, configurez Cloud Shell pour qu'il utilise votre projet.

    gcloud config set project [PROJECT_ID]
    
  5. Dans Cloud Shell, activez les API nécessaires.

    gcloud services enable container.googleapis.com \
        cloudbuild.googleapis.com \
        sourcerepo.googleapis.com \
        containeranalysis.googleapis.com
    
  6. Dans Cloud Shell, créez un cluster GKE que vous utiliserez pour déployer l'exemple d'application de ce tutoriel.

    gcloud container clusters create hello-cloudbuild \
        --num-nodes 1 --zone us-central1-b
    
  7. Si vous n'avez jamais utilisé Git dans Cloud Shell, configurez-le avec votre nom et votre adresse e-mail. Git les utilisera pour vous identifier en tant qu'auteur des commits que vous créerez dans Cloud Shell.

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

Une fois que vous avez terminé ce tutoriel, vous pouvez éviter de continuer à payer des frais en supprimant les ressources que vous avez créées. Pour en savoir plus, consultez la section Effectuer un nettoyage.

Créer les dépôts Git dans Cloud Source Repositories

Dans cette section, vous allez créer les deux dépôts Git (app et env) utilisés dans ce tutoriel, puis initialiser l'application avec un exemple de code.

  1. Dans Cloud Shell, créez les deux dépôts Git.

    gcloud source repos create hello-cloudbuild-app
    gcloud source repos create hello-cloudbuild-env
    
  2. Clonez l'exemple de code depuis GitHub.

    cd ~
    git clone https://github.com/GoogleCloudPlatform/gke-gitops-tutorial-cloudbuild \
        hello-cloudbuild-app
    
  3. Configurez Cloud Source Repositories en tant que dépôt distant.

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

Le code que vous venez de cloner contient une simple application "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)

Créer une image de conteneur avec Cloud Build

Le code que vous avez cloné contient déjà le fichier Dockerfile suivant :

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

Vous pouvez utiliser ce fichier Dockerfile pour créer une image de conteneur avec Cloud Build, puis stocker cette image dans Container Registry.

  1. Dans Cloud Shell, créez une compilation Cloud Build basée sur le dernier commit à l'aide de la commande suivante :

    cd ~/hello-cloudbuild-app
    COMMIT_ID="$(git rev-parse --short=7 HEAD)"
    gcloud builds submit --tag="gcr.io/${PROJECT_ID}/hello-cloudbuild:${COMMIT_ID}" .
    

    Cloud Build diffuse les journaux générés par la création de l'image de conteneur sur votre terminal lorsque vous exécutez cette commande.

  2. Une fois la compilation achevée, vérifiez que votre nouvelle image de conteneur est bien disponible dans Container Registry.

    ACCÉDER À CONTAINER REGISTRY

    image hello-cloudbuild dans Container Registry

Créer le pipeline d'intégration continue

Dans cette section, vous allez configurer Cloud Build afin qu'il exécute automatiquement un petit test unitaire, qu'il génère l'image de conteneur, puis qu'il déploie cette dernière sur Container Registry. L'envoi d'un nouveau commit vers Cloud Source Repositories déclenche automatiquement ce pipeline. Le fichier cloudbuild.yaml (déjà inclus dans le code) correspond à la configuration du pipeline.

steps:
# This step runs the unit tests on the app
- name: 'python:3.7-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'
  - 'gcr.io/$PROJECT_ID/hello-cloudbuild:$SHORT_SHA'
  - '.'

# This step pushes the image to Container Registry
# The PROJECT_ID and SHORT_SHA variables are automatically
# replaced by Cloud Build.
- name: 'gcr.io/cloud-builders/docker'
  id: Push
  args:
  - 'push'
  - 'gcr.io/$PROJECT_ID/hello-cloudbuild:$SHORT_SHA'
  1. Ouvrez la page Déclencheurs de Cloud Build.

    ACCÉDER À LA PAGE "DÉCLENCHEURS"

  2. Cliquez sur Créer un déclencheur.

  3. Sélectionnez la source "Cloud Source Repositories", puis cliquez sur Continuer.

  4. Sélectionnez le dépôt hello-cloudbuild-app, puis cliquez sur Continuer.

  5. Dans l'écran "Paramètres du déclencheur", saisissez les paramètres suivants :

    • Nom : hello-cloudbuild
    • Branche (expression régulière) : master
    • Configuration de la compilation : cloudbuild.yaml
  6. Cliquez sur Créer un déclencheur.

    Conseil : Si vous devez créer des déclencheurs de compilation pour de nombreux projets, vous pouvez utiliser l'API Build Triggers.

  7. Dans Cloud Shell, transférez le code de l'application vers Cloud Source Repositories pour déclencher le pipeline d'intégration continue (CI) dans Cloud Build.

    cd ~/hello-cloudbuild-app
    git push google master
    
  8. Ouvrez la console Cloud Build.

    ACCÉDER À CLOUD BUILD

    Vous devriez constater qu'une compilation est en cours d’exécution ou s’est achevée récemment. Vous pouvez cliquer sur le nom de la compilation pour suivre son exécution et examiner ses journaux.

Créer le pipeline de diffusion continue

Cloud Build est également utilisé pour le pipeline de diffusion continue. Le pipeline s'exécute chaque fois qu'un commit (validation) est déployé sur la branche candidate du dépôt hello-cloudbuild-env. Le pipeline applique la nouvelle version du manifeste au cluster Kubernetes et, en cas de succès, copie le manifeste dans la branche production. Ce processus a les propriétés suivantes :

  • La branche candidate correspond à l'historique des tentatives de déploiement.
  • La branche production correspond à l'historique des déploiements réussis.
  • Dans Cloud Build, une vue permet d'identifier les déploiements réussis et en échec.
  • Vous pouvez restaurer n'importe quel déploiement antérieur (opération de "rollback") en exécutant à nouveau la compilation correspondante dans Cloud Build. Lors d'un rollback, la branche production est également mise à jour afin de refléter fidèlement l'historique des déploiements.

Dans cette étape, vous allez modifier le pipeline d'intégration continue pour mettre à jour la branche candidate du dépôt hello-cloudbuild-env, ce qui entraînera le déclenchement du pipeline de diffusion continue.

Autoriser Cloud Build à accéder à GKE

Pour pouvoir déployer l'application dans votre cluster Kubernetes, Cloud Build a besoin du rôle IAM "Développeur de conteneur". Dans Cloud Shell, exécutez la commande suivante :

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

Initialiser le dépôt hello-cloudbuild-env

Vous devez initialiser le dépôt hello-cloudbuild-env avec deux branches (production et candidate) et un fichier de configuration Cloud Build décrivant le processus de déploiement.

  1. Dans Cloud Shell, clonez le dépôt hello-cloudbuild-env, puis créez la branche production. Pour l'instant, le dépôt ne contient aucun fichier.

    cd ~
    gcloud source repos clone hello-cloudbuild-env
    cd ~/hello-cloudbuild-env
    git checkout -b production
    
  2. Copiez le fichier cloudbuild-delivery.yaml disponible dans le dépôt hello-cloudbuild-app, puis validez la modification.

    cd ~/hello-cloudbuild-env
    cp ~/hello-cloudbuild-app/cloudbuild-delivery.yaml ~/hello-cloudbuild-env/cloudbuild.yaml
    git add .
    git commit -m "Create cloudbuild.yaml for deployment"
    

    Le fichier cloudbuild-delivery.yaml décrit le processus de déploiement qui doit être exécuté dans Cloud Build. Ce processus comporte deux étapes :

    1. Cloud Build applique le manifeste sur le cluster GKE.

    2. En cas de succès, Cloud Build copie le manifeste sur la branche 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_ZONE=us-central1-b'
      - '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. Créez une branche candidate, puis transférez les deux branches vers Cloud Source Repositories pour qu'elles soient accessibles.

    git checkout -b candidate
    git push origin production
    git push origin candidate
    
  4. Accordez le rôle IAM "Rédacteur de dépôt source" au compte de service Cloud Build pour le dépôt 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
    

Créer le déclencheur pour le pipeline de diffusion continue

Dans cette section, vous allez configurer Cloud Build pour qu'il soit déclenché par un déploiement vers la branche candidate du dépôt hello-cloudbuild-env.

  1. Ouvrez la page Déclencheurs de Cloud Build.

    ACCÉDER À LA PAGE "DÉCLENCHEURS"

  2. Cliquez sur Ajouter un déclencheur.

  3. Sélectionnez la source "Cloud Source Repositories", puis cliquez sur Continuer.

  4. Sélectionnez le dépôt hello-cloudbuild-env, puis cliquez sur Continuer.

  5. Dans l'écran "Paramètres du déclencheur", saisissez les paramètres suivants :

    • Nom : hello-cloudbuild-deploy
    • Branche (expression régulière) : candidate
    • Configuration de la compilation : cloudbuild.yaml
  6. Cliquez sur Créer un déclencheur.

Modifier le pipeline d'intégration continue afin de déclencher le pipeline de diffusion continue

Dans cette section, vous allez ajouter certaines étapes au pipeline d'intégration continue pour qu'il génère une nouvelle version du manifeste Kubernetes, puis qu'il la déploie dans le dépôt hello-cloudbuild-env afin de déclencher le pipeline de diffusion continue.

  1. Copiez la version "étendue" du fichier cloudbuild.yaml pour le dépôt app.

    cd ~/hello-cloudbuild-app
    cp cloudbuild-trigger-cd.yaml cloudbuild.yaml
    

    Le fichier cloudbuild-trigger-cd.yaml est une version étendue du fichier cloudbuild.yaml. Cette version étendue ajoute les étapes mentionnées ci-dessous, qui permettent de générer le nouveau manifeste Kubernetes et de déclencher le pipeline de diffusion continue.

    # 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 gcr.io/${PROJECT_ID}/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. Validez les modifications et déployez-les sur Cloud Source Repositories.

    cd ~/hello-cloudbuild-app
    git add cloudbuild.yaml
    git commit -m "Trigger CD pipeline"
    git push google master
    

    Cette opération déclenche le pipeline d'intégration continue dans Cloud Build.

  3. Examinez la compilation de l'intégration continue.

    ACCÉDER À CLOUD BUILD

    Vous devriez constater qu'une compilation est en cours d’exécution ou s’est achevée récemment pour le dépôt hello-cloudbuild-app. Vous pouvez cliquer sur le nom de la compilation pour suivre son exécution et examiner ses journaux. La dernière étape de ce pipeline consiste à déployer le nouveau manifeste sur le dépôt hello-cloudbuild-env, ce qui entraîne le déclenchement du pipeline de diffusion continue.

  4. Examinez la compilation de la diffusion continue.

    ACCÉDER À CLOUD BUILD

    Vous devriez constater qu'une compilation est en cours d’exécution ou s’est achevée récemment pour le dépôt hello-cloudbuild-env. Vous pouvez cliquer sur le nom de la compilation pour suivre son exécution et examiner ses journaux.

Tester le pipeline complet

Le pipeline CI/CD complet est maintenant configuré. Dans cette section, vous allez le tester de bout en bout.

  1. Accédez à la page des "Services GKE".

    ACCÉDER AUX SERVICES GOOGLE KUBERNETES ENGINE

    La liste ne doit contenir qu'un seul service : hello-cloudbuild. Ce service a été créé par la "compilation de diffusion continue" qui vient de s'exécuter.

  2. Cliquez sur le point de terminaison associé au service hello-cloudbuild. Vous devriez voir la mention "Hello World!". Si le point de terminaison n'apparaît pas ou si vous constatez une erreur de l'équilibreur de charge, patientez quelques minutes pour laisser à l'équilibreur de charge le temps de terminer son initialisation. Si nécessaire, cliquez sur Actualiser pour mettre à jour la page.

  3. Dans Cloud Shell, remplacez "Hello World" par "Hello Cloud Build" (dans l'application comme dans le test unitaire).

    cd ~/hello-cloudbuild-app
    sed -i 's/Hello World/Hello Cloud Build/g' app.py
    sed -i 's/Hello World/Hello Cloud Build/g' test_app.py
    
  4. Validez la modification et déployez-la sur Cloud Source Repositories.

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

    Cette opération déclenche le pipeline CI/CD complet.

  5. Attendez quelques minutes, puis rechargez l'application dans votre navigateur. Vous devriez maintenant voir la mention "Hello Cloud Build!".

Tester le rollback

Dans cette section, vous allez restaurer la version de l'application qui affiche la mention "Hello World!".

  1. Ouvrez la console Cloud Build pour le dépôt hello-cloudbuild-env.

    ACCÉDER À CLOUD BUILD

  2. Cliquez sur la deuxième build (compilation) la plus récente disponible.

  3. Cliquez sur Recompiler.

  4. Une fois la compilation terminée, rechargez l'application dans votre navigateur. Vous devriez maintenant voir à nouveau la mention "Hello World!".

Nettoyer

Pour éviter que les ressources utilisées dans ce tutoriel soient facturées sur votre compte Google Cloud Platform :

  1. Dans la console GCP, accédez à la page "Projets".

    Accéder à la page Projets

  2. Dans la liste des projets, sélectionnez celui que vous souhaitez supprimer, puis cliquez sur Supprimer.
  3. Dans la boîte de dialogue, saisissez l'ID du projet, puis cliquez sur Arrêter pour supprimer le projet.

Supprimer les ressources

Si vous souhaitez conserver le projet GCP que vous avez utilisé dans ce tutoriel, supprimez les différentes ressources :

  1. Supprimez les dépôts Git locaux.

    cd ~
    rm -rf ~/hello-cloudbuild-app
    rm -rf ~/hello-cloudbuild-env
    
  2. Supprimez les dépôts Git dans Cloud Source Repositories

    gcloud source repos delete hello-cloudbuild-app --quiet
    gcloud source repos delete hello-cloudbuild-env --quiet
    
  3. Supprimez les déclencheurs Cloud Build.

    1. Ouvrez la page Déclencheurs de Cloud Build.

      ACCÉDER À LA PAGE "DÉCLENCHEURS"

    2. Pour chaque déclencheur, cliquez sur les trois points verticaux situés à droite du nom du déclencheur, puis cliquez sur Supprimer.

  4. Supprimez les images dans Container Registry.

    gcloud beta container images list-tags \
        gcr.io/${PROJECT_ID}/hello-cloudbuild \
        --format="value(tags)" | \
        xargs -I {} gcloud beta container images delete \
        --force-delete-tags --quiet \
        gcr.io/${PROJECT_ID}/hello-cloudbuild:{}
    
  5. Supprimez l'autorisation accordée à Cloud Build pour la connexion à 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. Supprimez le cluster GKE.

    gcloud container clusters delete hello-cloudbuild \
        --zone us-central1-b
    

Étape suivante

Cette page vous a-t-elle été utile ? Évaluez-la :

Envoyer des commentaires concernant…

Tutoriels Kubernetes Engine