Cloud Scheduler を使用した Compute インスタンスのスケジュール設定

このチュートリアルでは、Cloud Scheduler と Cloud Functions を使用して、リソースラベルを使用し、定期的なスケジュールで Compute Engine インスタンスを自動的に開始および停止する方法を示します。

目標

  • Cloud Functions で、Compute Engine インスタンスの起動関数と停止関数を作成してデプロイする。
  • Cloud Scheduler を使用して一連のジョブを作成し、devリソースラベルを持つインスタンスをスケジュールして、通常の営業時間に一致させるために、月曜日から金曜日の 09:00-17:00 に実行します。

費用

このチュートリアルでは、課金対象である次の Google Cloud コンポーネントを使用します。

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

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

始める前に

  1. Cloud Scheduler 用に環境を設定します。

    環境設定

  2. Cloud Functions, Pub/Sub, and Compute Engine API を有効にします。

    API を有効にする

アプリケーション アーキテクチャ

このソリューションでは、次の Google Cloud コンポーネントを使用します。

  1. Compute Engine インスタンス: スケジュールに従って実行される Compute Engine インスタンス。
  2. Cloud Functions 関数: スケジュールに従ってインスタンスを起動および停止する関数。
  3. Pub/Sub メッセージ:開始イベントと停止イベントごとに送受信されるメッセージ。
  4. Cloud Scheduler ジョブ: スケジュールに従ってインスタンスの起動と停止の呼び出しを行うジョブ。

Cloud Scheduler が Pub/Sub を介して Compute Engine インスタンスをスケジュールするシステムアーキテクチャの図

ロケーションの要件

一部のコンポーネントは特定のリージョンでのみサポートされています。

  1. Compute Engine インスタンス: Compute Engine のリージョンとゾーンにリストされているすべてのリージョンでサポートされます。
  2. Cloud Functions ファンクション: Cloud Functions ロケーションとしてリストされているリージョンでサポートされます。
  3. Pub/Sub メッセージ: Pub/Sub はグローバル サービスであるため、グローバルでサポートされます。
  4. Cloud Scheduler ジョブ: 現在のすべての App Engine ロケーションでサポートされます。

おすすめの方法: HTTP ではなく Pub/Sub を使用する理由

Pub/Sub トリガーの代わりに Cloud Functions の HTTP トリガーを使用して、このアーキテクチャをシンプルにしたいと考えるかもしれません。

Cloud Scheduler が HTTP 経由で Compute Engine インスタンスのスケジュールを設定する様子を示すシステム アーキテクチャ図

HTTP 経由でスケジュールした場合、誰でも Compute Engine インスタンスのスケジュールを設定できることを示すシステム アーキテクチャ図

より安全な設定を作成するには、代わりに Pub/Sub 関数を使用することをお勧めします。

Compute Engine インスタンスを設定する

コンソール

  1. Cloud Console の [VM インスタンス] ページに移動します。
    [VM インスタンス] ページに移動
  2. [インスタンスを作成] をクリックします。
  3. [名前] を dev-instance に設定します。
  4. [リージョン] で、us-west1 を選択します。
  5. [ゾーン] で、[us-west1-b] を選択します。
  6. [管理、セキュリティ、ディスク、ネットワーク、単一テナンシー] セクションを展開します。
  7. [管理]で、[ラベルを追加]をクリックします。KeyenvValuedevを入力します。
  8. ページの下部にある [作成] をクリックします。

gcloud

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

Pub/Sub を使用して Cloud Functions 関数を設定する

関数を作成してデプロイする

Console

起動の関数を作成する

  1. Cloud Console の [Cloud Functions] ページに移動します。
    [Cloud Functions] ページに移動
  2. [関数を作成] をクリックします。
  3. [名前] を startInstancePubSub に設定します。
  4. [割り当てられるメモリ] はデフォルト値のままにします。
  5. [トリガー]で [Cloud Pub/Sub]を選択します。
  6. [トピック]で [Create new topic...]を選択します。
  7. [新しい pub/sub トピック] ダイアログ ボックスが表示されます。
    1. [名前] に「start-instance-event」と入力します。
    2. [作成] をクリックしてダイアログ ボックスを閉じます。
  8. [ランタイム]で、[Node.js 8]を選択します。
  9. コードテキストブロックの上にある [index.js]タブを選択します。
  10. スターター コードを次のコードに置き換えます。

    const Compute = require('@google-cloud/compute');
    const compute = new Compute();
    
    /**
     * 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 payload = _validatePayload(
          JSON.parse(Buffer.from(event.data, 'base64').toString())
        );
        const options = {filter: `labels.${payload.label}`};
        const [vms] = await compute.getVMs(options);
        await Promise.all(
          vms.map(async (instance) => {
            if (payload.zone === instance.zone.id) {
              const [operation] = await compute
                .zone(payload.zone)
                .vm(instance.name)
                .start();
    
              // Operation pending
              return operation.promise();
            }
          })
        );
    
        // 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 = (payload) => {
      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;
    };
  11. コードテキストブロックの上にある [package.json]タブを選択します。

  12. スターター コードを次のコードに置き換えます。

    {
      "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": ">=8.0.0"
      },
      "scripts": {
        "test": "mocha test/*.test.js --timeout=20000"
      },
      "devDependencies": {
        "mocha": "^7.0.0",
        "proxyquire": "^2.0.0",
        "sinon": "^9.0.0"
      },
      "dependencies": {
        "@google-cloud/compute": "^1.0.0"
      }
    }
    
  13. [実行する関数]にstartInstancePubSubを入力します。

  14. [作成] をクリック

停止の関数を作成する

  1. Cloud Console にCloud Functionsページが表示されているはずです。
  2. [関数を作成] をクリックします。
  3. [名前] を stopInstancePubSub に設定します。
  4. [割り当てられるメモリ] はデフォルト値のままにします。
  5. [トリガー]で [Cloud Pub/Sub]を選択します。
  6. [トピック]で [Create new topic...]を選択します。
  7. [新しい pub/sub トピック] ダイアログ ボックスが表示されます。
    1. [名前] に「stop-instance-event」と入力します。
    2. [作成] をクリックしてダイアログ ボックスを閉じます。
  8. [ランタイム]で、[Node.js 8]を選択します。
  9. コードテキストブロックの上にある [index.js]タブを選択します。
  10. スターター コードを次のコードに置き換えます。

    const Compute = require('@google-cloud/compute');
    const compute = new Compute();
    
    /**
     * 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 payload = _validatePayload(
          JSON.parse(Buffer.from(event.data, 'base64').toString())
        );
        const options = {filter: `labels.${payload.label}`};
        const [vms] = await compute.getVMs(options);
        await Promise.all(
          vms.map(async (instance) => {
            if (payload.zone === instance.zone.id) {
              const [operation] = await compute
                .zone(payload.zone)
                .vm(instance.name)
                .stop();
    
              // Operation pending
              return operation.promise();
            } else {
              return Promise.resolve();
            }
          })
        );
    
        // 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 = (payload) => {
      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;
    };
  11. コードテキストブロックの上にある [package.json]タブを選択します。

  12. スターター コードを次のコードに置き換えます。

    {
      "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": ">=8.0.0"
      },
      "scripts": {
        "test": "mocha test/*.test.js --timeout=20000"
      },
      "devDependencies": {
        "mocha": "^7.0.0",
        "proxyquire": "^2.0.0",
        "sinon": "^9.0.0"
      },
      "dependencies": {
        "@google-cloud/compute": "^1.0.0"
      }
    }
    
  13. [実行する関数]にstopInstancePubSubを入力します。

  14. [作成] をクリック

gcloud

Pub/Sub トピックを作成します。

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

コードを取得

  1. コードをダウンロードします。

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

    または、zip 形式のサンプルをダウンロードし、ファイルを抽出してもかまいません。

  2. 適切なディレクトリに移動します。

    cd nodejs-docs-samples/functions/scheduleinstance/
    

起動の関数と停止の関数を作成する

nodejs-docs-samples/functions/scheduleinstance/ディレクトリにいるはずです。

gcloud functions deploy startInstancePubSub \
    --trigger-topic start-instance-event \
    --runtime nodejs8
gcloud functions deploy stopInstancePubSub \
    --trigger-topic stop-instance-event \
    --runtime nodejs8

(省略可)ファンクションが動作することを確認する

Console

インスタンスを停止する

  1. Cloud Console の [Cloud Functions] ページに移動します。
    [Cloud Functions] ページに移動
  2. stopInstancePubSubという名前の関数をクリックします。
  3. 複数のタブ([全般]、[トリガー]、[ソース]、[テスト])が表示されます。[テスト] タブをクリックします。
  4. [トリガーとなるイベント] に、次のテキストを入力します。

    {"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}
    

    • これは、{"zone":"us-west1-b", "label":"env=dev"}の base64 エンコードされた文字列です

    • 独自の文字列をエンコードするには、任意のオンライン base64 エンコード ツールを使用してください。

  5. [関数をテスト] ボタンをクリックします。

  6. 実行が完了すると、[出力]の下にSuccessfully stopped instance dev-instanceが表示されます。実行の終了までに最長で 60 秒かかります。

    • 代わりにerror: 'Error: function failed to load.'が表示される場合は、関数がデプロイを完了するまで 10 秒ほど待ってから、再試行してください。

    • 代わりにerror: 'Error: function execution attempt timed out.'が表示される場合は、次のステップに進んで、インスタンスがシャットダウンするのに長い時間がかかっているかどうかを確認してください。

    • 実行が終了しても何も表示されない場合は、タイムアウトになっただけの可能性もあります。次のステップに進んで、インスタンスのシャットダウンに時間がかかっているだけかどうかを確認してください。

  7. Cloud Console の [VM インスタンス] ページに移動します。
    [VM インスタンス] ページに移動

  8. dev-instanceという名前のインスタンスの名前の横に灰色の四角があり、停止していることを確認します。シャットダウンが完了するまでに最長で 30 秒かかります。

    • 停止が完了していない場合は、ページの上部にある [更新] をクリックしてみてください。

インスタンスを起動する

  1. Cloud Console の [Cloud Functions] ページに移動します。
    [Cloud Functions] ページに移動
  2. startInstancePubSubという名前の関数をクリックします。
  3. 複数のタブ([全般]、[トリガー]、[ソース]、[テスト])が表示されます。[テスト] タブをクリックします。
  4. [トリガーとなるイベント] に、次のテキストを入力します。

    {"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}
    

    • 繰り返しますが、これは{"zone":"us-west1-b", "label":"env=dev"}の base64 エンコードされた文字列です
  5. [関数をテスト] ボタンをクリックします。

  6. 実行が完了すると、[出力]の下にSuccessfully started instance dev-instanceが表示されます。

  7. Cloud Console の [VM インスタンス] ページに移動します。
    [VM インスタンス] ページに移動

  8. dev-instanceという名前のインスタンスの名前の横に、実行中であることを示す緑色のチェックマークが付いていることを確認します。起動処理が完了するまでに最長で 30 秒かかります。

gcloud

インスタンスを停止する

  1. 関数を呼び出してインスタンスを停止します。

    gcloud functions call stopInstancePubSub \
        --data '{"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}'
    
    • これは、{"zone":"us-west1-b", "label":"env=dev"}の base64 エンコードされた文字列です

    • 独自の文字列をエンコードするには、任意のツールを使用してください。 次に、base64コマンドラインツールを使用した例を示します。

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

    関数が終了すると、次のように表示されます。

    result: Successfully stopped instance dev-instance
    

    実行の終了までに最長で 60 秒かかります。

    • 次のエラーが出力されることがあります。

      error: 'Error: function failed to load.`
      

      この場合は、関数のデプロイが完了するまで 10 秒ほど待ってからやり直してください。

    • 次のエラーが出力されることがあります。

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

      この場合は、次のステップに進んで、インスタンスのシャットダウンに時間がかかっているだけかどうかを確認してください。

    • 何も表示されない場合は、関数がタイムアウトになっただけの可能性もあります。 この場合は、次のステップに進んで、インスタンスのシャットダウンに時間がかかっているだけかどうかを確認してください。

  2. インスタンスのステータスが TERMINATED であることを確認します。シャットダウンが完了するまでに最長で 30 秒かかります。

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

インスタンスを起動する

  1. 関数を呼び出してインスタンスを起動します。

    gcloud functions call startInstancePubSub \
        --data '{"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsICJsYWJlbCI6ImVudj1kZXYifQo="}'
    
    • 繰り返しますが、これは{"zone":"us-west1-b", "label":"env=dev"}の base64 エンコードされた文字列です

    関数が終了すると、次のように表示されます。

    result: Successfully started instance dev-instance
    
  2. インスタンスのステータスが RUNNING であることを確認します。起動処理が完了するまでに最長で 30 秒かかります。

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

Cloud Scheduler ジョブを設定して Pub/Sub を呼び出す

ジョブを作成する

Console

起動ジョブを作成する

  1. Cloud Console のCloud Schedulerページに移動します。
    [Cloud Scheduler] ページに移動
  2. [ジョブを作成] をクリックします。
  3. [名前] を startup-dev-instances に設定します。
  4. [頻度] に「0 9 * * 1-5」と入力します。
  5. [タイムゾーン] で、目的の国とタイムゾーンを選択します。この例では、United StatesLos Angelesを使用します。
  6. [ターゲット]で、[Pub/Sub]を選択します。
  7. [トピック]に「start-instance-event」と入力します。
  8. [ペイロード] に、次のテキストを入力します。
    {"zone":"us-west1-b","label":"env=dev"}
    
  9. [作成] をクリックします。

停止ジョブを作成する

  1. Cloud Console のCloud Schedulerページが表示されているはずです。
  2. [ジョブを作成] をクリックします。
  3. [名前] を shutdown-dev-instances に設定します。
  4. [頻度] に「0 17 * * 1-5」と入力します。
  5. [タイムゾーン] で、目的の国とタイムゾーンを選択します。この例では、United StatesLos Angelesを使用します。
  6. [ターゲット]で、[Pub/Sub]を選択します。
  7. [トピック]に「stop-instance-event」と入力します。
  8. [ペイロード] に、次のテキストを入力します。
    {"zone":"us-west1-b","label":"env=dev"}
    
  9. [作成] をクリックします。

gcloud

起動ジョブを作成する

gcloud beta 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'

停止ジョブを作成する

gcloud beta 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'

(省略可)ジョブが動作することを確認する

Console

インスタンスを停止する

  1. Cloud Console のCloud Schedulerページに移動します。
    [Cloud Scheduler] ページに移動
  2. shutdown-dev-instancesという名前のジョブについては、ページの右端にある [今すぐ実行]ボタンをクリックします。
  3. Cloud Console の [VM インスタンス] ページに移動します。
    [VM インスタンス] ページに移動
  4. dev-instanceという名前のインスタンスの名前の横に灰色の四角があり、停止していることを確認します。シャットダウンが完了するまでに最長で 30 秒かかります。

インスタンスを起動する

  1. Cloud Console のCloud Schedulerページに移動します。
    [Cloud Scheduler] ページに移動
  2. startup-dev-instancesという名前のジョブについては、ページの右端にある [今すぐ実行]ボタンをクリックします。
  3. Cloud Console の [VM インスタンス] ページに移動します。
    [VM インスタンス] ページに移動
  4. dev-instanceという名前のインスタンスの名前の横に、実行中であることを示す緑色のチェックマークが付いていることを確認します。起動処理が完了するまでに最長で 30 秒かかります。

gcloud

インスタンスを停止する

  1. スケジューラ ジョブを実行してインスタンスを停止します。

    gcloud beta scheduler jobs run shutdown-dev-instances
    
  2. インスタンスのステータスが TERMINATED であることを確認します。シャットダウンが完了するまでに最長で 30 秒かかります。

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

インスタンスを起動する

  1. スケジューラ ジョブを実行してインスタンスを起動します。

    gcloud beta scheduler jobs run startup-dev-instances
    
  2. インスタンスのステータスが RUNNING であることを確認します。起動処理が完了するまでに最長で 30 秒かかります。

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

クリーンアップ

インスタンススケジューリングのチュートリアルが終了したら、Google Cloud で作成したリソースをクリーンアップして、割り当てを消費したり、将来的に課金されたりしないようにすることができます。次のセクションで、リソースを削除または無効にする方法を説明します。

Cloud Scheduler ジョブの削除

  1. Cloud Console のCloud Schedulerページに移動します。

    [Cloud Scheduler] ページに移動

  2. ジョブの横にあるチェックボックスをクリックします。

  3. ページの上部にある [ジョブの削除] ボタンをクリックして、削除操作を確定します。

Pub/Sub トピックを削除する

  1. Cloud Console の [Pub/Sub] ページに移動します。

    [Pub/Sub] ページに移動

  2. トピックの横にあるチェックボックスをクリックします。

  3. ページの上部にある [削除] をクリックして、削除操作を確定します。

Cloud Functions 関数の削除

  1. Cloud Console の [Cloud Functions] ページに移動します。

    [Cloud Functions] ページに移動

  2. 関数の横にあるチェックボックスをクリックします。

  3. ページの上部にある [削除] ボタンをクリックして、削除操作を確定します。

Compute Engine インスタンスの削除

Compute Engine インスタンスを削除するには:

  1. Cloud Console で、[VM インスタンス] ページに移動します。

    [VM インスタンス] ページに移動

  2. 削除するインスタンスをクリックします。
  3. [削除] をクリックしてインスタンスを削除します。

プロジェクトの削除

課金をなくす最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。

プロジェクトを削除するには:

  1. Cloud Console で [リソースの管理] ページに移動します。

    [リソースの管理] ページに移動

  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

次のステップ