Inhabilita el uso de la facturación con notificaciones

En este documento, se explica cómo inhabilitar automáticamente la facturación en un proyecto cuando los costos alcanzan o superan el presupuesto del proyecto. Cuando inhabilitas la facturación en un proyecto, finalizas todos los Google Cloud servicios del proyecto, incluidos losservicios del nivel gratuito. Para obtener una respuesta más detallada a las notificaciones de presupuesto, consulta Cómo controlar el uso de recursos con notificaciones.

Es posible que limites los costos porque tienes una cantidad máxima de dinero que puedes invertir en Google Cloud. En estos casos, cuando se alcance el límite de tu presupuesto, es posible que estés dispuesto a cerrar todos tus Google Cloud servicios y el uso para dejar de incurrir en costos. Inhabilitar la facturación de tu proyecto es un método eficiente para dejar de generar costos en ese proyecto.

Limitaciones

  • Hay un retraso entre el momento en que se generan los costos y el momento en que se reciben las notificaciones de presupuesto, por lo que es posible que se generen costos adicionales por un uso que no llegó en el momento en que se detuvieron todos los servicios. Seguir los pasos de este ejemplo no garantiza que no gastarás más que tu presupuesto. Si tienes una cantidad limitada de fondos, establece el presupuesto máximo por debajo de los fondos disponibles para tener en cuenta los retrasos de facturación.

  • No puedes inhabilitar la facturación en un proyecto que esté bloqueado a una cuenta de facturación. Para obtener más información sobre cómo bloquear y desbloquear proyectos, consulta Protege el vínculo entre un proyecto y su cuenta de facturación.

Antes de comenzar

Antes de comenzar, debes completar las siguientes tareas:

  1. Habilita la API de Cloud Billing
  2. Crea un presupuesto que tenga un solo proyecto
  3. Configura notificaciones de presupuesto programáticas

Configura una función de Cloud Run

Para inhabilitar Facturación de Cloud en un proyecto, crea una función de Cloud Run y configúrala para que llame a la API de Cloud Billing.

  1. Completa los pasos que se describen en Crea una función de Cloud Run. Asegúrate de que el tipo de activador esté configurado con el mismo tema de Pub/Sub que usará tu presupuesto.
  2. Agrega las siguientes dependencias:

    Node.js

    Copia lo siguiente en tu archivo 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

    Copia lo siguiente en tu archivo requirements.txt:

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

  3. Copia el siguiente código en tu función de Cloud Run:

    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")
    
    

  4. Establece el Punto de entrada en la función correcta para ejecutar:

    Node.js

    Establece el Punto de entrada en stopBilling.

    Python

    Establece el Punto de entrada en stop_billing.

  5. Revisa la lista de variables de entorno que se configuran automáticamente para determinar si necesitas configurar de forma manual la variable GOOGLE_CLOUD_PROJECT en el proyecto para el que deseas inhabilitar la Facturación de Cloud.

  6. Haz clic en IMPLEMENTAR.

Configura los permisos de la cuenta de servicio

Tu función de Cloud Run se ejecuta como una cuenta de servicio creada automáticamente. Para inhabilitar la facturación, debes otorgarle permisos a la cuenta de servicio para cualquier servicio del proyecto que necesite modificar. Para ello, completa los siguientes pasos:

  1. Para identificar la cuenta de servicio correcta, visualiza los detalles de la función de Cloud Run. La cuenta de servicio se encuentra en la parte inferior de la página.
  2. Ve a la página IAM en la consola de Google Cloud para configurar los permisos correspondientes.

    Ve a la página IAM

  3. Para modificar los permisos de la cuenta de facturación, en la consola de Google Cloud, ve a la página Administración de cuentas de Facturación, agrega la cuenta de servicio como responsable en la cuenta de Facturación de Cloud y establece los permisos de cuenta de facturación adecuados.

    Ve a la página Administración de cuentas en Facturación de Cloud

Obtén más información para configurar permisos para las cuentas de Facturación de Cloud.

Prueba que la Facturación de Cloud esté inhabilitada

Cuando el presupuesto envíe una notificación, el proyecto especificado ya no tendrá una cuenta de Facturación de Cloud asociada. Para asegurarte de que la función funcione como se espera, sigue los pasos que se indican en Cómo probar una función de Cloud Run.

Si se realiza correctamente, el proyecto ya no será visible en la cuenta de Facturación de Cloud, y los recursos del proyecto estarán inhabilitados, incluida la función de Cloud Run si está en el mismo proyecto.

Para seguir usando los Google Cloud recursos del proyecto, en la consola de Google Cloud, vuelve a habilitar la Facturación de Cloud de forma manual para tu proyecto.

¿Qué sigue?

Revisa otros ejemplos de notificaciones programáticas para aprender a hacer lo siguiente: