AWSで構築するMastodonサーバー

個人的に小規模なMastodonサーバーを運用しているのですが、勉強がてらAWSの各種サービスを組み合わせてインフラを構築しています。大手のサーバーの運用停止が相次ぐ中で今更感は拭えませんが、今回はそのアーキテクチャをご紹介します。Mastodonは典型的なRailsアプリケーションなので、似たようなシステムを構築する際に参考になればと思います。

この記事は2019年6月時点での情報に基づいて書かれています。また、AWSの各サービスそのものについては簡単な知識があることを前提にしています。

現在の構成

運用開始から1年半ほどで徐々に拡張してきた結果、全体の構成は以下の図のようになっています。SES以外は東京リージョンにあります。

ちなみにこの図はAWSアーキテクチャアイコンを使用して作成していますが、利用にあたっては色々と規約が定められているので、提案書や設計書などでこういった図を作成する際には事前に一通り目を通すとよいと思います。

EC2

MastodonはDocker版を導入していて、t3.smallのEC2インスタンス上で稼働しています。1つのEC2インスタンス上にNginxとアプリケーションとElasticsearchが同居している構成で、Mastodonで用意されているweb/sidekiq/streaming/esの4つのコンテナが動作しています。ストレージはEBSでgp2の32GiB、程よく

$ docker system prune

などで掃除しないと未使用コンテナでいっぱいになります。

RDS/ElastiCache

データベースはRDSでPostgreSQLを、キャッシュはElastiCacheでRedisをそれぞれ用意しています。現在は正直全部EC2インスタンス上で動かしても耐えられるくらいのトラフィック量ですが、マネージドサービスはメンテナンスが楽で将来的な拡張も容易になるので導入しています。これらはEC2インスタンスとだけ通信できればよいのでプライベートサブネットに置いています。RDSのストレージは32GiBにしていますが、失敗しました。そんなに使いません。よほど大規模でない限り16GiBでも余裕だと思います。

Elastic Load Balancer

EC2インスタンスの手前にはApplication Load Balancerを噛ませています。現在EC2インスタンスは1つなので負荷分散もなにもないのですが、これも将来的な拡張性と、ALBを使用しているとAWS Certificate ManagerでSSL証明書を取得できるので、それを利用するために導入しています。

S3

トゥートに含まれる画像や動画などはEC2上に置かずS3の公開バケットに置いています。S3はEBSと異なり容量上限にぶつかることがないので、課金額にさえ注意を払っていれば管理は楽です。他のサーバーから流入してくるデータは放置しておくとストレージ使用量が膨れ上がる一方なので

$ docker-compose run --rm web bin/tootctl media remove

は週1回cronで実行しています。

CloudFront

S3の手前にはCloudFrontを噛ませています。これに関しては、なんとなくCDN使ってみたかった、という以上に深い意味はなにもありません。あまり値段が張るのも厳しいので価格クラスは真ん中のUS/Canada/Europe/Asia/Middle East/Africaの設定にしています。CloudFrontにもACMで取得したSSL証明書を使っています。CloudFrontは動的コンテンツの配信にも利用できるようになっていて、ALBの手前にも噛ませる選択肢はありましたが、以前某社がセキュリティ事故を起こしていた事例がありリスキーな感じがしたので見送っています。

SES

メールアドレス検証やパスワード再設定などでユーザーに送るメールの配信はSESを使っています。SESは東京リージョンでサービス提供されていないので、これだけオレゴンに置いてあります。

misc

他にはドメインの管理をRoute53で、システム全体のモニタリングをCloudWatchで行っています。

費用

現在のところ以上の構成で、EC2とRDSはNo Upfrontのリザーブドインスタンス、ElastiCacheはAll Upfrontのリザーブドインスタンスを購入した状態で月額5000円前後の請求額になっています。

今後拡張したいポイント

まだ未検証ですが考えていることがいくつかあります。

EC2の冗長化

せっかくALBを使っているので、例えばEC2インスタンスはインスタンスサイズを落として2台構成にして2つのAZに配置し、負荷の低いときはAuto Scalingで片方を落としておく、という構成にすることで現状よりは可用性やコスト効率性を高められると考えています。ただ、現状ElasticsearchがEC2内(EBS内の方が正確でしょうか)にインデックスを保存しているため、そのままでは同一AMIから複数のインスタンスを立ち上げるといった構成を取ることができません。この対策については後述します。

Elasticsearchのアプリケーションサーバーからの切り離し

上述したようにEC2冗長化の妨げになっているのはElasticsearchです。この対策として最も簡単なのはAWSのElasticsearch Serviceを導入することです。ただ、個人運用の小規模システムに導入するにはそれなりに費用がかかるのであまり現実的ではありません。代替手段としてElasticsearch用のEC2インスタンスを別に用意するという方法を検討しています。なお、これはあくまで個人運用レベルの話なので、業務で高可用なシステムを構築する際にはElasticsearch Serviceの利用をお勧めします。

ECSへの移行

EC2インスタンス上の各サービスはDocker運用なので、各コンテナをECS+Fargateで動かすことでサーバーレス化する、という構成も考えられます。Fargateも費用的なネックがあるので個人運用レベルではECSのEC2起動タイプの方が現実味はありますが、いずれにせよ各サービスがコンテナ化されているメリットを引き出せるアーキテクチャにしたいところです。

まとめ

以前は自宅サーバーを運用していたりオンプレミス環境でインフラ構築をしたりしていたこともありますが、AWSをはじめクラウドサービスを使い始めるとオンプレミスには戻れない便利さがあります。個人でも業務でもマネージドサービスをフル活用して、よりスケーラブルなシステムを構築できるよう勉強していきたいところです。