Exemples de réponses automatiques de contrôle des coûts

Exemple d'architecture de référence

Schéma d'un exemple d'utilisation de notifications automatisées d'alerte budgétaire pour automatiser une réponse de contrôle des coûts.
Figure 1 : illustre un exemple d'utilisation des alertes de budget pour automatiser les réponses de contrôle des coûts à l'aide de Pub/Sub pour les notifications automatisées et des fonctions Cloud Run pour automatiser une réponse.

Si vous maîtrisez les coûts et souhaitez contrôler votre environnement par rapport à votre budget, vous pouvez utiliser les notifications de budget automatisées pour automatiser votre réponse en fonction de la notification budgétaire.

Les notifications budgétaires utilisent des sujets Pub/Sub pour fournir un état en temps réel du budget Cloud Billing, en utilisant l'évolutivité, la flexibilité et la fiabilité du middleware de messagerie d'entreprise pour le cloud.

Ce document contient des exemples et des instructions détaillées pour utiliser les notifications de budget avec les fonctions Cloud Run en vue d'automatiser la gestion des coûts.

Configurer les notifications de budget

La première étape consiste à activer un sujet Pub/Sub pour le budget. Pour en savoir plus, consultez la page Gérer les notifications d'alerte budgétaire.

Une fois que vous avez activé les notifications de budget, veillez à prendre note des informations suivantes :

  • Sujet Pub/Sub : il s'agit du point de terminaison des notifications configuré pour le budget.
  • ID de budget: il s'agit d'un ID unique pour le budget, qui est indiqué dans toutes les notifications. Vous pouvez localiser l'ID du budget depuis le budget sous Manage notifications (Gérer les notifications). L'ID s'affiche lorsque vous sélectionnez Connect a Pub/Sub topic to this budget (Associer un sujet Pub/Sub à ce budget).

La section "Gérer les notifications" de la console Google Cloud vous permet d'associer un sujet Pub/Sub à un budget. Elle inclut l'ID du budget, le nom du projet et le sujet Pub/Sub.

Écouter les notifications

L'étape suivante consiste à écouter les notifications en vous abonnant au sujet Pub/Sub. Si le sujet n'a aucun abonné, Pub/Sub abandonnera les messages publiés et vous ne pourrez pas les récupérer plus tard.

Bien qu'il existe de nombreuses façons de créer un abonnement associé au sujet, ces exemples utilisent des déclencheurs de fonctions Cloud Run.

Créer une fonction Cloud Run

Pour créer une fonction Cloud Run, procédez comme suit :

  1. Dans la console Google Cloud, accédez à la page Fonctions Cloud Run.

    Accéder à la page "Cloud Run Functions"

  2. Cliquez sur CRÉER UNE FONCTION et donnez-lui un nom en relation avec le budget.

  3. Sous Trigger (Déclencheur), sélectionnez Pub/Sub topic (Sujet Pub/Sub).

  4. Sélectionnez le sujet que vous avez configuré dans le budget.

  5. Fournissez le code source et les dépendances que la fonction doit exécuter.

  6. Assurez-vous de définir la Fonction à exécuter sur le nom de fonction correct.

Page "Créer une fonction" dans la section "Fonctions Cloud Run" de la console Google Cloud. Elle inclut le nom de la fonction, la quantité de mémoire allouée, le type de déclencheur et le sujet Pub/Sub que vous avez configuré dans le budget.

Décrire votre fonction Cloud Run

Pour indiquer à la fonction Cloud Run ce qu'elle doit faire avec la notification reçue, vous pouvez soit écrire le code à l'aide de l'éditeur intégré, soit importer un fichier. Pour en savoir plus sur les notifications que le code recevra, consultez la section Format des notifications.

Par exemple, une fonction peut enregistrer les notifications, les attributs et les données Pub/Sub reçus lorsqu'elle est déclenchée par une notification de budget. Pour en savoir plus, consultez la section Déclencheurs Pub/Sub.

Afficher les événements de votre fonction Cloud Run

Après avoir enregistré la fonction Cloud Run, vous pouvez cliquer sur AFFICHER LES JOURNAUX pour afficher les notifications de budget enregistrées. Les journaux des appels de fonctions s'affichent alors.

Permet de localiser la section "Afficher les journaux" à l'écran et la liste des événements de fonction Cloud Run dans la console Google Cloud.

Tester votre fonction Cloud Run

