tl;dr
この記事では、dockerとconsulを使ってスケーラビリティを高めた環境を構築する手順を説明します。
ざっくりで色々と端折っているところがあります。
docker-compose scale web=5 のように、簡単にサーバーを増やせたりする運用が可能になります。
ネットワークの作成
consul用とmastodon用で異なるdocker-compose.ymlを使うので、同じネットワークが必要になるため予め作っておきます。
docker network create consul-network
consulを使う
consulは docker-nginx-lb を使います。こちらmastodonとは関係ないディレクトリにgit cloneしてきます。
docker-compose.ymlの編集
このリポジトリには、docker-compose.ymlが含まれているので、 少し編集します。
networks:
  default:
    external:
      name: consul-network
を追加し、先ほど作成したネットワークに接続します。
nginx.confの編集
リポジトリに含まれているnginx.confを編集します。
テンプレートになっており、rangeと書いてある部分に自動的にserverが追加されていきます。
mastodon.web や mastodon.streaming は Tag:Name の関係になっています。
streamingはWebsocketとして読めるように修正します。
- upstream web {
+ upstream app {
  least_conn;
- {{range service "production.app"}}server {{.Address}}:{{.Port}} max_fails=3 
+ {{range service "mastodon.web"}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;
  {{else}}server 127.0.0.1:65535; # force a 502{{end}}
}
server {
-  listen 80 default_server;
+  listen 3000 default_server;
+  client_max_body_size 10m;
  location / {
-   proxy_pass http://app;
+   proxy_pass http://web;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}
+ upstream streaming {
+   least_conn;max_fails=3 
+   {{range service "mastodon.streaming"}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;
+   {{else}}server 127.0.0.1:65535; # force a 502{{end}}
+ }
+ 
+ server {
+   listen 4000 default_server;
+   client_max_body_size 10m;
+ 
+   location / {
+     proxy_pass http://streaming;
+     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+     proxy_set_header Host $host;
+     proxy_set_header X-Real-IP $remote_addr;
+     proxy_http_version 1.1;
+     proxy_set_header Upgrade $http_upgrade;
+     proxy_set_header Connection "upgrade";
+   }
+ }
mastodon側の修正
docker-compose.ymlの編集
同じように、ネットワークに接続させます。
もしもすでにサービスを稼働している場合、ネットワークが変更されるのでIPアドレスに注意してください。
networks:
  default:
    external:
      name: consul-network
を追加し、先ほど作成したネットワークに接続します。
一度実行してみる
ここまできたら、mastodon と docker-nginx-lb それぞれで docker-compose up --build します。 ホスト側で http://(ホストIP):8500 にアクセスし、Consul UI にアクセスします。
このように表示されたら、Consulが正しく動いています。
環境変数の設定
docker-nginx-lb の docker-compose.ymlでは、 registrator も一緒に動くようになっているので、環境変数に
    environment:
      SERVICE_NAME: web
      SERVICE_3000_NAME: web
      SERVICE_TAGS: mastodon
と定義されているコンテナを見つけると、サービスとして登録してくれます。 一つだけポートが開いているサーバーの場合は、 name という形式のサービス名で登録され、 複数のポートが空いている場合 は name-3000(Name-Port) という形式で登録されるので注意が必要です。(また、名前に アンダーバー_ は使用できません)
webの修正
    environment:
      SERVICE_NAME: web
      SERVICE_3000_NAME: web
      SERVICE_TAGS: mastodon
streamingの修正
    environment:
      SERVICE_NAME: streaming
      SERVICE_4000_NAME: streaming
      SERVICE_TAGS: mastodon
修正し起動させると、 registrator が serviceを見つけてconsulに登録してくれます。
consulはserviceが変更された通知を受け取ると、nginxのconfを自動的に上書きし、nginxを自動的にリロードします。
デプロイ(参考程度)
docker-compose build
docker-compose scale web=10                                                                                                                                                                                                                   
docker-compose ps | grep "mastodonto_web_[1-5] " | awk '{print $1}' | xargs docker stop
docker-compose up --build --force-recreate -d web
docker-compose scale web=5
おまけ
実際にこの構築手順で作ったインスタンスこちらです。
おもったよりお魚が集まらなかったので終了しました。
