🐶

Cloud Functions + Cloud Scheduler + Slackbotで死活監視

2024/07/16に公開

Webサービスの死活監視をするにあたって、なるべく軽量・簡単な仕組みが欲しかったので、GCPを使ってサーバレスで安価に実装してみました。Cloud Functionsの簡単なチュートリアルにもなっています。

Flow
Cloud Scheduler(定期実行)
↓
Cloud Functions ⇄ Webサービス
↓
Slack API → Slack

1. Slackbotの用意

こちらを参考にして、トークンの発行とチャンネルの用意を行いました。
用意できたら、あとはAPIにPOSTするだけでSlackに投稿できるようになります。

https://zenn.dev/kou_pg_0131/articles/slack-api-post-message

2. Cloud Functionsの利用

Cloud Functionsは、AWSでいうとLambdaにあたるものです。
自前で用意した関数をデプロイすることで、HTTPSのエンドポイントを用意してくれるシンプルなサーバレスアーキテクチャです。ここでいう関数とは何かというと、文字通りプログラミング言語の関数に該当しており、PythonやNode.jsなど複数の言語・環境に対応しています。

デプロイできる言語・環境
https://cloud.google.com/functions/docs/concepts/execution-environment?hl=ja

今回はNode.jsを想定して進めます。Node.jsでは、exportすることでデプロイできるようになります。

index.js
// アクセスするとOKとだけ返すAPI
export const sampleFunction = async (req, res) => {
  res.send("OK");
};

2-1. gcloudコマンドの用意

まず、GCPの利用開始とgcloudコマンドのセットアップを行う必要があります。
https://cloud.google.com/sdk/docs/install?hl=ja

2-2. package.jsonと環境

なるべくシンプルにするため、TypeScriptは使わず素のJavaScriptで解説します。

package.json
{
  "main": "index.js",
  "type": "module",
  "scripts": {
    "dev": "functions-framework --target=monitor",
    "deploy": "gcloud functions deploy monitor --gen2 --runtime nodejs22 --trigger-http --allow-unauthenticated --memory=128Mi --region=asia-northeast1"
  },
  "devDependencies": {
    "@google-cloud/functions-framework": "^3.1.0"
  }
}
$ npm i

@google-cloud/functions-frameworkを使えば、ローカルで動作テストをしながら開発することができます。(型定義も含まれるため、TypeScriptを使う場合も必須です。)

--target=monitor... deploy monitor ...について、今回は監視ツールなのでmonitorという関数を用意し、それを利用することを意味しています。後述するスクリプトの関数名と合わせる必要があります。

gcloudコマンドのオプションについては割愛します。

2-3. index.jsの用意

では、monitor関数を実際に用意してみます。

index.js
// 監視するWebサービス
const url = "https://exampe.com/status";

// Slack情報
const slackApiToken = "YOUR_SLACK_TOKEN";
const slackChannel = "#monitoring";
const slackUser = "@your-name";

// デプロイする関数
export const monitor = async (req, res) => {
  const statusResponse = await fetch(url);

  const formData = new FormData();
  formData.set("token", slackApiToken);
  formData.set("channel", slackChannel);
  formData.set("text", statusResponse.ok ? "OK" : `<${slackUser}> ERROR!`);

  await fetch("https://slack.com/api/chat.postMessage", {
    method: "post",
    body: formData
  });

  res.send(statusResponse.ok ? "OK" : "ERROR");
};

運用中のWebサービスにアクセスしてレスポンスを取得し、SlackのAPIに結果をPOSTするスクリプトです。urlは、実際に監視するサービスのURL、Slack情報は先に用意したものに置き換えてください。

2-4. 開発サーバの起動とデプロイ

コマンドの用意は、package.jsonで完了しています。

2-4-1. 開発サーバの起動

$ npm run dev

functions-frameworkを使うことで、開発サーバを起動することができます。ローカルでポートを開けてエンドポイント(http://localhost:8080/)が発行されるので、それにアクセスすることで動作テストをすることができます。
今回は、ブラウザにOKと表示され、用意したSlackチャンネルにOKとポストされれば成功です。逆に、urlにわざと失敗するURLを指定して起動しなおし、メンション付きでERROR!と届けばこちらも成功です。

2-4-2. Cloud Functionsにデプロイ

$ npm run deploy

デプロイに成功したら、エンドポイントのURLが発行され、コマンドラインに表示されます。(ブラウザ上で管理ツールからも確認できます。)

https://{リージョン名}-{プロジェクトID}.cloudfunctions.net/{関数名}

このURLにアクセスし、開発サーバと同じ結果になれば成功です!

3. Cloud Scheduler

https://console.cloud.google.com/cloudscheduler?hl=ja

Cloud Schedulerは、cron形式で記述できる定期実行ツールです。定期実行する内容としてHTTPアクセスを指定できるので、上記のエンドポイントのURLを入力すればOKです。

今回は10分ごとに監視することにします。

*/10 * * * *

管理画面から簡単に設定できるため、詳しい操作は割愛します。

4. スクリプトの改善点

ステータス監視のためのURLを1つにしていますが、実際に運用しているページやAPIを羅列してアクセスすることで、どこで傷害が出ているかを簡易的に特定する仕組みを作ることもできます。

死活監視プログラム自体が動作していることを確認したかったので、OKの場合にもSlackに投稿するようにしています。ただ、頻度が多くなることで投稿回数が多くなるので、OKの場合は投稿を間引いてしまってもいいかもしれません。下記は、12時間に1回投稿する例です。

間引きの例
const now = new Date();

if(now.getHours() % 12 === 0 && now.getMinutes() < 10){
  formData.set("text", "OK");
  // ...
}

他にも、SMTPを使ったメール送信、別のプロジェクト管理ツールへのアラートなども運用として考えられます。サーバレスは好きな言語で機能開発だけに集中できるので、開発環境さえ整えば思いついたものを爆速で試せるメリットもありますね。

Discussion