Les notifications sont envoyées à Pub/Sub et les abonnés reçoivent les messages. Pour tester un exemple de notification afin de vous assurer que votre fonction s'exécute comme prévu, publiez un message dans Pub/Sub en utilisant cet objet comme corps du message :

{
    "budgetDisplayName": "name-of-budget",
    "alertThresholdExceeded": 1.0,
    "costAmount": 100.01,
    "costIntervalStart": "2019-01-01T00:00:00Z",
    "budgetAmount": 100.00,
    "budgetAmountType": "SPECIFIED_AMOUNT",
    "currencyCode": "USD"
}

Vous pouvez également ajouter des attributs de messages, tels que l'ID du compte de facturation. Pour en savoir plus, consultez la documentation complète sur le format de notification.

Envoyer des notifications à Slack

L'e-mail n'est pas toujours le meilleur moyen de rester informé des coûts associés à votre utilisation du cloud, surtout si votre budget est critique et sensible au facteur temps. Avec les notifications, vous pouvez transférer vos messages budgétaires vers d'autres plates-formes.

Dans cet exemple, nous décrivons comment transférer les notifications de budget vers Slack. Ainsi, chaque fois que Cloud Billing publie une notification de budget, une fonction Cloud Run publie un message, à l'aide d'un bot, sur un canal Slack de l'espace de travail du bot.

Configurer un canal Slack et des autorisations

La première étape consiste à créer un espace de travail Slack ainsi que les jetons de l'utilisateur bot utilisés pour appeler l'API Slack. Les jetons d'API peuvent être gérés à l'adresse https://api.slack.com/apps. Pour obtenir des instructions détaillées, consultez la page concernant les utilisateurs bot sur le site de Slack.

Configurer les notifications Slack.

Écrire une fonction Cloud Run

  1. Créez une fonction en suivant les étapes décrites dans Créer une fonction Cloud Run. Assurez-vous que le déclencheur est défini sur le même sujet Pub/Sub que celui sur lequel votre budget est configuré.

  2. Ajoutez des dépendances :

    Node.js

    Copiez ce qui suit dans le fichier package.json :

    {
      "name": "cloud-functions-billing",
      "private": "true",
      "version": "0.0.1",
      "description": "Examples of integrating Cloud Functions with billing",
      "main": "index.js",
      "engines": {
        "node": ">=16.0.0"
      },
      "scripts": {
        "compute-test": "c8 mocha -p -j 2 test/periodic.test.js --timeout=600000",
        "test": "c8 mocha -p -j 2 test/index.test.js --timeout=5000 --exit"
      },
      "author": "Ace Nassri <anassri@google.com>",
      "license": "Apache-2.0",
      "dependencies": {
        "@google-cloud/billing": "^4.0.0",
        "@google-cloud/compute": "^4.0.0",
        "google-auth-library": "^9.0.0",
        "googleapis": "^143.0.0",
        "slack": "^11.0.1"
      },
      "devDependencies": {
        "@google-cloud/functions-framework": "^3.0.0",
        "c8": "^10.0.0",
        "gaxios": "^6.0.0",
        "mocha": "^10.0.0",
        "promise-retry": "^2.0.0",
        "proxyquire": "^2.1.0",
        "sinon": "^18.0.0",
        "wait-port": "^1.0.4"
      }
    }
    

    Python

    Copiez ce qui suit dans le fichier requirements.txt :

    slackclient==2.9.4
    google-api-python-client==2.131.0
    

  3. Écrivez du code ou utilisez l'exemple suivant pour publier des notifications de budget sur un canal de discussion Slack à l'aide de l'API Slack.

  4. Assurez-vous que les paramètres postMessage de l'API Slack suivants sont correctement définis :

    • Jeton d'accès OAuth de l'utilisateur bot
    • Nom de la chaîne

Exemple de code :

Node.js

const slack = require('slack');

// TODO(developer) replace these with your own values
const BOT_ACCESS_TOKEN =
  process.env.BOT_ACCESS_TOKEN || 'xxxx-111111111111-abcdefghidklmnopq';
const CHANNEL = process.env.SLACK_CHANNEL || 'general';

exports.notifySlack = async pubsubEvent => {
  const pubsubAttrs = pubsubEvent.attributes;
  const pubsubData = Buffer.from(pubsubEvent.data, 'base64').toString();
  const budgetNotificationText = `${JSON.stringify(
    pubsubAttrs
  )}, ${pubsubData}`;

  await slack.chat.postMessage({
    token: BOT_ACCESS_TOKEN,
    channel: CHANNEL,
    text: budgetNotificationText,
  });

  return 'Slack notification sent successfully';
};

Python

import base64
import json
import os

import slack
from slack.errors import SlackApiError

# See https://api.slack.com/docs/token-types#bot for more info
BOT_ACCESS_TOKEN = "xxxx-111111111111-abcdefghidklmnopq"
CHANNEL = "C0XXXXXX"

slack_client = slack.WebClient(token=BOT_ACCESS_TOKEN)


def notify_slack(data, context):
    pubsub_message = data

    # For more information, see
    # https://cloud.google.com/billing/docs/how-to/budgets-programmatic-notifications#notification_format
    try:
        notification_attr = json.dumps(pubsub_message["attributes"])
    except KeyError:
        notification_attr = "No attributes passed in"

    try:
        notification_data = base64.b64decode(data["data"]).decode("utf-8")
    except KeyError:
        notification_data = "No data passed in"

    # This is just a quick dump of the budget data (or an empty string)
    # You can modify and format the message to meet your needs
    budget_notification_text = f"{notification_attr}, {notification_data}"

    try:
        slack_client.api_call(
            "chat.postMessage",
            json={"channel": CHANNEL, "text": budget_notification_text},
        )
    except SlackApiError:
        print("Error posting to Slack")

Vous pouvez maintenant tester votre fonction Cloud Run pour afficher un message dans Slack.

Plafonner (désactiver) la facturation pour mettre fin à toute utilisation

Cet exemple vous montre comment plafonner les coûts et arrêter l'utilisation d'un projet en désactivant Cloud Billing. La désactivation de la facturation sur un projet entraîne la résiliation de tous les services Google Cloud du projet, y compris les services en version gratuite.

Pourquoi désactiver la facturation ?

Vous pouvez vouloir plafonner les coûts si l'on vous impose une limite stricte sur ce que vous pouvez dépenser sur Google Cloud. C'est typiquement le cas des étudiants, chercheurs ou développeurs travaillant dans des environnements de bac à sable. Dans de telles circonstances, il est important de bloquer les dépenses, voire d'arrêter tous les services Google Cloud et leur utilisation dès lors que le seuil budgétaire est atteint.

Dans notre exemple, nous utilisons acme-backend-dev comme projet de non-production, sur lequel Cloud Billing peut être désactivé en toute sécurité.

Configure le plafond budgétaire dans la console Google Cloud.

Avant de commencer à utiliser cet exemple, assurez-vous d'avoir effectué les opérations suivantes:

Affiche la liste des alertes Cloud Billing dans la console Google Cloud.

Écrire une fonction Cloud Run

Vous devez ensuite configurer votre fonction Cloud Run pour qu'elle appelle l'API Cloud Billing. Cela permet à la fonction Cloud Run de désactiver Cloud Billing pour le projet acme-backend-dev utilisé dans cet exemple.

  1. Créez une fonction en suivant les étapes décrites dans Créer une fonction Cloud Run. Assurez-vous que le déclencheur est défini sur le même sujet Pub/Sub que celui sur lequel votre budget est configuré.

  2. Ajoutez les dépendances suivantes :

    Node.js

    Copiez ce qui suit dans le fichier package.json :

    {
      "name": "cloud-functions-billing",
      "private": "true",
      "version": "0.0.1",
      "description": "Examples of integrating Cloud Functions with billing",
      "main": "index.js",
      "engines": {
        "node": ">=16.0.0"
      },
      "scripts": {
        "compute-test": "c8 mocha -p -j 2 test/periodic.test.js --timeout=600000",
        "test": "c8 mocha -p -j 2 test/index.test.js --timeout=5000 --exit"
      },
      "author": "Ace Nassri <anassri@google.com>",
      "license": "Apache-2.0",
      "dependencies": {
        "@google-cloud/billing": "^4.0.0",
        "@google-cloud/compute": "^4.0.0",
        "google-auth-library": "^9.0.0",
        "googleapis": "^143.0.0",
        "slack": "^11.0.1"
      },
      "devDependencies": {
        "@google-cloud/functions-framework": "^3.0.0",
        "c8": "^10.0.0",
        "gaxios": "^6.0.0",
        "mocha": "^10.0.0",
        "promise-retry": "^2.0.0",
        "proxyquire": "^2.1.0",
        "sinon": "^18.0.0",
        "wait-port": "^1.0.4"
      }
    }
    

    Python

    Copiez ce qui suit dans le fichier requirements.txt :

    slackclient==2.9.4
    google-api-python-client==2.131.0
    

  3. Copiez le code suivant dans la fonction Cloud Run.

  4. Définissez la fonction à exécuter sur stopBilling (Node) ou stop_billing (Python).

  5. Selon votre environnement d'exécution, la variable d'environnement GOOGLE_CLOUD_PROJECT peut être définie automatiquement. Consultez la liste des variables d'environnement définies automatiquement et déterminez si vous devez définir manuellement la variable GOOGLE_CLOUD_PROJECT sur le projet pour lequel vous souhaitez plafonner (désactiver) Cloud Billing.

