はじめに
私が運営しているSaaSサービスは、定期的なメンテナンスが必要になる。
例えば、機能Aは毎月1日にメンテナンス、機能Bは毎月第1月曜日にメンテナンスなどなど。
サービスのメンテナンス予定は、Statuspage で公開しているのだが、定期的なメンテナンス情報を毎回手入力するのが辛いので自動化してみた。
構成
- メンテナンスの予定は yaml の設定ファイルに保存してある。
- Go で書いたスクリプトが設定ファイルを読み込んで、数日先までのメンテナンス情報として組み立て、Statuspage へ Scheduled Maintenance として登録している。
- Go のスクリプトは GitHub Actions で毎日起動している。
- 監視は Datadog で行っている。
設定ファイル
メンテナンス予定の設定ファイルは、次のような内容になる。
- service: ServiceA
recurring:
- day: 1st saturday
start: 1h00m
time: 6h
上の例では、ServiceA というサービスが、第一土曜日 1:00 から 6時間ほどメンテナンスされる。
ソースコード
https://github.com/nshmura/statuspage-recurring-maintenance
工夫したところ
宣言的設定
メンテナンス予定の設定ファイル(yaml) と、現在の Statuspage の登録情報を比較して、差分をなくすように登録、削除、変更するようになっている。
冪等性
メンテナンス登録処理は、冪等性を持った作りになっている。例えば、すでに登録済みの日の対して、何度処理を実行しても同じ登録状態になる。
このため Statuspage との通信エラーなどで一部の登録が失敗しても、リトライするだけで回復する。
自動回復性
毎日の登録処理では、その日から一週間先までのメンテナンスを登録するようになっている。
宣言的設定になっていて冪等性があるため、ある日、通信エラーなどの一時的な理由で登録に失敗しても、次の日の登録処理で自動的に回復する。
メンテナンス期間が重なったときの制御
次のようなメンテナンス期間の設定があったとする。
- 毎日 00:00 から 10分間
- 日曜日 00:05 から 24時間
それぞれのメンテナンスを個別に Statuspage へ登録すると、日曜日の 00:10 にメンテナンスが開けてしまう。(Statuspage の Component の状態が Under maintenance
から Operational
になってしまう)
これはまずいので、期間がかぶっている場合は、1つのメンテナンスとして Statuspage へ登録するようになっている。
監視
毎日の登録処理が成功したら GitHub Actions から Datadog へイベントを登録している。
Datadog 側では、完了イベントが2日以上届かなければ Slack へアラートするようにしている。
まとめ
- 自動化によって運用負荷が下がった。
- 宣言的設定と冪等性をもたせた設計によって、自動回復するような処理になった。
- 自動回復するので、一時的なエラーで処理がコケても、人に面倒をかけることがなくなった 👍