まえがき
こんにちは、インフラグループの yjszk です。
今回は、Cronitorというツールについてご紹介します。Cronitorはジョブの状態を簡単に管理することができるモニタリングサービスです。
このサービスは、Cronジョブの監視を行うことができ、提供されているSDKは複数のプログラミング言語で利用可能で、設定をYAMLでエクスポートし、コード管理することができるのも魅力の1つです。
今回は、Python SDKを使用してCronitorを設定する方法について説明します。
Cronitorとは
Cronitorは、ジョブの状態を管理するためのモニタリングサービスであり、ジョブの開始時や終了時にCronitorのエンドポイントを叩くことで、ジョブの成功可否や実行時間、標準出力や標準エラー出力などを監視することができます。
CronitorCLIやcURLを使う方法でCronitorを利用することができます。
Cronitorは、既存のジョブに変更を加えることなく監視設定を追加できるため、ジョブに改修を加えたくない場合にも適しています。
例えば、1分おきに動くジョブがある場合、Cronitorの設定例は以下のようになります。
- Cronitor cliを使う場合
*/1 * * * * cronitor exec {JOB_KEY} /home/ec2-user/test.sh >> /home/ec2-user/test.log 2>&1
- cURLを使う場合
MONITOR_URL='https://cronitor.link/p/{API_KEY}/{JOB_ID}' */1 * * * * curl $MONITOR_URL?state=run; /home/ec2-user/test.sh >> /home/ec2-user/test.log && curl $MONITOR_URL?state=complete || curl $MONITOR_URL?state=fail 2>&1
このように監視設定を既存のジョブに変更なく加えることが可能です。
通知はSlackやメールなど多数のサービスに対応しています。
Python SDKによる設定のコード管理
ある程度大きいサービスになると、バッチ処理は大量に存在し、ジョブ一つ一つにGUIで設定するのは骨が折れ、設定をコード管理をしたい思いが溢れてしまいます。
APIのドキュメントを見ると全ての機能がAPI経由で利用可能とあります。エクセレント。
まずは雰囲気を掴むためにGUIでMonitorを作ってみます。
GUIでのジョブ作成
- 監視設定
- LinuxのCronジョブ
- 15分おきに実行
- タイムゾーンは日本時間
- 通知先はあらかじめ設定したSlack(Settings→Alertsで任意の通知方法を設定)
設定ができたら、表示される画面にCronitorへテレメトリーを送る方法が書かれているので、それに従い、crontabにCronitor通知を埋め込みます。
すると、以下のような画面になり、モニタリングが開始されます。
SDKによる設定
今回はPythonのSDKを使用します。
pip install cronitor
Pythonがインストールされてる環境において、やることはこれだけです。グレート。
既存設定のエクスポート
以下のコードでエクスポートが可能です。コードと同階層にcronitor.yaml
で出力されます。
import cronitor # APIKEYは https://cronitor.io/app/settings/api cronitor.api_key = 'APIKEYを入れる' cronitor.generate_config()
先ほどのジョブはこのようにYAMLで出力されます。
jobs: XXXXXX: # jod keyはユニークなので隠しています environments: - production grace_seconds: 60 group: dev name: testing-job notify: - slack platform: linux cron realert_interval: every 8 hours schedule: '*/15 * * * *' timezone: Japan
これでコード管理できる状態になりました。これをAPI経由で変更してみましょう。
コード化した設定の適用
Monitor名を変更します。
jobs: XXXXXX: # jod keyはユニークなので隠しています environments: - production grace_seconds: 60 group: dev name: testing-job-rename # -renameを追加 notify: - slack platform: linux cron realert_interval: every 8 hours schedule: '*/15 * * * *' timezone: Japan
以下のコードを実行します。
import cronitor cronitor.api_key = 'APIKEYを入れる' cronitor.read_config('./cronitor.yaml') cronitor.apply_config()
変更されました。素晴らしい。
Dry-Run
Dry-Runで適用前に設定を確認することもできます。試しに誤った設定を書いてDry-Runしてみます。
jobs: XXXXXX: # jod keyはユニークなので隠しています environments: - production grace_seconds: 60 group: dev name: testing-job-rename notify: - slack - discord # 存在しない通知先を追加した platform: linux cron realert_interval: every 8 hours schedule: '*/15 * * * *' timezone: Japan
以下コードでDry-Runできます。
import cronitor cronitor.api_key = 'APIKEYを入れる' cronitor.read_config('./cronitor.yaml') cronitor.validate_config()
実行結果です。意図した通り「存在しない通知先」とエラーが出ています。
$ python3 cronitor_config_validate.py XXXXXX: notify: - Invalid notification list template "discord".
Dry-Runと設定適用ができたら何ができるでしょうか。CI/CDができます。
PRやマージに応じてバリデーションや設定が自動で適用されるよう、CI/CDの仕組みを組んでみましょう。
GitHub Actionsによるパイプライン化の例
APIKEYはGitHub Secretsに格納することします。YAMLは一つしか存在しないこととし、デプロイのコードに関しては必要最低限のみの実装とします。
- 実行コード
import cronitor import os import sys cronitor.api_key = os.getenv('CRONITOR_SECRET') cronitor.read_config('./cronitor.yaml') if cronitor.validate_config(): cronitor.apply_config() else: # Validateがうまくいかなかった場合に異常終了させる sys.exit(1)
- GitHub ActionsのYAML
name: cronitor config apply on: pull_request: branches: - main types: [closed] jobs: check: name: cronitor config apply runs-on: ubuntu-latest if: github.event.pull_request.merged == true permissions: id-token: write contents: read defaults: run: shell: bash working-directory: ./ steps: - name: Checkout uses: actions/checkout@v3 - name: Set up Python 3.8 uses: actions/setup-python@v4 with: python-version: 3.8 cache: 'pip' - name: pip install run: pip install cronitor - name: validate_and_apply id : validate_and_apply env: CRONITOR_SECRET: ${{ secrets.CRONITOR_SECRET }} run: | python cronitor_config_apply.py
先ほどの誤った設定をGitHub Actions上で適用しようとすると想定通り失敗しました。
ハマりどころ
Monitorの作成はGUIからかAPIからの2種類あり、Cronitor cliを使用する場合は、以下のようになります。
- GUIからの場合は、Cronitor側で自動的にIDが採番されるので、cronitor execするときにCronitor cliのAPIKEY設定が不要です。
- API経由の場合は自動採番されない(自分で決める必要がある)ので、cronitor execするときにCronitor cliのAPIKEY設定が必要です。
この仕様はAnonymous Eventsという形でドキュメントに記載されています。
API経由でMonitorを作成した場合は、Cronitor cliのAPIKEY設定をしていないとモニタリングが始まらないので要注意です。
終わりに
実際にこれらを用いて運用をする場合、例えば監視したい環境ごとにEnvironmentやGroupで分けると思いますが、その場合YAMLファイルは複数になるので、そのあたりをコード化する必要があると思います。
個人的にはPull Requestを作った時にCIで設定のdiffを出したいですね。今後の課題としたいです。
参考
Cronitor料金 cronitor.io
cronの書式確認に便利 crontab.guru