Esempi di risposte automatiche sul controllo dei costi

Esempio di architettura di riferimento

Diagramma di un esempio di utilizzo delle notifiche programmatiche relative agli avvisi relativi al budget
            per automatizzare una risposta al controllo dei costi.
Figura 1: illustra un esempio di utilizzo degli avvisi relativi al budget per automatizzare le risposte al controllo dei costi utilizzando Pub/Sub per la pubblicità programmatica notifiche e Cloud Functions per automatizzare una risposta.

Se sei attenti ai costi e hai bisogno di controllare ambiente rispetto al tuo budget, puoi utilizzare notifiche relative al budget programmatico per automatizzare la risposta al controllo dei costi in base alla notifica del budget.

Utilizzo delle notifiche relative al budget Pub/Sub per fornire lo stato in tempo reale del budget della fatturazione Cloud, utilizzando la scalabilità, la flessibilità e l'affidabilità dei middleware orientato al messaggio per il cloud.

Questa pagina contiene esempi e istruzioni dettagliate su come utilizzare le notifiche relative al budget con Cloud Functions per automatizzare la gestione dei costi.

Configurare le notifiche relative al budget

Il primo passaggio consiste nell'abilitare un argomento Pub/Sub per il tuo budget. Questa procedura è descritta dettagliatamente all'indirizzo Gestire le notifiche di avviso relativo al budget per la pubblicità programmatica.

Dopo aver attivato le notifiche relative al budget, tieni presente quanto segue:

  • Argomento Pub/Sub: queste sono le notifiche configurate endpoint per il budget.
  • ID budget: si tratta di un ID univoco per il budget incluso in tutte le notifiche. Puoi individuare l'ID budget nel tuo budget in Gestisci notifiche. L'ID verrà visualizzato dopo che avrai selezionato Collega un Pub/Sub a questo budget.

La sezione Gestisci notifiche della console Google Cloud, in cui puoi
         connettere un argomento Pub/Sub a un budget. Include
         ID budget, nome del progetto e argomento Pub/Sub.

Ascoltare le notifiche

Il passo successivo è ascoltare le notifiche iscrivendoti al tuo Pub/Sub. Se non hai un abbonato, Pub/Sub eliminerà i messaggi pubblicati e non puoi recuperarli in seguito.

Sebbene esistano molti modi per iscriverti al tuo argomento, per questi esempi utilizzeremo Trigger di funzioni Cloud Functions.

Crea una funzione Cloud

Per creare una nuova Cloud Function:

  1. Nella console Google Cloud, vai alla pagina Cloud Functions.

    Vai alla pagina Cloud Functions

  2. Fai clic su CREA FUNZIONE e assegna alla funzione un nome significativo per il tuo budget.

  3. In Trigger, seleziona l'argomento Pub/Sub.

  4. Seleziona l'argomento che hai configurato nel tuo budget.

  5. Fornisci il codice sorgente e le dipendenze per l'esecuzione della funzione.

  6. Assicurati di impostare la Funzione da eseguire sul nome corretto della funzione.

La pagina Crea funzione nella sezione Cloud Functions nel
         nella console Google Cloud. Include il nome della funzione, la quantità di memoria
         allocato, il tipo di trigger e l'argomento Pub/Sub
         configurato nel tuo budget.

Descrizione della Cloud Function

Per indicare alla Cloud Function cosa vuoi che faccia con notifica, puoi scrivere il codice utilizzando l'editor in linea o caricare un file. Per informazioni dettagliate sulle notifiche che riceverà il codice, vedi Formato delle notifiche.

Ad esempio, una funzione potrebbe registrare le notifiche Pub/Sub ricevute, e dati quando vengono attivati da una notifica relativa al budget. Per saperne di più, vedi Trigger Pub/Sub.

Visualizzare gli eventi della Cloud Function

Dopo aver salvato la Cloud Function, puoi fare clic su VISUALIZZA LOG per visualizza le notifiche relative al budget registrato. Mostra i log della tua funzione per le chiamate.

Mostra dove puoi trovare i log di visualizzazione sullo schermo e l'elenco di
         degli eventi della funzione Cloud Function nella console Google Cloud.

Testa la Cloud Function

Le notifiche vengono inviate a Pub/Sub e gli abbonati ricevono messaggi. Per testare una notifica di esempio e assicurarti che la funzione funziona come previsto, pubblica un messaggio in Pub/Sub utilizzando questo oggetto come corpo del messaggio:

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

Puoi anche aggiungere attributi del messaggio come l'ID account di fatturazione. Visualizza la formato di notifica documentazione per ulteriori informazioni.

Invia notifiche a Slack

L'email non è sempre il modo migliore per rimanere aggiornati sui costi del cloud in particolare se il budget è critico e non richiede tempi di elaborazione. Con notifiche puoi inoltrare i messaggi relativi al budget ad altri mezzi.

In questo esempio viene descritto come inoltrare le notifiche relative al budget a Slack. In questo modo, ogni volta che fatturazione Cloud pubblica un una notifica relativa al budget, una Cloud Function utilizza un bot per pubblicare un messaggio un canale Slack dell'area di lavoro del bot.

Configurazione di un canale Slack e delle autorizzazioni

Il primo passaggio consiste nel creare la tua area di lavoro Slack e i token utente del bot utilizzate per chiamare l'API Slack. I token delle API possono essere gestiti https://api.slack.com/apps. Per istruzioni dettagliate, vedi Utenti del bot sul sito di Slack.

Configura le notifiche Slack.

Scrivi una Cloud Function

  1. Crea una nuova funzione seguendo la procedura descritta in Crea una funzione Cloud Functions. Assicurati che il trigger sia impostato sullo stesso argomento Pub/Sub che il tuo budget è impostato per utilizzare.

  2. Aggiungi dipendenze:

    Node.js

    Copia quanto segue in 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": "^126.0.0",
        "slack": "^11.0.1"
      },
      "devDependencies": {
        "@google-cloud/functions-framework": "^3.0.0",
        "c8": "^8.0.0",
        "gaxios": "^6.0.0",
        "mocha": "^10.0.0",
        "promise-retry": "^2.0.0",
        "proxyquire": "^2.1.0",
        "sinon": "^16.0.0",
        "wait-port": "^1.0.4"
      }
    }
    

    Python

    Copia quanto segue in requirements.txt:

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

  3. Scrivi il codice o utilizza l'esempio di seguito per pubblicare notifiche relative al budget a un Canale di chat di Slack tramite l'API Slack.

  4. Assicurati che i seguenti parametri postMessage dell'API Slack siano impostati correttamente:

    • Token di accesso OAuth dell'utente del bot
    • Nome canale

Esempio di codice:

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

Ora puoi Testa la funzione Cloud Functions per visualizzare un messaggio in Slack.

Limita (disattiva) la fatturazione per interrompere l'utilizzo

Questo esempio mostra come limitare i costi e interrompere l'utilizzo per un project, disabilitando la fatturazione Cloud. Disabilitazione della fatturazione in un progetto comporterà la terminazione di tutti i servizi Google Cloud nel progetto, tra cui servizi di livello gratuito.

Perché disattivare la fatturazione?

Potresti limitare i costi perché hai un limite fisso alla quantità di denaro che possono spendere su Google Cloud. È un comportamento tipico di studenti, ricercatori o che lavorano in ambienti sandbox. In questi casi vuoi interrompere potrebbe essere disposta a chiudere tutti i servizi Google Cloud e l'utilizzo quando viene raggiunto il limite del budget.

Nel nostro esempio, utilizziamo acme-backend-dev come progetto non di produzione per il quale La fatturazione Cloud può essere disabilitata in modo sicuro.

Configura il limite del budget nella console Google Cloud.

Prima di iniziare a utilizzare questo esempio, assicurati di aver eseguito le seguenti operazioni:

Mostra l&#39;elenco degli avvisi di fatturazione Cloud nella
         nella console Google Cloud.

Scrivi una Cloud Function

A questo punto devi configurare la Cloud Function per chiamare l'API Cloud Billing. Questa opzione consente alla Cloud Function di disabilitare Fatturazione Cloud per il nostro progetto di esempio acme-backend-dev.

  1. Crea una nuova funzione seguendo la procedura descritta in Crea una funzione Cloud Functions. Assicurati che il trigger sia impostato sullo stesso argomento Pub/Sub che il tuo budget è impostato per utilizzare.

  2. Aggiungi le seguenti dipendenze:

    Node.js

    Copia quanto segue in 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": "^126.0.0",
        "slack": "^11.0.1"
      },
      "devDependencies": {
        "@google-cloud/functions-framework": "^3.0.0",
        "c8": "^8.0.0",
        "gaxios": "^6.0.0",
        "mocha": "^10.0.0",
        "promise-retry": "^2.0.0",
        "proxyquire": "^2.1.0",
        "sinon": "^16.0.0",
        "wait-port": "^1.0.4"
      }
    }
    

    Python

    Copia quanto segue in requirements.txt:

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

  3. Copia il codice seguente nella Cloud Function.

  4. Imposta la funzione da eseguire su "stopBilling" (Node) o "stop_billing" (Python).

  5. A seconda del runtime, GOOGLE_CLOUD_PROJECT potrebbe essere impostata automaticamente. Esamina l'elenco di variabili di ambiente impostate automaticamente e determinare se è necessario impostare manualmente GOOGLE_CLOUD_PROJECT al progetto per a cui vuoi limitare (disabilitare) la fatturazione Cloud.

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

