Yuki's Tech Blog

仕事で得た知見や勉強した技術を書きます。

【AWS:ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得】セクション8: 【S3/CloudFront】画像を配信しようで知らなかったことをざっくりまとめてみた

目次

概要

WordPressから画像を投稿したら、それがS3に保存されるように設定します。画像の配信自体もS3から行うようにします。その後、CloudFrontを使って、画像をキャッシュして画像配信を高速化します。

インフラ設計における重要な5つの観点

インフラ設計には、重要な観点が5つ存在します。

観点 内容 具体的指標
可用性 サービスを継続的に利用できるか 稼働率目標復旧時間、災害対策
性能・拡張性 システムの性能が十分で、将来的においても拡張しやすいか 性能目標、拡張性
運用・保守性 運用と保守がしやすいか 運用時間、バックアップ、運用監視、メンテナンス
セキュリティ 情報が安全に守られているか 資産の公開範囲、ガイドライン、情報漏洩対策
移行性 現行システムを他のシステムに移行しやすくなっているか 移行方式の規定、設備、データ、移行スケジュール

上記の中でも上の4つ(可用性、性能・拡張性、運用・保守性、セキュリティ)が重要です。 中でも特に重要なのが可用性です。

今回は画像配信の高速化を行うので、性能・拡張性にフォーカスします。

画像の保存場所をストレージではなくS3に分ける4つの理由

以下の4つの理由が考えられます。

  1. Webサーバーのストレージが画像で一杯になるのを防ぐ
  2. HTMLへのアクセスと画像へのアクセスを分けることで負荷分散する
    Webサーバーに画像を入れてWebサーバーから配信すると、画像へのアクセスもWebサーバーに来てしまいます。つまり、HTMLへのアクセスと画像へのアクセスのどちらもWebサーバーへ来てしまい、Webサーバーの負荷が上がります。そのため、画像を別のところへ保存することで、負荷分散ができるようにしてます。
  3. Webサーバーの台数を増やしやすくする
    Webサーバー上に画像を保存する場合、Webサーバーの台数を増やすときに画像を同期させる必要があります。そのため、スケールアウト(新たにサーバーの台数を増やすこと)が難しいです。ここで、画像の保存場所が分離されていると、Webサーバーの台数を簡単に増やすことができます。
  4. コンテンツ配信サービス(CloudFront)から配信することで、画像配信を高速化できる

S3とは

S3とは、 安価で耐久性の高いAWSクラウドストレージサービスです。 ざっくりいうと、S3はクラウド上のファイルの保存場所のことです。

S3の4つの特徴

  1. 非常に安価
  2. 高い耐久性
  3. 容量無制限。1ファイル最大5TBまで
    ファイル数に関しては制限がないです。
  4. バケットやオブジェクトに対してアクセス制限を設定できる
    バケットやオブジェクトに対してアクセス制限を設定できるので、セキュリティ面がしっかりしています。

S3を使う上で重要な概念

重要概念 意味
バケット オブジェクトの保存場所。名前はグローバルでユニークな必要があります。 S3を使う際にはまずバケットを作って、その中にファイルを保存していきます。
オブジェクト オブジェクトとは、バケットに保存されるファイルなどのデータ本体のことです。バケットにオブジェクトが格納されると、オブジェクトにURLが付与されます。バケット内オブジェクト数は無制限です。
キー キーとは、オブジェクトがバケットに格納されるときに付与されるURLパスのことです。

S3のよくある利用シーン4つ

  1. 静的コンテンツの配信
    img画像はS3に保存して、S3から配信します。
  2. バッチ連携用のファイル置き場
    バッチとは定期的に実行するプログラムのことです。S3にバッチ連携用のファイルを置いて、バッチでそのファイルを参照して処理を行います。
  3. ログなどの出力先
    定期的にS3にログを送ります。CloudTrailの部分でS3を設定しました。
  4. 静的Webホスティング
    静的なWebサイト(ランディングページなど)など簡単なWebページなら、サーバーを使わなくてもS3から公開できます。

S3のバケットを作成する

作業手順

手順1:
S3のダッシュボードを開きます。次に「バケットを作成」をクリックします。バケット名にはグローバルで一意な名前を入力します(他のユーザーが付けているバケット名は付けられません)。リージョンはアジアンパシフィック(東京)を選択します。 Image from Gyazo

手順2:
次にブロックパブリックアクセスという項目を設定します。ここでは バケットとオブジェクトに対して外からのアクセスを禁止するかを設定します。外からアクセスされたくないファイルをバケットに置く場合はチェックした方が良いです。 今回はインターネットに配信する画像をバケットに置くため、オフにしておきます。承認のチェックボックスもオンにしておきます。

