5.5. 静的コンテンツの配信

5.5.1. Overview

本ガイドラインでは、AWSサービスを使用した静的コンテンツ(画像、 CSS、JavaScript…etc)の配信について説明する。

5.5.1.1. AWSを利用したCDNによる静的コンテンツの配信

AWSではコンテンツ配信ネットワークサービスとして、Amazon CloudFrontが提供されている。 本ガイドラインでは、オリジン(コンテンツの保存先)としてAmazon S3を利用し、S3上の静的コンテンツをCloudFrontを使用してCDNで配信する方法を説明する。

5.5.1.1.1. AWSを用いたCDNによる配信

ここでは、S3とCloudFrontを組み合わせたCDNによる静的コンテンツの配信方式を紹介する。

  • S3とCloudFrontを利用したCDN

S3をオリジンサーバとし、配信する静的コンテンツを配置する。 CloudFrontは複数のエッジロケーションへキャッシュを行い、最適なエッジロケーションから配信を行う。

../_images/StaticContentsCDNAWS.png
項番 説明
(1)
CloudFrontはS3から多数あるエッジロケーションへコンテンツをキャッシュする。
(2)
CloudFrontはアクセスするユーザを最寄りのエッジロケーションへ誘導しコンテンツを配信する。

5.5.1.2. AWSを用いたCDN利用時の静的コンテンツの更新

ここでは、S3とCloudFrontを組み合わせたCDNによる、更新後の静的コンテンツをキャッシュタイムアウトを待たずに配信する方式を紹介する。

方式としては、キャッシュクリア方式 と、コンテンツバージョン管理方式 がある。方式の詳細と使い分けについては、CDN利用時の静的コンテンツの更新 を参照されたい。

5.5.1.2.1. キャッシュクリア方式

キャッシュクリア方式とは、CloudFrontのキャッシュをクリアすることで、 キャッシュタイムアウトを待たずに更新後の静的コンテンツをクライアントに配信する方式である。

../_images/StaticContentsClearCache.png
項番 説明
(1)
S3に保存されている静的コンテンツを更新する。
(2)
管理者は、CloudFrontにある(1)で更新した静的コンテンツのキャッシュをCloudFront のCreateInvalidation APIでクリアする。
(3)
CloudFrontはアクセスするユーザを最寄りのエッジロケーションへ誘導する。
(4)
CloudFrontに静的コンテンツのキャッシュがないため、S3から更新後の静的コンテンツを取得し、CloudFrontにキャッシュする。更新後の静的コンテンツをCloudFrontから配信する。

5.5.1.2.2. コンテンツバージョン管理方式

コンテンツバージョン管理方式とは、静的コンテンツをバージョン管理して、整合性を保った状態で更新を行うための方式である。

S3上で更新対象の静的コンテンツをバージョン別フォルダに入れておくなどし、バージョンごとに静的コンテンツへのパスが異なるようにする。更新時には、依存元(更新対象の静的コンテンツを参照している静的コンテンツ)で、更新後の静的コンテンツを利用するようにパスを書き換える。その後、CloudFrontから依存元のキャッシュをクリアする。

依存関係のある静的コンテンツへのパスを整合性のある状態で切り替えることで、更新前と更新後の静的コンテンツが混在した状態でクライアントが取得することを防ぎ、整合性のとれた状態で静的コンテンツを配信する。

以下にHTMLファイルでJavaScriptファイル(main.jsでsub.jsの関数を呼び出している)を読み込んでいる時の例を示す。

  • v1リリース時
../_images/StaticContentsChangePathDeliver_1.png
項番 説明
(1)
HTMLファイルでは、v1フォルダ配下にあるJavaScriptファイルを読み込むように記述する。
(2)
(1)でのHTMLファイルの記述に従い、v1フォルダ配下のJavaScriptファイルをCloudFrontのキャッシュ、キャッシュがなければ、S3から取得する。
(3)
CloudFrontはコンテンツをクライアントへ配信する。
  • v2リリース時
../_images/StaticContentsChangePathDeliver_2.png
項番 説明
(1)
S3上のHTMLファイルを、v2フォルダ配下にあるJavaScriptファイルを読み込むように更新する。
(2)
CloudFrontのHTMLファイルのキャッシュをクリアする。
(3)
クライアントがHTMLファイルを取得しようとすると、CloudFrontにHTMLファイルのキャッシュがないため、S3から更新後のHTMLファイルを取得し、CloudFrontにキャッシュして配信する。 HTMLファイルがキャッシュクリアされる前に、クライアントがHTMLファイルを読み込んだ場合でも、JavaScriptファイルは、HTMLファイルに記述したパスに従って読み込むため、整合性が保たれる。
(4)
(1)でのHTMLファイルの記述に従い、v2フォルダ配下のJavaScriptファイルをCloudFrontのキャッシュ、キャッシュがなければ、S3から取得する。
(5)
CloudFrontはコンテンツをクライアントへ配信する。

5.5.2. How to use

5.5.2.1. Amazon S3の利用

静的コンテンツの保存先としてS3を利用する際の手順を説明する。

5.5.2.1.1. バケットの作成

S3にファイルをアップロードする前にバケットを作成する必要がある。 バケットの作成方法についてはAWS公式ドキュメントバケットの作成を参照されたい。

Note

S3では、静的ウェブサイトをホストするときに、バケット名とドメイン名を一致させる必要がある。バケット作成後はバケット名を変更できないため、バケットを作成する際には注意されたい。 詳細は静的ウェブサイトのホスティング ドメイン名を登録するを参照されたい。

5.5.2.1.2. コンテンツのアップロード

S3のバケット内を下記例の様に既存の資材と同じフォルダ構成にすることで、プロジェクト内の資材からスムーズに移行することができる。

オンライン版クラウド拡張開発プロジェクトの作成で利用した、 Macchinetta Server Framework for Java (1.x)のマルチプロジェクト構成のブランクプロジェクトのフォルダ構成を例にS3バケットのフォルダ構成例を以下に示す。

  • プロジェクト内の既存コンテンツのフォルダ構成例
${contextPath}
└─resources
    ├─css
    ├─image
    └─js
  • S3バケットのフォルダ構成例
${S3BucketRoot}
└─resources
    ├─css
    ├─image
    └─js

上記フォルダ構成に従って、S3上に静的コンテンツをアップロードする。

Note

アプリケーションをリリースする際、合わせて静的コンテンツをS3へアップロードする必要があるので注意されたい。

5.5.2.2. Amazon S3上のコンテンツのAmazon CloudFrontによる配信

S3上のコンテンツをCloudFrontを使用して配信する。 AWS側の設定はAmazon S3 での CloudFront の使用を参照されたい。 アプリケーション側では、静的コンテンツのパスをCloudFrontのURLに書き換えるだけで良い。 下記では、JSPで使用している静的コンテンツの参照先をプロジェクト内の資材からCloudFrontに変更する設定例を説明する。

  • application.yml
# (1)
content:
  url: https://d111111abcdef8.cloudfront.net
  • include.jsp
<!-- (2) -->
<spring:eval expression="@environment.getProperty('content.url')" var="contentUrl" />
  • contentUrlの利用
<!-- omitted -->
<!-- (3) -->
<img alt="" src="${contentUrl}/resources/image/logo.jpg">
<!-- omitted -->
項番 説明
(1)
プロパティにCloudFrontのURLを設定する。(例では${content.url}で参照される)
(2)
SpringのEnvironment経由でcontentUrlとしてプロパティを取得する。 このプロパティは複数画面で使用するので、 include.jspなどの共通部分で宣言する。
(3)
設定したcontentUrlを使用するため、静的コンテンツのpathに${contentUrl}を設定する。 画像、CSS、JavaScript等の静的コンテンツのパスすべてに設定する必要がある。

Note

content.urlを環境依存プロパティにすることで、環境ごとに静的コンテンツの参照先を変更することができる。

5.5.2.3. Amazon CloudFront利用時のAmazon S3上のコンテンツの更新

5.5.2.3.1. コンテンツバージョン管理方式

コンテンツバージョン管理方式はクラウドベンダに依存しない方式であるため、実装方法は コンテンツバージョン管理方式 を参照されたい。

5.5.3. How to extend

5.5.3.1. アクセス制限

ここではCloudFrontに対するアクセスを制限する方法を2つ紹介する。

  • AWS WAFによる制限
    IPアドレスや地域などの条件でアクセスを制限したい場合。
  • 署名による制限
    有料・プライベートコンテンツなどへのアクセスを制限したい場合。

Warning

CloudFrontへのアクセス制限を設定しても、S3上のコンテンツが公開されている場合、S3に直接接続することでCloudFrontに設けたアクセス制限が適用されずにコンテンツへアクセスすることができてしまう。 コンテンツの保護を行いたい場合、CloudFrontへの接続制限に加えS3への直接アクセスを制限する必要がある。 詳細はオリジンアクセスアイデンティティを使用してAmazon S3コンテンツへのアクセスを制限するを参照されたい。

5.5.3.1.1. AWS WAFによる制限

Amazonが提供するウェブアプリケーションファイアウォールであるAWS WAFを使用することで、 定義した条件(IP アドレス、HTTP ヘッダー、HTTP 本文、URI 文字列…etc)に基づき、CloudFrontに対するウェブリクエストを許可、ブロックすることができる。

IP アドレスによる制限が可能なので、開発中等でまだ公開したくない場合や、特定のユーザにのみ公開したい場合などに有効な制限方法である。

WAFに定義可能な制限項目の詳細はAWS公式ドキュメントWhat is AWS WAF and AWS Shield Advanced?を、WAFとCloudFrontを組み合わせた際の振る舞いはHow AWS WAF Works with Amazon CloudFront Featuresを参照されたい。

5.5.3.1.2. 署名による制限

CloudFrontはコンテンツへのアクセスコントロールを行いたい場合、署名付きURLまたはCookieを使用して制限することができる。 CDNを使用してプライベートコンテンツを供給する場合に有効な制限方法である。

詳細はCloudFront を使用してプライベートコンテンツを供給するを参照されたい。

署名付きURLと署名付きCookieのどちらを使用するかの選択については署名付き URL と署名付き Cookie の選択を参照されたい。

Note

署名付き URL や署名付き Cookie を作成するために、有効なCloudFront キーペアが必要となる。 IAM ユーザでは CloudFront キーペアを作成することができず、AWS アカウントのルート認証情報を使用してキーペアを作成する必要があるので注意されたい。 詳細は信頼された署名者の CloudFront キーペアを作成するを参照されたい。

5.5.3.2. Amazon Route 53を利用したDNSフェイルオーバー

Amazon Route 53を使用することで、CloudFrontへのアクセスが一時的にできなくなった場合に、S3を直接参照させるDNSフェイルオーバーを設定することができる。 Route53のDNSフェイルオーバーについての詳細は 公式ドキュメントを参照されたい。

平常時はCloudFrontを使用してコンテンツを配信し、 障害発生時にはS3からコンテンツを配信するように設定する場合の設定手順を以下に示す。

  1. Route 53のヘルスチェックを作成する
  2. レコードセットを作成する
    • Failover Record Type:PrimaryにはCloudFrontを指定
    • Failover Record Type:SecondaryにはS3を指定
  3. Primaryのレコードセットに作成したヘルスチェックを紐付ける

設定の詳細はAmazon Route 53 ヘルスチェックの作成と DNS フェイルオーバーの設定を参照されたい。

Note

本ガイドラインで説明したDNSフェイルオーバーでは、CloudFrontの障害時にS3を直接参照させることでフェイルオーバーを実現している。 アクセス制限で紹介したようにS3への直接アクセスを制限している場合、このフェイルオーバーを利用することができないので注意されたい。