Automatiser l'optimisation des coûts avec Cloud Functions, Cloud Scheduler et Cloud Monitoring


Ce document vous explique comment utiliser Cloud Functions pour identifier et nettoyer les ressources cloud gaspillées, planifier des fonctions pour s'exécuter avec Cloud Scheduler, et utiliser les règles d'alerte Cloud Monitoring pour les exécuter en fonction de l'utilisation observée. Ce document est destiné aux développeurs, aux ingénieurs SRE, aux architectes cloud et aux administrateurs d'infrastructure cloud qui recherchent une approche systématique et automatisée pour identifier et réduire les dépenses inutiles liées au cloud.

Dans ce document, nous partons du principe que vous connaissez les éléments suivants :

Objectifs

  • Supprimer les adresses IP inutilisées : sur Google Cloud, les adresses IP statiques sont des ressources gratuites lorsqu'elles sont associées à un équilibreur de charge ou à une instance de machine virtuelle (VM). Lorsqu'une adresse IP statique est réservée, mais non utilisée, elle fait l'objet d'une facturation horaire. Dans les applications qui dépendent fortement d'adresses IP statiques et du provisionnement dynamique à grande échelle, ce gaspillage peut devenir important au fil du temps.
  • Supprimer les disques persistants orphelins ou inutilisés : les disques persistants sont inutilisés ou orphelins s'ils ont été créés sans être associés à une VM, ou si une machine possède plusieurs disques et qu'un ou plusieurs disques sont dissociés.
  • Migrer vers des classes de stockage plus économiques : Google Cloud propose plusieurs classes de stockage d'objets. Utilisez la classe qui correspond le mieux à vos besoins.

Architecture

Le schéma suivant décrit la première partie du déploiement, dans laquelle vous programmez une fonction Cloud pour identifier et nettoyer les adresses IP inutilisées.

Architecture d'une fonction Cloud qui identifie et nettoie les adresses IP inutilisées.

Le premier exemple couvre les étapes suivantes :

  • Créer une VM Compute Engine avec une adresse IP externe statique et une autre adresse IP externe statique inutilisée.
  • Déployer une fonction Cloud pour identifier les adresses inutilisées.
  • Créer une tâche Cloud Scheduler pour programmer l'exécution de la fonction à l'aide d'un déclencheur HTTP.

Dans le schéma suivant, vous programmez une fonction Cloud pour identifier et nettoyer les disques persistants non associés et orphelins.

Architecture d'une fonction Cloud qui identifie et nettoie les disques persistants inutilisés.

Le deuxième exemple couvre les étapes suivantes :

  • Créer une VM Compute Engine avec deux disques persistants et un disque persistant dissocié distinct. L'un des disques est orphelin car il est dissocié de la VM.
  • Déployer une fonction Cloud pour identifier les disques persistants non associés et orphelins.
  • Créer une tâche Cloud Scheduler pour programmer l'exécution de la fonction Cloud à l'aide d'un déclencheur HTTP.

Dans le schéma suivant, vous allez déclencher une fonction Cloud pour migrer un bucket de stockage vers une classe de stockage plus économique avec une règle d'alerte Monitoring.

Architecture d'une fonction Cloud qui migre un bucket de stockage.

Le troisième exemple couvre les étapes suivantes :

  • Créer deux buckets de stockage, ajouter un fichier au bucket actif et y générer du trafic.
  • Créer un tableau de bord Monitoring pour consulter l'utilisation du bucket.
  • Déployer une fonction Cloud pour migrer le bucket inactif vers une classe de stockage plus économique.
  • Déclencher la fonction à l'aide d'une charge utile dont le rôle est de simuler une notification reçue d'une règle d'alerte Monitoring.

Coûts

Dans ce document, vous utilisez les composants facturables suivants de Google Cloud :

Obtenez une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût. Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai gratuit.

Une fois que vous avez terminé les tâches décrites dans ce document, 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.

