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

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

目標

  • Cloud Functions で、Compute Engine インスタンスの起動関数と停止関数を作成してデプロイする。
  • Cloud Scheduler で、インスタンスを通常の営業時間(月曜日から金曜日の 09:00〜17:00)の間稼働させるスケジュール ジョブを作成する。

料金

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

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

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを出すことができます。 GCP を初めてご利用の場合は、無料トライアルをご利用いただけます。

始める前に

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

    環境設定

  2. Cloud Functions、Cloud Pub/Sub、Compute Engine必要な API を有効にします。

    API を有効にする

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

このソリューションは、次の GCP コンポーネントで構成されています。

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

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

ロケーションの要件

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

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

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

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

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

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

より安全な設定のために、Cloud Pub/Sub 関数を使用することをおすすめします。

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

Console

  1. GCP Console の [VM インスタンス] ページに移動します。
    [VM インスタンス] ページに移動
  2. [インスタンスを作成] をクリックします。
  3. [名前] を「workday-instance」に設定します。
  4. [リージョン] で [us-west1] を選択します。
  5. [ゾーン] で [us-west1-b] を選択します。
  6. ページの下部にある [作成] をクリックします。

gcloud

gcloud compute instances create workday-instance \
    --network default \
    --zone us-west1-b

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

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

Console

起動の関数を作成する

  1. GCP 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 6] を選択します。
  9. コードテキスト ブロックの上にある [index.js] タブを選択します。
  10. スターター コードを次のコードに置き換えます。

    const Buffer = require('safe-buffer').Buffer;
    const Compute = require('@google-cloud/compute');
    const compute = new Compute();
    
    /**
     * Starts a Compute Engine instance.
     *
     * Expects a PubSub message with JSON-formatted event data containing the
     * following attributes:
     *  zone - the GCP zone the instance is located in.
     *  instance - the name of the instance.
     *
     * @param {!object} event Cloud Function PubSub message event.
     * @param {!object} callback Cloud Function PubSub callback indicating completion.
     */
    exports.startInstancePubSub = (event, callback) => {
      try {
        const pubsubMessage = event.data;
        const payload = _validatePayload(
          JSON.parse(Buffer.from(pubsubMessage.data, 'base64').toString())
        );
        compute
          .zone(payload.zone)
          .vm(payload.instance)
          .start()
          .then(data => {
            // Operation pending.
            const operation = data[0];
            return operation.promise();
          })
          .then(() => {
            // Operation complete. Instance successfully started.
            const message = 'Successfully started instance ' + payload.instance;
            console.log(message);
            callback(null, message);
          })
          .catch(err => {
            console.log(err);
            callback(err);
          });
      } catch (err) {
        console.log(err);
        callback(err);
      }
    };
    
    /**
     * Validates that a request payload contains the expected fields.
     *
     * @param {!object} payload the request payload to validate.
     * @returns {!object} the payload object.
     */
    function _validatePayload(payload) {
      if (!payload.zone) {
        throw new Error(`Attribute 'zone' missing from payload`);
      } else if (!payload.instance) {
        throw new Error(`Attribute 'instance' missing from payload`);
      }
      return payload;
    }
  11. コードテキスト ブロックの上にある [package.json] タブを選択します。

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

    {
      "name": "cloud-functions-schedule-instance",
      "version": "0.0.1",
      "private": true,
      "license": "Apache-2.0",
      "author": "Google Inc.",
      "repository": {
        "type": "git",
        "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git"
      },
      "engines": {
        "node": ">=8"
      },
      "scripts": {
        "test": "mocha test/*.test.js --timeout=20000"
      },
      "devDependencies": {
        "@google-cloud/nodejs-repo-tools": "^3.3.0",
        "mocha": "^5.2.0",
        "proxyquire": "^2.0.0",
        "sinon": "^7.0.0"
      },
      "dependencies": {
        "@google-cloud/compute": "^0.11.0",
        "safe-buffer": "^5.1.2"
      }
    }
    
  13. [実行する関数] に「startInstancePubSub」と入力します。

  14. [作成] をクリックします。