Node.js

const {CloudBillingClient} = require('@google-cloud/billing');
const {InstancesClient} = require('@google-cloud/compute');

const PROJECT_ID = process.env.GOOGLE_CLOUD_PROJECT;
const PROJECT_NAME = `projects/${PROJECT_ID}`;
const billing = new CloudBillingClient();

exports.stopBilling = async pubsubEvent => {
  const pubsubData = JSON.parse(
    Buffer.from(pubsubEvent.data, 'base64').toString()
  );
  if (pubsubData.costAmount <= pubsubData.budgetAmount) {
    return `No action necessary. (Current cost: ${pubsubData.costAmount})`;
  }

  if (!PROJECT_ID) {
    return 'No project specified';
  }

  const billingEnabled = await _isBillingEnabled(PROJECT_NAME);
  if (billingEnabled) {
    return _disableBillingForProject(PROJECT_NAME);
  } else {
    return 'Billing already disabled';
  }
};

/**
 * Determine whether billing is enabled for a project
 * @param {string} projectName Name of project to check if billing is enabled
 * @return {bool} Whether project has billing enabled or not
 */
const _isBillingEnabled = async projectName => {
  try {
    const [res] = await billing.getProjectBillingInfo({name: projectName});
    return res.billingEnabled;
  } catch (e) {
    console.log(
      'Unable to determine if billing is enabled on specified project, assuming billing is enabled'
    );
    return true;
  }
};

/**
 * Disable billing for a project by removing its billing account
 * @param {string} projectName Name of project disable billing on
 * @return {string} Text containing response from disabling billing
 */
const _disableBillingForProject = async projectName => {
  const [res] = await billing.updateProjectBillingInfo({
    name: projectName,
    resource: {billingAccountName: ''}, // Disable billing
  });
  return `Billing disabled: ${JSON.stringify(res)}`;
};

Python

import base64
import json
import os

from googleapiclient import discovery

PROJECT_ID = os.getenv("GCP_PROJECT")
PROJECT_NAME = f"projects/{PROJECT_ID}"
def stop_billing(data, context):
    pubsub_data = base64.b64decode(data["data"]).decode("utf-8")
    pubsub_json = json.loads(pubsub_data)
    cost_amount = pubsub_json["costAmount"]
    budget_amount = pubsub_json["budgetAmount"]
    if cost_amount <= budget_amount:
        print(f"No action necessary. (Current cost: {cost_amount})")
        return

    if PROJECT_ID is None:
        print("No project specified with environment variable")
        return

    billing = discovery.build(
        "cloudbilling",
        "v1",
        cache_discovery=False,
    )

    projects = billing.projects()

    billing_enabled = __is_billing_enabled(PROJECT_NAME, projects)

    if billing_enabled:
        __disable_billing_for_project(PROJECT_NAME, projects)
    else:
        print("Billing already disabled")


def __is_billing_enabled(project_name, projects):
    """
    Determine whether billing is enabled for a project
    @param {string} project_name Name of project to check if billing is enabled
    @return {bool} Whether project has billing enabled or not
    """
    try:
        res = projects.getBillingInfo(name=project_name).execute()
        return res["billingEnabled"]
    except KeyError:
        # If billingEnabled isn't part of the return, billing is not enabled
        return False
    except Exception:
        print(
            "Unable to determine if billing is enabled on specified project, assuming billing is enabled"
        )
        return True


