Help us understand the problem. What is going on with this article?

Serverlessで日々のAWSコストを算出する

More than 1 year has passed since last update.

最近、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と結構お高い額を請求されます。
基本的に乱打するものではないと思いますが注意!

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした