Google BigQuery

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

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

今回は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. 最速で理解したい人のためのIT用語集

関連記事

  1. Adobe Analytics

    Adobe AEP SDK: リバースプロキシを使ったアプリ計測検証方法

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

  2. Databricks

    Databricks: Spark DataFramesをJDBCから作成する

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

  3. Adobe Analytics

    Looker: エンジニアがBIで分析ダッシュボードを作る

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

  4. Google Analytics

    Google Analytics 4 + BigQueryでよく使う基本的なSQL例

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

  5. Adobe Analytics

    Adobe Analytics: BigQuery+Lookerでアトリビューション分析

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

  6. Google BigQuery

    Treasure DataからBigQueryにデータを移動させる方法

    こんにちは、エクスチュアの酒井です。今回は、TreasureDat…

最近の記事

  1. モダンデータスタックなワークフローオーケストレーションツール…
  2. Streamlit in Snowflakeによるダッシュボ…
  3. Streamlit in SnowflakeによるStrea…
  4. Streamlitを使った簡単なデータアプリケーション作成ガ…
  5. 生成AI機能を活かしたデータカタログ製品「Secoda」を試…
  1. IT用語集

    オンラインストレージ(Online Storage)って何?
  2. Google Cloud Platform

    Google Compute Engine: 一定時間経過したらタスクを強制終了…
  3. 未分類

    ThoughtSpotとSnowflakeを使ってセルフBIの世界を体験してみた…
  4. Amazon Web Services

    【初心者向け】AWSを学ぶ前に確認したい用語
  5. Tableau

    Tableauのリレーションシップを理解して過剰結合を防ぐ
PAGE TOP