LambdaとAPI GatewayとAurora Servelessでwordpress動かしてみた

# そもそもLambdaとAPI GatewayとAurora Servelessでwordpressは動くのか
社長 「wordpressを全面に出すのはあれやから、staticファイルで吐くやつほしいなあ」
社長 「コストを限りなく下げて」
社長 「でもwordpressのインターフェイスは捨てがたいよねえ」
社長 「( ﾟдﾟ)ﾉ ﾖﾛ」

ということで、始まった低コストで作るwordpress環境構築ですが

結論から言うと

```
LambdaとAPI GatewayとAurora Servelessでwordpressは動きます。
yes, you can...
(実運用できるとは言っていない)
```

# Lambdaはサーバではないので、ファイルが置けない
wordpressってファイルを置くことが求められるので、アップロードされたときにどうするか・・・。

```
そうだ、俺達にはS3というサービスがあるじゃないか!!
```

ということで、S3にアップロードするプラグインを使えばこの問題は解決します。

# Lambdaはインターネットに口を開けてないよね?

```
そこで登場API Gateway
(しかも激安、3億リクエストで200円ぐらい)
```
* ELB(ALB)でも可能ですが、コストが少しあがるんで「低コスト」という要件から外れます
* とはいえ安いですけども

# RDS(データベース)がそこまで安くないよね?
* これはしょうがないけど、それでも安くするために
* Aurora Serverlessの登場です
  * さすがクラスメソッド様、[こんな記事(RDSとAurora Serverlessの費用比較)](https://dev.classmethod.jp/articles/calculate-amazon-aurora-serverless-costs/)を書いてくれています

# 事前準備
1. S3のバケットを2個つくる
  1. 画像などをアップする用
  2. ソースコード全般をアップする用
3. wordpress環境
  1. dockerでも良いですが、ソースコード一式が必要です
  2. プラグインのファイルもまるごと必要です
3. awscliやaws-sam-cliやmysql-clientコマンドが必要
4. aurora-serverlessを立ち上げて、id/passとかサーバのエンドポイントなどコピーしつつ、ローカルでdumpしたデータベースのデータを入れ込む

## S3のバケットを2個つくる
これは単純に2個つくるだけですので、割愛します。画像用の1つはパブリックというか誰でも読み取れるようにしておいてください。

awsコマンドが通るようにしておいてください。aws s3 cpとかできるように。

## wordpress環境
dockerでもvirtual boxでもec2でもなんでもいいですが、ファイルをすべて取得する必要があります。動いたwordpressにS3に画像をアップロードするプラグインを入れてください。今回は「WP Offload S3 Lite」というものを使いました。

必要なテーマとかプラグインとかを入れるのはここの手順で行いますが、それらがLambda上で必ず動くという保証はどこにもないので都度都度修正する必要があるかと思います。

あと、そのwordpressのデータベースのデータをdumpしておいて、後でaurora-serverlessに入れ込みます。

## S3のバケットつくっておく
このままなんで説明の必要がないかと思います。wp-uploadsとかwp-sourceとかわかりやすいバケット名をつけておけばいいでしょう

## awscliやaws-sam-cliやmysql-clientコマンドが必要
```
# mac環境であると仮定してしまってますが・・・
$ brew install awscli
$ brew tap aws/tap
$ brew install aws-sam-cli
$ brew install mysql-client
```

## aurora-serverlessを立ち上げて、id/passとかサーバのエンドポイントなどコピーしつつ、ローカルでdumpしたデータベースのデータを入れ込む
id / pass / endpointをコピペしとく。ローカルのデータのdumpを流し込む。

# ルーティングは自分でどうにかしないといけない
これが結構ポインかもしれない。あくまでLambdaとかAPI GatewayとかはもともとはAPI的に使うことを想定しているのでWEBサーバではないのでルーティングは自分で指示してあげないといけないし、レスポンスタイプも都度都度指定してあげないといけない。

例えば、画像のmime/typeを判断してHTTPヘッダをつけてやるとか、ディレクトリアクセスのときはindex.phpにふってあげるとか。。。

結構パターンがあると思うので網羅出来ない可能性があります。何度も言いますが間違っても本番運用なさらぬよう・・・(する人はいないだろと突っ込まれそうですがw)

## ディレクトリ構成はこんな感じ
```
$ tree -d
.
serverless-output.yaml
template.yaml
└── src
    └── server
        └── router.php
        └── php.ini
        └── Prod
            └── Index
                ├── ここにwordpressのファイルをすべて置く
```
## router.php
多少のPHPを書かねばなりませぬ。

```php

<?php
// All requests through API Gateway are HTTPS.
$_SERVER['HTTPS'] = 'on';
$root = $_SERVER['DOCUMENT_ROOT'];

// REQUEST_URIベースで処理されるので、ここで加工しておく必要がある
$_SERVER['REQUEST_URI'] = str_replace('/Index', '/Prod/Index', $_SERVER['REQUEST_URI']);
$urls = parse_url($_SERVER['REQUEST_URI']);

// 画像その他
if (preg_match('/\.([a-zA-Z]{2,3})$/', $urls['path'], $matches)) {
    $mime = [
        'css' => 'text/css',
        'js' => 'application/javascript',
        'png' => 'image/png',
        'jpeg' => 'image/jpeg',
        'jpg' => 'image/jpeg',
        'svg' => 'image/svg+xml',
        'gif' => 'image/gif',
        'ico' => 'image/vnd.microsoft.icon',
    ];
    if (isset($mime[$matches[1]])) {
        if (is_readable($root . $urls['path'])) {
            header('Content-type: ' . $mime[$matches[1]]);
            readfile($root . $urls['path']);
        } else {
            header("HTTP/1.0 404 Not Found");
        }

        return true;
    }
}

// ディレクトリアクセスと思われ
if (substr($urls['path'], -1) == '/') {
    $file = $root . $urls['path'] . 'index.php';
    if (file_exists($file)) {
        require $file;
        return true;
    }
}

// どれにも該当しないのでそのまま読みこむが正しいかどうかは・・・
require $root . $urls['path'];

```

### template.yaml
パッケージするときにつかう設定ファイルです。
[ここ](https://github.com/stackery/php-lambda-layer)にのってあるものとほぼ同じです。

```
            Handler: router.php
```
ここだけ違いますかね。

# パッケージしてデプロイします

パッケージして

```
sam package \
    --template-file template.yaml \
    --output-template-file serverless-output.yaml \
    --s3-bucket ソースコード用につくったS3のバケット名
```

デプロイします

```
sam deploy \
    --template-file serverless-output.yaml \
    --stack-name ソースコード用につくったS3のバケット名 \
    --capabilities CAPABILITY_IAM
```

これでAPI GatewayのマネジメントコンソールいけばURLが発行されるので、そのURLにアクセスすれば見事wordpressが表示されます。

# 参考リンク
* https://github.com/stackery/php-lambda-layer
* http://blog.serverworks.co.jp/tech/2018/11/30/lambda-php/
* https://qiita.com/kojima_akira/items/b2c1363e79f17a1880db

# まとめ
* 動くのは動く
* だが本番で使えるかどうかはまた別問題(押すなよ、押すなよ)
* wordpressをstaticにして、ファイルをS3に上げるプラグインは一度ローカルに落とすものが多い
  * プラグインを自作するのがおそらく一番近道
  * いろいろAWSでごにょろうと思えば出来なくもないが茨の道なのでおすすめしない
* プラグインによっては修正変更を余儀なくされる場合もある
* https絡みのトラブルも発生するかも
* ここまでやる人件費と時間を考えたら、[shifter](https://www.getshifter.io/)とか[Strattic](https://www.strattic.com/)とかを使えばいいんじゃないという身も蓋もない終わり方で締めたいと思いますw