Ressourcennutzung mit Benachrichtigungen steuern

In diesem Dokument wird erläutert, wie Sie Budgetbenachrichtigungen verwenden, um die Ressourcennutzung selektiv zu steuern.

Wenn Sie die Abrechnung für ein Projekt deaktivieren, werden alle Dienste beendet und alle Ressourcen schließlich gelöscht. Wenn Sie eine differenziertere Rückmeldung benötigen, können Sie Ressourcen selektiv steuern. Sie können beispielsweise einige Compute Engine-Ressourcen beenden, während Cloud Storage-Ressourcen intakt bleiben. Wenn Sie nur einige Ressourcen beenden, senken Sie Ihre Kosten, ohne Ihre Umgebung vollständig zu deaktivieren.

Im folgenden Beispiel werden im Projekt Untersuchungen mit einer Reihe von virtuellen Compute Engine-Maschinen (VMs) durchgeführt und die Ergebnisse in Cloud Storage-Buckets gespeichert. Wenn die Budgetbenachrichtigungen als Trigger verwendet werden, werden nach Überschreiten des Budgets alle Compute Engine-Instanzen von dieser Cloud Run-Funktion heruntergefahren. Die gespeicherten Ergebnisse sind davon nicht betroffen.

Hinweis

Vor dem Beginn müssen Sie die folgenden Aufgaben ausführen:

  1. Cloud Billing API aktivieren
  2. Budget erstellen
  3. Programmatische Budgetbenachrichtigungen einrichten

Cloud Run-Funktion einrichten

  1. Führen Sie die Schritte unter Cloud Run-Funktion erstellen aus. Achten Sie darauf, dass Sie für den Triggertyp dasselbe Pub/Sub-Thema festlegen, das von Ihrem Budget verwendet wird.
  2. Fügen Sie die folgenden Abhängigkeiten hinzu:

    Node.js

    Kopieren Sie Folgendes in die Datei 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": ">=18.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",
        "@slack/web-api": "^7.15.0",
        "google-auth-library": "^9.0.0",
        "googleapis": "^143.0.0"
      },
      "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

    Kopieren Sie Folgendes in die Datei requirements.txt:

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

  3. Kopieren Sie den folgenden Code in Ihre Cloud Run-Funktion:

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

  4. Legen Sie den Einstiegspunkt auf die richtige auszuführende Funktion fest:

    Node.js

    Legen Sie den Einstiegspunkt auf limitUse fest.

    Python

    Legen Sie den Einstiegspunkt auf limit_use fest.

  5. Prüfen Sie die Liste der automatisch festgelegten Umgebungsvariablen und legen Sie fest, ob die Variable GCP_PROJECT manuell für das Projekt festgelegt werden muss, in dem die virtuellen Maschinen ausgeführt werden.

  6. Legen Sie den ZONE Parameter fest. Dieser Parameter ist die Zone, in der Instanzen beendet werden, wenn das Budget überschritten wird.

  7. Klicken Sie auf DEPLOY (Bereitstellen).

Dienstkontoberechtigungen konfigurieren

Ihre Cloud Run-Funktion wird als automatisch erstelltes Dienstkonto ausgeführt. Zum Steuern der Nutzung müssen Sie dem Dienstkonto für alle Dienste im Projekt die Berechtigungen erteilen, die zum Ändern erforderlich sind. Führen Sie dazu die folgenden Schritte aus:

  1. Sehen Sie sich die Details der Cloud Run-Funktion an, um das richtige Dienstkonto zu ermitteln. Das Dienstkonto ist am Ende der Seite aufgeführt.
  2. Rufen Sie in der Google Cloud Console die Seite IAM auf, um die geeigneten Berechtigungen festzulegen.

    Zur IAM-Seite

Prüfen, ob Instanzen beendet wurden

Folgen Sie der Anleitung unter Cloud Run-Funktion testen, um zu prüfen, ob die Funktion wie erwartet funktioniert.

Wenn der Test erfolgreich ist, werden Ihre Compute Engine-VMs in der Google Cloud Console beendet.

Nächste Schritte

Weitere Beispiele für programmatische Benachrichtigungen finden Sie hier: