
DoiT InternationalのCTOとして、私が日々の業務で楽しみにしているのがお客様との対話です。気づきが多く、毎回新しい学びがあります。
先週、あるお客様から「Google Cloud PlatformとSlackを連携させるにはどうするのがベストか」というチケットが届きました。
具体的には、Google Cloudプロジェクト内で何らかのアクティビティ(たとえばインスタンスの起動・停止、新しいバケットの作成・削除など)が発生したときに、Slackチャンネルに通知を受け取りたい、というご要望です。なかなか面白いアイデアですよね。google.comでざっと検索しても決定打となる情報は見当たらなかったので、SlackとGoogle Cloud Platformを連携させる最も手早くシンプルな方法を自分で考えることにしました。
幸い、エレガントで完全にサーバーレスな解決策があります。本記事ではその仕組みを解説します。さらに嬉しいお知らせとして、本日gSlackをオープンソースとして公開します。ご自身のGCPプロジェクトに数分でデプロイでき、Slackチャンネルへ即座に、かつ柔軟に通知を送れます。

gSlackはStackdriver Loggingを活用しています。これはGoogleの一元化されたログ基盤で、Google Cloud Platform(およびAmazon Web Services)から収集したログデータやイベントを保存・検索・分析・監視し、アラートを発することができます。Googleのクラウドサービスのほとんどは、ログをStackdriver Loggingに送信しています。私が特に注目したのは、Google Cloud Platform環境内の変更を含む「アクティビティログ」です。
Google Cloud Consoleではこのように表示されます。

Google Stackdriver LoggingのUI
Stackdriver Loggingの嬉しい機能のひとつが、新しいログエントリをGoogle Cloud Storage、Google BigQuery、Google Pub/Subへ自動エクスポートできる点です。「エクスポート」を設定するだけで、あとは魔法のように動いてくれます。
必要だったのは、Stackdriver LoggingからSlackへログエントリを中継する仕組みです。このユースケースにはPub/Subが最適でした。Pub/Subをご存じない方のために補足すると、これは独立したアプリケーション間でメッセージを送受信できる、Googleのフルマネージドなリアルタイムメッセージングサービスです。
Pub/Subエクスポートの設定はとても簡単で、ログフィルター(私は「アクティビティ」ログだけが必要だったのでlogName="projects/doit-playground/logs/cloudaudit.googleapis.com%2Factivity"を指定)と、メッセージのプッシュ先となるPub/Subトピック名を指定するだけです。

Pub/Subシンクの設定
これで、Stackdriver Loggingに新しいエントリが追加されるたびに、自動的にPub/Subトピックへプッシュされるようになりました。なかなか便利ですよね。
次に、Pub/SubとSlackをつなぐ「のり」のような仕組みが必要です。Pub/Subに発行された新着メッセージをSlack通知として投稿させるためです。ありがたいことに、Googleには(ベータ版で)Cloud Functionsがあります。クラウドサービスを構築・連携するためのサーバーレス環境です。要するに、NodeJSで「関数」を書き、バケットへのファイル追加、HTTPリクエスト、そして(もうお察しの通り!)Pub/Subトピックへの新着メッセージなど、サポートされているトリガーで実行させることができます。
全体の流れは次のようになります。StackDriver Loggingがプロジェクト内の特定アクティビティを記録し、それを自動的にPub/Subトピックへ送信。さらにそれがCloud Functionsを起動し、公式のSlack NodeJS SDKを使ってSlackチャンネルにメッセージを送信する、という仕組みです。

gSlackのアーキテクチャ図
Cloud Functionsをセットアップするには、コードとpackage.jsonを含むzipファイルをアップロードします。

Google Cloud Functionsのセットアップ
すべてのアクティビティログをSlackチャンネルに流してしまわないよう(中にはそれほど重要でないものもあります)、またSlackに届くメッセージを見やすく整形するために、もうひとつGoogleのマネージドサービスを使うことにしました。Google Cloud Datastoreです。
Google Cloud Datastoreは、自動スケーリング・高パフォーマンス・開発のしやすさを兼ね備えたマネージドNoSQLドキュメントデータベースです。Cloud Functionsとのネイティブ連携に加え、エントリ(Datastoreの用語で「kinds」と「properties」)をすばやく編集できる使いやすいUIも備えています。
gSlackの実行時設定、特に「どのメッセージを発行するか」「Slackに投稿されるメッセージをどう見せるか」を永続的に保存するために、Google Cloud Datastoreのような仕組みが欠かせません。

標準UIでDatastoreのデータを編集
ログエントリのセットごとに、test、message、そして通知の送信先となるslackChannelを設定します。
testはboolean値を返す有効なJS式である必要があります。trueが返ればテストは通り、メッセージがSlackに送信されます。たとえば、Google Compute Engineからのメッセージのみを対象に、インスタンスの「start」「stop」イベントを追跡したい場合は、次のようなtestを使います。
$.protoPayload.serviceName==='compute.googleapis.com' && ( $.protoPayload.methodName==='v1.compute.instances.start' || $.protoPayload.methodName==='v1.compute.instances.stop') && $.operation.last同様に、messageは有効なJS文字列テンプレートである必要があります。これが評価されてメッセージが生成されます。例:
Instance '${$.protoPayload.resourceName.split('/').slice(-1)[0]}' was ${$.protoPayload.methodName==='v1.compute.instances.start'?'started':'stopped'} at zone '${$.resource.labels.zone}' by '${$.protoPayload.authenticationInfo.principalEmail}' in project '${$.resource.labels.project_id}'結果として、次のような通知がSlackに届きます。私の検証では、実際のイベント発生からSlackチャンネルにメッセージが届くまで、わずか5秒ほどでした。

実際のSlack通知
testsとmessagesはいくつでも追加でき、Compute Engine、App Engine、Cloud Storage、BigQuery、さらにはBillingなど、さまざまなGoogle Cloud Platformサービスを解析できます。実際、こうしたサンプルのいくつかをgSlackリポジトリに同梱しています。
ソースコード一式とデプロイ手順は、GitHubのgSlackリポジトリで公開しています。スターやプルリクエストでgSlackの改善にぜひご協力ください ;-)
いつも通り、ご提案やアイデアは[email protected]までお気軽にどうぞ。
追伸:このサンプルをわずか数時間で書き上げ、本記事の執筆にも力を貸してくれたDoiT InternationalのCloud Architect、Shahar Frankに感謝します。