1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

簡単Webサイトホスティング③特定のURLを定期的にモニタリングするCloudFormationテンプレート

Last updated at Posted at 2021-01-18

はじめに

Amazon Web Services(AWS)が提供する、Amazon CloudFrontAmazon S3 と呼ばれるサービスを組み合わせることで、 HTMLやJavaScript、画像、ビデオなどで構成される静的Webサイトの配信基盤安価に構築することができます。本記事では、リソースのセットアップを自動で行うことのできる、AWS CloudFormation を用いることで、これらの配信基盤を ミスなく迅速に構築 する手順をご説明します。なお、今回使用する CloudFormation テンプレートは、以下の GitHub リポジトリで公開しています。

TL;DR

以下の CloudFormation テンプレートを実行することで、 静的Webサイトのホスティング基盤を迅速かつお手軽 に実現します。下にあるボタンをクリックすると、自身のAWSアカウント(Asia Pacific Tokyo - ap-northeast-1)で、この CloudFormation テンプレートを実行することが可能となります。

cloudformation-launch-stack

作成されるAWSリソース全体のアーキテクチャ図は、過去の記事をご覧ください。このうち本記事では、以下のリソースに焦点を当ててご説明します。

architecture.png

特定の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 が正常に動作しているかどうかを継続的に監視することが可能 となります。

関連リンク

  1. ワンクリックで配信基盤を構築 - CloudFormation を用いて簡単Webサイトホスティング
  2. CloudFrontにWAFをアタッチ - CloudFormation を用いて簡単Webサイトホスティング
  3. 特定のURLを定期的にモニタリングする - CloudFormation を用いて簡単Webサイトホスティング
  4. CloudFrontのリアルタイムログをKibanaで可視化する - CloudFormation を用いて簡単Webサイトホスティング
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?