ランサーズ(Lancers)エンジニアブログ > AWS > Aurora > AWSでWordPressのスケールアウト

AWSでWordPressのスケールアウト

kanazawa|2017年03月06日
Aurora

インフラエンジニアの金澤です。
今回は、AWS上のWordPressサーバーをスケールアウトするために行った手順について紹介いたします。

ランサーズで運用しているWordPressサービス

ランサーズでは10以上のWordPressサービスをAWSで運用しています。
ランサーズと比べてアクセス数が多くなく、負荷も低いのでこれらのサービスを1台のEC2で運用してきましたが、リソースが不足してきたため、複数台にスケールアウトできるように準備し始めました。

スケールアウトするために解決すべき問題

WordPressのEC2をスケールアウトするには、以下の問題を解決する必要があります。

MySQL

EC2のローカル上にMySQLがインストールされた状態では、複数台構成にできません。
MySQLを別サーバーに移動する必要があります。

uploadsディレクトリ

wp-content/uploadsディレクトリには、記事投稿時にアップロードされた写真等のメディアデータが格納されます。
EC2上にこのディレクトリがある状態では複数台構成にできません。
uploadsディレクトリを別サーバーに移動する必要があります。

pluginsディレクトリ

wp-content/pluginsディレクトリには、WordPressのプラグインが格納されています。
複数台構成にすると、管理画面からプラグインを追加しても、1台のサーバーにしか反映されません。
全サーバーにプラグインが配布されるような仕組みを作る必要があります。

ログ

複数台構成にすると、各サーバーにログが分散され、解析が困難になります。
アクセスログを解析したい場合は、別途ログを集約する仕組みを構築することになります。

スケールアウトするために行なった準備

以下、上記の問題を解決するために行った手順について紹介いたします。

スケールアウト前

元々は、1台のEC2にグローバルIPを付与して運用していました。
https通信については、必要なドメインのみSSL証明書を申請していました。

Git化

ランサーズでは、WordPressのプロジェクトは、全てGitHubで管理しています。

wp-content/plugins ディレクトリはGit化し、プラグインの追加もGitHubに反映しています。
プラグインの追加は本番サーバーの管理画面では行わず、開発環境で追加し、検証が完了したものをgit pullでリリースするフローにしています。
※wp-config.phpやwp-content/uploadsディレクトリはGit管理から外しています。

ELBを追加

スケールアウトの第一歩として、まずELB経由で通信する構成に変更します。
グローバルIPアドレスは必要なくなるため、EC2はプライベートVPCに移動させます。

このタイミングで、ELBの以下の機能を利用するように設定しました。

AWSのSSL証明書設定(https化)

AWSの無料SSL証明書が利用できるようになったため、サービスをhttps化しました。

SSL Termination

ELBのSSL Termination機能を利用することで、EC2内ではhttpのままで通信できます。
ELBアクセス時にhttp、httpsのどちらかでアクセスされたかを判定するために、X-Forwarded-Proto環境変数を利用するため、wp-config.php に以下の記述を追加します。
(wp-settings.phpの読み込み前に記述)

if (!empty( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' ) {
    $_SERVER['HTTPS']='on';
}
 
/** Sets up WordPress vars and included files. */
require_once(ABSPATH . 'wp-settings.php');

MySQLをRDSに移行

RDS for MySQLを作成し、EC2内のMySQLをRDSに移行します。

MyISAMのテーブルが含まれているとRDSの機能が制限されますので、特に理由がなければInnoDBに変換しておいたほうが良いでしょう。

uploadsディレクトリをS3に移行

wp-content/uploadsディレクトリのコンテンツはS3に格納します。

S3に格納するために必要なプラグインは以下の2つになります。

Amazon Web Servicesプラグイン

プラグインを追加後、wp-config.phpに以下の設定を追加します。

define( 'DBI_AWS_ACCESS_KEY_ID', 'XXXXXXXXXXXXXXXXXXXX' );
define( 'DBI_AWS_SECRET_ACCESS_KEY', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' );

WP Offload S3 Liteプラグイン

Webサイトホスティングを有効にしたS3バケットを作成し、プラグインを追加、設定します。
既存のuploadsディレクトリのコンテンツは、S3にアップしておく必要があります。
aws s3コマンドでS3にコピーします。

$ aws s3 sync ./wordpressディレクトリ名/wp-content/uploads s3://S3バケット名/wordpressディレクトリ名/wp-content/uploads

DB側のupload情報も修正が必要になります。
ここが一番面倒な作業になります。
このブログの記事を参考にさせていただきました。

wp_postmetaテーブルにデータ追加

INSERT文をSQLで生成し、出力されたINSERT文を適用してデータを追加します。

SELECT
  CONCAT(
    'INSERT INTO wp_postmeta(post_id, meta_key, meta_value) VALUES (',
    post_id,
    ', \'amazonS3_info\', \'a:3:{s:6:\"bucket\";s:13:\"S3バケット名\";s:3:\"key\";s:',
    length(meta_value) + 29,
    ':\"wordpress/wp-content/uploads/',
    meta_value,
    '\";s:6:\"region\";s:14:\"ap-northeast-1\";}\');'
  ) AS record
FROM
  wordpress.wp_postmeta
WHERE
  meta_key = '_wp_attached_file'
;

※length(meta_value) + 29の29という数字はuploadsディレクトリまでのパスの文字数です。
例えば、wordpress/wp-content/uploads/ というパスであれば、パスの文字数が29になるので、29を加算します。

データ追加が上手く行けば、管理画面の「メディア」メニューにアップロードしたデータのURLが、S3WebサイトホスティングのURLになります。

wp_postテーブルのURL修正

wp_postテーブルや、その他、アップロード画像をURL参照しているテーブルのURLも、S3のURLに変更します。
この作業はバックアップも兼ねて、mysqldumpでテーブルデータをエクスポートしてから、エディタでURLを変更後、インポートし直すのが良いと思います。

リリースシステムとの連携

ここまで準備すれば、EC2をスケールアウト可能になります。
複数台構成のEC2にリリースを行うために、リリースシステムからリリースするフローに変更しました。
ランサーズには、専用のリリースシステムがあります。
このリリースシステムに、WordPress系プロジェクトのリリース機能を追加します。
リリースシステム上でgit pullして、ansible経由でWordPress全サーバーに同期します。
WordPressサーバー側はGit管理する必要がなくなるため、このタイミングで.gitディレクトリを削除します。

今後の課題

ログの集約

fluentd + S3プラグインでログをS3に集約します。
ログサーバーにも転送し、全WordPressサーバーのアクセスログは、ログサーバーで参照するようにします。

DBのスケールアウト

HyperDBプラグインを導入すると、参照系と更新系を分離できるようになります。
RDSのリードレプリカを作成し、参照系はHAProxy等で分散させるようにします。

最後に

実は、WordPressのEC2はまだ1台のままです。(笑
スケールアウトの準備をした過程で、リソースがELB、EC2、RDS、S3に分散された結果、もう少しだけ耐えられそうな見込みになったためです。
もう少しアクセスが増えたら、EC2をスケールアウトし始めることになると思います。
今回は、その準備ができましたというお話でした。