背景:組織の制約でチャットツールのトークンが使えない
開発の現場では、監視ツールやCIの通知をチャットアプリに飛ばして運用している方が多いと思います。ただ、組織の制約でチャットアプリのトークンが自由に使えない、というケースもあるはずです。
自分の組織も例外ではありませんでした。
- GitLabで何かが発生したときに、トークン経由でチャットに通知を投げたい
- 何かしらアラートが上がったときも同様に通知したい
こういったシーンでトークンを使いたかったのですが、組織で運用している以上、トークンの発行には申請が必要で、取り回しがどうしても面倒でした。
そこで今回は、チャットツールとは別に、通知専用の環境を自前で構成してみたという話です。
前提として、自由に使えるサーバーがあることが条件になります。
構成
セルフホストのサーバー上に、ntfy という通知用ミドルウェアを立てます。
[GitLab] ─┐
├─→ [ntfy サーバー(セルフホスト)] ─→ [ブラウザ(購読側)]
[Grafana] ─┘
- GitLabや、メトリクスからアラートを発行するGrafanaといった送信側が、ntfyサーバーに対して通知を投げる
- クライアント側(ブラウザ)では、ntfyの「トピック」を購読しておく
- ntfy自体がWeb UIを持ったWebアプリなので、そのUI上から購読設定ができる
- 購読しているトピックに通知が飛んでくると、ブラウザに通知が届く
かなりニッチな構成だと思います。普通の人はチャットツールを使えばいい話なので。ただ、制約がある環境ではこういう選択肢もある、ということで。
ntfyのトピックと認証について
ntfyには認証機能がひととおり揃っています。ユーザー名・パスワードでの認証や、どの通知をどのユーザーに見せるかといったアクセス制御も可能です。
ただ今回はそこまで作り込まず、シンプルな運用にしました。
- セルフホストサーバーにアクセスできるユーザーは、全員ntfyサーバーにアクセスできる
- ntfyにアクセスできるユーザーは、トピック名さえ分かれば誰でも自由に購読できる
ntfyでは通知の宛先の単位を「トピック」と呼びます。トピックを購読しておくと、そのトピックに対して発行された通知が届く、という仕組みです。GitLab側からは、ntfyサーバーの特定トピックに向けて自由に通知を投げるだけです。
ハマったところ:HTTPS対応とローカルCA
ntfyはブラウザの通知の仕組みを使うため、ブラウザを閉じていると通知が来ないという問題があります。
ここはブラウザのバックグラウンド通知に対応しているので、その仕組みを使えばタブを閉じていても、Chromeなどのブラウザ自体がバックグラウンドで動いていれば通知が届く状態にできます。
ただし、バックグラウンド通知にはHTTPS(SSL通信)が必須です。セルフホストサーバーなので、証明書を自前で用意する必要が出てきました。今回の環境構築で一番手間だったのがここです。
mkcertでローカルCAを作る
これは mkcert を使って、独自のローカルCAを作成することで解決しました。
単純な自己署名証明書でもいいのですが、その場合は利用者の端末それぞれに証明書を入れてもらう必要があります。今後こういった内部向けアプリが増えることを考えると、都度証明書を配って回るのは現実的ではありません。
そこで、
- ローカルCAの証明書を一度だけ発行して配布する
- 以降のアプリは、そのCAで署名した証明書を使う
という構成にしました。これなら配布は最初の一回で済みます。
構築自体は簡単
ntfy自体は公式のDockerイメージが提供されているので、Dockerが使える環境さえあれば、セルフホストサーバー上で動かすこと自体はそれほど手間なくできます。
注意点
1. HTTPSポートに加えてHTTPポートも開けておく
証明書の話の続きですが、通知を送る側であるGitLabサーバーやアラートを飛ばすサーバーからも、ntfyに通知を投げる必要があります。
送信側のサーバーにローカルCAの証明書を入れて回るのは結構難しいので、HTTPSポートだけでなくHTTPポートも用意しておくのが現実的だと思います。
- HTTPS:ブラウザ(購読側)からのアクセス用。バックグラウンド通知のため必須
- HTTP:GitLabやGrafana(送信側)からのアクセス用
結果として、2つのポートを受ける構成になります。
2. ntfyはサブパス配信に対応していない
これがntfyを使う上でのちょっとした注意点です。
自分の環境では普段、Traefikでリバースプロキシを組み、ポート1つでいろいろなアプリをセルフホストサーバーから配信しています。しかしntfyはサブパス配信に対応していないため、この構成とうまく噛み合いませんでした。
そのため、ntfyについてはリバースプロキシを経由せず、サーバーのファイアウォールにHTTPS・HTTPの2つポートを直接開けてやる必要がありました。
できあがった環境
最終的に、こんな運用ができるようになりました。
- GitLab:パイプラインが成功/失敗すると、PC上に通知が届く。通知をクリックするとマージリクエストに直接飛べる
- Grafana:Webアプリのメトリクスを取っていて、アラートが出た場合もntfyに通知が飛ぶ。クリックするとアラートの詳細に飛べる
使ってみた感想
既存のチャットツールにトークンで連携するよりも、通知の種類ごとにクリックしたときの遷移先を細かく設定できるのが良かったです。既存ツールに組み込むより、最終的な使い勝手は上回りました。
あとは、ツールが分かれていることで通知専用のものとチャット専用のもので住み分けができたのも、意外と悪くなかったと思っています。
以上、セルフホストサーバーにntfyを立てて通知基盤を作った話でした。
