ようへいの日々精進XP

よかろうもん

Healthchecks.io チュートリアル

tl;dr

最近, Healthchecks.io という Web サービスを教えていただきました. SaaSだけではなく, 仕組み自体は OSS で提供されていて Docker でサクッと試すことが出来ます.

healthchecks.io

github.com

Healthchecks.io とは

シンプル

Django で書かれた Cron ジョブをモニタリングするツールです. どのようにモニタリングするかと言うと, サイトにも掲載されているように Cron ジョブが終了したら, Healthchecks.io から払い出される HTTP エンドポイントに対してリクエストを投げることで Cron ジョブが正常に終了することをモニタリングします.

以下は, サイトのトップページに掲載されている Cron 定義です.

# m h dom mon dow command
  8 6 *   *   *   /home/user/backup.sh && curl -fsS --retry 3 https://hc-ping.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx > /dev/null

backup.sh が正常に終了しなかった場合, curl -fsS --retry 3 https://hc-ping.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx > /dev/null が実行されないことになります.

ドキュメントの中でこの URL は Ping URL と呼ばれています.

Healthchecks.io は Ping URL にリクエストを送信する度に, そのリクエストを記録し, 監視対象 (この例で言うと backup.sh) の Ping の値を更新します. 最後に受信した Ping から設定した時間 (期間) が経過すると, その監視対象は遅延しているとみなされ, Healthchecks.io は「猶予期間」を待ってから Ping がない場合にはアラートを送信します. 以下, 期間と猶予期間を設定する Web ユーザーインターフェースです.

f:id:inokara:20181219001224p:plain

上記の設定例だと, Ping は 30 分毎に送信され, 猶予期間は 30 分となり, 30 分 + 30 分 = 60 分間 Ping の送信が無い場合にはアラート送信されます. この設定は監視対象毎に設定が可能となりますので, 1 つの Cron ジョブ毎に設定が可能ということになります.

尚, 以下のように Ping URL に /fail を追加することで, 監視対象の障害発生を通知することが出来ます. 以下はドキュメントより引用した Python コードです.

import requests
URL = "https://hc-ping.com/your-uuid-here"

def do_work():
    # Do your number crunching, backup dumping, newsletter sending work here.
    # Return a truthy value on success.
    # Return a falsy value or throw an exception on failure.
    return True

success = False
try:
    success = do_work()
finally:
    # On success, requests https://hc-ping.com/your-uuid-here
    # On failure, requests https://hc-ping.com/your-uuid-here/fail
    requests.get(URL if success else URL + "/fail")

Healthchecks.io の主な機能はこれだけ (良い意味で!) となり, 実にシンプルで理解しやすいツールになっていると思います.

インテグレーション

以下のような外部サービスと連携が可能なようです.

  • Slack
  • Email
  • Webhook
  • PagerTree
  • HipChat
  • VictorOps
  • OpsGenie

おなじみの Slack をはじめ, いにしへのプロトコルになりつつある電子メールや Webhook 等, 通知系のサービスとの連携がデフォルトで行えるようになっています.

料金プラン

Healthchecks.io は無償枠以外に以下のような料金プランが用意されています.

healthchecks.io

無料枠でも 20 Checks で各 Check 毎に 100 ログエントリとあるので, 通常の利用範囲 (ちょっとした Web サービス) であれば無料枠でも十分なのでは思います.

その他

REST API も提供されていますので, 監視対象の追加や削除, 監視の一時停止等を API で操作することが出来ますし, 幾つかの言語で API をラップしたクライアントライブラリが有志の方々によってリリースされています.

healthchecks.io

尚, API を利用する為には, [Account Settings] → [Account] → [API Access] にて API キーを払い出す必要があります.

チュートリアル

Docker にて

以下の docker-compose.yml を利用して, ローカル環境に Healthchecks.io を起動します.

github.com

起動すると, Healthchecks.io 以外に MariaDBMailHog というテスト用のシンプルな SMTP サーバーが起動します. 尚, 今回の検証環境は以下の通りとなっています.

$ docker version
Client: Docker Engine - Community
 Version:           18.09.0
 API version:       1.39
 Go version:        go1.10.4
 Git commit:        4d60db4
 Built:             Wed Nov  7 00:47:43 2018
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.0
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.4
  Git commit:       4d60db4
  Built:            Wed Nov  7 00:55:00 2018
  OS/Arch:          linux/amd64
  Experimental:     true

$ docker-compose --version
docker-compose version 1.23.2, build 1110ad01

起動

docker-compose up -d を実行すると, 以下のようなコンテナが起動します.

$ docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS                              NAMES
822062af97fc        docker-healthchecks_hc   "/entrypoint.sh /sta…"   27 hours ago        Up 27 hours         0.0.0.0:9090->9090/tcp             docker-healthchecks_hc_1
d5684cbb2484        mariadb                  "docker-entrypoint.s…"   27 hours ago        Up 27 hours         3306/tcp                           docker-healthchecks_db_1
0a2910fbde7d        mailhog/mailhog          "MailHog"                27 hours ago        Up 27 hours         1025/tcp, 0.0.0.0:8025->8025/tcp   docker-healthchecks_mailhog_1

コンテナが起動したら, 以下を実行して管理者権限を持つユーザーを作成します.

$ docker-compose exec hc ./manage.py createsuperuser
Username: admin
Email address: admin@example.com
Password:
Password (again):
Superuser created successfully.

作成したユーザー (実際には Email address) を使って, Docker で起動している Healthchecks.io にブラウザで http://localhost:9090 にアクセスしてログインします.

f:id:inokara:20181219013119p:plain

チェック (監視対象) の追加

以下のように実行して API を利用して監視対象の追加を行います.

$ export API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
$ curl http://localhost:9090/api/v1/checks/ \
    --header "X-Api-Key: ${API_KEY}" \
    --data '{"name": "my-first-check", "tags": "my-test", "timeout": 3600, "grace": 60}'

各パラメータは以下のような内容になっています.

  • name : 監視対象の名前
  • tags : 監視対象をグループ化する際に便利なタグを付与することが出来ます
  • timeout : Period (期間)
  • grace : 猶予期間

以下のように出力されます.

{
  "ping_url": "http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
  "timeout": 3600,
  "tags": "my-test",
  "update_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
  "pause_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b/pause",
  "last_ping": null,
  "channels": "",
  "next_ping": null,
  "name": "my-first-check",
  "grace": 60,
  "n_pings": 0,
  "status": "new"
}

ping_url が払い出されていることが判ります.

監視

以下のように ping_url に対して curl でアクセスしてみます.

curl http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b -w "\n"

以下のように出力されます.

$ curl http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b -w "\n"
OK

監視対象の状態を確認してみます.

curl -s http://localhost:9090/api/v1/checks/?tag=my-test  --header "X-Api-Key: ${API_KEY}" | jq .

以下のように出力されます.

$ curl -s http://localhost:9090/api/v1/checks/?tag=my-test  --header "X-Api-Key: ${API_KEY}" | jq .
{
  "checks": [
    {
      "ping_url": "http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
      "timeout": 3600,
      "tags": "my-test",
      "update_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
      "pause_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b/pause",
      "last_ping": "2018-12-19T23:10:46+00:00",
      "channels": "",
      "next_ping": "2018-12-20T00:10:46+00:00",
      "name": "my-first-check",
      "grace": 60,
      "n_pings": 2,
      "status": "up"
    }
  ]
}

ブラウザでは以下のように出力されます. Log の部分に Ping URL へのアクセスが記録されていることが判ります.

f:id:inokara:20181220090524p:plain

監視の一時停止

メンテナンス等で, Cron バッチ等を一時的に停止する必要がある場合, 以下のように Ping URL のパスに pause を付与してリクエストを送信することで, 監視を一時停止することが出来ます.

curl -XPOST http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b/pause --header "X-Api-Key: ${API_KEY}"

以下のように出力されます.

{
  "timeout": 3600,
  "pause_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b/pause",
  "last_ping": "2018-12-19T23:48:49+00:00",
  "name": "my-first-check",
  "grace": 60,
  "ping_url": "http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
  "n_pings": 2,
  "status": "paused",
  "tags": "my-test",
  "channels": "",
  "next_ping": "2018-12-20T00:48:49+00:00",
  "update_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b"
}

監視の再開は, Ping URL にアクセスすることで再開されます.

期間や猶予期間の変更

監視対象を登録した際に設定した期間や猶予期間は以下のように変更します. 期間を 3600 秒から 60 秒に変更してみます.

curl http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b \
    --header "X-Api-Key: ${API_KEY}" \
    --data '{"name": "my-first-check", "tags": "my-test", "timeout": 60, "grace": 60}'

以下のように出力されます.

{
  "timeout": 60,
  "pause_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b/pause",
  "last_ping": "2018-12-19T23:50:16+00:00",
  "name": "my-first-check",
  "grace": 60,
  "ping_url": "http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
  "n_pings": 3,
  "status": "down",
  "tags": "my-test",
  "channels": "",
  "next_ping": "2018-12-19T23:51:16+00:00",
  "update_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b"
}

監視対象との疎通が取れなくなった場合

Cron ジョブ等が正常に実行されなかった場合等, 設定した期間と猶予期間の時間を超えるとステータスが Down に変わります. 期間だけを超える場合には Late というステータスになります. 以下は, API を利用して監視対象の状態を取得している実行例です.

$ curl -s http://localhost:9090/api/v1/checks/?tag=my-test --header "X-Api-Key: ${API_KEY}" | jq .
{
  "checks": [
    {
      "timeout": 60,
      "pause_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b/pause",
      "last_ping": "2018-12-19T23:50:16+00:00",
      "name": "my-first-check",
      "grace": 60,
      "ping_url": "http://localhost:9090/ping/4111b763-2319-4bdd-8c0c-70ce621c2b4b",
      "n_pings": 3,
      "status": "down",
      "tags": "my-test",
      "channels": "",
      "next_ping": "2018-12-19T23:51:16+00:00",
      "update_url": "http://localhost:9090/api/v1/checks/4111b763-2319-4bdd-8c0c-70ce621c2b4b"
    }
  ]
}

statusdown になっていることが判ります. ブラウザで確認すると以下のように Current Status が down となっていることが判ります.

f:id:inokara:20181220091136p:plain

以上

Cron ジョブの稼働監視を一覧化するにあたって, 以前に Jenkins を使うことを検討したことが有りました.

hogehuga.inokara.com

Jenkins の「外部ジョブの監視」を利用することで, Cron の実行結果の一覧を Jenkins で確認することは出来ることを確認しましたが, Healthchecks.io のように期間や猶予期間を指定するということは出来なかったと記憶しています (現在は可能かもしれませんが). 期間や猶予期間を指定出来ることで, Cron ジョブの監視以外にも定期的に実行される (それが Cron で実行されているのであれば, Cron ジョブ監視になってしまいますが...) バックエンドのサービス等の死活監視にも利用可能なのではと考えています.

今回は Docker を使って, 超簡単に Healthchecks.io をチュートリアルしてみました. 本当にシンプルで特に難しいこともなく基本的な機能を触ることが出来ました. Slack への通知等も簡単に行えるようなので, 時間を見つけて試してみたいと思います. また, サードパーティ製のライブラリをアプリケーションに組み込みんでみて, 実運用のアプリケーションでどのように使えるかも検証してみたいと考えています.