はじめに
Amazon Web Services(AWS)が提供する、Amazon CloudFront
や Amazon S3
と呼ばれるサービスを組み合わせることで、 HTMLやJavaScript、画像、ビデオなどで構成される静的Webサイトの配信基盤 を安価に構築することができます。本記事では、リソースのセットアップを自動で行うことのできる、AWS CloudFormation
を用いることで、これらの配信基盤を ミスなく迅速に構築 する手順をご説明します。なお、今回使用する CloudFormation テンプレートは、以下の GitHub リポジトリで公開しています。
TL;DR
以下の CloudFormation
テンプレートを実行することで、 静的Webサイトのホスティング基盤を迅速かつお手軽 に実現します。下にあるボタンをクリックすると、自身のAWSアカウント(Asia Pacific Tokyo - ap-northeast-1)で、この CloudFormation
テンプレートを実行することが可能となります。
作成されるAWSリソース全体のアーキテクチャ図は、過去の記事をご覧ください。このうち本記事では、以下のリソースに焦点を当ててご説明します。
特定のURLのモニタリング
システムを運用するにあたって モニタリングは不可欠 です。モニタリングを行うことで、 システムの健全性と可用性を追求することが可能 となります。このうち、「ブラックボックスモニタリング」や「フロントエンド監視」「外形監視」と呼ばれる、 ユーザが目にする外部的な振る舞いを確認することが特に重要である とされています。なぜなら、個別のコンポーネントの正常性ではなく、アプリケーションが正常に動いているかどうかが、ユーザにとって最も重要となるからです。
これを実現させるために、AWSには Amazon CloudWatch Synthetics というサービスが用意されており、 Canary
と呼ばれるスクリプトを用いて特定のURLを定期的に監視することが可能です。 Canary
は、Lambda上で実行される Node.isスクリプトで、指定したURLの可用性やレイテンシーの確認して、 UI のスクリーンショットを保存することができます。また、CloudWatch カスタムメトリクスを生成するので、可用性やレイテンシーなどの数値を継続して追跡することが可能です。
IAM Role
まず、 Amazon CloudWatch Synthetics
に付与する IAM Role を設定します。このIAM Roleは、 S3バケットに対する書き込み権限 や CloudWatch Logsに対するログの書き込み権限 、 CloudWatch に対するメトリクスの送信権限 などをCloudWatch Syntheticsに付与します。
Parameters:
CanaryName:
Type: String
AllowedPattern: .+
Description: CloudWatch Synthetics Canary Name [required]
Resources:
IAMRoleForSynthetics:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: 'sts:AssumeRole'
Description: A role required for CloudWatch Synthetics to access S3 and CloudWatch Logs.
Policies:
- PolicyName: !Sub 'CloudWatchLogsSynthetics-${CanaryName}-${AWS::Region}'
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- 's3:PutObject'
- 's3:GetBucketLocation'
Resource: !Sub arn:aws:s3:::${S3ForSynthetics}/*
- Effect: Allow
Action:
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/cwsyn-${CanaryName}-*
- Effect: Allow
Action:
- 's3:ListAllMyBuckets'
Resource: '*'
- Effect: Allow
Action:
- 'cloudwatch:PutMetricData'
Resource: '*'
Condition:
StringEquals:
cloudwatch:namespace: CloudWatchSynthetics
RoleName: !Sub 'SyntheticsRole-${CanaryName}-${AWS::Region}'
Amazon S3
次に、 Amazon CloudWatch Synthetics
が取得/作成したログやスクリーンショットを保存するS3バケットを作成します。
Parameters:
CanaryName:
Type: String
AllowedPattern: .+
Description: CloudWatch Synthetics Canary Name [required]
Resources:
S3ForSynthetics:
Type: 'AWS::S3::Bucket'
UpdateReplacePolicy: Retain
DeletionPolicy: Retain
Properties:
BucketName: !Sub synthetics-${CanaryName}-${AWS::Region}-${AWS::AccountId}
LifecycleConfiguration:
Rules:
- Id: ExpirationInDays
ExpirationInDays: 60
Status: Enabled
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
Amazon CloudWatch Synthetics
CloudWatch Synthetics の Canary を作成します。Canaryの作成自体は CloudWatch Synthetics 上で行われますが、 通常のLambda関数と同様に Lambdaサービス上で新規のLambda関数が作成 されます。下記のテンプレートでは、 指定したドメインおよびパスに対してリクエストを送信し、スクリーンショットを取得する関数 がLambda上に作成され、 5分に1回の頻度でこの関数が自動的に実行 されます。また、先ほど作成したIAM RoleおよびS3バケットの紐づけも行なっているため、Canaryの実行結果が S3バケット、CloudWatch Logs、CloudWatch メトリクスなどに書き込まれます 。
なおCanaryを作成する際には、その名前を指定する必要がありますが、 数字と小文字、一部の記号のみを使用して21文字以内でなければならない と文字制限が厳しいため、テンプレート上で Canaryの命名規則をを他のリソース名と共通化する場合は注意が必要 です。
Parameters:
CanaryName:
Type: String
AllowedPattern: .+
Description: CloudWatch Synthetics Canary Name [required]
DomainName:
Type: String
AllowedPattern: .+
Description: The watched domain name [required]
WatchedPagePath:
Type: String
Default: /index.html
AllowedPattern: .+
Description: The watched page path [required]
Resources:
Synthetics:
Type: 'AWS::Synthetics::Canary'
Properties:
ArtifactS3Location: !Sub s3://${S3ForSynthetics}
Code:
Handler: pageLoadBlueprint.handler
Script: !Sub >
var synthetics = require('Synthetics');
const log = require('SyntheticsLogger');
const pageLoadBlueprint = async function () {
// INSERT URL here
const URL = "https://${DomainName}${WatchedPagePath}";
let page = await synthetics.getPage();
const response = await page.goto(URL, {waitUntil: 'domcontentloaded', timeout: 30000});
//Wait for page to render.
//Increase or decrease wait time based on endpoint being monitored.
await page.waitFor(15000);
await synthetics.takeScreenshot('loaded', 'loaded');
let pageTitle = await page.title();
log.info('Page title: ' + pageTitle);
if (response.status() !== 200) {
throw "Failed to load page!";
}
};
exports.handler = async () => {
return await pageLoadBlueprint();
};
ExecutionRoleArn: !GetAtt IAMRoleForSynthetics.Arn
FailureRetentionPeriod: 31
Name: !Ref CanaryName
RuntimeVersion: syn-nodejs-2.0
Schedule:
DurationInSeconds: '0'
Expression: rate(5 minutes)
StartCanaryAfterCreation: true
SuccessRetentionPeriod: 31
CloudWatch Alarm
上記のテンプレートのみで CloudWatch Synthetics の設定は全て完了 し、5分に1回の頻度でモニタリングを開始します。この外形監視がなんらかの理由で失敗した際に通知を受け取ることができるようにするために、最後に CloudWatch Alarm を作成します。このアラームは、 Canaryの成功率が90%を下回った場合にAmazon SNSに対して通知を発行 します。
Resources:
CloudWatchAlarmSynthetics:
Type: 'AWS::CloudWatch::Alarm'
Properties:
ActionsEnabled: true
AlarmActions:
- !Ref SNSForAlertArn
AlarmDescription: !Sub 'CloudWatch Synthetics による定期モニタリングで、${DomainName}${WatchedPagePath} への GET の *失敗率が上昇* しています。このエラーが継続する場合は、 *トラフィックの増大* もしくは *内部処理に異常が発生* している可能性があります。'
AlarmName: !Sub 'Notice-${CanaryName}-Synthetics-AccessError'
ComparisonOperator: LessThanThreshold
DatapointsToAlarm: 1
Dimensions:
- Name: CanaryName
Value: !Ref CanaryName
EvaluationPeriods: 1
MetricName: SuccessPercent
Namespace: CloudWatchSynthetics
OKActions:
- !Ref SNSForAlertArn
Period: 300
Statistic: Average
Threshold: 90
TreatMissingData: notBreaching
以上で、特定のURLに対して定期的にアクセスを行い、このエンドポイントの正常性を確認することのできる、CloudWatch Synthetics の Canary を設定することができました。これまでの記事で作成した CloudFront の URL をこの Canary の監視先に指定することで、 CloudFront が正常に動作しているかどうかを継続的に監視することが可能 となります。
関連リンク
- ワンクリックで配信基盤を構築 - CloudFormation を用いて簡単Webサイトホスティング
- CloudFrontにWAFをアタッチ - CloudFormation を用いて簡単Webサイトホスティング
- 特定のURLを定期的にモニタリングする - CloudFormation を用いて簡単Webサイトホスティング
- CloudFrontのリアルタイムログをKibanaで可視化する - CloudFormation を用いて簡単Webサイトホスティング