WordPressをはじめとした管理者が自由に投稿できるタイプのCMS冗長化は、DBを Amazon RDS などに向けてもテーマの編集やアップロードした画像、各種ファイルの扱いなどが面倒でした。
Amazon S3 に画像をアップロードするようにするWordPressプラグインなども有りますし、複数サーバー間のrsync、lsyncdでファイルの内容を同期するなどの方法も有りますが、先日東京リージョンでもリリースされた Amazon EFS を利用すると簡単に「複数サーバーで共用のドキュメントルート」を実現する事が出来ます。
Amazon EFS (Elastic File System)はマネージドなNFSサービスで複数のEC2インスタンスからマウント・アクセスする事が可能です。
以下手順
AWSマネジメントコンソールにログイン。
新しいVPCを作ります。
作成したVPCに新しいサブネットを2つ作ります。ここではAZ冗長化の為に1a AZと1c AZにサブネットを作成します。
インターネットゲートウェイを作成します。
作成したインターネットゲートウェイをVPCにアタッチします。
作成したVPCのデフォルトルートテーブルにルーティングを追加。
0.0.0.0/0 を先ほど作成したインターネットゲートウェイに向けます。
Webアクセス用のセキュリティグループを追加。VPCの選択ミスに注意。
SSH/HTTP/HTTPSをまとめて許可。SSHは本来はセキュリティグループを分けてより適切に制御した方が好ましいです。
Webサーバ用のEC2インスタンスを起動していく。Amazon Linux 2 インスタンスを選択。
インスタンスタイプの選択。
VPCの選択を忘れない事。サブネットはとりあえず1aの方を選択する。自動割り当てパブリックIPは有効にする。
ストレージの設定。
セキュリティグループは「既存のセキュリティグループ」からWeb用に作成した物を適用。
キーペアが無ければ新しく作成して手元にダウンロードする。
マシンの起動を待つ。
起動したらダウンロードしたキーペアを鍵ファイルにSSH接続。
PHP関連とApacheを導入。
yum install php php-common php-opcache php-gd php-mysqlnd php-mbstring php-fpm httpd
データベース冗長化の為にAmazon RDS for MySQL のインスタンスを作成する。RDSの画面からMySQLを起動していく。
MySQL 5.7.21を選択。
マルチAZ設定を有効化。これでDB側が複数AZに冗長化されます。
DB名やユーザー、パスワードなどを適当に設定。メモしておく事。
作成したVPCを選択。DBサブネットグループは新規作成。
DBパラメータグループ、オプショングループはデフォルトのまま。本来は別で作成しておいた方がいいです。後から設定を変更する際にデフォルトのままだと面倒です。
EC2インスタンスにmysql (mysql-serverではない)をインストール。パッケージとしてはmariadbが降ってきます。
RDSのエンドポイント名をメモ。
RDSに適用されているセキュリティグループにWeb用セキュリティグループからのTCP: 3306許可を追加。
mysqlコマンドからRDSに接続が出来る事を確認。
ドキュメントルート冗長化の為のEFSを起動していきます。
作成したVPCとサブネットを選択。セキュリティグループはとりあえずデフォルトのまま。
パフォーマンスモードはとりあえずそのまま。
EFSが利用可能になるのを待ちます。
EFS用のセキュリティグループを作成。
EFS用セキュリティグループにWeb用セキュリティグループからの全許可を追加して保存。
EFSインスタンスの画面からマウント方法を確認する。必要なEFSマウントヘルパーを導入する。
sudo yum install -y amazon-efs-utils
現在のVPCの設定ではDNS名でアクセスできないという警告が出ているので対応する。
VPCの設定で「DNSホスト名の編集」を「はい」に変更。
EFSにDNS名でアクセスできるようになります。
先ほどのEFS接続方法がより具体的な内容に変化している。
EFSのセキュリティグループの設定を先ほど作成したEFS用のセキュリティグループに変更。これでWebサーバからのNFSアクセスが通るようになります。
手順通りにコマンドを実行しEFSがマウントできたことを確認。今回は手動で叩いていますが、EC2のユーザーデータに仕込んでおくと起動時にマウントしてくれるようになります。
Apacheを起動。
EC2のDNS名で接続できることを確認。
EFSマウント配下にドキュメントルート用のディレクトリを作成、Apacheのドキュメントルート設定もそこを参照するように変更。今回は /efs/wp に実態を配置、 /var/www/html/wp をそこへのシンボリックリンクにして、/var/www/html/wp をドキュメントルートにしています。
Apacheを再起動して反映。閲覧テスト用のファイルをドキュメントルートに配置。
/etc/php.ini の設定で date.timezone を Asia/Tokyo に設定しておく。PHP設定変更後もApache再起動を実施。
testと書いたindex.html、<?php phpinfo(); が実行される info.php が閲覧できることを確認。
WordPressをセットアップしていきます。tar.gzでのアーカイブをwgetでダウンロード。
アーカイブをドキュメントルート配下に展開。この際にEFSは少しディスクI/Oが遅い事が分かります。ゆくゆくはCloudFrontなどでCDNキャッシュする事も検討した方がいいかもしれません。ファイル展開後はファイルの権限をApacheのものに変更。先ほど作成したindex.htmlとinfo.phpは削除しておきます。
WebブラウザでアクセスしWordPressのセットアップを進める。
DBの向き先はRDSのエンドポイント。その他WordPressのID・パスワードは適当に設定しメモしておく。
セットアップ完了。
現在起動しているEC2インスタンスのAMI(マシンイメージ)を取得。外部からのアクセスが有る状況でもないので「再起動しない」オプションは有効でOK。
作成したAMIから2つ目のEC2インスタンスを起動していく。サブネットはAZ冗長化の為に1cの方を選択。
マシン起動後にSSHログイン、先に1aで起動している方と同様にEFSマウント。先ほども書いたようにユーザーデータにしておくと最初からマウントされた状態になるかと思います。
1aで起動している方のDNS名、同1cのDNS名でどちらもWordPressサイトが閲覧できることを確認。
テーマを切り替えてみます。
もう片方にも反映されました。
画像アップロードを含む記事を作成してみます。
どちらのDNS名でも画像が見られることを確認。これで冗長化を実現できている事が分かります。同期用の設定などを組まなくていいのは楽ですね。
最後にロードバランサ―を立てます。Application Load Balancerを使います。
既存のサブネットを登録。
Web用のセキュリティグループを設定。本来このセキュリティグループにSSH許可は不要なのでALB用に別でセキュリティグループを作成した方がいいです。
ターゲットグループには起動済みのEC2インスタンス2つを追加。
作成したロードバランサーのDNS名をメモ。
ALBのDNS名でWordPressサイトが閲覧できることを確認。
以上でWebサーバー、DBサーバーが冗長化されただけでなく、コンテンツの同期も実現した環境が完成しました。ここまで所要時間は大体1時間強~2時間ほどでした。後は以下を検討していけばいいと思います。
セッション維持:
今回セッション維持は考えていません。WordPressに記事を投稿する際は起動している適当なインスタンスに直接アクセスするなど適当な方法を使います。
オートスケーリング:
AMI作成+ユーザーデータによるEFSマウント設定でオートスケーリングさせます。ファイルの同期はEFSをマウントするだけで完了します。
セキュリティグループ周り:
もうちょっと適切な内容で整理した方がいいです。
Apahce、PHPの設定、MySQLの設定:
今回は何も触っていないのでもちろん要チューニングです
CloudFront導入:
ファイルアクセスのレスポンスが気になるようであれば導入。実際どの程度の負荷まで耐えられるかは未知数。
AWS WAF導入:
既にALBが有るのでそこにAWS WAFを追加する事が出来ます。
あとはEFSを利用したドキュメントルートがどの程度のI/Oまで耐えられるかですね。ほぼ読み込みなら問題ない気がしていますが、これを実運用するならもちろん負荷テストは必要になるかと思います。場合によってはNFSからEC2ローカルに同期するような構成も検討が必要でしょう。以上、EFSでWordPressを冗長化してみた記事でした。
■ 2018年10月27日追記
Amazon Elastic File System (EFS) のプロビジョンドスループット機能が2018年 8月より利用できるようになっています。これを使えば I/O パフォーマンスは改善されるかも?
新機能 – Amazon Elastic File System (EFS) のプロビジョンドスループット | Amazon Web Services ブログ