AWSの請求情報をembulkを使用してTreasure Dataに転送し、Re:dashで可視化

皆様こんにちは。

お酒を飲むと100倍しゃべる @takemotto です。
リブセンスでインフラエンジニアをやってます。
『Livesense Advent Calendar 2016』の15日目の記事を担当することになりました。
よろしくお願いします。

尚、リブセンスでは他に2本のAdvent Calendarもやっております。こちらもよろしくお願いします。


* [Livesenseその2 Advent Calendar 2016](http://qiita.com/advent-calendar/2016/livesense_2)
* [Livesenseその3 Advent Calendar 2016](http://qiita.com/advent-calendar/2016/livesense_3)

#背景
弊社では年々、オンプレからAWSを移行するするサービスが増えてきています。
そこで全社的にAWS費用圧縮の啓蒙活動行うことでをコスト意識高めよう　→　AWSのコストを可視化してみようということになりました。
今回はその辺を記事にまとめました。
AWSにはもともと [コストエクスプローラ-] (https://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/cost-explorer-what-is.html) という機能があり、費用をサービス別、日別に分析することが可能です。
ですが、今回は社内にあるAWSの複数アカウントのコストを集約して可視化したかったのでRe:dashを採用することにしました。

#概要
AWSの請求情報(csv)をs3バケットに出力できます。
詳しくは、[請求レポートで使用量を確認する](http://docs.aws.amazon.com/ja_jp/awsaccountbilling/latest/aboutv2/detailed-billing-reports.html)　を参照してください。
ローカルPCからEmbuklコマンドを実行して、s3バケットの請求情報をTreasure Data(以下、TD)に転送します。
その後、TDにインポートした請求情報をデータソースとして、Re:dashで可視化（グラフ化）します。

![AWS Design (2).png](https://qiita-image-store.s3.amazonaws.com/0/95324/78134e49-e33a-6c60-8f0f-be9c9e79bb6c.png)


#前提条件
* TDのアカウントがあること
    * APIがあること（TDのMy profileから確認可能です）
* AWSのアカウント（以下の権限を含む）があること
    * AmazonS3ReadOnlyAccess
    * Billing
* IAMで上記アカウントのアクセスキーを発行がされていること
    * アクセスキー、シークレットキーがあること
* tdコマンドがインストールされていること

```tdインストール
$ gem install td
```

#実行環境

* Mac OS X 10.12.1
* td 0.15.2
* embulk 0.8.15
* embulk-input-s3 (0.2.8)
* embulk-output-td (0.3.12)
* embulk-decoder-commons-compress (0.4.0)
* embulk-filter-column (0.5.4)
* embulk-filter-typecast (0.1.5)
* Re:dash 0.12.0+b2449


#AWSのセットアップ
##s3バケットの作成
AWSの請求情報出力先のs3バケットを作成してください。
今回は「aws-billing-report」としました。
s3バケットのアクセス許可は適切に。

##請求情報設定
AWSマネジメントコンソールから「請求ダッシュボード」→「レポート」→「レポートの作成」でレポートの設定を行ってください。
設定する内容は以下の通りです。

* レポート名：任意
* 時間単位：時間別
* S3バケット：先程作成したs3バケットを指定

設定が完了すると、当該s3バケットに請求情報(csv)が出力されます。
がしかし出力されるまでに1日かかる場合があるので、気長に待ちましょう。

##AWS credencialsの設定
ローカルのMacにAWS credencialsの設定を行います。
事前作成したユーザで取得したAccess kyeとSecret Access kyeを設定してください。

```mac
$ aws configure
AWS Access Key ID [None]: [AWSのアクセスキー]
AWS Secret Access Key [None]: [AWSのシークレットキー]
Default region name [None]: ap-northeast-1
Default output format [None]: json
```

#Treasure Dataのセットアップ
##アカウント設定
ローカルのMacに設定します。
Treasure Dataのアカウントを設定します

```mac
$ td account -f
Enter your Treasure Data credentials. For Google SSO user, please see https://docs.treasuredata.com/articles/command-line#google-sso-users
Email: [TDアカウント]
Password (typing will be hidden):[TDパスワード]
Authenticated successfully.
Use 'td db:create <db_name>' to create a database.
$
```

##データベース作成
TD上にデータベースを作成します。
今回、TD側のデータベース名は「aws_billing」としました。

```
td db:create aws_billing
```

#Embulkのセットアップ
## インストール
ローカルのMacにインストールします。
いろんなプラグインを駆使します。

```
$ curl --create-dirs -o ~/.embulk/bin/embulk -L "http://dl.embulk.org/embulk-latest.jar" -k
$ chmod +x ~/.embulk/bin/embulk
$ echo 'export PATH="$HOME/.embulk/bin:$PATH"' >> ~/.bashrc
$ source ~/.bashrc
$ embulk gem install embulk-output-td
$ embulk gem install embulk-input-s3
$ embulk gem install embulk-decoder-commons-compress
$ embulk gem install embulk-filter-column
$ embulk gem install embulk-filter-typecast
```

## embulk guessの実行
まずs3バケット上にある請求情報(csv)をembulk guessコマンドで読み込み、
データファイルのレイアウトを推測します。
なお、請求情報のファイルがzipファイルであるため、decodersの設定を入れてます。
このdecodersを入れることで、解凍してからファイルを読み込みます。

```seed.yml
in:
  type: s3
  bucket: aws-billing-report
  path_prefix: [AWSの12桁ユーザID]-aws-billing-detailed-line-items-2016
  access_key_id: [アクセスキー]
  secret_access_key: [シークレットキー]
  decoders:
   - {type: commons-compress}
```

```
$ embulk guess seed.yml -o config.yml
~省略~
in:
  type: s3
  bucket: aws-billing-report
  path_prefix: [AWS account number(12桁)]-aws-billing-detailed-line-items-2016
  access_key_id: [アクセスキー]
  secret_access_key: [シークレットキー]
  decoders:
  - {type: commons-compress}
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    quote: '"'
    escape: '"'
    trim_if_not_quoted: false
    skip_header_lines: 1
    allow_extra_columns: false
    allow_optional_columns: false
    columns:
    - {name: InvoiceID, type: long}
    - {name: PayerAccountId, type: long}
    - {name: LinkedAccountId, type: long}
    - {name: RecordType, type: string}
    - {name: ProductName, type: string}
    - {name: RateId, type: long}
    - {name: SubscriptionId, type: long}
    - {name: PricingPlanId, type: long}
    - {name: UsageType, type: string}
    - {name: Operation, type: string}
    - {name: AvailabilityZone, type: string}
    - {name: ReservedInstance, type: boolean}
    - {name: ItemDescription, type: string}
    - {name: UsageStartDate, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
    - {name: UsageEndDate, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
    - {name: UsageQuantity, type: string}
    - {name: BlendedRate, type: string}
    - {name: BlendedCost, type: string}
    - {name: UnBlendedRate, type: string}
    - {name: UnBlendedCost, type: string}
Created 'config.yml' file.
$
```

geuss成功しました。
がこのまま使うとこの後のembulk runでコケるのと、
filterをいろいろかけたいので最終的にconfig.ymlを以下のようにしました。

```config.yml
in:
  type: s3
  bucket: aws-billing-report
  path_prefix: [AWS account number(12桁)]-aws-billing-detailed-line-items-20
  access_key_id: [AWS アクセスキー]
  secret_access_key: [AWS シークレットキー]
  decoders:
    - {type: commons-compress}
  parser:
    charset: UTF-8
    newline: CRLF
    type: csv
    delimiter: ','
    quote: '"'
    escape: '"'
    trim_if_not_quoted: false
    skip_header_lines: 1
    allow_extra_columns: false
    allow_optional_columns: false
    columns:
    - {name: invoiceid, type: string}
    - {name: payeraccountid, type: string}
    - {name: linkedaccountid, type: string}
    - {name: recordtype, type: string}
    - {name: productname, type: string}
    - {name: rateid, type: string}
    - {name: subscriptionid, type: string}
    - {name: pricingplanid, type: string}
    - {name: usagetype, type: string}
    - {name: operation, type: string}
    - {name: availabilityzone, type: string}
    - {name: reservedinstance, type: string}
    - {name: itemdescription, type: string}
    - {name: usagestartdate, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
    - {name: usageenddate, type: timestamp, format: '%Y-%m-%d %H:%M:%S'}
    - {name: usagequantity, type: string}
    - {name: blendedrate, type: double}
    - {name: blendedcost, type: double}
    - {name: unblendedrate, type: double}
    - {name: unblendedcost, type: double}
filters:
  - type: column
    columns:
      - {name: 'productname'}
      - {name: 'unblendedcost'}
      - {name: 'usagestartdate'}
  - type: typecast
    columns:
      - {name: 'usagestartdate', type: long}
out:
  type: td
  apikey: [TD APIキー]
  database: aws_billing
  table: biiling
  time_column: usagestartdate
  mode: replace
```

###ポイント
* TDはカラム名に大文字を使用できないため、小文字に変換します。
* カラムの型をいい感じに変換します。（string、doubleのみにした）
* TDのAPIキーは、td apikey:show　で確認できます。
* 必要なカラムだけTDにインポートしたいため、「filters」の「type: column」でカラムを絞っています。
* TDでは以下のデータタイプのみ使用できます。

```
Treasure Data supports the following data types:
int
long
double
float
string
array<T>
```
　timestamp型は使用できないので、「filters」の「type: typecast」でlong型に変換してます。
　この設定がないとstring型でインポートされます。

## embulk runの実行
まずembulk runの前にembulk previewを実行して動作確認します。

```
$ embulk preview config.yml |more
2016-12-10 22:21:07.826 +0900: Embulk v0.8.15
2016-12-10 22:21:19.416 +0900 [INFO] (0001:preview): Loaded plugin embulk-input-s3 (0.2.8)
2016-12-10 22:21:19.501 +0900 [INFO] (0001:preview): Loaded plugin embulk-filter-column (0.6.0)
2016-12-10 22:21:19.532 +0900 [INFO] (0001:preview): Loaded plugin embulk-filter-typecast (0.1.5)
2016-12-10 22:21:21.033 +0900 [INFO] (0001:preview): Loaded plugin embulk-decoder-commons-compress (0.4.0)
+-------------------------------+----------------------+---------------------+
|            productname:string | unblendedcost:double | usagestartdate:long |
+-------------------------------+----------------------+---------------------+
|                AWS CloudTrail |                  0.0 |       1,470,009,600 |
|                AWS CloudTrail |                  0.0 |       1,470,013,200 |
```

いけそうです。
ではembulk runで実際にTDにインポートしてみます。

```
$ embulk run config.yml
~長いので省略〜
```

成功しました。
TDにテーブルが作成されていればOKです。
ここまでくればRe:dashで可視化させるだけです。

#Re:dashのセットアップ
##Re:dashインストール
ローカルMacにRe:dashを入れましょう。
こちらを参考にしてください。すいません。
参考:[「Re:dash」を「Docker for Mac」で動かしてみた](http://qiita.com/tbuchi888/items/275bb2ed341c2936c9c3)

インストールが終わったらアクセスしてみましょう。admin/adminでログインできます。
![スクリーンショット 2016-12-12 15.22.48.png](https://qiita-image-store.s3.amazonaws.com/0/95324/8a39654e-4429-f7df-a2ce-5277ae48d4d5.png)

##Re:dash Data Source追加
Data SourceにTDを追加します。このボタンをクリック。
![スクリーンショット 2016-12-12 15.25.00.png](https://qiita-image-store.s3.amazonaws.com/0/95324/ee9edf14-414c-a312-49ac-e7e1363eb477.png)
次に「New Data Source」をクリック。以下のように設定しました。
ApikeyはTDのapiキーを設定してください。
![スクリーンショット 2016-12-12 15.38.11.png](https://qiita-image-store.s3.amazonaws.com/0/95324/35e3b624-ccf8-56b1-4792-1968452c1f61.png)

##Re:dash クエリを作成
クリエを作成します。
![スクリーンショット 2016-12-12 15.44.01.png](https://qiita-image-store.s3.amazonaws.com/0/95324/be892a05-ea7f-a565-eb28-e10faf4834e9.png)

クエリはこんな感じです。クエリが成功したら、名前をつけて「save」ボタンで保存しましょう。
クエリ名は「aws billing」としました。

```
SELECT productname,
       TD_TIME_FORMAT(usagestartdate, 'yyyy-MM-dd', 'JST') AS DATE,
       SUM(unblendedcost) AS cost
FROM biiling
GROUP BY productname,
         TD_TIME_FORMAT(usagestartdate, 'yyyy-MM-dd', 'JST')
```

##Re:dash グラフ化
「NEW VISUALIZATION」でグラフを作成して、「save」します。
![スクリーンショット 2016-12-12 18.08.47.png](https://qiita-image-store.s3.amazonaws.com/0/95324/8cafb3f2-0b86-b293-64c3-efe1f94b2bb0.png)
　

グラフは以下ように設定しました。
![スクリーンショット 2016-12-12 17.07.52.png](https://qiita-image-store.s3.amazonaws.com/0/95324/283a98b1-c8cb-1271-7591-a03a40fec303.png)
　

##Re:dash ダッシュボード作成
「New Dashboard」をクリックして、ダッシュボードを作成します。名前は「aws billing」としました。
![スクリーンショット 2016-12-12 17.11.20.png](https://qiita-image-store.s3.amazonaws.com/0/95324/a7de2c19-0cbb-6804-f262-41b25bd4b706.png)

　
ダッシュボードにWidgetを追加します。
![スクリーンショット 2016-12-12 17.14.51.png](https://qiita-image-store.s3.amazonaws.com/0/95324/582719b0-efef-e2a4-4a55-da08064d1173.png)
　

さきほど作成したクエリ「aws billing」を指定して、「Add to Dashboard」をクリックします。
![スクリーンショット 2016-12-12 17.15.58.png](https://qiita-image-store.s3.amazonaws.com/0/95324/6717aa40-bb9f-caf3-5f6b-f801dce7e3bd.png)
　
　
完成です。
![スクリーンショット 2016-12-12 17.17.37.png](https://qiita-image-store.s3.amazonaws.com/0/95324/bf654d5c-fda8-fc51-fc0f-0aa1829fc467.png)

#まとめ
* 複数AWSアカウントで実施する場合、アクセスキー、シークレットキーを指定する部分がネックなると思います。この対策としてLiquidというテンプレートを使用することで、設定ファイル(今回ではconfig.yml)に環境変数が使用できます。この辺をうまく活用すれば、AWSアカウント毎のアクセスキー、シークレットキーを設定できると思います。他にいい方法があったら教えてください。
* これは言っては元も子もないですが、自分のAWSアカウントだけでコスト分析したいのであればAWSの機能を使った方がよさそうですｗ
* 最後までお付き合いいただき、ありがとうございました。

# 最後に
明日は @boscoworks さんのアドベントカレンダー16日目の記事です。
お楽しみに！