Menonaktifkan penggunaan penagihan dengan notifikasi

Dokumen ini menjelaskan cara menonaktifkan penagihan secara otomatis di project saat biaya Anda memenuhi atau melebihi anggaran project. Saat menonaktifkan penagihan pada project, Anda akan menghentikan semua layanan Google Cloud dalam project, termasuk layanan Paket Gratis. Untuk respons yang lebih terperinci terhadap notifikasi anggaran, lihat Mengontrol penggunaan resource dengan notifikasi.

Anda mungkin membatasi biaya karena Anda memiliki jumlah maksimum uang yang dapat dibelanjakan untuk Google Cloud. Dalam kasus ini, saat batas anggaran tercapai, Anda mungkin bersedia menonaktifkan semua layanan dan penggunaan Google Cloud untuk berhenti menimbulkan biaya. Menonaktifkan penagihan di project Anda adalah metode yang efisien untuk berhenti menimbulkan biaya dalam project tersebut.

Batasan

  • Terdapat jeda antara timbulnya biaya dan penerimaan notifikasi anggaran, sehingga Anda mungkin dikenai biaya tambahan untuk penggunaan yang belum muncul pada saat semua layanan dihentikan. Mengikuti langkah-langkah dalam contoh ini tidak menjamin bahwa Anda tidak akan membelanjakan lebih dari anggaran. Jika Anda memiliki jumlah dana terbatas, tetapkan anggaran maksimum di bawah dana yang tersedia untuk memperhitungkan keterlambatan penagihan.

  • Anda tidak dapat menonaktifkan penagihan pada project yang terkunci ke akun penagihan. Untuk mempelajari lebih lanjut cara mengunci dan membuka kunci project, lihat Mengamankan link antara project dan akun penagihannya.

Sebelum memulai

Sebelum memulai, Anda harus menyelesaikan tugas-tugas berikut:

  1. Mengaktifkan Cloud Billing API
  2. Membuat anggaran yang dicakup ke satu project
  3. Menyiapkan notifikasi anggaran terprogram

Menyiapkan fungsi Cloud Run

Untuk menonaktifkan Penagihan Cloud untuk sebuah project, buat fungsi Cloud Run dan konfigurasikan untuk memanggil Cloud Billing API.

  1. Selesaikan langkah-langkah di Membuat fungsi Cloud Run. Pastikan Jenis pemicu ditetapkan ke topik Pub/Sub yang sama dengan yang akan digunakan anggaran Anda.
  2. Tambahkan dependensi berikut:

    Node.js

    Salin kode berikut ke file package.json Anda:

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

    Salin kode berikut ke file requirements.txt Anda:

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

  3. Salin kode berikut ke fungsi Cloud Run Anda:

    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. Tetapkan Titik entri ke fungsi yang benar untuk dieksekusi:

    Node.js

    Tetapkan Entry point ke stopBilling.

    Python

    Tetapkan Entry point ke stop_billing.

  5. Tinjau daftar variabel lingkungan yang ditetapkan secara otomatis untuk menentukan apakah Anda perlu menetapkan variabel GOOGLE_CLOUD_PROJECT secara manual ke project yang ingin Anda nonaktifkan Penagihan Cloud-nya.

  6. Klik DEPLOY.

Mengonfigurasi izin akun layanan

Fungsi Cloud Run Anda berjalan sebagai akun layanan yang dibuat otomatis. Untuk menonaktifkan penagihan, Anda harus memberikan izin akun layanan ke layanan apa pun di project yang perlu diubah dengan menyelesaikan langkah-langkah berikut:

  1. Identifikasi akun layanan yang benar dengan melihat detail fungsi Cloud Run Anda. Akun layanan tercantum di bagian bawah halaman.
  2. Buka halaman IAM di konsol Google Cloud untuk menetapkan izin yang sesuai.

    Buka halaman IAM

  3. Untuk mengubah izin akun penagihan, di konsol Google Cloud, buka halaman Pengelolaan akun Penagihan, tambahkan akun layanan sebagai akun utama di akun Penagihan Cloud, lalu tetapkan izin akun penagihan yang sesuai.

    Buka halaman Pengelolaan akun di Penagihan Cloud

Pelajari lebih lanjut cara mengonfigurasi izin untuk akun Penagihan Cloud.

Menguji bahwa Penagihan Cloud dinonaktifkan

Saat anggaran mengirimkan notifikasi, project yang ditentukan tidak akan lagi memiliki akun Penagihan Cloud yang terkait. Untuk memastikan fungsi Anda berfungsi seperti yang diharapkan, ikuti langkah-langkah di Menguji fungsi Cloud Run.

Jika berhasil, project tidak akan terlihat lagi di akun Penagihan Cloud dan resource dalam project akan dinonaktifkan, termasuk fungsi Cloud Run jika berada dalam project yang sama.

Untuk terus menggunakan resource Google Cloud dalam project, di konsol Google Cloud, aktifkan kembali Penagihan Cloud secara manual untuk project Anda.

Langkah berikutnya

Tinjau contoh notifikasi terprogram lainnya untuk mempelajari cara melakukan hal berikut: