Google BigQuery

GCP: 今月のGCP課金額をslackに自動的に書き込む

こんにちは、エクスチュアCTOの権です。

今回はGCPの課金額をslackに自動的に書き込むプログラムを作って見ます。

GCPは低コストでクラウド環境を構築できるのでとても良いのですが、うっかりテスト用の設定を作ったまま放置してしまって課金されてたり、なんてことありませんか?
毎日slackに今月の課金額をポストしてくれると、少しはダメージが少なくなるかも知れません。

やることは以下のとおりです。
1. GCPのBillingレポートをBigQueryにエクスポートする
2. BigQueryのBilligテーブルにクエリを投げて、レポートを抽出する
3. slackのwebhookを使って、レポートをslackのチャネルにポストする

1. GCPのBillingレポートをBigQueryにエクスポートする

まずはBigQueryにBillingエクスポート用のデータセットを作ります。
わかりやすく billing という名前にでもしておきます。

次にGCPのBillingメニューの中の、Billing Exportを開きます。
そして、先ほど作ったbillingデータセットを指定して、Enable Billing Exportボタンをクリックします。

BigQuery billing export has been successfully enabled というメッセージが表示されればOKです。
次は、このテーブルに対してクエリを投げて見ます。

2. BigQueryのBilligテーブルにクエリを投げて、レポートを抽出する

Billing Export設定をしてから小一時間ほどすると、billingデータセットの中に2つのテーブルが出て来ます。

gcp_billing_export_* というテーブルと、 gcp_billing_export_v1_* というテーブルです。

v1の方が今月発表された新しいスキーマのテーブルなので、新しいv1テーブルでクエリを書いて見ます。
今月の現時点の、プロジェクト名と製品名ごとに0.01ドル以上の課金額を表示します。

#standardSQL
select format_timestamp('%Y/%m', usage_start_time, 'Asia/Tokyo') as mon,
project.name as project,
service.description as service, 
round(sum(cost * 100)) / 100 as cost
from billing.gcp_billing_export_v1_008EC3_C14E1F_66E889
where format_timestamp('%Y/%m', usage_start_time, 'Asia/Tokyo') = format_timestamp('%Y/%m', current_timestamp, 'Asia/Tokyo')
and cost >= 0.01
group by mon, project, service
order by project

結果はこうなります。

次は、このデータをSlackのチャネルに定期的に投稿するプログラムを書いて見ます。

3. slackのwebhookを使って、レポートをslackのチャネルにポストする

SlackのIncoming Webhookという機能を使って、メッセージをSlackの特定のチャネルにポストします。

Slackのアカウントを持っている前提で、以下のURLからWebhook URLを取得します。

Incoming Webhook Integration

メッセージを書き込みたいチャネルを選んで、緑色のAdd Incoming Webhook integrationボタンをクリックすればOKです。

Webhook URLが表示されるので、これをメモしておきます。

そして、Webhook URLにBillingテーブルに対するクエリ結果をポストすればSlackにメッセージが表示されます。
Node.jsで書いて見ます。

var Slack = require('slack-node');
require('date-utils');

//webhook url
webhookUri = "https://hooks.slack.com/services/foo/bar/baz"; 
slack = new Slack();
slack.setWebhook(webhookUri);

var BigQuery = require('@google-cloud/bigquery');
var projectId = 'myprojectid'; // gcp project id
var bigquery = BigQuery({
    projectId: projectId
});
var datasetName = 'billing';
var dataset = bigquery.dataset(datasetName);
var table = dataset.table('gcp_billing_export_v1_hoge'); //billing table

//query
var query = 'SELECT format_timestamp(\'%Y/%m\', usage_start_time, \'Asia/Tokyo\') as mon, ' +
'project.name as project, service.description as service, round(sum(cost * 100)) / 100 as cost ' +
'FROM billing.gcp_billing_export_v1_hoge ' +
'where format_timestamp(\'%Y/%m\', usage_start_time, \'Asia/Tokyo\') = format_timestamp(\'%Y/%m\', current_timestamp, \'Asia/Tokyo\') ' +
'AND cost >= 0.01 ' +
'GROUP BY mon, project, service order by project';

var options = {
    query: query,
    useLegacySql: false
};

var bqresult = "";
var project_name = "";
var cnt = 0;
var subtotal = 0;
var total = 0;

//query結果をproject毎にまとめる
bigquery.query(options, function(err, rows) {
    if (!err) { 
        for (var i=0; i<rows.length; i++) {
            var row = rows[i];
            if (cnt == 0) {
                project_name = row["project"];
                cnt = 1;
            }
            //projectとprojectの間には罫線を入れる
            if (project_name != row["project"]) {
                bqresult += "----------\n";
                bqresult += "小計 $" + (Math.floor(subtotal * Math.pow(10, 2)) / Math.pow(10, 2)) + "\n\n";
                subtotal = 0;
            }
            bqresult += row["project"] + "\t" + row["service"] + "\t$" + row["cost"] + "\n";
            subtotal += row["cost"];
            total += row["cost"];
            project_name = row["project"];
        }
        bqresult += "----------\n";
        bqresult += "小計 $" + (Math.floor(subtotal * Math.pow(10, 2)) / Math.pow(10, 2)) + "\n\n";
        bqresult += "合計 $" + (Math.floor(total * Math.pow(10, 2)) / Math.pow(10, 2)) + "\n"; 
        
        var dt = new Date();
        var fd = dt.toFormat("YYYY-MM-DD");
        //slackに投稿        
        slack.webhook({
          channel: "#alert",
          username: "ctobot",
          icon_emoji: ":dollar:",
          text: "今月のGCPコスト (as of " + fd + ")\n" + bqresult
        }, function(err, response) {
          console.log(response);
        });
    }
});

実行すると、Slackのチャネルにメッセージが表示されます。

モザイクだらけでアレなのと、通貨設定がドルなのですが、そこはスルーしてください。

注意点として、GCPの課金エクスポートは、エクスポート設定をしたタイミングからの課金額しか反映されません。
月の途中でエクスポート設定をしても月初の金額は分からないので気をつけてください。

あとは、このプログラムをGCE上のLinuxインスタンスで毎日cronすれば良いですね。

以上、今回はGCP課金額をslackに自動投稿する方法についてでした。
弊社ではGCPを利用した分析基盤の構築支援などを行なっております。
お問い合わせはこちらからどうぞ。

関連記事

  1. Google BigQuery

    Tableau : BigQueryでLOD計算が使えない場合の対処法

    こんにちは、エクスチュアの渡部です。Tableau×BigQu…

  2. Adobe Analytics

    Adobe AnalyticsからDWHレポートをGoogle Cloud Storageにアップロ…

    こんにちは、エクスチュアCTOの権です。以前、AdobeAna…

  3. Google Cloud Platform

    Google Compute EngineのUbuntu VMにスワップ領域を作成する

    こんにちは、エクスチュアの権泳東(コン・ヨンドン)です。今回は…

  4. Adobe Analytics

    Adobe Analytics: BigQueryにロードしたデータフィードをDataStudioで…

    こんにちは、エクスチュアCTOの権です。前回のブログで、Big…

  5. Adobe Analytics

    Adobe Analytics: データフィードをBigQueryで集計する

    こんにちは、エクスチュアCTOの権です。前回のブログで、Ado…

  6. Firebase Analytics

    Firebase Analyticsの新しいBigQueryスキーマを試す

    こんにちは、エクチュアの権泳東(コン・ヨンドン)です。「お名前なん…

最近の記事

  1. Google Compute EngineのUbuntu V…
  2. Firebase Analyticsの新しいBigQuery…
  3. Adobe Cloud Platform Auditor (…
  4. Google Analytics Standardのデータを…
  5. Google Tag Manager上でGoogle Ana…
  1. Firebase Analytics

    Firebase Analyticsの新しいBigQueryスキーマを試す
  2. Google Cloud Platform

    Google Compute EngineのUbuntu VMにスワップ領域を作…
  3. Adobe Analytics

    Adobe AnalyticsからDWHレポートをGoogle Cloud St…
  4. Adobe Analytics

    Adobe Analytics: AppMeasurement.jsの実装開発作…
  5. Ad Hoc Analysis

    Adobe Analytics: Ad Hoc Analysisでセグメントの条…
PAGE TOP