def __disable_billing_for_project(project_name, projects):
    """
    Disable billing for a project by removing its billing account
    @param {string} project_name Name of project disable billing on
    """
    body = {"billingAccountName": ""}  # Disable billing
    try:
        res = projects.updateBillingInfo(name=project_name, body=body).execute()
        print(f"Billing disabled: {json.dumps(res)}")
    except Exception:
        print("Failed to disable billing, possibly check permissions")

Configurer les autorisations du compte de service

La fonction Cloud Run est exécutée en tant que compte de service automatiquement créé. Pour que le compte de service puisse désactiver la facturation, vous devez lui accorder les autorisations appropriées, telles que Administrateur de facturation.

Pour identifier le bon compte de service, consultez les informations de la fonction Cloud Run. Le compte de service est répertorié au bas de la page.

Indique l&#39;emplacement des informations du compte de service dans la section &quot;Fonction Cloud Run&quot; de la console Google Cloud.

Vous pouvez gérer les autorisations de l'administrateur de la facturation sur la page Facturation de la console Google Cloud.

Pour accorder des privilèges de Billing Account Administrator (Administrateur de compte de facturation) au compte de service, sélectionnez le nom du compte de service.

Indique où sélectionner le nom du compte de service et le rôle &quot;Administrateur du compte de facturation&quot; dans la section &quot;Autorisations&quot; de la console Google Cloud.

Vérifier que Cloud Billing est désactivé

Lorsque le budget envoie une notification, le projet spécifié n'a plus de compte de facturation Cloud. Si vous souhaitez tester la fonction, publiez un exemple de message semblable à celui ci-dessus. Le projet ne sera plus visible sous le compte de facturation Cloud et les ressources du projet seront désactivées, y compris la fonction Cloud Run si elle se trouve dans ce projet.

Indique que l&#39;exemple de projet n&#39;est plus visible dans la liste des projets associés au compte de facturation Cloud. Cela permet de vérifier que Cloud Billing est désactivé pour le projet.

Vous pouvez réactiver manuellement Cloud Billing pour votre projet dans la console Google Cloud.

Contrôler l'utilisation de manière sélective

Le plafonnement (la désactivation) de Cloud Billing, tel qu'il est décrit dans l'exemple précédent, est binaire et final. Le projet est soit activé, soit désactivé. Lorsque le projet est désactivé, tous les services sont arrêtés et toutes les ressources finissent par être supprimées.

Si vous souhaitez obtenir une réponse plus nuancée, vous pouvez contrôler les ressources de manière sélective. Par exemple, si vous souhaitez arrêter certaines ressources Compute Engine, mais garder Cloud Storage intact, vous pouvez contrôler l'utilisation de manière sélective. Cela réduit votre coût horaire sans désactiver complètement votre environnement.

Vous pouvez écrire des règles aussi nuancées que vous le souhaitez. Cependant, dans notre exemple, le projet effectue des recherches sur plusieurs machines virtuelles Compute Engine et stocke les résultats dans Cloud Storage. Cet exemple de fonction Cloud Run arrête toutes les instances Compute Engine, mais n'a aucune incidence sur les résultats stockés une fois le budget dépassé.

Écrire une fonction Cloud Run

  1. Créez une fonction en suivant les étapes décrites dans Créer une fonction Cloud Run. Assurez-vous que le déclencheur est défini sur le même sujet Pub/Sub que celui sur lequel votre budget est configuré.

  2. Assurez-vous que vous avez ajouté les dépendances décrites dans Plafonner (désactiver) la facturation pour mettre fin à toute utilisation.

  3. Copiez le code suivant dans la fonction Cloud Run.

  4. Définissez la fonction à exécuter sur limitUse (Node) ou limit_use (Python).

  5. Selon votre environnement d'exécution, la variable d'environnement GCP_PROJECT peut être définie automatiquement. Consultez la liste des variables d'environnement définies automatiquement et déterminez si vous devez définir manuellement la variable GCP_PROJECT sur le projet exécutant les machines virtuelles.

  6. Définissez le paramètre ZONE. Dans cet exemple, il s'agit de la zone dans laquelle les instances seront arrêtées.

Node.js

const {CloudBillingClient} = require('@google-cloud/billing');
const {InstancesClient} = require('@google-cloud/compute');

const PROJECT_ID = process.env.GOOGLE_CLOUD_PROJECT;
const PROJECT_NAME = `projects/${PROJECT_ID}`;
const instancesClient = new InstancesClient();
const ZONE = 'us-central1-a';

