Déploiement continu sur Google Kubernetes Engine (GKE) avec Cloud Build

1. Présentation

Dans cet atelier, vous allez apprendre à configurer un pipeline de livraison continue pour GKE avec Cloud Build. Cet atelier explique comment déclencher des jobs Cloud Build pour différents événements Git, ainsi qu'un modèle simple pour les versions Canary automatisées dans GKE.

Voici les étapes à suivre :

  • Créer l'application GKE
  • Automatiser les déploiements pour les branches Git
  • Automatiser les déploiements pour la branche principale Git
  • Automatiser les déploiements pour les tags Git

2. Avant de commencer

Pour ce guide de référence, vous avez besoin d'un projet Google Cloud. Vous pouvez en créer un ou sélectionner un projet existant :

  1. Sélectionnez ou créez un projet Google Cloud.

ACCÉDER À LA PAGE DE SÉLECTION DE PROJET

  1. Activez la facturation pour votre projet.

ACTIVER LA FACTURATION

3. Préparer l'environnement

  1. Créez des variables d'environnement à utiliser tout au long de ce tutoriel :
    export PROJECT_ID=$(gcloud config get-value project)
    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
    
    export ZONE=us-central1-b
    export CLUSTER=gke-progression-cluster
    export APP_NAME=myapp
    
  2. Activez les API suivantes :
    • Resource Manager
    • GKE
    • Cloud Source Repositories
    • Cloud Build
    • Container Registry
    gcloud services enable \
        cloudresourcemanager.googleapis.com \
        container.googleapis.com \
        sourcerepo.googleapis.com \
        cloudbuild.googleapis.com \
        containerregistry.googleapis.com \
        --async
    
  3. Clonez l'exemple de source et accédez au répertoire de l'atelier :
    git clone https://github.com/GoogleCloudPlatform/software-delivery-workshop.git gke-progression
    
    cd gke-progression/labs/gke-progression
    rm -rf ../../.git
    
  4. Remplacez les valeurs d'espace réservé dans l'exemple de dépôt par votre fichier PROJECT_ID : cette étape vous permet de créer des instances des différents fichiers de configuration propres à votre environnement actuel.Pour consulter un exemple des modèles mis à jour, exécutez la commande suivante.
    cat k8s/deployments/dev/frontend-dev.yaml.tmpl
    
    Effectuez la substitution de variable en exécutant la commande suivante.
    for template in $(find . -name '*.tmpl'); do envsubst '${PROJECT_ID} ${ZONE} ${CLUSTER} ${APP_NAME}' < ${template} > ${template%.*}; done
    
    Pour examiner un exemple du fichier après la substitution, exécutez la commande suivante.
    cat k8s/deployments/dev/frontend-dev.yaml
    
  5. Si vous n'avez pas encore utilisé Git dans Cloud Shell, définissez les valeurs user.name et user.email que vous souhaitez utiliser :
    git config --global user.email "YOUR_EMAIL_ADDRESS"
    git config --global user.name "YOUR_USERNAME"
    
  6. Stockez le code de l'exemple de dépôt dans Cloud Source Repositories :
    gcloud source repos create gke-progression
    git init
    git config credential.helper gcloud.sh
    git remote add gcp https://source.developers.google.com/p/$PROJECT_ID/r/gke-progression
    git branch -m main
    git add . && git commit -m "initial commit"
    git push gcp main
    
  7. Créez votre cluster GKE.
    gcloud container clusters create ${CLUSTER} \
        --project=${PROJECT_ID} \
        --zone=${ZONE}
    
  8. Accordez à Cloud Build les droits d'accès à votre cluster.Cloud Build déploiera l'application sur votre cluster GKE et aura besoin des droits d'accès pour ce faire.
    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member=serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com \
        --role=roles/container.developer
    

Votre environnement est prêt !

4. Créer votre application GKE

