Disattivare l'utilizzo della fatturazione con le notifiche

Questo documento spiega come disattivare automaticamente la fatturazione in un progetto quando i costi soddisfano o superano il budget del progetto. Quando disattivi la fatturazione in un progetto, tutti i Google Cloud servizi al suo interno vengono interrotti, inclusi i servizi del livello gratuito. Per una risposta più sfumata alle notifiche relative al budget, consulta Controllare l'utilizzo delle risorse con le notifiche.

Potresti limitare i costi perché hai un importo massimo che puoi spendere per Google Cloud. In questi casi, quando viene raggiunto il limite del budget, potresti decidere di disattivare tutti i tuoi Google Cloud servizi e l'utilizzo per non dover più sostenere costi. La disattivazione della fatturazione nel progetto è un metodo efficace per evitare di sostenere costi.

Limitazioni

  • Esiste un ritardo tra l'insorgenza dei costi e la ricezione delle notifiche relative al budget, pertanto potresti incorrere in costi aggiuntivi per l'utilizzo che non è stato registrato al momento dell'interruzione di tutti i servizi. Seguire i passaggi descritti in questo esempio non garantisce che non spenderai più del tuo budget. Se disponi di una quantità limitata di fondi, imposta il budget massimo al di sotto di quelli disponibili per tenere conto dei ritardi nella fatturazione.

  • Non puoi disattivare la fatturazione in un progetto bloccato su un account di fatturazione. Per approfondire il blocco e lo sblocco dei progetti, consulta Proteggere il collegamento tra un progetto e il relativo account di fatturazione.

Prima di iniziare

Prima di iniziare, devi completare le seguenti attività:

  1. Abilita l'API Cloud Billing
  2. Creare un budget limitato a un singolo progetto
  3. Configurare le notifiche relative al budget programmatico

Configurare una funzione Cloud Run

Per disattivare la fatturazione Cloud per un progetto, crea una funzione Cloud Run e configurala in modo che chiami l'API Cloud Billing.

  1. Completa i passaggi descritti in Creare una funzione Cloud Run. Assicurati che Tipo di trigger sia impostato sullo stesso argomento Pub/Sub utilizzato dal budget.
  2. Aggiungi le seguenti dipendenze:

    Node.js

    Copia quanto segue nel file 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 quanto segue nel file requirements.txt:

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

  3. Copia il seguente codice nella funzione 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. Imposta il punto di ingresso sulla funzione corretta da eseguire:

    Node.js

    Imposta Punto di ingresso su stopBilling.

    Python

    Imposta Punto di ingresso su stop_billing.

  5. Esamina l'elenco delle variabili di ambiente impostate automaticamente per determinare se devi impostare manualmente la variabile GOOGLE_CLOUD_PROJECT per il progetto per cui vuoi disattivare la fatturazione Cloud.

  6. Fai clic su ESEGUI IL ROLLOUT.

Configura le autorizzazioni degli account di servizio

La funzione Cloud Run viene eseguita come account di servizio creato automaticamente. Per disattivare la fatturazione, devi concedere all'account di servizio le autorizzazioni per tutti i servizi del progetto che deve modificare completando i seguenti passaggi:

  1. Identifica l'account di servizio corretto visualizzando i dettagli della funzione Cloud Run. L'account di servizio è elencato nella parte inferiore della pagina.
  2. Vai alla pagina IAM nella console Google Cloud per impostare le autorizzazioni appropriate.

    Vai alla pagina IAM

  3. Per modificare le autorizzazioni dell'account di fatturazione, nella console Google Cloud vai alla pagina Gestione account di fatturazione, aggiungi l'account di servizio come principio nell'account di fatturazione Cloud e imposta le autorizzazioni dell'account di fatturazione appropriate.

    Vai alla pagina Gestione account in Fatturazione Cloud

Scopri di più su come configurare le autorizzazioni per gli account di fatturazione Cloud.

Verifica che la fatturazione Cloud sia disattivata

Quando il budget invia una notifica, al progetto specificato non sarà più associato un account di fatturazione Cloud. Per assicurarti che la funzione funzioni come previsto, segui i passaggi descritti in Testare una funzione Cloud Run.

In caso di esito positivo, il progetto non è più visibile nell'account di fatturazione Cloud e le risorse al suo interno vengono disattivate, inclusa la funzione Cloud Run se si trova nello stesso progetto.

Per continuare a utilizzare le Google Cloud risorse del progetto, nella console Google Cloud, riattiva manualmente la Fatturazione Cloud per il progetto.

Passaggi successivi

Esamina altri esempi di notifiche programmatiche per scoprire come svolgere le seguenti operazioni: