23
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ServerlessAdvent Calendar 2017

Day 8

Serverlessで日々のAWSコストを算出してSlackへデイリー通知する

Last updated at Posted at 2017-12-08

最近、Cost Explorer APIというものが新しくリリースされ、請求ダッシュボードから見られるコストが取得できるようになりました。
Introducing the AWS Cost Explorer API

これを使用し、Serverless FrameworkでEC2やCloudFrontなど各サービス毎のコストを算出してみます。

serverless.yml

serverless.yml
service: cost-checker

provider:
  name: aws
  runtime: nodejs6.10
  region: us-east-1

  iamRoleStatements:
    - Effect: Allow
      Action:
        - ce:GetCostAndUsage
      Resource: "*"

functions:
  costCheck:
    handler: cost.check
    events:
      - schedule: cron(0 1 * * ? *)
    timeout: 300

Cost Explorer API はバージニア北部でしか使えないため region: us-east-1 を指定しdeployします。
cronはUTC表記のため、今回は日本時間の朝10時にCloudWatchEventsでLambdaが実行されます。

Cost Explorer API

cost.js
const AWS = require('aws-sdk');

const costexplorer = new AWS.CostExplorer();

module.exports.check = () => {
  const params = {
    Granularity: 'DAILY',
    Metrics: [ 'UnblendedCost' ],
    GroupBy: [{
      Type: 'DIMENSION',
      Key: 'SERVICE',
    }],
    TimePeriod: {
      Start: '2017-12-07',
      End: '2017-12-08',
    },
  };

  costexplorer.getCostAndUsage(params, (err, data) => {
    if (err) {
      console.error(err, err.stack);
      return;
    }

    console.log(data);    
  });
};

これだけで2017-12-07の各コストが取得できます。
細かいAPIの使い方はこちら
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/CostExplorer.html

動的に日付を取得する

これだけでは、2017-12-07の分しか取得できないため、TimePeriodを動的に指定できるようにします。

const _ = require('lodash');

const now = new Date();
const start = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
const end = new Date(now.getFullYear(), now.getMonth(), now.getDate());

const TimePeriod = {
  Start: `${start.getFullYear()}-${_.padStart(start.getMonth() + 1, 2, 0)}-${_.padStart(start.getDate(), 2, 0)}`,
  End: `${end.getFullYear()}-${_.padStart(end.getMonth() + 1, 2, 0)}-${_.padStart(end.getDate(), 2, 0)}`,
};

now.getDate() - 1で実行日の前日を取得、この方法であれば月をまたいだときも日付を自動で生成してくれます。
また、lodashを使い_.padStart()で1桁の場合でも簡単に0で埋めることができます。

Slackに送る

かなり雑ですが、costexplorer.getCostAndUsage()で取得した値を、Slackのmessage apiのattachments.fieldsに詰めて送信しています。

const costs = [];
_.each(data.ResultsByTime, (item) => {
  _.each(item.Groups, (group) => {
    costs.push({
      serviceName: _.head(group.Keys),
      value: _.round(group.Metrics.UnblendedCost.Amount * 120, 2),
    });
  });
});

const message = {
  username: 'コストさん',
  channel: '#cost',
  text: `${TimePeriod.Start}のコストです。:money_with_wings:`,
  attachments: [
    {
      fields: _.map(costs, (item) => {
        return {
          title: item.serviceName,
          value: item.value,
          short: true,
        }
      });,
    }
  ],
};

slack.post(message);

金額はドルで返ってくるので、1ドル120円換算にして、小数点2位まで表示

Slack上では、こんな感じで投稿されて便利です。
sc.png

おわり

実際のところ、デイリーでコストを出しても毎日のアクセス数の上下で変わってくるので、よくわからないw
でも、一気にコストを削ったときにこうして見られるのは楽しい。一時的に使ったサーバーを消し忘れたとか、設定のミスとかもこういったレポートで、すぐに気がつけるんじゃないかなーと思います。
何よりメンバーにコスト感が生まれるし、どのAWSサービス使ってるかわかって良い。

Cost Explorer APIは1コール$0.01と結構お高い額を請求されます。
基本的に乱打するものではないと思いますが注意!

23
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?