手順3:
次にバケットのバージョニングを設定します。バージョニングとは、同じファイル名のファイルを保存したときにそれぞれのバージョンを保存するかという意味です。今回はそこまでする必要がないので無効にします。 次にデフォルトの暗号化は、特に必要ないので無効化にします。最後に「バケットを作成」をクリックします。そうするとバケットを作成できます。 Image from Gyazo

手順4:
S3を操作する権限をもつIAMユーザーを作成します。 S3はデフォルトでアクセスを拒否していて、許可されたユーザーにだけアクセスさせるようになっています。そのため、S3のアクセス権限を持ったIAMユーザーを作成します。IAMのダッシュボードに移動して、「ユーザー」→「ユーザーを追加」をクリックします。次に、ユーザー名を入力します。今回はユーザー名をblog_test_wpにしました。WordPressからS3にアクセスするので、アクセスの種類をプログラムにします。 Image from Gyazo

手順5:
既存のポリシーを直接アタッチを選択して、AmazonS3FullAccessにチェックします。これはS3の操作ならなんでもできるという権限です。タグは特に設定せずに「確認」→「ユーザーの作成」をクリックします。 ユーザーの作成に成功すると、 IAMの認証情報がCSVファイルとして提供されているので、必ずダウンロードします。

Image from Gyazo

WordPressの画像をS3にアップロードしてみる

作業手順

手順1:
まずはWordPressの管理画面を開いて、「WordPressからS3に画像を簡単にアップロードできるように設定できるプラグイン」のインストールをします。プラグインの「新規追加」をクリックします。次に、WP offload mediaというプラグインをインストールします。

しかし表示されないので、以下のコマンドを実行して追加のライブラリをインストールします。

# ターミナルで実行
# ライブラリのアップデート
$ sudo yum update -y

# 動画7-3の内容(念の為実行)
# PHP7.2のインストール
$ sudo amazon-linux-extras install -y php7.2

# PHPとphp-mbstringのインストール
$ sudo yum install -y php php-mbstring

# 動画8-5の内容(念の為実行)
# php-xmlのインストール
$ sudo yum install -y php-xml

# 動画上ではインストールしていないライブラリのインストール(必須)
$ sudo yum install -y php-gd
$ sudo yum install php-devel.x86_64

# サーバーの再起動(必須)
$ sudo systemctl restart httpd.service

次に、AWSのS3の画面に移動し、ACLを有効にします。 最後にWordPressの管理画面でスーパーリロード(ブラウザのキャッシュを使わずにリロード)をします。Cmd + Shift + Rでできます。

WP OFFload mediaで検索してもヒットしないので、offload mediaで検索します。該当プラグインがあったので今すぐインストールします。その後、「有効化」を押して有効化します。 Image from Gyazo

手順2:
WP OFFload mediaというプラグインを動かすのに必要なライブラリをEC2インスタンス内でインストールします。

sudo yum install -y php-xml

WebサーバーであるApacheが今インストールしたライブラリをちゃんと読み込めるために、Apacheを再起動します。

sudo systemctl restart httpd.service

手順3:
次にWordPressの管理画面からプラグインの設定をします。「設定」→「WP Offload Media」をクリックします。 Add Credentialsに書いてあるphpのコードをwp-config.phpのif文より上に追加します。 その後、IAMユーザーのaccess-key-idとsecret-access-keyを入力します。これらの情報はIAMユーザーを作成したときにダウンロードしたcsvファイルに書いています。

// 省略

define( 'AS3CF_SETTINGS', serialize( array(
    'provider' => 'aws',
    'access-key-id' => '********************',
    'secret-access-key' => '**************************************',
) ) );

// 省略

その後、プラグインの設定画面からバケットを選択して、セーブすればOKです。 Image from Gyazo

以上でWordPressの管理画面から画像を保存すると、S3に保存されてS3から画像が配信されます。WordPressの記事に画像を挿入して保存すると、その画像がS3のバケットに保存されます。そして、画像はS3から配信されます。

CloudFrontとは

CloudFrontとは、 高速にコンテンツを配信するサービスです。コンテンツを配信するサービスはCDNと呼ばれています。CloudFrontはCDNAWSサービスです。

CloudFrontの仕組みは、オリジンサーバー(元となる画像を配信するサーバー)上にあるコンテンツを、世界100箇所以上にあるエッジサーバーにコピーして、そこから配信を行います(今回の場合はS3がオリジンサーバーに該当します)。

(※)CDNとは、Content Delivery Networkの略です。

CloudFrontの2つの特徴

  1. 高速
    ユーザーから最も近いエッジサーバーから画像を配信するので、オリジンサーバーから画像を配信するよりも高速です。
  2. 効率的
    エッジサーバーでコンテンツのキャッシングを行うので、オリジンサーバーに負荷をかけずに配信できます。

CloudFrontがあると何が嬉しいのか?

CloudFrontがあることで、画像の配信が高速化され、S3の負荷が軽減されます。 S3のみを用いる場合、画像のリクエストがS3にあるとS3が画像を配信します。CloudFrontがある場合、画像のリクエストがCludFrontにきます。CloudFrontではオリジンサーバー(S3)から事前にコンテンツをキャッシュしているので、そのキャッシュから画像を配信します。

まとめると、画像配信の性能を向上させたい場合、画像配信するサーバーの前にCDNというコンテンツ配信サービスを入れることで、画像配信の高速化であったり、負荷軽減ができます。

CloudFrontを設定して、CloudFrontから画像を配信できるようにする

手順2以降の手順をざっくりまとめます。まずOffload Mediaで画像の配信ドメイン独自ドメインを登録することで、画像の配信ドメイン独自ドメインになります。しかし、これだけだと画像のURLにアクセスしても、独自ドメインが画像のS3のURLに紐づいていないので何も表示されません。そこでRoute53でCNAMEレコードを作成して、独自ドメインにアクセスがあったら、CloudFrontのドメイン名にルーティングするようにします。Route53からCloudFrontにルーティングされた際に、独自ドメインとCloudFrontのドメイン名の紐付けをCloudFrontが認識できるように、CloudFrontのディストリビューションにも独自ドメインを代替ドメインとして登録します。代替ドメインを登録する際にSSLサーバー証明書が必要なので、そちらをCertificate Managerから発行します。これが手順2以降の全体の流れです。

作業手順

手順1:
CloudFrontから画像を配信できるようにします。そのために、CloudFrontのディストリビューション(CloudFrontの配信ルール)の作成をします。S3のサーバーをオリジンとして、CloudFrontから配信するというディストリビューションを作成します。これだけでCloudFrontがS3にある画像をコピーして、CloudFrontから配信できるようになります。

CloudFrontのダッシュボードから「CloudFrontディストリビューションを作成」をクリックします。オリジンドメインとはオリジンサーバーのドメインのことです。S3をオリジンサーバーとするので、S3のドメインを入力します。オリジンパスにはS3の中でも特定のディレクトリ以下を指定したい場合に使用します。今回は使用しないので、何も入力しません。次のS3バケットアクセスは、ユーザーが画像にアクセスするときにS3のURLからはアクセスしてほしくなくてCloudFrontからのみアクセスしてほしい場合はOrigin access control settingsを選択します。今回の場合はS3とCloudFrontでの画像配信の速さを計測したいのでPublicにしておきます。 Image from Gyazo

次にデフォルトのキャッシュビヘイビアを設定していきます。ここにはキャッシュの方法やHTTPでアクセスする方法などが書いています。特に設定する必要はないのでこのままにします。次に設定の項目を設定します。料金クラスはどこから配信するかを設定します。「すべてのエッジロケーションを使用する」を選択します。残りの部分は特に設定しなくて大丈夫なので、「ディストリビューションを作成」をクリックします。 Image from Gyazo

手順2:
今のままだと画像のドメインがCloudFrontのドメインになっています。それでもいいですが、独自ドメインから画像が配信されるようにしたいので、それらの設定をしていきます(SEO的にサイト自体のドメインと画像のドメインは一致していた方が良いです)。まず、Certificate ManagerでSSLサーバー証明書を発行します。 Certificate Managerは、 証明書を発行管理するためのAWSサービスです。

まずCloudFrontのダッシュボードで作成したディストリビューションの「ID」→「設定の編集」をクリックします。その後、代替ドメイン名 (CNAME)に画像を配信したいドメインを入力します。 今回はサブドメインを画像配信用のドメインとして入力します(static.blog-test.xyz)。CloudFrontで独自ドメインを設定するためにはSSL証明書を取得する必要があるので、「証明書をリクエスト」をクリックします。そうするとAWS Certificate Managerのページが開きます。「パブリック証明書」→「次へ」をクリックします。次にドメイン名を入力します。何のドメイン名に対してSSL証明書を発行するかを意味します。*.blog-test.xyzとかいて全てのサブドメインに対してSSL証明書を発行します。blog-test.xyzも追加しておきます。 Image from Gyazo

検証方法の項目は、証明書を発行する前に今回リクエストしたドメインを自分が本当に持っているかをAWS側が確認するための項目です。DNSの設定を自分で行う権利を持っているので、DNS検証をクリックします。最後にリクエストをクリックします。

AWS Certificate Manager (ACM)の「証明書を一覧」→「証明書ID」をクリックします。ドメインの部分で「Route53でレコードを作成」をクリックします。この設定をすることでドメインに対してSSL証明書が発行されます。ここで作るCNAMEレコードはあくまで検証用のレコードです。 Image from Gyazo

CloudFrontの画面に戻って、カスタムSSL証明書の項目で先ほど作った証明書を選択します。残りの項目は特に変更しないで大丈夫なので、「変更を保存」をクリックします。これでCloudFrontの画面を見ると代替ドメインが登録できたことが確認できました。 Image from Gyazo

これでCloudFrontのドメイン(https://d3qk0pabqi5dh8.cloudfront.net)に独自に発行したサブドメインを発行させることができました。しかし、画像が配信されるときは独自のサブドメインで配信されません。

(※) SSLサーバー証明書とは、 Webサーバーの持ち主が実在することを示す証明書です。ブラウザとWebサーバー間で暗号化した通信(HTTPS通信)をするときに必要です。 また、サブドメインとはオリジナルのドメインの先頭を.で区切って追加するドメインのことです。SSLサーバー証明書は省略してSSL証明書と呼ばれることがあります。

手順4:
次にRoute53で独自ドメインとCloudFrontドメインのCNAMEレコードを作成します(CNAMEは別名という意味です)。今回独自ドメインで画像を配信したいですが、独自ドメイン名でアクセスされたときにCloudFrontのドメインに転送したいです。そうすることでCloudFrontから画像を配信できるようにします。そのために、 Route53で独自ドメインとCloudFrontドメインのCNAMEレコードを作成して、この独自ドメインにアクセスが来たらCloudFrontのドメインにアクセスがいくようにルーティングします。

Route53のダッシュボードからホストゾーンを選択して、「レコードの作成」をクリックします。レコード名にstaticと入力して、レコードタイプにCNAMEを選択します。値にはCloudFrontのドメイン名を入力します。これで「レコードを作成」をクリックします。これで独自ドメインとCloudFrontドメインを紐付けるCNAMEレコードを作成できました。

Image from Gyazo

手順5:
最後にOffload Mediaで画像の配信ドメイン独自ドメインを登録します。これをすることで、Offload Mediaで画像を投稿すると、WordPressでユーザーに表示される画像のURLが独自ドメインになります。画像自体はOffload Mediaで画像を投稿すると、S3に保存されS3のURLは変わらず存在しています。ただ、ユーザーに表示される画像のURLのドメイン独自ドメインになります。

WordPressの管理画面で「設定」→「WP Offload Media」を選択します。 Custom Domain NameにCNAMEで登録した画像用のサブドメインを登録します。その後「Save Changes」をクリックします。

以上で設定は完了です。WordPressのページに行って画像のURLを確認するとサブドメインになっていることが確認できました。 Image from Gyazo

CloudFrontから画像が配信されることで、S3より高速化されているのかをチェックする

ブラウザから画像のURLにアクセスして、スーパーリロード(ブラウザのキャッシュを使用しないリロード)するとわかります。

↓ CloudFrontから配信される画像 Image from Gyazo

↓ S3から配信される画像 Image from Gyazo

CloudFrontから配信される画像の取得時間が14msなのに対して、S3から配信される画像の取得時間は47msです。このように、初回の画像取得速度が大きく異なります。2回目以降はブラウザのキャッシュを使用して画像を表示するので、速度差はあまり出ませんが、ややCloudFrontの方が早いです。

また、海外から画像にアクセスする場合、CloudFrontの方が断然早いです。理由は、S3は東京リージョンに設置されているため海外からアクセスするのに時間がかかりますが、CloudFrontはエッジサーバーから画像を配信しているので、海外に近いサーバーから画像を配信できるからです。複数回リロードしても結構差が出るそうです。

インフラ構成図

前回のインフラ構成図にCloudFront、ACM(AWS Certificate Manager )、S3を追加しました。 Image from Gyazo

参考記事

AWS:ゼロから実践するAmazon Web Services。手を動かしながらインフラの基礎を習得 | Udemy

サイトを変更したのに更新されていない!ブラウザのキャッシュを回避して閲覧する方法 | 株式会社ティウェブ

キャッシュ

CloudFront使って、キャッシュを利用してみた

AWS のアーキテクチャ図を描きたい ! でもどうすれば良いの ?