Dans cette section, vous allez créer et déployer l'application de production initiale que vous utiliserez tout au long de ce tutoriel.

  1. Créez l'application avec Cloud Build :
    gcloud builds submit --tag gcr.io/$PROJECT_ID/$APP_NAME:1.0.0 src/
    
  2. Déployez manuellement dans les environnements Canary et de production : créez les déploiements et les services de production et Canary à l'aide des commandes kubectl apply.
    kubectl create ns production
    kubectl apply -f k8s/deployments/prod -n production
    kubectl apply -f k8s/deployments/canary -n production
    kubectl apply -f k8s/services -n production
    
    Le service déployé ici acheminera le trafic vers les déploiements Canary et de production.
  3. Vérifiez le nombre de pods en cours d'exécution. Assurez-vous que quatre pods sont en cours d'exécution pour l'interface, dont trois pour le trafic de production et un pour les versions Canary. En d'autres termes, les modifications apportées à votre version Canary ne toucheront qu'un utilisateur sur quatre, soit 25 % des utilisateurs.
    kubectl get pods -n production -l app=$APP_NAME -l role=frontend
    
  4. Récupérez l'adresse IP externe des services de production.
    kubectl get service $APP_NAME -n production
    
    Une fois que l'équilibreur de charge a renvoyé l'adresse IP, passez à l'étape suivante.
  5. Enregistrez l'adresse IP externe pour l'utiliser ultérieurement.
    export PRODUCTION_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}"  --namespace=production services $APP_NAME)
    
  6. Examinez l'application. Vérifiez la version du service. Le message "Hello World v1.0" doit s'afficher.
    curl http://$PRODUCTION_IP
    

Félicitations ! Vous avez déployé l'application exemple. Vous allez maintenant configurer des déclencheurs pour déployer vos modifications de manière continue.

5. Automatiser les déploiements pour les branches Git

Dans cette section, vous allez configurer un déclencheur qui exécutera un job Cloud Build lors du commit d'une branche autre que main. Le fichier Cloud Build utilisé ici créera automatiquement un espace de noms et un déploiement pour toutes les branches existantes ou nouvelles, ce qui permettra aux développeurs de prévisualiser leur code avant l'intégration à la branche principale.

  1. Configurez le déclencheur : le composant clé de ce déclencheur est l'utilisation du paramètre branchName pour faire correspondre main et du paramètre invertRegex défini sur "true", qui modifie le modèle branchName pour qu'il corresponde à tout ce qui n'est pas main. Pour information, vous trouverez les lignes suivantes dans build/branch-trigger.json.
      "branchName": "main",
      "invertRegex": true
    
    De plus, les dernières lignes du fichier Cloud Build utilisé avec ce déclencheur créent un espace de noms portant le nom de la branche qui a déclenché le job, puis déploient l'application et le service dans le nouvel espace de noms. Pour information, vous trouverez les lignes suivantes dans build/branch-cloudbuild.yaml
      kubectl get ns ${BRANCH_NAME} || kubectl create ns ${BRANCH_NAME}
      kubectl apply --namespace ${BRANCH_NAME} --recursive -f k8s/deployments/dev
      kubectl apply --namespace ${BRANCH_NAME} --recursive -f k8s/services
    
    Maintenant que vous comprenez les mécanismes utilisés, créez le déclencheur avec la commande gcloud ci-dessous.
    gcloud beta builds triggers create cloud-source-repositories \
      --trigger-config build/branch-trigger.json
    
  2. Pour examiner le déclencheur, accédez à la page Déclencheurs Cloud Build dans la console.Accéder aux déclencheurs
  3. Créez une branche :
    git checkout -b new-feature-1
    
  4. Modifiez le code pour indiquer la version 1.1. Modifiez src/app.py et remplacez la réponse 1.0 par la réponse 1.1.
    @app.route('/')
    def hello_world():
        return 'Hello World v1.1'
    
  5. Validez la modification et transférez-la vers le dépôt distant :
    git add . && git commit -m "updated" && git push gcp new-feature-1
    
  6. Pour examiner la compilation en cours, accédez à la page Historique Cloud Build dans la console. Accéder aux compilations Une fois la compilation terminée, passez à l'étape suivante.
  7. Récupérez l'adresse IP externe du service de branche nouvellement déployé.
    kubectl get service $APP_NAME -n new-feature-1
    
    Une fois que l'équilibreur de charge a renvoyé l'adresse IP, passez à l'étape suivante.
  8. Enregistrez l'adresse IP externe pour l'utiliser ultérieurement.
    export BRANCH_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}"  --namespace=new-feature-1 services $APP_NAME)
    
  9. Examinez l'application. Vérifiez la version du service. Le message "Hello World v1.0" doit s'afficher.
    curl http://$BRANCH_IP
    

6. Automatiser les déploiements pour la branche principale Git

Avant de publier le code en production, il est courant de le libérer dans un petit sous-ensemble de trafic actif avant de migrer tout le trafic vers la nouvelle base de code.

Dans cette section, vous mettez en œuvre un déclencheur qui est activé lorsque le code est validé dans la branche principale. Le déclencheur déploie le déploiement Canary qui reçoit 25 % de tout le trafic actif vers la nouvelle révision.

  1. Configurez le déclencheur pour la branche principale :
    gcloud beta builds triggers create cloud-source-repositories \
      --trigger-config build/main-trigger.json
    
  2. Pour examiner le nouveau déclencheur, accédez à la page Déclencheurs Cloud Build dans la console.Accéder aux déclencheurs
  3. Fusionnez la branche avec la ligne principale et transférez-la vers le dépôt distant :
    git checkout main
    git merge new-feature-1
    git push gcp main
    
  4. Pour examiner la compilation en cours, accédez à la page Historique Cloud Build dans la console. Accéder aux compilations Une fois la compilation terminée, passez à l'étape suivante.
  5. Examiner plusieurs réponses du serveurExécutez la commande suivante et notez qu'environ 25 % des réponses affichent la nouvelle réponse Hello World v1.1.
    while true; do curl -w "\n" http://$PRODUCTION_IP; sleep 1;  done
    
    Lorsque vous êtes prêt à continuer, appuyez sur Ctrl+c pour quitter la boucle.

7. Automatiser les déploiements pour les tags Git

Une fois le déploiement Canary validé avec un petit sous-ensemble de trafic, vous déployez le déploiement sur le reste du trafic actif.

Dans cette section, vous allez configurer un déclencheur qui est activé lorsque vous créez un tag dans le dépôt. Le déclencheur ajoute le tag approprié à l'image, puis déploie les mises à jour en production, en s'assurant que 100 % du trafic accède à l'image taguée.

  1. Configurez le déclencheur de balise :
    gcloud beta builds triggers create cloud-source-repositories \
      --trigger-config build/tag-trigger.json
    
  2. Pour examiner le nouveau déclencheur, accédez à la page Déclencheurs Cloud Build dans la console.Accéder aux déclencheurs
  3. Créez un tag et transférez-le vers le dépôt distant :
    git tag 1.1
    git push gcp 1.1
    
  4. Pour examiner la compilation en cours, accédez à la page Historique Cloud Build dans la console.Accéder aux compilations
  5. Examinez plusieurs réponses du serveur. Exécutez la commande suivante et notez que 100 % des réponses affichent la nouvelle réponse "Hello World v1.1". Cela peut prendre un certain temps, car les nouveaux pods sont déployés et leur état est vérifié dans GKE.
    while true; do curl -w "\n" http://$PRODUCTION_IP; sleep 1;  done
    
    Lorsque vous êtes prêt à continuer, appuyez sur Ctrl+c pour quitter la boucle.Félicitations ! Vous avez créé des déclencheurs CI/CD dans Cloud Build pour les branches et les tags afin de déployer vos applications sur GKE.

8. Nettoyage

Supprimer le projet

  1. Dans la console Cloud, accédez à la page Gérer les ressources.
  2. Dans la liste des projets, sélectionnez le projet 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.