MovableType AWS版 + S3 + CloudFront に移行しました
## 後日談(2014.8.6)
やってみてわかったんですが、rsyncだとS3への反映が遅いのと、設定間違えて更新頻度上がりすぎて課金地獄というリスクもあり、ちょっと使い勝手悪かったです。
いまだと、CloudFrontは配信元のExiresを優先してくれたり、HostなどのHTTPヘッダーやCookieを通過しそれぞれを考慮してキャッシュしてくれるようになっているので、普通のMT(非S3)+CloudFrontの方がお勧めだったりします。
[CloudFront + S3以外 というのも有力な選択肢だと思ってる](http://blog.takeyu-web.com/2014/08/cloudfront-s3.html)
---
オーバースペックですが、練習も兼ねて、このブログを[MovableType6 AWS版](http://www.sixapart.jp/movabletype/aws/)(microインスタンス) + [S3](http://aws.amazon.com/jp/s3/) + [CloudFront](https://aws.amazon.com/jp/cloudfront/)に移行しました。
## 構成
シンプルにこんな感じです。
- MT6(AWS) microインスタンス
- S3FS
- rsync
- S3 StaticWebHosting
- CloudFront
詳しい導入手順はあとでまとめて書きます。
また、AMIのアップデートの度にいちいち手作業は面倒なので、Chefレシピを書いておきたい。
### MT6(AWS) microインスタンス
MTライセンス料無料がやっぱりありがたい。
通常の管理画面操作は高速で快適。再構築中などで負荷がかかっていなければ。
- [CPUバースト対策](http://unching-star.hatenablog.jp/entry/2014/05/02/145200)
- [Movable Type for AWS(AMI)(Amazon Linux AMI 2013.09) yumエラー対策](http://blog.takeyu-web.com/mt/2014/05/movable-type-for-awsamiamazon-linux-ami-201309-yum.html)
### S3FS
静的ファイルはすべてS3上に配置します。これにより、MTサーバ側が非力でも、コンテンツ配信の負荷は気にしなくてよくなるほか、たとえサーバが落ちてもページを表示することができます。
S3 APIを使用してアップロードするプラグインや、s3cmdを使って自力で同期するスクリプトを書く方法もあるのですが、今回はもっとも手軽で確実なS3FSとrsyncを利用することにしました。
[s3fs-fuse](https://github.com/s3fs-fuse/s3fs-fuse)
これを使うことで、S3をNFSのように扱うことができます。便利。
「他のS3クライアントと互換性がない」と言われ続けていたS3FSですが、昨年の1.68で対応済みとなっています。
[ChangeLog for S3FS](https://github.com/s3fs-fuse/s3fs-fuse/blob/master/ChangeLog)
[Issue 27: Feature Request: Compatability with other S3FS clients](http://code.google.com/p/s3fs/issues/detail?id=27)
そのままMTの書き出し先にしてもよいですが、アクセスのたびにHTTPリクエストが発生するため、非常に遅いので、僕はrsyncで同期を取るようにしています。
### rsync
こんな感じのスクリプトで同期しています。
`/etc/cron.d/s3sync`
```
SHELL=/bin/sh
* * * * * root /bin/bash /app/movabletype/tools/s3sync.sh > /dev/null 2>&1
```
`/app/movabletype/tools/s3sync.sh`
```bash
#!/bin/bash
LOCKFILE=/tmp/s3sync.lockfile
(
flock -n 200 || exit 1
/usr/bin/rsync -avz --delete-after /data/file/static/ /mnt/blog.takeyu-web.com/
) 200>$LOCKFILE
```
### S3 Static Web Hosting
これを設定しないと、S3に置くだけでは`http://blog.takeyu-web.com/mt/`のようなアクセスの時、`/mt/index.html`を返すことができません。
有効にすることでManagement Console上に表示されるエンドポイント(`Endpoint: bucketname.s3-website-ap-northeast-1.amazonaws.com`というやつ)をCloudFrontのOriginに設定します。
### CloudFront
S3は確かに安心なのですが、レスポンスは遅いので表示の高速化を行いたいときはCDNを組み合わせます。ここでは同じくAWSのCloudFrontを利用しました。
とりあえず気をつけるのは、Originは自動補完されるS3のバケット名ではなく、StaticWebHostingのエンドポイントを指定することぐらいです。(小一時間ハマりました)
※なお、CloudFrontは別にS3でなくてもOriginに指定できるので、無理に使う必要はないです。
## 検討中のこと
### CloudFront側へのキャッシュ制御
MinimumTTLは有効期限を長くするために使うものなので、コレではない。
S3オブジェクトのメタデータで指定できるが、いちいち設定できないので自動化したいところ。AWS APIでスクリプトを書く?
参考:[CloudFrontのキャッシュ有効期限を1時間にする(S3オリジン) - suz-lab](http://blog.suz-lab.com/2011/06/cloudfront1s3.html)
### 更新から反映までのタイムラグ
Expiresの件とも絡んできますが
更新 → S3に同期 → CloudFrontキャッシュ切れ
ということでタイムラグが気になります。
更新の際に記事のHTMLだけでもS3にコピーの上、CloudFront の API を叩いて Invalidating Object を登録するとかしたほうがいいかも。
## 発展可能性?
実証サイトはまだ作っていませんが、この仕組みを発展させてELBとたくさんのmicroインスタンスを組み合わせることで、ユーザーログインや検索も高いスケーラビリティをもって実現できる・・・と思います。たぶん。
基本的に管理インスタンス以外にはファイルは置かないことがポイント。それによりスケールアウトしやすくなります。
※DataAPIによるサムネイル生成など、管理用インスタンス以外からの静的ファイル更新がある場合は、もうひと工夫要るでしょう
※DataAPIへのアクセスはクロスドメインになるので、[DataAPICORSAllowOrigin環境変数](http://www.movabletype.jp/beta/60/dataapicorsalloworigin.html)を使用することになるでしょう