Avant de commencer

  1. Connectez-vous à votre compte Google Cloud. Si vous débutez sur Google Cloud, créez un compte pour évaluer les performances de nos produits en conditions réelles. Les nouveaux clients bénéficient également de 300 $ de crédits gratuits pour exécuter, tester et déployer des charges de travail.
  2. Dans Google Cloud Console, sur la page de sélection du projet, sélectionnez ou créez un projet Google Cloud.

    Accéder au sélecteur de projet

  3. Vérifiez que la facturation est activée pour votre projet Google Cloud.

  4. Activer les API Compute Engine, Cloud Functions, and Cloud Storage.

    Activer les API

  5. Dans Google Cloud Console, sur la page de sélection du projet, sélectionnez ou créez un projet Google Cloud.

    Accéder au sélecteur de projet

  6. Vérifiez que la facturation est activée pour votre projet Google Cloud.

  7. Activer les API Compute Engine, Cloud Functions, and Cloud Storage.

    Activer les API

  8. Dans la console Google Cloud, activez Cloud Shell.

    Activer Cloud Shell

    En bas de la fenêtre de la console Google Cloud, une session Cloud Shell démarre et affiche une invite de ligne de commande. Cloud Shell est un environnement shell dans lequel Google Cloud CLI est déjà installé, et dans lequel des valeurs sont déjà définies pour votre projet actuel. L'initialisation de la session peut prendre quelques secondes.

  9. Vous exécutez toutes les commandes de ce document depuis Cloud Shell.

Configurer votre environnement

Dans cette section, vous allez configurer l'infrastructure et les identités requises pour cette architecture.

  1. Dans Cloud Shell, clonez le dépôt et accédez au répertoire gcf-automated-resource-cleanup :

    git clone https://github.com/GoogleCloudPlatform/gcf-automated-resource-cleanup.git && cd gcf-automated-resource-cleanup/
    
  2. Définissez les variables d'environnement et définissez le dossier du dépôt comme le dossier $WORKDIR, dans lequel vous exécutez toutes les commandes :

    export PROJECT_ID=$(gcloud config list \
        --format 'value(core.project)' 2>/dev/null)
        WORKDIR=$(pwd)
    
  3. Installez Apache Bench, un outil de génération de charge Open Source :

    sudo apt-get install apache2-utils
    

Nettoyer les adresses IP inutilisées

Dans cette section, vous allez effectuer les étapes suivantes :

  • Créer deux adresses IP statiques
  • Créer une VM qui utilise une adresse IP statique
  • Examiner le code de la fonction Cloud
  • Déployer la fonction Cloud
  • Tester la fonction Cloud à l'aide des tâches Cloud Scheduler

Créer des adresses IP

  1. Dans Cloud Shell, accédez au répertoire unused-ip :

    cd $WORKDIR/unused-ip
    
  2. Exportez les noms des adresses IP en tant que variables :

    export USED_IP=used-ip-address
    export UNUSED_IP=unused-ip-address
    
  3. Créez deux adresses IP statiques :

    gcloud compute addresses create $USED_IP \
        --project=$PROJECT_ID --region=us-central1
    gcloud compute addresses create $UNUSED_IP \
        --project=$PROJECT_ID --region=us-central1
    

    Cet exemple utilise la région us-central1, mais vous pouvez choisir une autre région et y faire référence tout au long de ce document.

  4. Vérifiez que les deux adresses ont été créées :

    gcloud compute addresses list --filter="region:(us-central1)"
    

    Dans la sortie, l'état RESERVED signifie que les adresses IP ne sont pas utilisées :

    NAME               ADDRESS/RANGE  TYPE      REGION       SUBNET  STATUS
    unused-ip-address  35.232.144.85  EXTERNAL  us-central1          RESERVED
    used-ip-address    104.197.56.87  EXTERNAL  us-central1          RESERVED
    
  5. Définissez l'adresse IP utilisée en tant que variable d'environnement :

    export USED_IP_ADDRESS=$(gcloud compute addresses describe $USED_IP \
        --region=us-central1 --format=json | jq -r '.address')
    

