AWSが提供するアカウント・アクティビティのリアルタイム分析のダッシュボードをカスタマイズする
先日、アマゾンがアカウント・アクティビティのリアルタイムタイム分析ソリューションのリファレンス実装を公開しました。
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が提供するアカウント・アクティビティのリアルタイム分析ソリューションにメトリウスを追加する方法を紹介しました。
各サービス間のデータ結合部分やデータベースは修正せずに、分析・表示レイヤーでメトリクスのバリエーションを増やすだけでカスタマイズが完了しました
データ基盤を作る際は、このように分離度・拡張性の高いシステムを作りたいものです。