exports.limitUse = async pubsubEvent => {
  const pubsubData = JSON.parse(
    Buffer.from(pubsubEvent.data, 'base64').toString()
  );
  if (pubsubData.costAmount <= pubsubData.budgetAmount) {
    return `No action necessary. (Current cost: ${pubsubData.costAmount})`;
  }

  const instanceNames = await _listRunningInstances(PROJECT_ID, ZONE);
  if (!instanceNames.length) {
    return 'No running instances were found.';
  }

  await _stopInstances(PROJECT_ID, ZONE, instanceNames);
  return `${instanceNames.length} instance(s) stopped successfully.`;
};

/**
 * @return {Promise} Array of names of running instances
 */
const _listRunningInstances = async (projectId, zone) => {
  const [instances] = await instancesClient.list({
    project: projectId,
    zone: zone,
  });
  return instances
    .filter(item => item.status === 'RUNNING')
    .map(item => item.name);
};

/**
 * @param {Array} instanceNames Names of instance to stop
 * @return {Promise} Response from stopping instances
 */
const _stopInstances = async (projectId, zone, instanceNames) => {
  await Promise.all(
    instanceNames.map(instanceName => {
      return instancesClient
        .stop({
          project: projectId,
          zone: zone,
          instance: instanceName,
        })
        .then(() => {
          console.log(`Instance stopped successfully: ${instanceName}`);
        });
    })
  );
};

Python

import base64
import json
import os

from googleapiclient import discovery

PROJECT_ID = os.getenv("GCP_PROJECT")
PROJECT_NAME = f"projects/{PROJECT_ID}"
ZONE = "us-west1-b"


def limit_use(data, context):
    pubsub_data = base64.b64decode(data["data"]).decode("utf-8")
    pubsub_json = json.loads(pubsub_data)
    cost_amount = pubsub_json["costAmount"]
    budget_amount = pubsub_json["budgetAmount"]
    if cost_amount <= budget_amount:
        print(f"No action necessary. (Current cost: {cost_amount})")
        return

    compute = discovery.build(
        "compute",
        "v1",
        cache_discovery=False,
    )
    instances = compute.instances()

    instance_names = __list_running_instances(PROJECT_ID, ZONE, instances)
    __stop_instances(PROJECT_ID, ZONE, instance_names, instances)


def __list_running_instances(project_id, zone, instances):
    """
    @param {string} project_id ID of project that contains instances to stop
    @param {string} zone Zone that contains instances to stop
    @return {Promise} Array of names of running instances
    """
    res = instances.list(project=project_id, zone=zone).execute()

    if "items" not in res:
        return []

    items = res["items"]
    running_names = [i["name"] for i in items if i["status"] == "RUNNING"]
    return running_names


def __stop_instances(project_id, zone, instance_names, instances):
    """
    @param {string} project_id ID of project that contains instances to stop
    @param {string} zone Zone that contains instances to stop
    @param {Array} instance_names Names of instance to stop
    @return {Promise} Response from stopping instances
    """
    if not len(instance_names):
        print("No running instances were found.")
        return

    for name in instance_names:
        instances.stop(project=project_id, zone=zone, instance=name).execute()
        print(f"Instance stopped successfully: {name}")

Configurer les autorisations du compte de service

  1. La fonction Cloud Run est exécutée en tant que compte de service automatiquement créé. Pour contrôler l'utilisation, vous devez accorder au compte de service des autorisations sur tous les services du projet dont il aura besoin pour apporter des modifications.
  2. Pour identifier le bon compte de service, consultez les informations de la fonction Cloud Run. Le compte de service est répertorié au bas de la page.
  3. Dans la console Google Cloud, accédez à la page IAM pour définir les autorisations appropriées.
    Accéder à la page "IAM"
     
    Affiche l&#39;écran IAM dans la console Google Cloud, où vous pouvez définir les autorisations appropriées pour le compte de service qui exécute la fonction Cloud Run.

Vérifier que les instances sont arrêtées

Lorsque le budget envoie une notification, les machines virtuelles Compute Engine sont arrêtées.

Pour tester la fonction, publiez un exemple de message semblable à celui utilisé précédemment. Vous pouvez valider l'exécution réussie de la fonction en vérifiant les machines virtuelles Compute Engine dans la console Google Cloud.