Créer une VM

  1. Dans Cloud Shell, créez une instance :

    gcloud compute instances create static-ip-instance \
        --zone=us-central1-a \
        --machine-type=n1-standard-1 \
        --subnet=default \
        --address=$USED_IP_ADDRESS
    
  2. Vérifiez que l'une des adresses IP est maintenant utilisée :

    gcloud compute addresses list --filter="region:(us-central1)"
    

    Le résultat ressemble à ce qui suit :

    NAME               ADDRESS/RANGE  TYPE      REGION       SUBNET  STATUS
    unused-ip-address  35.232.144.85  EXTERNAL  us-central1          RESERVED
    used-ip-address    104.197.56.87  EXTERNAL  us-central1          IN_USE
    

Examiner le code de la fonction Cloud

  • Dans Cloud Shell, affichez la section principale du code :

    cat $WORKDIR/unused-ip/function.js | grep "const compute" -A 31
    

    Voici le résultat :

    const compute = new Compute();
    compute.getAddresses(function(err, addresses){ // gets all addresses across regions
         if(err){
             console.log("there was an error: " + err);
         }
         if (addresses == null) {
             console.log("no addresses found");
             return;
         }
         console.log("there are " + addresses.length + " addresses");
    
         // iterate through addresses
         for (let item of addresses){
    
              // get metadata for each address
              item.getMetadata(function(err, metadata, apiResponse) {
    
                  // if the address is not used AND if it's at least ageToDelete days old:
                  if ((metadata.status=='RESERVED') & (calculateAge(metadata.creationTimestamp) >= ageToDelete)){
                      // delete address
                      item.delete(function(err, operation, apiResponse2){
                          if (err) {
                              console.log("could not delete address: " + err);
                          }
                      })
                  }
              })
          }
           // return number of addresses evaluated
          res.send("there are " + addresses.length + " total addresses");
      });
    }
    

    Dans l'exemple de code précédent, prêtez attention aux éléments suivants :

    • compute.getAddresses(function(err, addresses){ // gets all addresses across regions
      

      utilise la méthode getAddresses pour récupérer les adresses IP de toutes les régions du projet.

    • // get metadata for each address
      item.getMetadata(function(err, metadata, apiResponse) {
         // if the address is not used:
             if (metadata.status=='RESERVED'){
      

      récupère les métadonnées de chaque adresse IP et vérifie leur champ STATUS.

    • if ((metadata.status=='RESERVED') &
      (calculateAge(metadata.creationTimestamp) >= ageToDelete)){
      

      vérifie si l'adresse IP est utilisée, calcule son âge avec une fonction d'aide, puis le compare à une constante (définie sur 0 pour les besoins de l'exemple).

    • // delete address
      item.delete(function(err, operation, apiResponse2){
      

      supprime l'adresse IP.

Déployer la fonction Cloud

  1. Dans Cloud Shell, déployez la fonction Cloud :

    gcloud functions deploy unused_ip_function --trigger-http --runtime=nodejs8
    
  2. Définissez l'URL du déclencheur en tant que variable d'environnement :

    export FUNCTION_URL=$(gcloud functions describe unused_ip_function \
        --format=json | jq -r '.httpsTrigger.url')
    

Planifier et tester la fonction Cloud

  1. Dans Cloud Shell, créez une tâche Cloud Scheduler permettant d'exécuter la fonction Cloud à 2h00 du matin tous les jours :

    gcloud scheduler jobs create http unused-ip-job \
        --schedule="* 2 * * *" \
        --uri=$FUNCTION_URL
    
  2. Testez la tâche par déclenchement manuel :

    gcloud scheduler jobs run unused-ip-job
    
  3. Vérifiez que l'adresse IP inutilisée a été supprimée :

    gcloud compute addresses list --filter="region:(us-central1)"
    

    Le résultat ressemble à ce qui suit :

    NAME             ADDRESS/RANGE  TYPE      REGION       SUBNET  STATUS
    used-ip-address  104.197.56.87  EXTERNAL  us-central1          IN_USE
    

Nettoyer les disques persistants inutilisés et orphelins

Dans cette section, vous allez effectuer les étapes suivantes :

  • Créer deux disques persistants
  • Créer une VM qui utilise l'un de ces disques
  • Dissocier le disque de la VM
  • Examiner le code de la fonction Cloud
  • Déployer la fonction Cloud
  • Tester la fonction Cloud à l'aide des tâches Cloud Scheduler

Créer des disques persistants

  1. Dans Cloud Shell, accédez au répertoire unattached-pd :

    cd $WORKDIR/unattached-pd
    
  2. Exportez les noms des disques en tant que variables d'environnement :

    export ORPHANED_DISK=orphaned-disk
    export UNUSED_DISK=unused-disk
    
  3. Créez les deux disques :

    gcloud beta compute disks create $ORPHANED_DISK \
       --project=$PROJECT_ID \
       --type=pd-standard \
       --size=500GB \
       --zone=us-central1-a
    gcloud beta compute disks create $UNUSED_DISK \
        --project=$PROJECT_ID \
        --type=pd-standard \
        --size=500GB \
        --zone=us-central1-a
    
  4. Vérifiez que les deux disques ont été créés :

    gcloud compute disks list
    

    Voici le résultat :

    NAME                LOCATION       LOCATION_SCOPE SIZE_GB TYPE         STATUS
    orphaned-disk       us-central1-a  zone           500     pd-standard  READY
    static-ip-instance  us-central1-a  zone           10      pd-standard  READY
    unused-disk         us-central1-a  zone           500     pd-standard  READY
    

Créer une VM et inspecter les disques

  1. Dans Cloud Shell, créez l'instance :

    gcloud compute instances create disk-instance \
        --zone=us-central1-a \
        --machine-type=n1-standard-1 \
        --disk=name=$ORPHANED_DISK,device-name=$ORPHANED_DISK,mode=rw,boot=no
    
  2. Inspectez le disque qui a été associé à la VM :

    gcloud compute disks describe $ORPHANED_DISK \
        --zone=us-central1-a \
        --format=json | jq
    

    Le résultat ressemble à ce qui suit :

    {
      "creationTimestamp": "2019-06-12T12:21:25.546-07:00",
      "id": "7617542552306904666",
      "kind": "compute#disk",
      "labelFingerprint": "42WmSpB8rSM=",
      "lastAttachTimestamp": "2019-06-12T12:24:53.989-07:00",
      "name": "orphaned-disk",
      "physicalBlockSizeBytes": "4096",
      "selfLink": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/disks/orphaned-disk",
      "sizeGb": "500",
      "status": "READY",
      "type": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/diskTypes/pd-standard",
      "users": [
        "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/instances/disk-instance"
      ],
      "zone": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a"
    }
    

    Dans l'exemple de code précédent, prêtez attention aux éléments suivants :

    • users identifie la VM à laquelle le disque est associé.
    • lastAttachTimestamp précise l'horodatage correspondant à la dernière fois que le disque a été associé à une VM.
  3. Inspectez le disque qui n'a pas été associé à une VM :

    gcloud compute disks describe $UNUSED_DISK \
        --zone=us-central1-a \
        --format=json | jq
    

    Le résultat ressemble à ce qui suit :

    {
      "creationTimestamp": "2019-06-12T12:21:30.905-07:00",
      "id": "1313096191791918677",
      "kind": "compute#disk",
      "labelFingerprint": "42WmSpB8rSM=",
      "name": "unused-disk",
      "physicalBlockSizeBytes": "4096",
      "selfLink": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/disks/unused-disk",
      "sizeGb": "500",
      "status": "READY",
      "type": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/diskTypes/pd-standard",
      "zone": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a"
    }
    

    Dans l'extrait de code précédent, les éléments suivants sont importants :

    • Le disque ne comporte aucune entrée users car il n'est pas utilisé par une VM actuellement.
    • Le disque ne comporte aucune entrée lastAttachedTimestamp car il n'a jamais été utilisé.
  4. Dissociez le disque persistant orphelin de la VM :

    gcloud compute instances detach-disk disk-instance \
        --device-name=$ORPHANED_DISK \
        --zone=us-central1-a
    
  5. Inspectez le disque orphelin :

    gcloud compute disks describe $ORPHANED_DISK \
        --zone=us-central1-a \
        --format=json | jq
    

    Le résultat ressemble à ce qui suit :

    {
      "creationTimestamp": "2019-06-12T12:21:25.546-07:00",
      "id": "7617542552306904666",
      "kind": "compute#disk",
      "labelFingerprint": "42WmSpB8rSM=",
      "lastAttachTimestamp": "2019-06-12T12:24:53.989-07:00",
      "lastDetachTimestamp": "2019-06-12T12:34:56.040-07:00",
      "name": "orphaned-disk",
      "physicalBlockSizeBytes": "4096",
      "selfLink": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/disks/orphaned-disk",
      "sizeGb": "500",
      "status": "READY",
      "type": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a/diskTypes/pd-standard",
      "zone": "https://www.googleapis.com/compute/v1/projects/automating-cost-optimization/zones/us-central1-a"
    }
    

    Dans l'extrait de code précédent, les éléments suivants sont importants :

    • Le disque ne comporte aucune entrée users car il n'est pas utilisé actuellement.
    • L'entrée lastDetachTimestamp s'affiche maintenant, indiquant quand le disque a été dissocié d'une VM, c'est-à-dire quand il a été utilisé pour la dernière fois.
    • Le champ lastAttachTimestamp est toujours présent.

Examiner le code de la fonction Cloud

  1. Dans Cloud Shell, affichez la section du code qui récupère tous les disques persistants du projet :

    cat $WORKDIR/unattached-pd/main.py | grep "(request)" -A 12
    

    Voici le résultat :

    def delete_unattached_pds(request):
        # get list of disks and iterate through it:
        disksRequest = compute.disks().aggregatedList(project=project)
        while disksRequest is not None:
            diskResponse = disksRequest.execute()
            for name, disks_scoped_list in diskResponse['items'].items():
                if disks_scoped_list.get('warning') is None:
                    # got disks
                    for disk in disks_scoped_list['disks']: # iterate through disks
                        diskName = disk['name']
                        diskZone = str((disk['zone'])).rsplit('/',1)[1]
                        print (diskName)
                        print (diskZone)
    

    La fonction utilise la méthode aggregatedList pour obtenir tous les disques persistants du projet Google Cloud où elle est exécutée, puis effectue une itération sur chacun des disques.

  2. Affichez la section du code qui vérifie que le champ lastAttachTimestamp existe et qui supprime le disque si ce n'est pas le cas :

    cat $WORKDIR/unattached-pd/main.py | grep "handle never" -A 11
    

    Voici le résultat :

    # handle never attached disk - delete it
    # lastAttachedTimestamp is not present
    if disk.get("lastAttachTimestamp") is None:
           print ("disk " + diskName + " was never attached - deleting")
           deleteRequest = compute.disks().delete(project=project,
                  zone=diskZone,
                  disk=diskName)
           deleteResponse = deleteRequest.execute()
           waitForZoneOperation(deleteResponse, project, diskZone)
           print ("disk " + diskName + " was deleted")
           Continue
    

    Cette section supprime le disque si lastAttachTimestamp n'existe pas, ce qui signifie que le disque n'a jamais été utilisé.

  3. Affichez la section du code qui calcule l'âge du disque s'il est orphelin, puis crée un instantané et supprime le disque :

    cat $WORKDIR/unattached-pd/main.py | grep "handle detached" -A 32
    

    Voici le résultat :

    # handle detached disk - snapshot and delete
    # lastAttachTimestamp is present AND users is not present AND it meets the age criterium
    if disk.get("users") is None \
        and disk.get("lastDetachTimestamp") is not None \
        and diskAge(disk['lastDetachTimestamp'])>=deleteAge:
    
        print ("disk " + diskName + " has no users and has been detached")
        print ("disk meets age criteria for deletion")
    
        # take a snapshot
        snapShotName = diskName + str(int(time.time()))
        print ("taking snapshot: " + snapShotName)
        snapshotBody = {
            "name": snapShotName
        }
        snapshotRequest = compute.disks().createSnapshot(project=project,
             zone=diskZone,
             disk=diskName,
             body=snapshotBody)
        snapshotResponse = snapshotRequest.execute()
        waitForZoneOperation(snapshotResponse, project, diskZone)
        print ("snapshot completed")
    
        # delete the disk
        print ("deleting disk " + diskName)
        deleteRequest = compute.disks().delete(project=project,
            zone=diskZone,
            disk=diskName)
        deleteResponse = deleteRequest.execute()
        waitForZoneOperation(deleteResponse, project, diskZone)
        print ("disk " + diskName + " was deleted")
        continue
    

    Cette section de code est utilisée lorsque users est répertorié et que lastDetachTimestamp s'affiche, ce qui signifie que le disque n'est pas utilisé actuellement, mais qu'il l'a été à un moment donné. Dans ce cas, la fonction Cloud crée un instantané du disque pour conserver les données, puis supprime le disque.

Déployer la fonction Cloud

  1. Dans Cloud Shell, déployez la fonction Cloud :

    gcloud functions deploy delete_unattached_pds \
        --trigger-http --runtime=python37
    
  2. Définissez l'URL du déclencheur de la fonction Cloud en tant que variable d'environnement :

    export FUNCTION_URL=$(gcloud functions describe delete_unattached_pds \
        --format=json | jq -r '.httpsTrigger.url')
    

Planifier et tester la fonction Cloud

  1. Dans Cloud Shell, créez une tâche Cloud Scheduler permettant d'exécuter la fonction Cloud à 2h00 du matin tous les jours :

    gcloud scheduler jobs create http unattached-pd-job \
        --schedule="* 2 * * *" \
        --uri=$FUNCTION_URL
    
  2. Testez la tâche :

    gcloud scheduler jobs run unattached-pd-job
    
  3. Vérifiez que l'instantané du disque orphelin a bien été créé :

    gcloud compute snapshots list
    

    Le résultat ressemble à ce qui suit :

    NAME                     DISK_SIZE_GB  SRC_DISK                           STATUS
    orphaned-disk1560455894  500           us-central1-a/disks/orphaned-disk  READY
    
  4. Vérifiez que le disque inutilisé et le disque orphelin ont bien été supprimés :

    gcloud compute disks list
    

    Voici le résultat :

    NAME                LOCATION       LOCATION_SCOPE SIZE_GB  TYPE         STATUS
    disk-instance       us-central1-a  zone           10       pd-standard  READY
    static-ip-instance  us-central1-a  zone           10       pd-standard  READY
    

Migrer des buckets de stockage vers des classes de stockage plus économiques

Vous pouvez utiliser les règles de cycle de vie d'objets de stockage de Google Cloud pour déplacer automatiquement les objets vers d'autres classes de stockage en fonction de leurs attributs, par exemple leur date de création ou leur état actuel. Cependant, ces règles n'ont pas d'informations concernant l'accès aux objets. Vous pouvez déplacer les objets plus récents vers un stockage Nearline si ceux-ci n'ont pas été utilisés depuis un certain temps.

Dans cette section, vous allez effectuer les étapes suivantes :

  • Créer deux buckets Cloud Storage
  • Ajouter un objet à l'un des buckets
  • Configurer Monitoring pour surveiller l'accès aux objets du bucket
  • Examiner le code de la fonction Cloud qui migre les objets d'un bucket de stockage régional vers un bucket de stockage Nearline
  • Déployer la fonction Cloud
  • Tester la fonction Cloud à l'aide d'une alerte Monitoring

Créer des buckets Cloud Storage et ajouter un fichier

  1. Dans Cloud Shell, accédez au répertoire migrate-storage :

    cd $WORKDIR/migrate-storage
    
  2. Créez le bucket Cloud Storage serving-bucket qui sera utilisé ultérieurement pour modifier les classes de stockage :

    export PROJECT_ID=$(gcloud config list \
        --format 'value(core.project)' 2>/dev/null)
    gsutil mb -c regional -l us-central1 gs://${PROJECT_ID}-serving-bucket
    
  3. Rendez le bucket public :

    gsutil acl ch -u allUsers:R gs://${PROJECT_ID}-serving-bucket
    
  4. Ajoutez un fichier texte au bucket :

    gsutil cp $WORKDIR/migrate-storage/testfile.txt  \
        gs://${PROJECT_ID}-serving-bucket
    
  5. Rendez le fichier public :

    gsutil acl ch -u allUsers:R gs://${PROJECT_ID}-serving-bucket/testfile.txt
    
  6. Vérifiez que le fichier est accessible :

    curl http://storage.googleapis.com/${PROJECT_ID}-serving-bucket/testfile.txt
    

    Voici le résultat :

    this is a test
    
  7. Créez un deuxième bucket nommé idle-bucket qui ne diffuse aucune donnée :

    gsutil mb -c regional -l us-central1 gs://${PROJECT_ID}-idle-bucket
    

Configurer un espace de travail Cloud Monitoring

Dans cette section, vous allez configurer Cloud Monitoring afin de surveiller l'utilisation des buckets pour comprendre quand les objets de bucket ne sont pas utilisés. Lorsque le bucket actif n'est pas utilisé, une fonction Cloud migre le bucket de la classe de stockage régionale vers la classe de stockage Nearline.

  1. Dans Google Cloud Console, accédez à Monitoring.

    Accéder à Cloud Monitoring

  2. Cliquez sur Nouvel espace de travail, puis sur Ajouter.

    Attendez que la configuration initiale soit terminée.

Créer un tableau de bord Cloud Monitoring

  1. Dans Monitoring, accédez à Tableaux de bord, puis cliquez sur Créer un tableau de bord.

  2. Cliquez sur Add Chart (Ajouter un graphique).

  3. Dans le champ Nom, saisissez Bucket Access.

  4. Pour consulter la métrique du contenu de la requête du bucket Cloud Storage, dans le champ Find resource and metric (Rechercher la ressource et la métrique), saisissez request, puis sélectionnez la métrique Nombre de requêtes pour la ressource gcs_bucket.

  5. Pour regrouper les métriques par nom de bucket, dans la liste déroulante Grouper par, cliquez sur bucket_name.

  6. Pour filtrer par nom de méthode, saisissez ReadObject dans le champ Filtre, puis cliquez sur Appliquer.

  7. Cliquez sur Save.

  8. Dans le champ Nom, saisissez Bucket Usage.

  9. Pour vérifier que le tableau de bord est accessible, placez le curseur sur Tableaux de bord et vérifiez que le tableau de bord Bucket Usage (Utilisation du bucket) s'affiche.

    Vous avez configuré Monitoring de manière à surveiller l'accès aux objets dans vos buckets. Le graphique n'affiche aucune donnée, car le trafic vers les buckets Cloud Storage est inexistant.

Générer une charge sur le bucket actif

Maintenant que la surveillance est configurée, vous pouvez utiliser Apache Bench pour envoyer du trafic vers le bucket actif.

  1. Dans Cloud Shell, envoyez des requêtes vers l'objet du bucket actif :

    ab -n 10000 \
        http://storage.googleapis.com/$PROJECT_ID-serving-bucket/testfile.txt
    
  2. Dans la console Google Cloud, accédez à Monitoring.

    Accéder à Cloud Monitoring

  3. Pour sélectionner le tableau de bord Bucket Usage (Utilisation du bucket), placez le curseur sur Tableaux de bord puis sélectionnez Bucket Usage. Vérifiez que le trafic n'est dirigé que vers le bucket actif. La série temporelle request_count metric n'est disponible que pour le bucket actif, car le bucket inactif ne reçoit aucun trafic.

Examiner et déployer la fonction Cloud

  1. Dans Cloud Shell, faites en sorte que le code qui utilise la fonction Cloud migre un bucket de stockage vers la classe de stockage Nearline :

    cat $WORKDIR/migrate-storage/main.py | grep "migrate_storage(" -A 15
    

    Le résultat est le suivant :

    def migrate_storage(request):
        # process incoming request to get the bucket to be migrated:
        request_json = request.get_json(force=True)
        # bucket names are globally unique
        bucket_name = request_json['incident']['resource_name']
    
        # create storage client
        storage_client = storage.Client()
    
        # get bucket
        bucket = storage_client.get_bucket(bucket_name)
    
        # update storage class
        bucket.storage_class = "NEARLINE"
        bucket.patch()
    

    La fonction Cloud utilise le nom de bucket transmis dans la requête pour passer la classe de stockage en stockage Nearline.

  2. Déployez la fonction Cloud :

    gcloud functions deploy migrate_storage --trigger-http --runtime=python37
    
  3. Définissez l'URL du déclencheur en tant que variable d'environnement pour l'utiliser dans la prochaine section :

    export FUNCTION_URL=$(gcloud functions describe migrate_storage \
        --format=json | jq -r '.httpsTrigger.url')
    

Tester et valider l'automatisation des alertes

  1. Donnez un nom au bucket inactif :

    export IDLE_BUCKET_NAME=$PROJECT_ID-idle-bucket
    
  2. Envoyez une notification de test à la fonction Cloud que vous avez déployée à l'aide du fichier incident.json :

    envsubst < $WORKDIR/migrate-storage/incident.json | curl -X POST \
        -H "Content-Type: application/json" $FUNCTION_URL -d @-
    

    Le résultat est le suivant :

    OK
    

    Le résultat ne se termine pas par un retour à la ligne, il est donc immédiatement suivi par l'invite de commande.

  3. Vérifiez que le bucket inactif a été migré vers le stockage Nearline :

    gsutil defstorageclass get gs://$PROJECT_ID-idle-bucket
    

    Voici le résultat :

    gs://automating-cost-optimization-idle-bucket: NEARLINE
    

Informations spécifiques à un environnement de production

Lorsque vous automatisez les optimisations de coûts dans votre propre environnement Google Cloud, tenez compte des points suivants :

  • Considérations générales : vous devez renforcer la sécurité des fonctions Cloud pouvant modifier ou supprimer des ressources Google Cloud.
  • Identification des gaspillages : ce document présente quelques exemples de dépenses inutiles. Il existe de nombreux autres exemples qui appartiennent généralement à l'une des trois catégories suivantes :
    • Ressources surprovisionnées : ressources provisionnées pour être plus importantes que nécessaire pour une charge de travail donnée, telles que les VM avec plus de puissance de processeur et de mémoire que nécessaire.
    • Ressources inactives : ressources totalement inutilisées.
    • Ressources partiellement inactives : ressources utilisées seulement pendant les horaires d'ouverture.
  • Automatisation du nettoyage : dans ce document, un processus en plusieurs étapes avec plusieurs opérations asynchrones est nécessaire pour créer un instantané et supprimer le disque. Les autres ressources Google Cloud, telles que les adresses IP non utilisées, peuvent faire appel à des opérations synchrones.
  • Déploiement à grande échelle : dans ce document, l'ID de projet Google Cloud est défini dans le code de la fonction Cloud. Pour déployer une telle solution à grande échelle, envisagez d'utiliser les API Cloud Billing ou Cloud Resource Manager pour obtenir la liste des projets associés à un compte de facturation ou à une organisation. Transmettez ensuite ces ID de projet Google Cloud à une fonction en tant que variables. Dans ce type de configuration, vous devez ajouter le compte de service de la fonction Cloud aux projets dans lesquels il peut nettoyer ou supprimer des ressources. Nous vous recommandons d'utiliser un framework de déploiement automatisé, tel que Cloud Deployment Manager ou Terraform.
  • Automatisation des alertes : ce document explique comment utiliser une simulation de charge utile provenant d'une alerte Monitoring pour déclencher la migration de la classe de stockage. Les règles d'alerte Monitoring peuvent être évaluées sur une période maximale de 23 heures et 59 minutes. Dans un environnement de production, cette restriction peut ne pas être assez longue pour considérer un bucket inactif avant de migrer sa classe de stockage. Envisagez d'activer les journaux d'audit des accès aux données sur le bucket Cloud Storage et de créer un pipeline qui les utilise pour évaluer si un bucket a été utilisé à des fins de diffusion au cours des 30 derniers jours. Pour plus d'informations, consultez la section Comprendre les journaux d'audit et envisagez de créer un récepteur agrégé pour envoyer les journaux à Pub/Sub, ainsi qu'un pipeline Dataflow pour les traiter.

Effectuer un nettoyage

Pour éviter que les ressources utilisées lors de ce tutoriel soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et supprimez les ressources individuelles.

Supprimer le projet

  1. Dans la console Google Cloud, accédez à la page Gérer les ressources.

    Accéder à 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.

Étape suivante