[AWS] CloudFront
Cloud AWS
Published: 2020-07-14

CloudFrontとは

CloudFrontとは、AWSのコンテンツ配信ネットワークサービスです。動画やアプリケーションを安全にかつ高速にユーザーに届けます。CloudFrontを端的に言えば、ユーザーがコンテンツを見ているときにコンテンツが始まるまでの待ち時間を短くするためのサービスです。

CloudFrontのメリット・デメリット

CloudFrontは、DDoS攻撃を軽減するための AWS Shield、コンテンツストレージとしてのAmazon S3、ELBやEC2と直接的につながります。

CloudFrontのメリットであり、最大の特徴は、コンテンツの高速化です。静的なコンテンツの場合は、CSSやJSなどの静的なファイルをキャッシュさせておき、また動的なコンテンツの場合は通信を高速化することでコンテンツを高速に返します。AWSはユーザーにコンテンツをより低いレイテンシーで届けるため、Amazon CloudFront では 42 か国 84 都市にある 216 の国と地域にグローバルなネットワーク環境を構築しています。このエッジロケーションによってユーザーは高速なコンテンツのリターンを受けることができます。

CloudFrontを使用すれば、ユーザーから一番近いCloudFrontのエッジロケーションネットワークに自動的にアクセスされることで高速な通信を可能にします。

例えば、一般的なレンタルサーバーなどに乗っているアプリケーションにユーザーがアクセスする場合、サーバーが応答しますが、そのネットワークは一般的なインターネットを通じてつながるので、状況によっては通信速度が悪くなったりする場合があります。しかし、AWSの場合は自前のエッジロケーションネットワークを使うので、比較的安定かつ高速な応答を実現します。さらにCloudFrontを利用していて、かつEC2などを利用している場合はEC2やS3などから取得するデータの通信料は発生しないのでコスト面のメリットもあります。

CloudFrontの使い方

CloudFrontの設定のためにはまずCloudFront コンソールをひらきます。次CloudFrontの対象となるコンテンツを選択します。例えばS3のバケットなどを選択します。CloudFrontの設定には入力する項目が複数ありますが、コンソールの流れに沿って進めていけば、問題なく終わります。最後にディストリビューションの作成を選択すれば終了です。ただ、ディストリビューションの作成ボタンを押した後に完了するまで20〜40分と意外に長時間かかりますので注意してください。ステータスが進行中からdeployedに変更すれば無事完了です。

テンプレートファイル(template file)

cloudformationで作るCloudFrontインスタンスのテンプレートの例を以下に示します。私が関与しているとあるサービスで実際に利用されているのテンプレートになります。セキュリティのため一時隠している部分があります。

このテンプレートファイルとは別にパラメタの値を設定するファイルを用意し、Parametersに設定した変数に値をセットすることが出来ます。

CloudFrontを作成する際、UserDataの中にサーバーセットアップ時の最初に実行するシェルを記載することが出来ます。大体この部分で必要なセットアップ作業を行います。

AWSTemplateFormatVersion: '2010-09-09'
Description: cloudfront
Parameters:
  RegionName:
    Type: String
  ServiceName:
    Type: String
  Phase:
    Type: String
    Default: dev
    AllowedValues:
      - dev
      - prd
  AcmArn:
    Type: String
  SubDomain:
    Type: String
  LPSubDomain:
    Type: String
  DeployId:
    Type: String
  FrontendEipAllocationId:
    Type: String

Resources:
  FrontCloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Origins:
        - Id: S3Origin
          DomainName: 
            Fn::ImportValue:
              !Sub ${ServiceName}-${Phase}-s3-MPDomainName
          S3OriginConfig:
            OriginAccessIdentity:
              Fn::ImportValue:
                !Sub ${ServiceName}-${Phase}-s3-FullCloudFrontOriginAccessIdentityMP
        Enabled: true
        DefaultRootObject: index.html
        PriceClass: PriceClass_200
        DefaultCacheBehavior:
          TargetOriginId: S3Origin
          ForwardedValues:
            QueryString: false
          MinTTL: '0'
          MaxTTL: '0'
          DefaultTTL: '0'
          ViewerProtocolPolicy: redirect-to-https
          AllowedMethods:
          - HEAD
          - GET
          CachedMethods:
          - HEAD
          - GET
          SmoothStreaming: 'false'
          ForwardedValues:
            QueryString: 'false'
            Cookies:
              Forward: none
        CustomErrorResponses:
        - ErrorCode: '403'
          ResponsePagePath: "/index.html"
          ResponseCode: '200'
          ErrorCachingMinTTL: '30'
        ViewerCertificate:
          AcmCertificateArn: !Sub ${AcmArn}
          SslSupportMethod: sni-only
        Aliases:
          - !Sub ${SubDomain}.xxxxx.jp
        WebACLId: 
          Fn::ImportValue:
            !Sub ${ServiceName}-${Phase}-waf-GlobalWebACL
      Tags:
      - Key: Phase
        Value: !Sub ${Phase}
      - Key: Name
        Value: !Sub ${ServiceName}-${Phase}-frontend-server

  ElasticIPAssociate:
    Type: AWS::EC2::EIPAssociation
    Properties:
      AllocationId: !Sub ${FrontendEipAllocationId}
      InstanceId: 
        Fn::ImportValue:
          !Sub ${ServiceName}-${Phase}-FrontendEc2-${DeployId}

  LPCloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Origins:
        - Id: S3Origin
          DomainName: 
            Fn::ImportValue:
              !Sub ${ServiceName}-${Phase}-s3-LPDomainName
          S3OriginConfig:
            OriginAccessIdentity: 
              Fn::ImportValue:
                !Sub ${ServiceName}-${Phase}-s3-FullCloudFrontOriginAccessIdentity
        Enabled: true
        DefaultRootObject: index.html
        PriceClass: PriceClass_200
        DefaultCacheBehavior:
          TargetOriginId: S3Origin
          ForwardedValues:
            QueryString: false
          MinTTL: '0'
          MaxTTL: '0'
          DefaultTTL: '0'
          ViewerProtocolPolicy: redirect-to-https
          AllowedMethods:
          - HEAD
          - GET
          CachedMethods:
          - HEAD
          - GET
          SmoothStreaming: 'false'
          ForwardedValues:
            QueryString: 'false'
            Cookies:
              Forward: none
        ViewerCertificate:
          AcmCertificateArn: !Sub ${AcmArn}
          SslSupportMethod: sni-only
        Aliases:
          - !Sub ${LPSubDomain}.xxxxx.jp
        WebACLId: 
          Fn::ImportValue:
            !Sub ${ServiceName}-${Phase}-waf-GlobalWebACL
      Tags:
      - Key: Phase
        Value: !Sub ${Phase}
      - Key: Name
        Value: !Sub ${ServiceName}-${Phase}-landing-page

Outputs:
  FrontDomainName:
    Value: !GetAtt FrontCloudFrontDistribution.DomainName
    Export:
      Name:
        Fn::Sub: "${ServiceName}-${Phase}-FrontCloudFrontDistribution"

  LPCloudFrontDistribution:
    Value: !GetAtt LPCloudFrontDistribution.DomainName
    Export:
      Name:
        Fn::Sub: "${ServiceName}-${Phase}-LPCloudFrontDistribution"

stackの作成コマンド

cloudformationからCloudFrontなどのインスタンスを利用するためにはAWS CLIから以下の様なコマンドをbashから実行します。これによってcloudformation上にstackが作成され、その下に各インスタンスが構築されます。

templateがテンプレートファイル、parameterがパラメタファイルになります。このテンプレートの例では、二つのファイルがbashを実行する同じディレクトリにある事を想定しています。

stack_name="stack_name"
template="template.yml"
parameters="parameters.json"
region="ap-northeast-1"

aws cloudformation create-stack --stack-name ${stack_name} \
  --disable-rollback \
  --parameters file://${parameter} \
  --capabilities CAPABILITY_IAM \
  --template-body file://${template} \
  --region ${region}

stackを更新する際、diffを見るコマンド

create-change-setにより、インスタンスを更新する際にその差分を確認することが出来ます。

stack_name="stack_name"
template="template.yml"
parameters="parameters.json"
region="ap-northeast-1"
change_set_name=${change_set_name}

aws cloudformation create-change-set --stack-name ${stack_name} \
  --change-set-name ${change_set_name} \
  --capabilities CAPABILITY_IAM \
  --parameters file://${parameter} \
  --template-body file://${template} \
  --region ${region}

stackの状態を確認するコマンド

現在のスタックの状態を確認することが出来ます。

stack_name="stack_name"
region="ap-northeast-1"

aws cloudformation describe-stacks stack-name ${stack_name} region ${region}

stackを削除するコマンド

スタックを削除し、それに伴いインスタンスを削除することが出来ます。

stack_name="stack_name"
region="ap-northeast-1"

aws cloudformation delete-stack --stack-name ${stack_name} --region ${region}

関連する記事