Consulを使ってMastodon!

## tl;dr
この記事では、dockerとconsulを使ってスケーラビリティを高めた環境を構築する手順を説明します。
ざっくりで色々と端折っているところがあります。

`docker-compose scale web=5` のように、簡単にサーバーを増やせたりする運用が可能になります。


## ネットワークの作成
consul用とmastodon用で異なるdocker-compose.ymlを使うので、同じネットワークが必要になるため予め作っておきます。

```
docker network create consul-network
```

## consulを使う
consulは [docker-nginx-lb](https://github.com/princemaple/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として読めるように修正します。


```diff
- 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 にアクセスします。

![image](https://qiita-image-store.s3.amazonaws.com/0/23900/b3684d76-e3f0-84ed-c4cb-98b3eced5f3e.png)

このように表示されたら、Consulが正しく動いています。

### 環境変数の設定
`docker-nginx-lb` の `docker-compose.yml`では、 `registrator` も一緒に動くようになっているので、環境変数に


```yaml:docker-compose.yml
    environment:
      SERVICE_NAME: web
      SERVICE_3000_NAME: web
      SERVICE_TAGS: mastodon
```
と定義されているコンテナを見つけると、サービスとして登録してくれます。 **一つだけポートが開いているサーバーの場合は、** `name` という形式のサービス名で登録され、 **複数のポートが空いている場合** は `name-3000(Name-Port)` という形式で登録されるので注意が必要です。（また、名前に アンダーバー_ は使用できません)

#### webの修正
```yaml:docker-compose.yml
    environment:
      SERVICE_NAME: web
      SERVICE_3000_NAME: web
      SERVICE_TAGS: mastodon
```
#### streamingの修正

```yaml:docker-compose.yml
    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
```

## おまけ
実際にこの構築手順で作ったインスタンスこちらです。

~~https://osakana.cloud~~

おもったよりお魚が集まらなかったので終了しました。