2019年2月24日日曜日

Google Cloud PubSub を使って Cloud Billing のアラートを Slack に通知する

概要

Cloud Billing は GCP の料金や請求情報を取得できる API です
直接料金を取得する方法はないのですがアラート機能があり特定の料金に達した場合に Cloud PubSub にメッセージを送信することができます
今回はその仕組みを使ってメッセージを受信した際に Slack にメッセージを送信してみたいと思います

環境

  • macOS 10.14.3
  • Ruby ruby 2.5.1p57 (2.6 だと cannot load such file -- google/protobuf_c (LoadError) になり動作しないっぽい)
  • Google Cloud Billing (2019/02/21 時点)
  • Google Cloud PubSub (2019/02/21 時点)

サービスアカウントの作成

Cloud PubSub API をコールするためにサービスアカウントを作成しましょう
今回は Ruby の Subscriber を用意するのでプログラムから認証情報を使えるように JSON のキーファイルも作成します

「サービスアカウント作成」を選択します

好きなサービスアカウント名を設定しましょう

権限は「PubSub 管理者」にしました
今回は Subscribe しかしないので Subscribe のみの権限でも OK です

役割は Google アカウントを指定しました
ここも好きな役割を指定する感じで良いです
ポイントは「キー」です
キーを作成する際に json or p12 が選択できますが今回は Ruby から使うので json を選択してください
作成すると同時に認証用の json ファイルもダウンロードできるので大切に保管しましょう

Cloud PubSub にトピックを作成する

次にトピックとサブスクリプションを作成します

まずはトピックです
好きなトピック名を設定してください
今回は「billing」にしました

次にサブスクリプションです
サブスクリプションはトピック内に複数作成することができます
配信タイプは pull を選択しましょう
受信時間はデフォルトの 10 秒でいいと思います
サーバにメッセージを保存できる期間もデフォルトのままでいいでしょう
これで「作成」を選択します

Google Cloud PubSub は基本的にトピックとサブスクリプションを指定してメッセージを受信します

とりあえず Subscriber の作成

作成したトピックとサブスクリプションを指定してメッセージを受信する Subscriber を作成しましょう
公式が PubSub 用のライブラリを公開してくれているので素直にそれを使います

  • bundle init
  • vim Gemfile
gem "google-cloud-pubsub"
  • bundle install --path vendor
  • vim app.rb
require 'google/cloud/pubsub'

pubsub = Google::Cloud::PubSub.new(
  project_id: 'project-123456',
  credentials: './project-123456-auth.json'
)
topic = pubsub.topic 'billing'
sub = pubsub.subscription 'slack'
subscriber = sub.listen do |msg|
  msg.acknowledge!
  puts msg.data
end
subscriber.start
sleep

とりあえずメッセージを受け取って表示するだけの subscriber です
最後に sleep を入れることでプロセスを常駐させます
あとでこれに Slack に通知する機能を付けます

  • bundle exec ruby app.rb

で起動するので PubSub のコンソールからメッセージを送信していましょう
ちゃんとメッセージが受信できれば OK です

Cloud Billing に予算のアラート設定する

「お支払い」->「予算とアラート」から作成できます
3 つの閾値を設定することができるのでお好きな閾値を設定してください

ポイントはアラートの設定の一番下にある「通知の管理」の部分です
先程作成したトピックを指定することができるので指定しましょう

Slack に通知する機能を追加する

先程の Subscriber にメッセージを受信したら Slack に通知する機能を付けましょう
Incomming Webhook URL が必要になるので Slack のインテグレーションから作成なり既存の URL を取得しておいてください

require 'google/cloud/pubsub'
require 'net/https'
require 'json'

pubsub = Google::Cloud::PubSub.new(
  project_id: 'project-123456',
  credentials: './project-123456-auth.json'
)
topic = pubsub.topic 'billing'
sub = pubsub.subscription 'slack'
subscriber = sub.listen do |msg|
  msg.acknowledge!
  url = 'https://hooks.slack.com/services/xxxxxxxxxx/yyyyyyyy/zzzzzzzzzzzzzzzzzzzzzzz'
  uri = URI.parse url
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  req = Net::HTTP::Post.new uri.request_uri
  req.content_type = 'application/json'
  req.body = {
    'username' => 'Cloud Billing Alert',
    'text' => "Alert Message: #{msg.data}",
    'icon_url' => 'https://slack.global.ssl.fastly.net/9fa2/img/services/hubot_128.png'
  }.to_json
  res = http.request req
end
puts 'start'
subscriber.start
sleep

url の部分は取得した Incomming Webhook URL を設定してください
class とかにしてないのでぐちゃっとしていますが net/https を使って POST リクエストを送信しているだけです
Incomming Webhook の payload に関してはこの辺りを参考にしてください

動作確認

Subscriber を起動しましょう
どうやら Cloud Billing のアラートを作成して「通知の管理」を有効にするとテスト用のメッセージを送信してくれているようです

おそらく Subscriber を起動すると以下のようにメッセージが飛んでくると思います

P.S
あとでわかったのですが 30 分おきに Cloud Billing が Publish しているようです
なのでこのままだと 30 分おきに通知が来てしまうので、costAmount の値をチェックして前回より大きくなっていたら通知するなどの工夫が必要そうです

あとはアイコンやメッセージを好きなように変更すれば OK だと思います
テストだけしたいので同じ JSON のメッセージをコンソールから Publish すれば OK です

{
 "budgetDisplayName": "base",
 "costAmount": 0.16,
 "costIntervalStart": "2019-02-01T08:00:00Z",
 "budgetAmount": 5.0,
 "budgetAmountType": "SPECIFIED_AMOUNT",
 "currencyCode": "USD"
}

最後に

Google Cloud PubSub と Cloud Billing を使って予算のアラートが閾値に達したときに Slack に通知する Subscriber を作成してみました
かなり簡単にできると思います

本当は毎日決められた時間に今月の使用料金を通知したかったのですが、Billing API に直接料金を取得できそうな API がなかったのでアラート機能を使いました
直接料金を確認したいのであればコンソールを見るしかないかなと思います

参考サイト

0 件のコメント:

コメントを投稿