読者です 読者をやめる 読者になる 読者になる

MastodonをAWSでシュッと動かすやつ

MastodonAWS で動かしたい人のために、https://github.com/r7kamura/mastodon-terraform というのをつくった。簡単に動かすという目的以外に、MastodonAWS で動かすために必要な設定をコードで表現することで、どういうインフラが必要になるのかを共有しようというねらいもある。

使い方

  1. https://github.com/r7kamura/mastodon-terraform を fork する
  2. CircleCI と連携する
  3. 適当な環境変数を与えてビルドする
  4. マストドン動く ✌(‘ω'✌ )三✌('ω’)✌三(✌'ω')✌

別に必ず fork しないといけない訳ではなくて、copy して使ったり terraform module として参照したりしても良い。

構築される環境

┌---------------┐
|  Web Browser  |
└---------------┘
▲               ▲
|               |
(HTTPS)         (WebSocket)
|               |
▼               |
┌------------┐  |
| CloudFront |  |
└------------┘  |
▲               |
|               |
(HTTP)          |
|               |
▼               ▼
┌---------------┐
|      ALB      |
└---------------┘
▲               ▲
|               |
(HTTP)          (WebSocket)
|               |
▼               ▼
┌------------------------┐
| ┌-Docker-┐ ┌-Docker--┐ |
| |  Puma  | | Express | |
| └--------┘ └---------┘ |
| ┌-Docker--┐            |
| | Sidekiq |     EC2    |
| └---------┘            |
└------------------------┘
▲                  ▲
|                  |
▼                  ▼
┌----------------┐ ┌-------------┐
| ┌------------┐ | |  ┌-------┐  |
| | PostgreSQL | | |  | Redis |  |
| └------------┘ | |  └-------┘  |
|       RDS      | | Elasticache |
└----------------┘ └-------------┘

静的ファイルのキャッシュ用に前段に CloudFront が居て、後ろに ALB (ロードバランサー) が居て、EC2 で Docker が動いてて、Docker で Puma (Web サーバ)、Express (WebSocket サーバ)、Sidekiq (Job Worker) が動いていて、更に RDS で PostgreSQL、Elasticache で Redis が動いている、という構成。

構成についての補足

一般的にはここに Nginx が加わるだろうけれど、Puma で直接 HTTP リクエストを受け付けることにした。

また静的ファイル配信用の S3 バケットも外して、Puma から直接配信するようにした。Docker を利用してイメージを差し替えるデプロイ方法においては、デプロイ時に assets をコンパイルして S3 に配置する作業が邪魔になることが多い。直接 Puma から静的ファイルを配信することになるけど、CloudFront でキャッシュしているのであまり問題無いと思う。あと Docker イメージ交換時に新旧 Docker コンテナに交互にリクエストを送ってしまうような事態を引き起こさないように、ALB の Sticky セッションを有効化している。

https://amakan.net/ と大体同じ構成ですね。

Docker イメージの用意

Docker イメージの内容は自前で用意してしまっても良かったけれど、本家の提供しているよくメンテされた Dockerfile に従っておくほうが良いだろうと考えて、公式の Dockerfile からビルドすることにした。この Dockerfile では Ruby と Node.js をまとめて同じイメージに入れている。最初は別々に分けようかと思ったけれど、assets の生成のために JavaScript のランタイムが必要なこと、そのために Node.js を利用していること、Node.js が WebSocket 用途でも利用されていることから、まあまとめて一つでも楽だから良いかという結論に落ち着いた。

Puma から静的ファイルを配信する必要があるので、Docker イメージの中に precompile された assets を含めてしまっている。これは、まず Mastodon の Docker イメージをビルドしたあと、ビルドしたイメージを利用して public/assets ディレクトリをマウントしながら assets:precompile を実行し、更に precompile された assets が配置された状態で再度 Docker イメージをビルドしている。

この辺の処理は https://github.com/r7kamura/mastodon-docker で実現していて、CircleCI を利用して自動的にそういう Docker イメージがビルドされるようにしてある。本家の Mastodon のコードが頻繁に更新されるので、新しいコードを取り込みたくなったら、 まず Docker イメージをビルドして、それからビルドされたイメージのタグを mastodon-terraform で指定する、という運用になる。インフラのコードとアプリケーションのコードでは変更サイクルが異なるので、リポジトリも分けておいた方が良いと思ってこういう形になった。

改善中のところ

指定できる変数が少なかったり、ところどころ壊れていたりする。コード書ける人がいたら Pull Request ほしい。練習用の雑な構成という訳ではなくて、ちゃんと育てて本番環境用途でも利用できる構成を想定してつくっているので、同じく MastodonAWS で運用する人達同士で相乗りしていけると良いなあと思う。