この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
先日、アマゾンがアカウント・アクティビティのリアルタイムタイム分析ソリューションのリファレンス実装を公開しました。
Introducing the Real-Time Insights on AWS Account Activity
AWS CloudTrailでアカウント・アクティビティを取得し、Amazon Kinesis Data Analyticsでリアルタイム分析し、DynamoDB に保存したメトリクスをダッシュボード表示します。
リージョン情報のメトリクスを追加
次の公式ドキュメントにて、ダッシュボードにリージョン毎のAPI呼び出し数のメトリクスを追加する手順が紹介されていたため、実際にやってみました。
AWS CloudTrail ログに含まれるリージョン情報を活用します
{
"eventVersion": "1.03",
"userIdentity": {
"type": "IAMUser",
"principalId": "111122223333",
"arn": "arn:aws:iam::111122223333:user/myUserName",
"accountId": "111122223333",
"accessKeyId": "AKIAIOSFODNN7EXAMPLE",
"userName": "myUserName"
},
"eventTime": "2015-08-26T20:46:31Z",
"eventSource": "s3.amazonaws.com",
"eventName": "GetBucketVersioning",
"awsRegion": "us-west-2",
"sourceIPAddress": "",
"userAgent": "[]",
"requestParameters": {
"bucketName": "myawsbucket"
},
"responseElements": null,
"requestID": "07D681279BD94AED",
"eventID": "f2b287f3-0df1-4961-a2f4-c4bdfed47657",
"eventType": "AwsApiCall",
"recipientAccountId": "111122223333"
}
メトリクスを追加する流れ
以下を修正します。
- ストリームデータを分析する Amazon Kinesis Data Analytics
- DynamoDB に保存されたメトリクスを表示するダッシュボードの HTML
対して
- アカウントアクティビティの記録するAWS CloudTrail
- Kinesis Analytics のアウトプットを DynamoDB に保存する Lambda
などは修正不要です。
リファレンス実装らしく、コア機能だけを提供し、ユーザーがカスタマイズしやすいソリューションとなっています。
Amazon Kinesis Data Analytics の修正
ソーススキーマにリージョン情報を追加し、リージョン毎の集計を行う PUMP を追加します。
ソーススキーマの変更
データソースを SQL 操作するために、JSON で渡ってくるインプットレコードと SQL 操作するためのスキーマのマッピングを行います。
Amazon Kinesis Data Analytics のコンソールに移動します
アプリケーション「RealTimeInsightsAccountActivityApp」を選択し、「Go to SQL results」をクリックします。
「Source Data」タブで「Edit schema」をクリックします。
「+ Add column」ボタンから添付画像のようにリージョン用カラムを追加し、「Save schema and update stream samples」ボタンをクリックして、スキーマ変更を保存します。
最後に先程の「Go to SQL results」から「awsRegion」カラムが追加されていることを確認します。
PUMP の変更
PUMP ではデータソースのストリーミングデータに対して SQL を実行します。 今回はリージョンを切り口とした分析を追加します。
「SQL Editor」ページから「Real-time analytics」タブを選択し、次の SQL を最後に追加します。
CREATE OR REPLACE PUMP "PUMP_FOR_CALLS_BY_REGION" AS
INSERT INTO "DESTINATION_SQL_STREAM"
SELECT eventTimeStamp, 'CallsPerRegion', "awsRegion" , 'None', 'Sum', callsPerRegion FROM (
SELECT STREAM STEP(cloudtraillogs."eventTimestamp" BY INTERVAL '10' SECOND) as eventTimeStamp, COUNT(*) callsPerRegion, "awsRegion"
FROM "SOURCE_SQL_STREAM_001" cloudtraillogs
GROUP BY "awsRegion", STEP(cloudtraillogs.ROWTIME BY INTERVAL '10' SECOND), STEP(cloudtraillogs."eventTimestamp" BY INTERVAL '10' SECOND));
入力ストリーム「DESTINATION_SQL_STREAM」に対してSQLを実行し、出力ストリーム「DESTINATION_SQL_STREAM」に結果を出力する PUMP「PUMP_FOR_CALLS_BY_REGION」 です。
SQL 修正後は「Save and run SQL」ボタンをクリックします。
DynamoDB からこのPUMPに対応するメトリクスが追加されていることを確認します。
ダッシュボードの修正
最後にダッシュボードを作成します。
ダッシュボードは S3 の Static website hosting 機能 を利用して HTML/JavaScript だけで実装されています。
ダッシュボードにメトリクスを追加するために、一部修正します。
ソースコードの取得
まずは、ローカルに HTML/JavaScript ファイルを取得します。
S3 バケット名には、 CloudFormation で指定したバケットを指定します。
$ aws s3 sync s3://YOUR-BUCKET-NAME .
download: s3://YOUR-BUCKET-NAME/css/font-awesome.min.css to css/font-awesome.min.css
download: s3://YOUR-BUCKET-NAME/fonts/fontawesome-webfont.woff to fonts/fontawesome-webfont.woff
download: s3://YOUR-BUCKET-NAME/css/custom.css to css/custom.css
download: s3://YOUR-BUCKET-NAME/fonts/fontawesome-webfont.eot to fonts/fontawesome-webfont.eot
download: s3://YOUR-BUCKET-NAME/fonts/fontawesome-webfont.woff2 to fonts/fontawesome-webfont.woff2
download: s3://YOUR-BUCKET-NAME/help.html to ./help.html
download: s3://YOUR-BUCKET-NAME/fonts/FontAwesome.otf to fonts/FontAwesome.otf
download: s3://YOUR-BUCKET-NAME/fonts/fontawesome-webfont.ttf to fonts/fontawesome-webfont.ttf
download: s3://YOUR-BUCKET-NAME/css/bootstrap.min.css to css/bootstrap.min.css
download: s3://YOUR-BUCKET-NAME/js/app-variables.js to js/app-variables.js
download: s3://YOUR-BUCKET-NAME/js/amazon-cognito-identity.min.js to js/amazon-cognito-identity.min.js
download: s3://YOUR-BUCKET-NAME/js/dash.js to js/dash.js
download: s3://YOUR-BUCKET-NAME/js/bootstrap.min.js to js/bootstrap.min.js
download: s3://YOUR-BUCKET-NAME/js/dashboard-use.js to js/dashboard-use.js
download: s3://YOUR-BUCKET-NAME/fonts/fontawesome-webfont.svg to fonts/fontawesome-webfont.svg
download: s3://YOUR-BUCKET-NAME/js/jquery.min.js to js/jquery.min.js
download: s3://YOUR-BUCKET-NAME/js/Chart.js to js/Chart.js
download: s3://YOUR-BUCKET-NAME/dash.html to ./dash.html
download: s3://YOUR-BUCKET-NAME/js/aws-cognito-sdk.min.js to js/aws-cognito-sdk.min.js
$ tree .
.
├── css
│ ├── bootstrap.min.css
│ ├── custom.css
│ └── font-awesome.min.css
├── dash.html
├── fonts
│ ├── FontAwesome.otf
│ ├── fontawesome-webfont.eot
│ ├── fontawesome-webfont.svg
│ ├── fontawesome-webfont.ttf
│ ├── fontawesome-webfont.woff
│ └── fontawesome-webfont.woff2
├── help.html
└── js
├── Chart.js
├── amazon-cognito-identity.min.js
├── app-variables.js
├── aws-cognito-sdk.min.js
├── bootstrap.min.js
├── dash.js
├── dashboard-use.js
└── jquery.min.js
3 directories, 19 files
js/dash.js の修正
@@ -294,6 +294,11 @@ function init() {
var serviceCallQueryTime = getTimeSecsAgo(15*60, currentTime);
var serviceCallChart = generateLineChart("callsByServiceCanvas", "No of service calls");
+ var regionCallChartData = {'labels': [], 'times': [], 'values': {}}
+ var regionCallQueryTime = getTimeSecsAgo(15*60, currentTime);
+ var regionCallChart = generateLineChart("callsByRegionCanvas", "No of region calls");
+
+
var ec2CallChartData = {'labels': [], 'times': [], 'values': {"ec2.amazonaws.com|null": []}}
var ec2CallQueryTime = getTimeSecsAgo(15*60, currentTime);
var ec2CallChart = generateLineChart("callsByEC2Canvas", "No of EC2 calls");
@@ -638,6 +643,14 @@ function init() {
});
+ var awsRegionParams = retrieveParams("CallsPerRegion", regionCallQueryTime);
+ docClient.query(awsRegionParams, function(err, data) {
+ if (err) console.log(err);
+ else {
+ regionCallChartData = updateLineChart(data, regionCallChartData, regionCallChart, splitFunc);
+ }
+ });
+
ec2CallQueryTime = getTimeSecsAgo(15*60);
docClient.query(ec2Params, function(err, data) {
if (err) console.log(err);
@@ -694,6 +707,16 @@ function init() {
});
+ var regionParams = retrieveParams("CallsPerRegion", regionCallQueryTime);
+
+ docClient.query(regionParams, function(err, data) {
+ if (err) console.log(err);
+ else {
+ regionCallQueryTime = fastUpdateLineChart(data, regionCallChartData, regionCallChart, regionCallQueryTime, splitFunc) ;
+ }
+
+ });
+
var ec2Params = retrieveParams("EC2Calls", ec2CallQueryTime);
docClient.query(ec2Params, function(err, data) {
dash.html の修正
@@ -300,7 +300,15 @@
</div>
</div>
<div class="row aws-mb-l">
- <div class="col-xs-10 col-xs-offset-1 col-xs-12">
+ <div class="col-md-5 col-md-offset-1 col-xs-12">
+ <div class="x_title">
+ <h3>Calls per AWS region <small> Over the last hour </small></h3>
+ </div>
+ <div class="x_content">
+ <canvas id="callsByRegionCanvas"/>
+ </div>
+ </div>
+ <div class="col-xs-5 col-xs-offset-1 col-xs-12">
<div class="x_title">
<h3>EC2 Calls <small> over the last hour </small></h3>
</div>
ソースコードを S3 に戻す
aws s3 sync
コマンドを先程とは逆方向(ローカル→S3)で実行します。
$ aws s3 sync . s3://YOUR-BUCKET-NAME
upload: ./dash.html to s3://YOUR-BUCKET-NAME/dash.html
upload: js/dash.js to s3://YOUR-BUCKET-NAME/js/dash.js
差分ファイルだけがアップロードされます。
動作確認
最後に、ダッシュボードにログインして確認します。
"Calls per AWS region" が追加されています。
まとめ
今回はAWSが提供するアカウント・アクティビティのリアルタイム分析ソリューションにメトリウスを追加する方法を紹介しました。
各サービス間のデータ結合部分やデータベースは修正せずに、分析・表示レイヤーでメトリクスのバリエーションを増やすだけでカスタマイズが完了しました
データ基盤を作る際は、このように分離度・拡張性の高いシステムを作りたいものです。