Lightsailの最安インスタンスにPlausibleを導入した際に起きた問題と解決策

最近ブログをリニューアルしたついでにアクセス解析も始めることにした。宗教上の理由でGoodle Analytics には頼らずなるべくセルフホスティングで動かしたい、ということで、OSSのPlausibleを試すことにした。

デフォルトの設定で起動するだけなら簡単だったが、自分の構成ではいくつかトラブルがあったので、それについて。

## 要約

- 普通に動かすなら公式の `docker-compose.yml` で簡単に起動できる
- PostgresqlをDocker外のホスト上で動かしてアクセスするには…
  - `localhost` の代わりにホストのインターフェースのIPを指定する。
  - データベースは事前に作成、設定をしておく
  - `docker-compose.yml` 上のデータベースの作成のコマンドは削除しておく
- メールが送信できない環境では（アカウントの認証ができないため）Postgresql上で直接認証済みに書き換える
- LightsailのCPUは1コアのうち常用できるのはさらにその一部。持続可能ゾーン（Sustainable zone）に収める必要がある。CPUバーストキャパシティーが尽きるまでは問題なく動くので注意。



## 要件

- Access解析ツールとしてPlausibleをVPSで動かす
- VPSは[AWS Lightsail][lightsail]で最も安価な3.5USDのUbuntuインスタンス
  - 結局パワー不足だったので5USDのプランに上げた
- Postgresqlはすでにホスト上で稼働しているのでこれを利用する  
  公式の`docker-compose.yml`にpostgresqlも含まれているが、これは利用しない。

## バージョン情報

```bash
$ uname -a
Linux <略> 5.11.0-1022-aws #23~20.04.1-Ubuntu SMP Mon Nov 15 14:03:19 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
$ psql --version
psql (PostgreSQL) 12.9 (Ubuntu 12.9-0ubuntu0.20.04.1)
$ docker -v
Docker version 20.10.11, build dea9396
$ docker-compose -v
docker-compose version 1.25.0, build unknown
```

plausible/hostingのコミットidは以下[^id]

```bash
$ git log -n 1 --oneline origin/master
f768205 (origin/master, origin/HEAD) Merge pull request #40 from oscartbeaumont/master
```


## Plausible について

OSSのGoogle analyticsの代替の一つ。いくつか選択肢があった[^other_tools]が、今回は
分散処理が得意[^elixir]らしいelixir製のplausibleを導入することにした。
なお、分散処理で**アクセス負荷に強い**からといって、貧弱なサーバで動かせるくらいに**アイドル状態での負荷が少ないわけではない**ことは後から知った。[^spec]

## 起動

[Getting started | Plausible docs](https://plausible.io/docs/self-hosting)
起動自体は公式のドキュメント通り、[公式のdocker-compose][github-hosting]で簡単に動かせる。

## データベースの設定

公式の `docker-compose.yml` ではDocker内で専用のpostgresqlを動かしている。しかし今回の公開用のサーバはすでにpleroma用のpostgresqlが動いているため、これを利用したい。



### データベースの初期化

Dockerコンポーズでは起動時にデータベースの作成等も行っている。今回は共用のpostgresqlを使うため、当然だが、管理者権限でのアクセスはさせない。
ということで、先にユーザーとデータベースは作っておく。

### ユーザの作成

```
$ sudo -u postgres createuser -P plausible #パスワードありでユーザーを作成
$ sudo -u postgres createdb -O plausible plausible
```

データベースの設定に関して、管理者権限が必要な設定もあるので、これもやっておく。

```
$ sudo -u postgres psql plausible
postgres-# CREATE EXTENSION citext;
```

### Postgresqlのアクセス制限の設定

デフォルトではpostgresqlはローカルホストからのアクセスしか受け取っていないので、他のホストからのアクセスを可能にする。
ipの制限についてはFWや次に設定する`pg_gba.conf`などでもできるので、ここでは管理をシンプルにすることを優先し全体に公開する

```diff:/etc/postgresql/12/main/postgresql.conf
- listen_addresses = 'localhost'
+ listen_addresses = '*'
```

`pg_hba.conf` でplausibleユーザにプライベートネットワーク（Docker含む）からのアクセスを許可する。

```diff:/etc/postgresql/12/main/pg_hba.conf
  # TYPE  DATABASE        USER            ADDRESS                 METHOD
  <中略>
  # IPv4 local connections:
  host    all             all             127.0.0.1/32            md5
+ host    plausible       plausible       172.16.0.0/12           md5
```

### 外部データベースの指定

plausibleでの外部データベースの指定を以下のように設定

- ユーザ名: plausible
- ホスト名: postgres
- 宛先ポート: 5432
- データベース名: plausible

```diff_ini:hosting/plausible-conf.env
  #中略
  #DATABASE_URL=postgres://localhost:5432/plausible_dev （デフォルト）
+ DATABASE_URL=postgres://plausible:<password>@postgres:5432/plausible
```

この段階では`postgres`という名前のホスト名はIPと紐づいておらず、動かない。
紐付けはdocker-compose.ymlの方で設定する。

### `docker-compose.yml`の修正

起動時にデータベースの作成をしないようにする。

postgresql の削除 

```diff_yaml:docker-compose.yml
-  plausible_db:
-    image: postgres:12
-    restart: always
-    volumes:
-      - db-data:/var/lib/postgresql/data
-    environment:
-      - POSTGRES_PASSWORD=postgres

   plausible:
     #中略
     depends_on:
-      - plausible_db
       - plausible_events_db
       - mail
```

データベースの作成の省略

```diff_yaml:docker-compose.yml
   plausible:
     image: plausible/analytics:latest
     restart: always
-    command: sh -c "sleep 10 && /entrypoint.sh db createdb && /entrypoint.sh db migrate && /entrypoint.sh db init-admin && /entrypoint.sh run"
+    command: sh -c "sleep 10 && /entrypoint.sh db migrate && /entrypoint.sh db init-admin && /entrypoint.sh run"
     #中略

```

ホスト名 `postgres` とIPの紐付け

```diff_yaml:docker-compose.yml
   plausible:
     #中略
     env_file:
       - plausible-conf.env
+    extra_hosts:
+      - "postgres:<サーバのIPアドレス>"
```
IPアドレスについては、`ip -a`で出した一覧のうち、`eth0`のプライベートIPを使用した。

### あらためて起動

```
$ sudo docker-compose up -d
```

これで期待通りにホストのpostgresを使うようになった。

## メール認証のスキップ
最初の管理ユーザーは`plausible-conf.env`で指定したユーザ名、メールアドレス、パスワードを元に起動時に作られる。しかしこの管理ユーザでも初回ログインの前にメール認証が必要となっている。

今回の環境ではメールが受け取れず[^mail-from-lightsail]、ログインまで進めない。

[ここ](https://github.com/plausible/analytics/discussions/700#discussioncomment-372215)によると、メール認証の無効化は設定できないが、データベース上で無理やり認証済みに書き換えるという荒技で解決できるとのこと。

早速試す。

```
sudo -u postgres psql plausible
postgres-# UPDATE users set email_verified=true;
```

これでログインできた。

## CPU負荷の異常への対応

### 問題の発生
起動後ある程度たつとsshでのアクセスが非常に遅くなるという問題が発生。
plausibleのリソースの問題かと思い、docker statsで確認してみる。

```
$ sudo docker stats
CONTAINER ID   NAME                            CPU %     MEM USAGE / LIMIT     MEM %     NET I/O           BLOCK I/O         PIDS
7ebcd86ab89f   hosting_plausible_1             260.15%   17.65MiB / 465.7MiB   3.79%     3.21GB / 3.81GB   1.84GB / 3.87MB   24
31cf05c8ffb3   hosting_plausible_events_db_1   200.14%   13.85MiB / 465.7MiB   2.97%     1.15GB / 2.03GB   4.52GB / 106kB    46
93581f2dd30e   hosting_mail_1                  0.00%     932KiB / 465.7MiB     0.20%     33.3kB / 89.2kB   1.59GB / 655kB    1
```

CPUの使用率がやばい。

LightsailでCPUを増やすにはかなりプランを上げる必要があるが、予算的に現実的ではない。諦めて別の手段を検討しようとした時、ふとLightsailにはバーストという、一時的に計算リソースを増やす機能があったことを思い出す。
これは起動直後は問題なかったという状況的にも関係していそう、ということで調べてみた。

### 持続可能ゾーンの確認

AWSのCPUはバーストという、上限付きで計算資源を増やせるという機能がある。てっきりオーバークロック的な上限突破的なイメージがあって勘違いしていたのだが、実態としては通常状態が著しく速度制限されるというのが近い模様。

今回の$3.5のインスタンスだと5%が持続可能ゾーンの上限であり、CPUバーストキャパシティーの貯金がある間は問題なく動くが、これが切れた段階で5%に制限される模様。

AWSコンソールで確認したところ、バースト中の消費は5%以上10%以下といったところ。

CPU数と違い、持続可能ゾーンの上限はメモリ同様、プランごとに緩和され、今回であれば月$5のひとつ上のインスタンスで10%になり、足りるはず。これなら予算的に許容範囲ということで、早速アップグレードする。

## 結果

$5に上げた後の様子が以下。

![CPU使用率グラフ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400984/eccfe1c8-3297-1426-b304-2c8d3686bb0e.png)

ちゃんと10%のラインに収まっている。

実際のPlausibleのダッシュボードはこんな感じ

![Screenshot 2021-12-19 at 11-40-16 Plausible · fireturtle net.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/400984/1631eaea-565c-d0dd-874e-dd2800e64901.png)

こんな雑なブログに一日10人弱の来客があることが分かり、うれしいやら恥ずかしいやら複雑な気持ち。

## その他参考ページ

- [Dockerコンテナのアプリからhost側にあるPostgresqlに接続したい](https://gist.github.com/toenobu/5026188d73b69046248c8792962a7b22)


[^id]: バージョンは振られていないので代わりにコミットIDを記載
[^other_tools]: 最も有名なのは多機能な[Matomo][matomo]、ついで軽量、シンプルが売りの[umami][umami],[plausible][plausible]が続くといった感じか
[^elixir]: 自分が触れた範囲だと、pleromaというMastodon互換のサーバがあり、これは実際にMastodonよりもかなり貧弱な環境でも問題なく動いている、といってもほったらかしているので負荷がかかったらどうなるかはわからないが。
[^spec]: 貧弱なサーバで零細ブログのアクセスを取る用途では[umamiのほうが軽いらしい][umami-comment]。
[^mail-from-lightsail]: たしかAWSはデフォルトで外部へのメール送信をブロックしているとか聞いた覚えがある（要出典）
[github-hosting]: https://github.com/plausible/hosting
[umami-comment]: https://github.com/plausible/analytics/issues/301#issuecomment-741772513
[lightsail]: https://aws.amazon.com/jp/lightsail/
[matomo]: https://matomo.org/
[umami]: https://umami.is/
[plausible]: https://plausible.io/