Configura le autorizzazioni degli account di servizio

La funzione Cloud Functions viene eseguita Un account di servizio creato automaticamente. Per fare in modo che l'account di servizio possa disabilitare la fatturazione, devi concedere le autorizzazioni corrette, ad esempio Amministratore fatturazione.

Per identificare l'account di servizio corretto, visualizza la Cloud Function i dettagli. L'account di servizio è elencato in fondo alla pagina.

Mostra dove si possono trovare le informazioni dell&#39;account di servizio nella
         Sezione funzione Cloud Function della console Google Cloud.

Puoi gestire Autorizzazioni Amministratore fatturazione il Pagina di fatturazione nella console Google Cloud.

Per concedere i privilegi Amministratore account di fatturazione all'account di servizio, seleziona il nome dell'account di servizio.

Mostra dove selezionare il nome dell&#39;account di servizio e l&#39;account di fatturazione
         Ruolo di amministratore nella sezione Autorizzazioni
         nella console Google Cloud.

Verifica che la fatturazione Cloud sia disabilitata

Quando il budget invia una notifica, il progetto specificato non non avranno più un account di fatturazione Cloud. Se vuoi testare la funzione, pubblica un messaggio di esempio con il messaggio di test riportato sopra. La non sarà più visibile L'account di fatturazione Cloud e le risorse nel progetto disabilitata, inclusa la Cloud Function se si trova nello stesso progetto.

Mostra che il progetto di esempio non è più visibile nell&#39;elenco di
         di progetti collegati all&#39;account di fatturazione Cloud. Questo convalida
         che la fatturazione Cloud sia disabilitata per il progetto.

Puoi riattivare manualmente la fatturazione Cloud per il tuo progetto nella console Google Cloud.

Controllo selettivo dell'utilizzo

Limitare (disattivare) la fatturazione Cloud come descritto nell'esempio precedente è binario e terminale. Il progetto è abilitato o disattivata. Quando è disabilitato, tutti i servizi vengono arrestati e tutte le risorse vengono e verrà poi eliminato.

Se hai bisogno di una risposta più articolata, puoi controllare selettivamente le risorse. Ad esempio, se vuoi arrestare alcune risorse Compute Engine, ma Cloud Storage è intatto, quindi puoi controllare selettivamente l'utilizzo. Questo riduce il costo orario senza disabilitare completamente l'ambiente.

Puoi scrivere norme personalizzate nel modo che preferisci. Tuttavia, per il nostro esempio, che sta conducendo ricerche con una serie di macchine virtuali Compute Engine e sta archiviando i risultati di archiviazione ideale in Cloud Storage. Questa funzione Cloud Functions esempio causerà l'arresto di tutte le istanze di Compute Engine, ma non i risultati archiviati dopo aver superato il budget.

Scrivi una Cloud Function

  1. Crea una nuova funzione seguendo la procedura descritta in Crea una funzione Cloud Functions. Assicurati che il trigger sia impostato sullo stesso argomento Pub/Sub che che il tuo budget è impostato per utilizzare.

  2. Assicurati di aver aggiunto le dipendenze descritte in Limita (disattiva) la fatturazione per interrompere l'utilizzo.

  3. Copia il codice seguente nella Cloud Function.

  4. Imposta la funzione da eseguire su "limitUse" (Nodo) o "limit_use" (Python).

  5. A seconda del runtime, GCP_PROJECT potrebbe essere impostata automaticamente. Esamina l'elenco di variabili di ambiente impostate automaticamente e determinare se è necessario impostare manualmente GCP_PROJECT al progetto che esegue nelle macchine virtuali.

  6. Imposta il parametro ZONE. Questa è la zona in cui le istanze interrotto per questo campione.

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

Configura le autorizzazioni degli account di servizio

  1. La funzione Cloud Functions viene eseguita un creato automaticamente. Per controllare l'utilizzo, devi concedere l'account di servizio autorizzazioni a qualsiasi servizio nel progetto che deve apportare modifiche.
  2. Per identificare l'account di servizio corretto, visualizza i dettagli del tuo la funzione Cloud Function. L'account di servizio è riportato in fondo alla .
  3. Nella console Google Cloud, vai alla pagina IAM per impostare le autorizzazioni appropriate.
    Vai alla pagina IAM
     
    Mostra la schermata IAM nella console Google Cloud.
         dove puoi impostare le autorizzazioni appropriate per l&#39;account di servizio
         che esegue la Cloud Function.

Verifica che le istanze siano arrestate

Quando il budget invia una notifica, lo stato vengono arrestate.

Per testare la funzione, pubblica un messaggio di esempio con messaggio di test riportato sopra. Per verificare che la funzione sia stata eseguita correttamente, e puoi controllare le macchine virtuali nella console Google Cloud.