AWS で WordPress を RDS とか S3 とか使って動かしてみる

少し前に AWS で DRBD やら Pacemaker やら Heartbeat やら GlusterFS を使って WordPress を HA 構成にしてみましたが、

なんで RDS とか S3 とか使わないの? 馬鹿なの? 死ぬの? とセルフツッコミが入ったので RDS や S3 を使ってみました。

VPC の作成

VPC は以前作ったものをそのまま使います。

おさらいすると、次のような感じです。

- VPC
   - Name tag               wp-vpc
   - CIDR block             10.1.0.0/16
   - Tenancy                Default
- Subnets
   - Name tag               wp-net-a
   - VPC                    wp-vpc
   - Availability Zone      ap-northeast-1a
   - CIDR block             10.1.1.0/24
   - Auto-assign Public IP  yes
- Subnets
   - Name tag               wp-net-c
   - VPC                    wp-vpc
   - Availability Zone      ap-northeast-1c
   - CIDR block             10.1.2.0/24
   - Auto-assign Public IP  yes
- Route Tables
   - Routes
      - Destination         0.0.0.0/0
      - Target              wp-gw
- Internet Gateways
   - Name tag               wp-gw
   - VPC                    wp-vpc
- Security Group
   - Security group name    default
   - VPC                    wp-vpc
   - inbound Rule
      - Type                ALL Traffic
      - Source              sg-xxxxxxxx (default)
   - inbound Rule
      - Type                SSH(22)
      - Source              My IP
   - inbound Rule
      - Type                All ICMP
      - Source              My IP
- Security Group
   - Security group name    public
   - VPC                    wp-vpc
   - inbound Rule
      - Type                HTTP
      - Source              Anywhere

IAM ロールを作成

WordPress から S3 にアップロードできるようにするために IAM ロールを作成します。

IAM ユーザーを作成して、そのユーザーの Access Key ID と Secret Access Key を使って S3 にアクセスすることも出来ますが、その場合は Access Key ID と Secret Access Key を EC2 インスタンス内に保存する必要があります。

一方、IAM ロールならインスタンスの作成時にロールを紐つけるだけで良いので、Access Key ID や Secret Access Key をインスタンスに保存する必要がなく、簡単かつ安全です。

特別な事情で IAM ロールが使えない場合以外は、IAM ロールを使うことが奨励されているようです。

IAM ロールを作成

IAM の Management console を開いて、左ペインの Roles から Create New Role をクリックします。

Step 1 : Set Role Name

Role Name に wp-role などと適当な名前を入力します。

Step 2 : Select Role Type

AWS Service Roles の Amazon EC2 を選択します。

Step 4 : Set Permissions

Custom Policy を選択して、テキストエリアに次を貼り付けます。Policy Name はなんでも良いです。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:*",
      "Resource": "*"
    }
  ]
}

この IAM ロールが紐付けられた EC2 インスタンスは S3 に対するフルアクセスが可能になります。

本当はもっと絞ったほうがいいのだろうけど Resource の指定方法がよくわかりませんでした。

RDS サブネットグループの作成

RDS のインスタンスを作る前に RDS サブネットグループを作成します。ここで指定したサブネットで RDS インスタンスは起動します。

RDS の Management Console の左ペインで Subnet Groups を選択して、Create DB Subnet Group をクリックします。

次のように入力して作成します。

  • Name wp-db-nets
  • Description WordPress Subnet Group
  • VPC ID wp-vpc (前回作ったやつ)
  • Availability Zone と Subnet ID を選択して以下のサブネットを追加
    • wp-net-a
    • wp-net-c

RDS インスタンス作成

RDS のインスタンスを作成します。

Step 1: Select Engine

mysql を選択します。

Step 2: Production?

Yes を選択します。

Step 3: Specify DB Details

Instance Specifications を次のように指定します。

  • DB Instance Class db.t2.micro
  • Allocated Storage 5 GB
  • Use Provisioned IOPS No

Settings には次のように入力します。

  • DB Instance Identifier wordpress
  • Master Username wordpress
  • Master Password wordpress
  • Confirm Password wordpress

Step 4: Configure Advanced Settings

次のように設定します。

  • Network & Security
    • VPN wp-vpc (前回作ったやつ)
    • DB Subnet Group wp-db-nets (↑で作ったやつ)
    • Publicly Accessible No
    • VPC Security Group default (同じセキュリティグループ同士で通信可能)
  • Database Options
    • Database Name wordpress
  • Backup
    • Backup Retention Period 0 days
  • Maintenance
    • Auto Minor Version Upgrade No

とくに記載していない部分はデフォルトのままにします。

インスタンスが立ち上がったら、Management console でインスタンスの画面を開いて Endpoint に表示されているホスト名を覚えておきます。

S3 Budket を作成

画像などをアップロードする先として S3 のバケットを作成します。

まず、S3 の Management console を開いて Create Bucket をクリックして適当な名前のバケットを作成します(仮に example-wordpress とします)。

作成したバケットを選択して、右上の方にある Properties をクリックします。

Permissions をクリック、Add bucket policy をクリックして、テキストエリアに下記を貼り付けて Save をクリックします

{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::example-wordpress/*"
        }
    ]
}

これで、このバケットにアップロードされたファイルは自動的に公開されるようになります。

なお、バケットの名前はグローバルに一意(すべてのアカウントで一意)でなければならないので、実際に example-wordpress などという名前のバケットは作れません、他の人が既にその名前でバケットを作っているからです。

EC2 インスタンスの作成

EC2 の Management Console の Instances から Lunch Instance をクリックして、次のようなインスタンスを1台だけ作成します。

Step 1: Choose an Amazon Machine Image (AMI)

Quick Start で Amazon Linux AMI 2014.03.2 (HVM) を選択します。

Step 2: Choose an Instance Type

t2.micro を選択します。

Step 3: Configure Instance Details

下記のみ変更して、その他はデフォルトのままにします。

Network                 wp-vpc
Auto-assign Public IP   Enable
IAM role                wp-role

Step 4: Add Storage

Volume Type を General Purpose (SSD) に変更します。

Step 5: Tag Instance

Name に wp-ap などと判りやすい名前を入力します。

Step 6: Configure Security Group

Select an existing security group を選択して default を選択します。

Step 7: Review Instance Launch

ざっくり内容を確認して、Launch をクリックします。

しばらく待つとインスタンスが起動するので SSH でログインします。

いろいろインストール

作成したインスタンスにいろいろインストールします。

yum

yum update します。

yum update

mysqlapachephp をインストールします。

yum install httpd24 php55 php55-opcache php55-mysqlnd mysql55

リブートします。

reboot

各種設定

各種設定を行います。

php

php の設定ファイルを作ります。

cat <<EOS> /etc/php-5.5.d/_default_.ini
expose_php = Off
error_reporting = E_ALL
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php/php.log
date.timezone = Asia/Tokyo
post_max_size = 500M
upload_max_filesize = 500M
memory_limit = 1G
EOS
cat /etc/php.d/_default_.ini

ログディレクトリを準備します。

mkdir /var/log/php/
chmod 777 /var/log/php/
touch /var/log/php/php.log
chmod 666 /var/log/php/php.log

ログローテートの設定を作成します。

cat <<EOS> /etc/logrotate.d/php
/var/log/php/*.log {
    missingok
    daily
    rotate 10
    ifempty
    create 0666 root root
}
EOS
cat /etc/logrotate.d/php

apache

いらなさそうな設定ファイルを空にします。

echo -n "" > /etc/httpd/conf.d/autoindex.conf
echo -n "" > /etc/httpd/conf.d/userdir.conf
echo -n "" > /etc/httpd/conf.d/welcome.conf

仮の index.html と ELB からのヘルスチェック先のページを作成します。

echo index > /var/www/html/index.html
echo readme > /var/www/html/readme.html

自動起動を有効にして起動します。

chkconfig httpd on
service httpd start

ELB の作成

ELB を作成します。

1. Define Load Balancer

Load Balancer name  wp-lb
Create LB Inside    wp-vpc

その他はデフォルトのままにします。

2. Configure Health Check

Ping Path           /readme.html

その他はデフォルトのままにします。

3. Select Subnets

ap-northeast-1aap-northeast-1c を追加します。

4. Assign Security Groups

defaultpublic を選択します。

5. Add EC2 Instances

↑で作成したインスタンス wp-ap を選択します。

Stickiness

ELB の作成後、Description の Port Configuration の近くにある Edit をクリックして Enable Load Balancer Generated Cookie Stickiness を選択します。

これをやっておかないと AP が複数になったときにセッションが維持されないことがあります(たぶん)。

ELB の DNS 名を登録

Route53 で ALIAS レコードで ELB を登録します。仮に aws.example.net だとします。

なお、ELB を作成してからしばらく時間をおかないと登録できませんでした。

登録したドメイン名をブラウザで閲覧して index.html が表示されれば正常に登録できています。

WordPress のインストール

WordPress をダウンロードして /var/www/html に展開します。

cd /usr/local/src/
wget http://ja.wordpress.org/wordpress-3.9.2-ja.zip
unzip wordpress-3.9.2-ja.zip
rm -fr /var/www/html/
mv wordpress /var/www/html/

wp-config.php を作ります。DB のホスト名には RDS の Endpoint のホスト名を指定します。

cd /var/www/html
mv wp-config-sample.php wp-config.php

sed wp-config.php -e "
  /^define('DB_NAME'/c     define('DB_NAME', 'wordpress');
  /^define('DB_USER'/c     define('DB_USER', 'wordpress');
  /^define('DB_PASSWORD'/c define('DB_PASSWORD', 'wordpress');
  /^define('DB_HOST'/c     define('DB_HOST', 'wordpress.xxxxxxxx.ap-northeast-1.rds.amazonaws.com');
" -i

curl https://api.wordpress.org/secret-key/1.1/salt/ > /tmp/secret

sed wp-config.php -e "
  /^define('AUTH_KEY'/r /tmp/secret
  /^define('AUTH_KEY'/d
  /^define('SECURE_AUTH_KEY'/d
  /^define('LOGGED_IN_KEY'/d
  /^define('NONCE_KEY'/d
  /^define('AUTH_SALT'/d
  /^define('SECURE_AUTH_SALT'/d
  /^define('LOGGED_IN_SALT'/d
  /^define('NONCE_SALT'/d
" -i

cat wp-config.php

ブザウザで http://aws.example.net/ にアクセスして WordPress のインストールウィザードに必要項目を入力してインストールを完了します。

この後、アップロードファイルの保存先の設定をするので、まだ記事の投稿は行いません。

WordPress のアップロード先設定

AWS SDK for PHP には S3 のストリームラッパーがあります。次のようなパスで S3 へのアップロードやダウンロードができるようになります。

  • s3://<BucketName>/<PathToFile>

WordPress がアップロードするディレクトリのパスをストリームラッパーのパスに変更して、S3 にアップロードされるようにしてみます。

まず、WordPress の次の URL を開きます。普通には弄れない内部的なオプションを変更するための画面なのだと思います。

  • http://aws.example.net/wp-admin/options.php

upload_pathupload_url_path を探して、次の通りに入力して保存します。

upload_path         s3://example-wordpress
upload_url_path     http://example-wordpress.s3-ap-northeast-1.amazonaws.com

upload_path に指定した値は /var/www/htmlWordPress のインストール先)からの相対パスになるようです。

なので、このままだと /var/www/html/s3://example-wordpress などという意味不明なパスになるので、WordPress のソースを弄って修正します。

wp-includes/functions.php の 1644 行目辺りをコメントアウトします。

    //} elseif ( 0 !== strpos( $upload_path, ABSPATH ) ) {
    //  // $dir is absolute, $upload_path is (maybe) relative to ABSPATH
    //  $dir = path_join( ABSPATH, $upload_path );

後は、S3 のストリームラッパーを登録するだけです。

AWS SDK for PHP は composer でインストールできるので、まずは composer をインストールします。

curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
chmod +x /usr/local/bin/composer

AWS SDK for PHP をインストールします。

cd /var/www/html
composer require aws/aws-sdk-php:\*

こんな場所で composer require すると composer.json とか vendor/ とかが丸見えになるのでよろしくありません。が、とりあえずそのままにします。

さらに wp-config.php に下記を追記します。

require 'vendor/autoload.php';
use Aws\S3\S3Client;
use Aws\Common\Enum\Region;
S3Client::factory(array('region' => Region::AP_NORTHEAST_1))->registerStreamWrapper();

これで S3 のストリームラッパーが登録され、アップロードファイルが S3 に保存されるようになりました。

適当に画像などをアップロードした後に S3 のバケットを閲覧してみると、アップロードされたファイルが保存されているのがわかります。

また、ブラウザで表示される画像の URL も S3 の URL になっています。

WordPress の補足

たぶん普通はこんなことしません。プラグインかなにかを使うものなのだと思いますが、実は WordPress ほとんど使ったことがなく、よく判らなかったので適当にソースを弄りました。

ググると下記のプラグインが出てきたのですが、プラグインのインストール方法とかをよく知らないので使いませんでした。

あるいは s3fs-fuse を使えば、単に /var/www/html/wp-content/uploads にマウントするだけで終わりそうです。

AMI の作成

最後に Auto Scaling を設定してみます、と言っても単にインスタンスをたくさん立ち上げただけです。

Auto Scaling には AMI が必要なので、作成済の EC2 インスタンスを AMI 化します。

インスタンスにログインして、AMI に含めたくないファイルを削除してシャットダウンします。

rm -f /root/.ssh/authorized_keys
rm -f /home/ec2-user/.ssh/authorized_keys

rm -f /etc/ssh/ssh_host_dsa_key
rm -f /etc/ssh/ssh_host_dsa_key.pub
rm -f /etc/ssh/ssh_host_key
rm -f /etc/ssh/ssh_host_key.pub
rm -f /etc/ssh/ssh_host_rsa_key
rm -f /etc/ssh/ssh_host_rsa_key.pub

find /var/log -type f | xargs rm -fv

rm -f /root/.bash_history

shutdown -h now

EC2 の Management console で インスタンスを選択して Create Image で AMI を作ります。

Launch configuration の作成

EC2 の Management console の Launch configuration で Create launch configuration をクリックします。

1. Choose AMI

My AMIs を選択して、↑で作成した AMI を選択します。

2. Choose Instance Type

t2.micro を選択します。

3. Configure details

Name に wp-auto などと判りやすい名前を設定します。

IAM role には wp-role を指定します。

4. Add Storage

Delete on Termination が On になっていることを確認します。なっていなければ On にします。

5. Configure Security Group

Select an existing security group を選択して default を選択します。

6. Review

ざっくり内容を確認して右下の Create launch configuration をクリックします。

Auto Scaling Group の作成

EC2 の Management console の Auto Scaling Groups で Create Auto Scaling Groups をクリックします。

Create an Auto Scaling group from an existing launch configuration を選択して、先ほど作成した Launch configuration を選択します。

1. Configure Auto Scaling group details

Group name          wp-group
Group size          起動したいインスタンスの数
Network             wp-vpc
Subnet              wp-net-a wp-net-c

Advanced Details を開いてさらに設定します。

Load Balancing      On wp-lb (チェックボックスを On にしてテキストボックスに ELB を入力)

2. Configure scaling policies

特になにも変更せずに次に進みます。

3. Configure Notifications

特になにも変更せずに次に進みます。

4. Configure Tags

特になにも変更せずに次に進みます。

5. Review

ざっくりと内容を確認して右下の Create Auto Scaling Groups をクリックします。

しばらく待つと、インスタンスがバコバコ起動して ELB に追加されます。

さいごに

試しにインスタンスの数を 100 台に設定してみたのですが、20 台目以降はインスタンスの作成に失敗しました。

EC2 の Management console の Limits を見ると t2.micro は 20 台がリミットになっているので、申請しなければ 20 台より多くは起動できないようです。

下図は 20 台起動したときの EC2 の Management console のキャプチャです。

f:id:ngyuki:20140824140252p:plain

祭りの後

f:id:ngyuki:20140824140326p:plain