こんにちは、エクスチュアの權泳東(権泳東/コン・ヨンドン)です。
今回は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を取得します。
メッセージを書き込みたいチャネルを選んで、緑色の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を利用した分析基盤の構築支援などを行なっております。
お問い合わせはこちらからどうぞ。
ブログへの記事リクエストはこちらまで











