AWS CloudFrontを使ってWordPressのメディアファイルだけS3に配置する
森永です。
前回の記事でWordPressにアクセスできるところまでいきました。
引き続き構築を行っていきます。今回の手順は順序を変えるとうまくいかないことがありますのでご注意下さい。
おさらい
こんな構成を作っていきます。
今回構築のメインとなるのは、CloudFrontの部分です。
CloudFrontにはURLによって振り分け先を変えるリバースプロキシの機能がありますので、メディアファイルを参照する場合のみS3に向くように設定をしていきます。
WordPressの基本設定
プラグインのセットアップ
Beanstalkで作成されたサーバは、AutoScalingで起動されているEC2インスタンスのため、基本的にローカルにファイルを保存してはいけません。そのため、本来サーバのローカルに格納される画像などのメディアファイルは、プラグインを使用してS3に格納するようにします。
管理画面から、以下のプラグインをインストールします。
- Amazon Web Services
- Amazon S3 and CloudFront
次に、プラグインからS3の操作が必要になるので、S3の権限を持ったIAMユーザを作成します([S3] > [Users] > [Create New Users])。プラグインの設定で、「Access Key ID」と「Secret Access Key」の情報が必要になるので、控えておきます。
作成したユーザに、S3のフルアクセス権限を付与します。
WordPressURL設定
この後の手順で、[WordPressアドレス]と[サイトアドレス]については、環境変数で動的な値になるように設定します。ただし、ここでの設定内容はDBに保存され、一部で環境変数に置き換わらずに使用されるようであるため、事前に最終的に外部公開するURLを指定することにしています。
※値を固定化するため、操作内容によってはサーバサイドとDBサイドで不整合が起こりますので、運用には十分注意してください。
WordPressの管理画面に入り、[設定]->[一般]から以下のように設定を行います。
- WordPressアドレス:www.example.com(外部公開するURL)
- サイトアドレス:www.example.com(外部公開するURL)
- タイムゾーン :東京
DNSの設定を行っていないので、設定するとアクセスができなくなります。(DBの値を書き換えたため)
wp-config.phpの書き換え
環境変数に動的な値になるように設定することで、IPアドレスでもアクセスできるようにします。
また、プラグインからS3にアクセス出来るようにアクセスキーとシークレットキーを設定します。
(IAM Roleで設定したいのですが、プラグインが対応していません。辛いです。。。)
以下の値をwp-config.phpの末尾に追記して下さい。
$ vi /var/www/html/wordpress/wp-config.php define('WP_SITEURL',"http://".$_SERVER['SERVER_NAME']."/"); define('WP_HOME',"http://".$_SERVER['SERVER_NAME']."/"); define('AWS_ACCESS_KEY_ID', 'アクセスキー'); define('AWS_SECRET_ACCESS_KEY', 'シークレットキー');
"管理サーバのIPアドレス/wp-admin/"にアクセスして管理画面にアクセスできることを確認します。
wp-config.php内で設定したため、WordPressアドレス、サイトアドレスが設定できなくなっています。
本番環境へのデプロイ
管理サーバでのWordPress設定が一段落したので、本番環境に設定した環境をデプロイします。
手動で、zipファイルを作成して、マネジメントコンソールからデプロイしてもいいのですが、更新が多くなった際に面倒なのでスクリプトを用意します。
管理サーバにスクリプトを設置し、WordPressの設定変更が終わったら実行するようにします。
#!/bin/bash date=`date '+%Y%m%d%H%M%S'` SCRIPT_DIR=$(cd $(dirname $0);pwd) WP_DIR="/var/www/html" FILENAME="wordpress_$date" S3_URL="デプロイするzipファイルを配置するS3バケットURL" APP_NAME="アプリケーション名" env_name=`aws elasticbeanstalk describe-environments --application-name $APP_NAME --query 'Environments[].EnvironmentName|[0]'` cd $WP_DIR zip -r $SCRIPT_DIR"/"$FILENAME".zip" . cd $SCRIPT_DIR aws s3 cp $FILENAME".zip" "s3://"$S3_URL aws elasticbeanstalk create-application-version --application-name $APP_NAME --version-label $FILENAME --source-bundle S3Bucket=$S3_URL,S3Key=$FILENAME".zip" aws elasticbeanstalk update-environment --environment-name ${env_name//\"/} --version-label $FILENAME
これを実行すると新たなアプリケーションを作成し、デプロイまでしてくれます。
アプリケーションのバージョン確認は[環境名]->[Application Versions]から行うことが出来ます。
CloudFrontとRoute53の設定
実はまだアクセス出来ていない物があり、表示がおかしくなっていたりします。(CSSを読み込めていない)
wp-config.phpに記載された値ではなく、DBに書かれた値を読みにいっているものがあるからです。
なので、先にCloudFrontとRoute53の設定を行います。
CloudFrontの設定
CloudFrontの向き先は基本的にはELBへ、/wp-content/uploads/*へのアクセスだけS3へむけます。
はじめに、ELBへ向けるデフォルトの設定をおこないます。
Webディストリビューションを選択します。
Beanstalkで作成されたELBをオリジナルドメインとして選択し、作成します。
[Allowed HTTP Methods]はPOSTが必要なので、[GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE]を選択し、Forwrdの設定もすべて通るようにして下さい。
[CNAME]にWordPressで設定した独自ドメインを設定しておきます。Route53にもあとで同じ設定を行います。
少し時間をおき、[Status]が「Deployed」になったら完了です。
Route53の設定
続けてRoute53の設定をしてしまいます。
CNAMEを使って設定するのではなくAレコードのAliasを使用したほうがパフォーマンスがいいです。(詳しくはこちら)
S3プラグインの設定
ここまでやって初めてプラグインの設定ができます!
S3のバケットを設定します。今回のWordPress用に作成するバケットの名前を指定します。
オプションは複数ありますが、とりあえず、[Remove Files From Server]のみONにしておきます。先にも説明した通り、メディアデータはすべてS3に格納されるため、ローカルサーバのファイルは不要になります。
出来たS3に向けてCloudFrontの設定も行います。
[Origin]に先ほどWordPressで作成したバケットを指定します。
続いて、[Behavior]を設定します。
- Path Pattern:/wp-content/uploads/*
- Origin:WordPressで作成したバケット
静的なファイルだけなので、その他の設定はそのままにしておきます。
WordPressの管理画面に戻り、プラグインの設定画面で、いま作成したCloudFrontのドメインを登録します。これで、プラグインでS3にアップロードされたメディアデータが、CloudFrontを経由して配信されることになります。
管理・保守
これにてWordPress環境の構築は完了です。
管理保守の手順をまとめておきます。
- サイトの閲覧は設定した独自ドメインへアクセスして行う。(本番サーバへのアクセス)
- WordPressの設定は管理サーバのIPアドレスへアクセスして行う。( http://IPアドレス/wp-admin/ )
- 管理サーバでの設定後、管理サーバ上でスクリプトを実行し、本番サーバへデプロイする。
以上です。
まとめ
簡単にWordPress環境をつくろう!でも、本番運用に耐えられる構成にしよう!と考えていたらあんまり簡単じゃなくなってしまいました。
理想としては管理サーバをなくして本番サーバ群だけにしたいのですが、EC2と設定ファイルを疎結合にする方法が思いつきませんでした。もう少し検証していい方法を見つけたらまたブログにまとめたいと思います。