Menjadwalkan VM Compute Engine untuk dimulai atau dihentikan


Tutorial ini menunjukkan cara menggunakan Cloud Scheduler dan Cloud Functions untuk memulai dan menghentikan instance Compute Engine secara otomatis sesuai jadwal rutin menggunakan label resource.

Tujuan

  • Tulis dan deploy serangkaian fungsi dengan Cloud Functions yang akan memulai dan menghentikan instance Compute Engine.
  • Buat kumpulan tugas dengan Cloud Scheduler yang menjadwalkan instance dengan label resource dev untuk dijalankan pada pukul 09.00-17.00, Senin-Jumat agar sesuai dengan jam kerja standar.

Biaya

Dalam dokumen ini, Anda menggunakan komponen Google Cloud yang dapat ditagih berikut:

  • Cloud Scheduler
  • Cloud Functions
  • Pub/Sub
  • Compute Engine

Untuk membuat perkiraan biaya berdasarkan proyeksi penggunaan Anda, gunakan kalkulator harga. Pengguna baru Google Cloud mungkin memenuhi syarat untuk mendapatkan uji coba gratis.

Sebelum memulai

  1. Siapkan lingkungan Anda untuk Cloud Scheduler.

    Menyiapkan Lingkungan Anda

  2. Enable the Cloud Functions, Pub/Sub, and Compute Engine APIs.

    Enable the APIs

Arsitektur aplikasi

Solusi ini mencakup komponen Google Cloud berikut:

Diagram arsitektur sistem yang menunjukkan Cloud Scheduler menjadwalkan instance Compute Engine melalui Pub/Sub

Persyaratan lokasi

Beberapa komponen hanya didukung di region tertentu:

  • Instance Compute Engine: didukung di region mana pun yang tercantum di Region dan zona.
  • Cloud Functions: didukung di region yang tercantum di Lokasi.
  • Pesan Pub/Sub: didukung secara global karena Pub/Sub adalah layanan global.
  • Tugas Cloud Scheduler dengan target Pub/Sub: didukung di lokasi Google Cloud mana pun.

Mengapa tidak HTTP, bukan Pub/Sub?

Sebaiknya sederhanakan arsitektur ini menggunakan Pemicu HTTP Cloud Functions, bukan Pemicu Pub/Sub.

Tutorial ini menggunakan Pub/Sub sebagai pemicu Cloud Functions karena metode ini sebelumnya lebih aman daripada menggunakan HTTP. Namun, HTTP juga merupakan pilihan yang valid dan kini dapat diamankan dengan mewajibkan autentikasi.

Untuk mempelajari cara mengamankan Cloud Functions, lihat ringkasan keamanan Cloud Functions. Untuk membandingkan antara pemicu HTTP dan Pub/Sub, lihat dokumentasi Pemicu Cloud Functions.

Menyiapkan instance Compute Engine

Konsol

  1. Buka halaman VM Instances di Konsol Google Cloud.
    Buka halaman VM instances.
  2. Klik Create instance.
  3. Tetapkan Name ke dev-instance.
  4. Pada Label, klik Tambahkan label.
  5. Klik Tambahkan label.
  6. Masukkan env untuk Key dan dev untuk Value.
  7. Untuk Region, pilih us-west1.
  8. Untuk Zone, pilih us-west1-b.
  9. Klik Save.
  10. Klik Create di bagian bawah halaman.

gcloud

gcloud compute instances create dev-instance \
    --network default \
    --zone us-west1-b \
    --labels=env=dev

Men-deploy fungsi yang dipicu oleh Pub/Sub melalui Cloud Functions

Membuat dan men-deploy fungsi

Konsol

Buat fungsi start.

  1. Buka halaman Cloud Functions di Konsol Google Cloud.
    Buka halaman Cloud Functions.
  2. Klik Buat fungsi.
  3. Untuk Lingkungan, pilih generasi ke-1.
  4. Setel Nama fungsi ke startInstancePubSub.
  5. Biarkan Region tetap pada nilai defaultnya.
  6. Untuk Jenis pemicu, pilih Cloud Pub/Sub.
  7. Untuk Select a Cloud Pub/Sub topic, klik Create a topic.
  8. Dialog Create topic akan muncul.
    1. Di bagian Topic ID, masukkan start-instance-event.
    2. Klik Create untuk menyelesaikan dialog.
  9. Klik Simpan di bagian bawah kotak Pemicu.
  10. Klik Berikutnya di bagian bawah halaman.
  11. Untuk Runtime, pilih Node.js 16 atau yang lebih baru.
  12. Untuk Entry point, masukkan startInstancePubSub.
  13. Di sisi kiri editor kode, pilih index.js.
  14. Ganti kode awal dengan kode berikut:

    const compute = require('@google-cloud/compute');
    const instancesClient = new compute.InstancesClient();
    const operationsClient = new compute.ZoneOperationsClient();
    
    async function waitForOperation(projectId, operation) {
      while (operation.status !== 'DONE') {
        [operation] = await operationsClient.wait({
          operation: operation.name,
          project: projectId,
          zone: operation.zone.split('/').pop(),
        });
      }
    }
    
    /**
     * Starts Compute Engine instances.
     *
     * Expects a PubSub message with JSON-formatted event data containing the
     * following attributes:
     *  zone - the GCP zone the instances are located in.
     *  label - the label of instances to start.
     *
     * @param {!object} event Cloud Function PubSub message event.
     * @param {!object} callback Cloud Function PubSub callback indicating
     *  completion.
     */
    exports.startInstancePubSub = async (event, context, callback) => {
      try {
        const project = await instancesClient.getProjectId();
        const payload = _validatePayload(event);
        const options = {
          filter: `labels.${payload.label}`,
          project,
          zone: payload.zone,
        };
    
        const [instances] = await instancesClient.list(options);
    
        await Promise.all(
          instances.map(async instance => {
            const [response] = await instancesClient.start({
              project,
              zone: payload.zone,
              instance: instance.name,
            });
    
            return waitForOperation(project, response.latestResponse);
          })
        );
    
        // Operation complete. Instance successfully started.
        const message = 'Successfully started instance(s)';
        console.log(message);
        callback(null, message);
      } catch (err) {
        console.log(err);
        callback(err);
      }
    };
    
    /**
     * Validates that a request payload contains the expected fields.
     *
     * @param {!object} payload the request payload to validate.
     * @return {!object} the payload object.
     */
    const _validatePayload = event => {
      let payload;
      try {
        payload = JSON.parse(Buffer.from(event.data, 'base64').toString());
      } catch (err) {
        throw new Error('Invalid Pub/Sub message: ' + err);
      }
      if (!payload.zone) {
        throw new Error("Attribute 'zone' missing from payload");
      } else if (!payload.label) {
        throw new Error("Attribute 'label' missing from payload");
      }
      return payload;
    };
  15. Di sisi kiri editor kode, pilih package.json.

  16. Ganti kode awal dengan kode berikut:

    {
      "name": "cloud-functions-schedule-instance",
      "version": "0.1.0",
      "private": true,
      "license": "Apache-2.0",
      "author": "Google Inc.",
      "repository": {
        "type": "git",
        "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git"
      },
      "engines": {
        "node": ">=16.0.0"
      },
      "scripts": {
        "test": "c8 mocha -p -j 2 test/*.test.js --timeout=20000"
      },
      "devDependencies": {
        "c8": "^8.0.0",
        "mocha": "^10.0.0",
        "proxyquire": "^2.0.0",
        "sinon": "^16.0.0"
      },
      "dependencies": {
        "@google-cloud/compute": "^4.0.0"
      }
    }
    
  17. Klik Deploy di bagian bawah halaman.

Buat fungsi berhenti.

  1. Anda seharusnya berada di halaman Cloud Functions di Konsol Google Cloud.
  2. Klik Buat fungsi.
  3. Untuk Lingkungan, pilih generasi ke-1.
  4. Setel Nama fungsi ke stopInstancePubSub.
  5. Biarkan Region tetap pada nilai defaultnya.
  6. Untuk Jenis pemicu, pilih Cloud Pub/Sub.
  7. Untuk Select a Cloud Pub/Sub topic, klik Create a topic.
  8. Dialog Create topic akan muncul.
    1. Di bagian Topic ID, masukkan stop-instance-event.
    2. Klik Create untuk menyelesaikan dialog.
  9. Klik Simpan di bagian bawah kotak Pemicu.
  10. Klik Berikutnya di bagian bawah halaman.
  11. Untuk Runtime, pilih Node.js 16 atau yang lebih baru.
  12. Untuk Entry point, masukkan stopInstancePubSub.
  13. Di sisi kiri editor kode, pilih index.js.
  14. Ganti kode awal dengan kode berikut:

    const compute = require('@google-cloud/compute');
    const instancesClient = new compute.InstancesClient();
    const operationsClient = new compute.ZoneOperationsClient();
    
    async function waitForOperation(projectId, operation) {
      while (operation.status !== 'DONE') {
        [operation] = await operationsClient.wait({
          operation: operation.name,
          project: projectId,
          zone: operation.zone.split('/').pop(),
        });
      }
    }
    
    /**
     * Stops Compute Engine instances.
     *
     * Expects a PubSub message with JSON-formatted event data containing the
     * following attributes:
     *  zone - the GCP zone the instances are located in.
     *  label - the label of instances to stop.
     *
     * @param {!object} event Cloud Function PubSub message event.
     * @param {!object} callback Cloud Function PubSub callback indicating completion.
     */
    exports.stopInstancePubSub = async (event, context, callback) => {
      try {
        const project = await instancesClient.getProjectId();
        const payload = _validatePayload(event);
        const options = {
          filter: `labels.${payload.label}`,
          project,
          zone: payload.zone,
        };
    
        const [instances] = await instancesClient.list(options);
    
        await Promise.all(
          instances.map(async instance => {
            const [response] = await instancesClient.stop({
              project,
              zone: payload.zone,
              instance: instance.name,
            });
    
            return waitForOperation(project, response.latestResponse);
          })
        );
    
        // Operation complete. Instance successfully stopped.
        const message = 'Successfully stopped instance(s)';
        console.log(message);
        callback(null, message);
      } catch (err) {
        console.log(err);
        callback(err);
      }
    };
    
    /**
     * Validates that a request payload contains the expected fields.
     *
     * @param {!object} payload the request payload to validate.
     * @return {!object} the payload object.
     */
    const _validatePayload = event => {
      let payload;
      try {
        payload = JSON.parse(Buffer.from(event.data, 'base64').toString());
      } catch (err) {
        throw new Error('Invalid Pub/Sub message: ' + err);
      }
      if (!payload.zone) {
        throw new Error("Attribute 'zone' missing from payload");
      } else if (!payload.label) {
        throw new Error("Attribute 'label' missing from payload");
      }
      return payload;
    };
  15. Di sisi kiri editor kode, pilih package.json.

  16. Ganti kode awal dengan kode berikut:

    {
      "name": "cloud-functions-schedule-instance",
      "version": "0.1.0",
      "private": true,
      "license": "Apache-2.0",
      "author": "Google Inc.",
      "repository": {
        "type": "git",
        "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git"
      },
      "engines": {
        "node": ">=16.0.0"
      },
      "scripts": {
        "test": "c8 mocha -p -j 2 test/*.test.js --timeout=20000"
      },
      "devDependencies": {
        "c8": "^8.0.0",
        "mocha": "^10.0.0",
        "proxyquire": "^2.0.0",
        "sinon": "^16.0.0"
      },
      "dependencies": {
        "@google-cloud/compute": "^4.0.0"
      }
    }
    
  17. Klik Deploy di bagian bawah halaman.

gcloud

Membuat topik Pub/Sub.

gcloud pubsub topics create start-instance-event
gcloud pubsub topics create stop-instance-event

Mendapatkan kode

  1. Download kodenya.

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    Atau, Anda dapat mendownload sampel sebagai file ZIP dan mengekstraknya.

  2. Buka direktori yang benar.

    cd nodejs-docs-samples/functions/scheduleinstance/
    

Membuat fungsi start dan stop.

Anda harus berada di direktori nodejs-docs-samples/functions/scheduleinstance/.

gcloud functions deploy startInstancePubSub \
    --trigger-topic start-instance-event \
    --runtime nodejs18 \
    --allow-unauthenticated
gcloud functions deploy stopInstancePubSub \
    --trigger-topic stop-instance-event \
    --runtime nodejs18 \
    --allow-unauthenticated

(Opsional) Memastikan fungsi berfungsi

Konsol

Menghentikan instance

  1. Buka halaman Cloud Functions di Konsol Google Cloud.
    Buka halaman Cloud Functions.
  2. Klik fungsi bernama stopInstancePubSub.
  3. Anda akan melihat sejumlah tab: General, Trigger, Source, Permissions, dan Testing. Klik tab Testing.
  4. Untuk Peristiwa pemicu, masukkan:

    {"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}
    

    • Ini hanyalah string berenkode base64 untuk {"zone":"us-west1-b", "label":"env=dev"}

    • Jika ingin mengenkode string sendiri, gunakan alat encoding base64 online apa pun.

  5. Klik tombol Uji fungsi.

  6. Setelah selesai berjalan, Anda akan melihat Successfully stopped instance dev-instance yang dicetak di bagian Output. Mungkin perlu waktu hingga 60 detik untuk menyelesaikan lari.

    • Jika Anda melihat error: 'Error: function failed to load.', cukup tunggu sekitar 10 detik hingga fungsi selesai di-deploy dan coba lagi.

    • Jika Anda melihat error: 'Error: function execution attempt timed out.', lanjutkan ke langkah berikutnya untuk melihat apakah instance perlu waktu yang lama untuk dimatikan.

    • Jika selesai berjalan, tetapi tidak menampilkan apa-apa, mungkin juga waktunya habis. Lanjutkan ke langkah berikutnya untuk melihat apakah instance membutuhkan waktu yang lama untuk dimatikan.

  7. Buka halaman VM Instances di Konsol Google Cloud.
    Buka halaman VM instances.

  8. Pastikan instance yang bernama dev-instance memiliki kotak abu-abu di samping namanya, yang menunjukkan bahwa instance telah berhenti. Mungkin perlu waktu hingga 30 detik untuk menyelesaikan penonaktifan.

    • Jika tampaknya belum selesai, coba klik Refresh di bagian atas halaman.

Memulai instance

  1. Buka halaman Cloud Functions di Konsol Google Cloud.
    Buka halaman Cloud Functions.
  2. Klik fungsi bernama startInstancePubSub.
  3. Anda akan melihat sejumlah tab: General, Trigger, Source, Permissions, dan Testing. Klik tab Testing.
  4. Untuk Peristiwa pemicu, masukkan:

    {"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}
    

    • Sekali lagi, ini hanyalah string berenkode base64 untuk {"zone":"us-west1-b", "label":"env=dev"}
  5. Klik tombol Uji fungsi.

  6. Setelah selesai berjalan, Anda akan melihat Successfully started instance dev-instance yang dicetak di bagian Output.

  7. Buka halaman VM Instances di Konsol Google Cloud.
    Buka halaman VM instances.

  8. Pastikan instance yang bernama dev-instance memiliki tanda centang hijau di samping namanya, yang menunjukkan bahwa instance tersebut sedang berjalan. Diperlukan waktu hingga 30 detik untuk menyelesaikan startup.

gcloud

Menghentikan instance

  1. Memanggil fungsi untuk menghentikan instance.

    gcloud functions call stopInstancePubSub \
        --data '{"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}'
    
    • Ini hanyalah string berenkode base64 untuk {"zone":"us-west1-b", "label":"env=dev"}

    • Jika Anda ingin mengenkode string Anda sendiri, gunakan alat apa pun. Berikut ini contoh penggunaan alat command line base64:

      echo '{"zone":"us-west1-b", "label":"env=dev"}' | base64
      
      eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo=
      

    Setelah fungsi selesai, Anda akan melihat tampilan berikut:

    result: Successfully stopped instance dev-instance
    

    Mungkin perlu waktu hingga 60 detik untuk menyelesaikan lari.

    • Jika sebaliknya Anda mendapatkan error:

      error: 'Error: function failed to load.`
      

      Tunggu sekitar 10 detik hingga fungsi selesai di-deploy dan coba lagi.

    • Jika sebaliknya Anda mendapatkan error:

      error: `Error: function execution attempt timed out.`
      

      Lanjutkan ke langkah berikutnya untuk melihat apakah instance perlu waktu yang lama untuk dimatikan.

    • Jika sebaliknya Anda tidak mendapatkan hasil, waktu fungsi tersebut mungkin habis. Lanjutkan ke langkah berikutnya untuk melihat apakah instance perlu waktu yang lama untuk dimatikan.

  2. Pastikan instance memiliki status TERMINATED. Mungkin perlu waktu hingga 30 detik untuk menyelesaikan penonaktifan.

    gcloud compute instances describe dev-instance \
        --zone us-west1-b \
        | grep status
    
    status: TERMINATED
    

Memulai instance

  1. Panggil fungsi untuk memulai instance.

    gcloud functions call startInstancePubSub \
        --data '{"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}'
    
    • Sekali lagi, ini hanyalah string berenkode base64 untuk {"zone":"us-west1-b", "label":"env=dev"}

    Setelah fungsi selesai, Anda akan melihat tampilan berikut:

    result: Successfully started instance dev-instance
    
  2. Pastikan instance memiliki status RUNNING. Diperlukan waktu hingga 30 detik untuk menyelesaikan startup.

    gcloud compute instances describe dev-instance \
        --zone us-west1-b \
        | grep status
    
    status: RUNNING
    

Menyiapkan tugas Cloud Scheduler untuk memanggil Pub/Sub

Membuat tugas

Konsol

Membuat tugas awal.

  1. Buka halaman Cloud Scheduler di Konsol Google Cloud.
    Buka halaman Cloud Scheduler.
  2. Klik Create a job.
  3. Biarkan region default.
  4. Tetapkan Name ke startup-dev-instances.
  5. Untuk Frequency, masukkan 0 9 * * 1-5.
    • Perintah ini akan dijalankan pada pukul 09.00 setiap hari Sen-Jum.
  6. Untuk Zona Waktu, pilih negara dan zona waktu yang Anda inginkan. Contoh ini akan menggunakan United States dan Los Angeles.
  7. Klik Lanjutkan.
  8. Untuk Jenis target, pilih Pub/Sub.
  9. Pilih start-instance-event dari dropdown topik.
  10. Untuk Message, masukkan info berikut:
    {"zone":"us-west1-b","label":"env=dev"}
    
  11. Klik Create.

Membuat tugas perhentian.

  1. Anda akan berada di halaman Cloud Scheduler di Konsol Google Cloud.
  2. Klik Create Job.
  3. Biarkan region default, lalu klik Next di bagian bawah halaman.
  4. Tetapkan Name ke shutdown-dev-instances.
  5. Untuk Frequency, masukkan 0 17 * * 1-5.
    • Perintah ini akan dijalankan pada pukul 17.00 setiap hari Sen-Jum.
  6. Untuk Zona Waktu, pilih negara dan zona waktu yang Anda inginkan. Contoh ini akan menggunakan United States dan Los Angeles.
  7. Klik Lanjutkan.
  8. Untuk Jenis target, pilih Pub/Sub.
  9. Pilih stop-instance-event dari dropdown topik.
  10. Untuk Message, masukkan info berikut:
    {"zone":"us-west1-b","label":"env=dev"}
    
  11. Klik Create.

gcloud

Membuat tugas awal.

gcloud scheduler jobs create pubsub startup-dev-instances \
    --schedule '0 9 * * 1-5' \
    --topic start-instance-event \
    --message-body '{"zone":"us-west1-b", "label":"env=dev"}' \
    --time-zone 'America/Los_Angeles' \
    --location us-central1

Membuat tugas perhentian.

gcloud scheduler jobs create pubsub shutdown-dev-instances \
    --schedule '0 17 * * 1-5' \
    --topic stop-instance-event \
    --message-body '{"zone":"us-west1-b", "label":"env=dev"}' \
    --time-zone 'America/Los_Angeles' \
    --location us-central1

(Opsional) Memverifikasi apakah tugas telah berfungsi

Konsol

Menghentikan instance

  1. Buka halaman Cloud Scheduler di Konsol Google Cloud.
    Buka halaman Cloud Scheduler.
  2. Untuk tugas bernama shutdown-dev-instances, klik tombol Jalankan sekarang di sisi paling kanan halaman.
  3. Buka halaman VM Instances di Konsol Google Cloud.
    Buka halaman VM instances.
  4. Pastikan instance yang bernama dev-instance memiliki kotak abu-abu di samping namanya, yang menunjukkan bahwa instance telah berhenti. Mungkin perlu waktu hingga 30 detik untuk menyelesaikan penonaktifan.

Memulai instance

  1. Buka halaman Cloud Scheduler di Konsol Google Cloud.
    Buka halaman Cloud Scheduler.
  2. Untuk tugas bernama startup-dev-instances, klik tombol Jalankan sekarang di sisi paling kanan halaman.
  3. Buka halaman VM Instances di Konsol Google Cloud.
    Buka halaman VM instances.
  4. Pastikan instance yang bernama dev-instance memiliki tanda centang hijau di samping namanya, yang menunjukkan bahwa instance tersebut sedang berjalan. Diperlukan waktu hingga 30 detik untuk menyelesaikan proses memulai.

gcloud

Menghentikan instance

  1. Jalankan tugas penjadwal untuk menghentikan instance.

    gcloud beta scheduler jobs run shutdown-dev-instances
    
  2. Pastikan instance memiliki status TERMINATED. Mungkin perlu waktu hingga 30 detik sampai perangkat selesai dinonaktifkan.

    gcloud compute instances describe dev-instance \
        --zone us-west1-b \
        | grep status
    
    status: TERMINATED
    

Memulai instance

  1. Jalankan tugas penjadwal untuk memulai instance.

    gcloud beta scheduler jobs run startup-dev-instances
    
  2. Pastikan instance memiliki status RUNNING. Diperlukan waktu hingga 30 detik untuk menyelesaikan startup.

    gcloud compute instances describe dev-instance \
        --zone us-west1-b \
        | grep status
    
    status: RUNNING
    

Pembersihan

Setelah menyelesaikan tutorial, Anda dapat membersihkan resource yang dibuat agar resource tersebut berhenti menggunakan kuota dan dikenai biaya. Bagian berikut menjelaskan cara menghapus atau menonaktifkan resource ini.

Menghapus tugas Cloud Scheduler

  1. Buka halaman Cloud Scheduler di Konsol Google Cloud.

    Buka halaman Cloud Scheduler.

  2. Klik kotak centang di samping pekerjaan Anda.

  3. Klik tombol Delete di bagian atas halaman dan konfirmasi penghapusan Anda.

Menghapus topik Pub/Sub

  1. Buka halaman Pub/Sub di Konsol Google Cloud.

    Buka halaman Pub/Sub

  2. Klik kotak centang di samping topik.

  3. Klik Hapus di bagian atas halaman dan konfirmasi penghapusan Anda.

Menghapus fungsi yang di-deploy melalui Cloud Functions

  1. Buka halaman Cloud Functions di Konsol Google Cloud.

    Buka halaman Cloud Functions.

  2. Klik kotak centang di samping fungsi Anda.

  3. Klik tombol Delete di bagian atas halaman dan konfirmasi penghapusan Anda.

Menghapus instance Compute Engine

Untuk menghapus instance Compute Engine:

  1. Di konsol Google Cloud, buka halaman Instance VM.

    Buka VM instances

  2. Pilih kotak centang untuk instance yang ingin Anda hapus.
  3. Untuk menghapus instance, klik Tindakan lainnya, klik Hapus, lalu ikuti petunjuknya.

Menghapus project

Cara termudah untuk menghilangkan penagihan adalah dengan menghapus project yang Anda buat untuk tutorial.

Untuk menghapus project:

  1. Di konsol Google Cloud, buka halaman Manage resource.

    Buka Manage resource

  2. Pada daftar project, pilih project yang ingin Anda hapus, lalu klik Delete.
  3. Pada dialog, ketik project ID, lalu klik Shut down untuk menghapus project.

Langkah selanjutnya