停止の関数を作成する

  1. GCP 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 6] を選択します。
  9. コードテキスト ブロックの上にある [index.js] タブを選択します。
  10. スターター コードを次のコードに置き換えます。

    const Buffer = require('safe-buffer').Buffer;
    const Compute = require('@google-cloud/compute');
    const compute = new Compute();
    
    /**
     * Stops a Compute Engine instance.
     *
     * Expects a PubSub message with JSON-formatted event data containing the
     * following attributes:
     *  zone - the GCP zone the instance is located in.
     *  instance - the name of the instance.
     *
     * @param {!object} event Cloud Function PubSub message event.
     * @param {!object} callback Cloud Function PubSub callback indicating completion.
     */
    exports.stopInstancePubSub = (event, callback) => {
      try {
        const pubsubMessage = event.data;
        const payload = _validatePayload(
          JSON.parse(Buffer.from(pubsubMessage.data, 'base64').toString())
        );
        compute
          .zone(payload.zone)
          .vm(payload.instance)
          .stop()
          .then(data => {
            // Operation pending.
            const operation = data[0];
            return operation.promise();
          })
          .then(() => {
            // Operation complete. Instance successfully stopped.
            const message = 'Successfully stopped instance ' + payload.instance;
            console.log(message);
            callback(null, message);
          })
          .catch(err => {
            console.log(err);
            callback(err);
          });
      } catch (err) {
        console.log(err);
        callback(err);
      }
    };
    
    /**
     * Validates that a request payload contains the expected fields.
     *
     * @param {!object} payload the request payload to validate.
     * @returns {!object} the payload object.
     */
    function _validatePayload(payload) {
      if (!payload.zone) {
        throw new Error(`Attribute 'zone' missing from payload`);
      } else if (!payload.instance) {
        throw new Error(`Attribute 'instance' missing from payload`);
      }
      return payload;
    }
  11. コードテキスト ブロックの上にある [package.json] タブを選択します。

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

    {
      "name": "cloud-functions-schedule-instance",
      "version": "0.0.1",
      "private": true,
      "license": "Apache-2.0",
      "author": "Google Inc.",
      "repository": {
        "type": "git",
        "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git"
      },
      "engines": {
        "node": ">=8"
      },
      "scripts": {
        "test": "mocha test/*.test.js --timeout=20000"
      },
      "devDependencies": {
        "@google-cloud/nodejs-repo-tools": "^3.3.0",
        "mocha": "^5.2.0",
        "proxyquire": "^2.0.0",
        "sinon": "^7.0.0"
      },
      "dependencies": {
        "@google-cloud/compute": "^0.11.0",
        "safe-buffer": "^5.1.2"
      }
    }
    
  13. [実行する関数] に「stopInstancePubSub」と入力します。

  14. [作成] をクリックします。

gcloud

Cloud 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 nodejs6
gcloud functions deploy stopInstancePubSub \
    --trigger-topic stop-instance-event \
    --runtime nodejs6

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

Console

インスタンスを停止する

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

    {"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsImluc3RhbmNlIjoid29ya2RheS1pbnN0YW5jZSJ9Cg=="}
    

    • これは、{"zone":"us-west1-b", "instance":"workday-instance"} を base64 でエンコードした文字列です。

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

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

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

    • 上記のメッセージではなく「error: 'Error: function failed to load.'」が表示された場合は、関数のデプロイが完了するまで 10 秒ほど待ってからやり直してください。

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

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

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

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

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

インスタンスを起動する

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

    {"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsImluc3RhbmNlIjoid29ya2RheS1pbnN0YW5jZSJ9Cg=="}
    

    • これも、{"zone":"us-west1-b", "instance":"workday-instance"} を base64 でエンコードした文字列です。
  5. [関数をテスト] ボタンをクリックします。

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

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

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

gcloud

インスタンスを停止する

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

    gcloud functions call stopInstancePubSub \
        --data '{"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsImluc3RhbmNlIjoid29ya2RheS1pbnN0YW5jZSJ9Cg=="}'
    
    • これは、{"zone":"us-west1-b", "instance":"workday-instance"} を base64 でエンコードした文字列です。

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

      echo '{"zone":"us-west1-b", "instance":"workday-instance"}' | base64
      
      eyJ6b25lIjoidXMtd2VzdDEtYiIsImluc3RhbmNlIjoid29ya2RheS1pbnN0YW5jZSJ9Cg==
      

    ファンクションが終了すると、次のように表示されます。

    result: Successfully stopped instance workday-instance
    

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

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

      error: 'Error: function failed to load.`
      

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

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

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

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

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

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

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

インスタンスを起動する

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

    gcloud functions call startInstancePubSub \
        --data '{"data":"eyJ6b25lIjoidXMtd2VzdDEtYiIsImluc3RhbmNlIjoid29ya2RheS1pbnN0YW5jZSJ9Cg=="}'
    
    • これも、{"zone":"us-west1-b", "instance":"workday-instance"} を base64 でエンコードした文字列です。

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

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

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

Cloud Pub/Sub を呼び出すように Cloud Scheduler ジョブを設定する

ジョブを作成する

Console

起動ジョブを作成する

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

停止ジョブを作成する

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

gcloud

起動ジョブを作成する

gcloud beta scheduler jobs create pubsub startup-workday-instance \
    --schedule '0 9 * * 1-5' \
    --topic start-instance-event \
    --message-body '{"zone":"us-west1-b","instance":"workday-instance"}' \
    --time-zone 'America/Los_Angeles'

停止ジョブを作成する

gcloud beta scheduler jobs create pubsub shutdown-workday-instance \
    --schedule '0 17 * * 1-5' \
    --topic stop-instance-event \
    --message-body '{"zone":"us-west1-b","instance":"workday-instance"}' \
    --time-zone 'America/Los_Angeles'

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

Console

インスタンスを停止する

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

インスタンスを起動する

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

gcloud

インスタンスを停止する

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

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

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

インスタンスを起動する

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

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

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

クリーンアップ

インスタンスのスケジュール設定のチュートリアルが終了したら、GCP で作成したリソースをクリーンアップして、今後料金が発生しないようにします。以下のセクションでは、このようなリソースを削除または無効にする方法を説明します。

Cloud Scheduler ジョブの削除

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

    [Cloud Scheduler] ページに移動

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

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

Cloud Pub/Sub トピックの削除

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

    [Cloud Pub/Sub] ページに移動

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

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

Cloud Functions 関数の削除

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

    [Cloud Functions] ページに移動

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

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

Compute Engine インスタンスの削除

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

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

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

  2. 次のチェックボックスをオンにします。 削除するインスタンス。
  3. インスタンスを削除するには、[削除] () をクリックします。

プロジェクトの削除

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

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

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

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

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

次のステップ