ENECHANGE Developer Blog

ENECHANGE開発者ブログ

Wordpress のメディアファイルを s3fs から efs に移行した話

ENECHANGE の川西( a.k.a. cuzic )です。

最近、いびきの軽減を目的として、のどちんこを切除する手術を受けました。 職場で昼寝していて、いびきが職場に鳴り響いていたのがなくなり、職場環境改善にもつながりました。

Wordpress のメディア(画像、動画)ファイルとは

Wordpress は、主に下記の3つで構成されています。

  • Wordpress の本体のコード( ENECHANGE では Git repo 上に管理されている)
  • 記事データ(ENECHANGE では AWS の RDS の MySQL にある)
  • メディアファイル(wp-uploads フォルダ以下にあるファイル群。本稿の主題)

ENECHANGE ではこのメディアファイルの管理する方式を変更しました。

Wordpress のメディアファイルの管理方式の問題点

Wordpress はメディア(画像、動画)をファイルとして保管しています。ファイルとして保管しているため、複数台構成とするとき、そのまま冗長化してしまうと、次のような問題があります。

  • アクティブ・スタンバイで運用する場合、アクティブ側にだけ画像ファイルがある状態となる。障害で切り替わったのち、画像が表示できない不具合が生じる
  • 両系アクティブの場合、サーバ1台だけにメディアファイルが存在する状態となるため、表示したときどのサーバに接続したかによって、画像が表示されたりされなかったりする。

このような問題点を解決する方法として、いろんなやり方がありますが、 ENECHANGE では s3fs を採用していました。

それまでの ENECHANGE の構成

ENECHANGE で Wordpress のメディアファイルを保存するのに使っていた s3fs は、その名から想像できるとおり、 AWS の S3 をファイルシステムとしてマウントする技術です。 s3fs を使って AWS の S3 にメディアファイルを配置することによって、記事の編集作業をするときにアクセスしていたサーバと記事を配信するときのサーバが異なっていても、同じメディアファイルを配信し、正常に表示できるようにしていました。

しかしながらこの方式には次のような問題点がありました。

  • 初期に構築した人がすでに enechange.jp のプロジェクトから離れてしまったため、設定等が分かる人はいない
  • s3fs は不具合が多く報告されており、継続して利用するのに不安がある
  • そもそも s3 の設計思想と、ファイルシステムとしてマウントする場合に求められる要件は大きく異なり、筋が良いと思えなかった。

そこで、代替案があれば、別の技術に乗り換えよう思っていました。ちょうど Wordpress のインフラ環境リニューアルのプロジェクトがあったので、 s3fs を別の技術に乗り替える作業に着手しました。

Amazon EFS とは

そこで白羽の矢が立ったのが、 Amazon EFS です。 EFS ( Elastic File System ) を簡単に説明すると、AWS のマネージドサービスの NFS ( Network File System ) です。

Amazon EFS を使えば、複数台のサーバでファイル共有がカンタンにできるようになるので、 Wordpress の冗長化目的に最適です。実際に Amazon の技術資料 で、Wordpress の冗長化には EFS を採用しています。

enechange.jp の初期構築のタイミングではまだ Amazon EFS が存在しなかったので、当時は仕方ありません。ですが、せっかくのインフラのリニューアルのタイミングで s3fs を使い続ける理由はありません。EFS に切り替えることになりました。

Amazon EFS への移行

Amazon EFS の利用はとてもカンタンで、少しの設定ですぐに利用できました。

ENECHANGE では EFS マウントヘルパーを利用して、マウントしました。

手順については、Amazon のドキュメント で詳しくまとまっています。

ENECHANGE では下記のような設定を記述しました。なお、ENECHANGE ではこのタイミングで Amazon Linux 2 の Elastic Beanstalk 環境に移行しており、Amazon Linux 2 の EB 環境向けの設定ファイル例となっています。

.ebextensions/amazon-efs-utils.config

.ebextensions 以下で、amazon-efs-utils という yum package をインストールしています。 amazon-efs-utils を使うことで Amazon EFS の設定をとても簡単にできます。 通常のNFS で接続する場合と比較して、amazon-efs-utils を使うと、EFS に最適な設定が自動的に有効化されるので、高いパフォーマンスで接続できます。

.ebextensions/amazon-efs-utils.config

packages:
  yum:
    amazon-efs-utils: []

.platform/hooks/prebuild/10_efs.sh

プラットフォームフック というのは Amazon Linux 2 で新たに導入された Elastic Beanstalk のカスタマイズ方法です。 プラットフォームフックを利用することで、.platform 以下の特定のディレクトリに記述したシェルスクリプトを、環境構築時やデプロイ時に実行できます。

.platform/prebuild ディレクトリのシェルスクリプトで EFS のマウントを実行しています。prebuild ディレクトリ内のスクリプトはアプリケーションを解凍して展開した直後、アプリケーションのセットアップを開始する前に実行されます。

#!/bin/bash

if [ ! -d /mnt/uploads ]; then
  mkdir /mnt/uploads
  chown webapp:webapp /mnt/uploads
fi

# Amazon Linux 2 以降の EB 環境では環境変数が自動的にセットされなくなったので
# 明示的に取得する必要がある
WORDPRESS_UPLOADS_EFS_ID=$(/opt/elasticbeanstalk/bin/get-config environment -k WORDPRESS_UPLOADS_EFS_ID)
mount | fgrep -q uploads ||
  mount -t efs $WORDPRESS_UPLOADS_EFS_ID:/ /mnt/uploads

シェルスクリプトに慣れた方であれば見れば何をしているのかは簡単に理解できるでしょう。

WORDPRESS_UPLOADS_EFS_ID という EB の環境プロパティの設定内容を、 WORDPRESS_UPLOADS_EFS_ID という環境変数に設定しています。 本番と staging でマウントすべき EFS の ID が異なりますので、その差を EB の環境プロパティ設定を使って吸収しています。

mount | fgrep -q uploads で、すでに mount 済かどうかをチェックしていて、まだ mount していない場合にだけ、マウント処理を実行しています。

.platform/hooks/predeploy/50_symlink_uploads.sh

.platform/predeploy ディレクトリのシェルスクリプトで uploads ディレクトリのシンボリックリンクの作成作業を実行しています。predeploy ディレクトリ内のスクリプトはアプリケーションのセットアップが終了したあと、デプロイを開始する前に実行されます。

#!/bin/bash

cd wp-content
ln -s /mnt/uploads uploads

このスクリプトの内容は簡単なので解説不要ですね。 wp-content/uploads にアクセスすると、/mnt/uploads 内のファイルにアクセスできるようにシンボリックリンクを作成しています。

おわりに

今回は Wordpress の Elastic Beanstalk 化に合わせて、 Amazon EFS を導入した件について説明しました。

設定例についても、掲載しているので、同じように Amazon EFS を導入しようとしている方のお役に立てると嬉しいです。