右往左往ブログ

日々よりみち

consul watchの変な挙動

watchとは

consulのwatch機能は、サービスなどを監視し、状態が変化したときに指定した処理を実行する機能です。

公式によると、以下の条件でwatchは発動するようです。 https://www.consul.io/docs/agent/watches.html

  • Key/Valueが変化したとき
  • Key Prefix配下が変化したとき
  • Serviceの数が変化したとき
  • nodeの数が変化したとき
  • 特定のServiceの状態が変化したとき
  • checkの状態が変化したとき
  • ユーザの指定したeventを発行したとき

ここではwatch機能の挙動を確認してみます。
自分の理解が足りないのか、ちょっと今のままでは使いづらいなという印象です…。
なお、検証したのは上記のうち「特定のServiceの状態が変化したとき」についてです。

使いづらいポイント

検証で後述しますが、まとめると以下です。

  • consulノードが起動/停止しても発動(チェック対象のサービスの状態にかかわらず)
  • consul reloadしても発動
    • しかも発動する回数が1回とは限らない
  • Serviceが停止/起動しても発動
    • しかも停止時と起動時でアクションを変更できない(どちらも同じアクションになる)

設定

今回はserver :1 , agent :2の構成で確認します。

基本設定

dc1_server

  • /etc/consul/conf.d/config.json
{
  "datacenter": "dc1",
  "data_dir": "/tmp/consul",
  "server": true,
  "bootstrap_expect": 1
}

consul自体の起動は、後でserviceとwatchのconfigを配置してから一緒に行います。

dc1_client[12]

2台登録します。(あまり今回の検証と関係ありませんが)

  • /etc/consul/conf.d/config.json
{
  "datacenter": "dc1",
  "data_dir": "/tmp/consul",
  "server": false,
  "retry_join": ["dc1server"]
}

Serviceの登録

dc1_server, dc1_client[12]

-config-dir配下にファイルを配置します。

  • /etc/consul/conf.d/service-filecheck.json
{
  "service": {
    "id": "file-check",
    "name": "file-check",
    "tags": ["master"],
    "checks": [
      {
        "script": "/tmp/filecheck.sh",
        "interval": "10s"
      }
    ]
  }
}

service監視用のスクリプトを配置します。

  • /tmp/filecheck.sh
#!/bin/bash

if [ -f "/tmp/testfile" ] ; then
  exit 0
fi
exit 2

単純にファイルの存在をチェックし、結果を返すだけのスクリプトです。 /tmp/testfile自体は空です。

watchの登録

dc1_server

/etc/consul/conf.d/watch-filecheck.json

{
  "watches": [
    {
      "type": "service",
      "service": "file-check",
      "handler": "/tmp/filecheck_handler.sh"
    }
  ]
}

起動

dc1_server, dc1_client[12]

consul agent -config-dir=/etc/consul/conf.d

検証

起動時にまず1回以上実行されます。
これは、3台を同時に起動しており、consul起動とService登録が順次行われたためと思われます。
起動順によるのか、1回だったり以下のとおり2回だったり、回数は不定です。
発動自体は想定通りなのですが、回数が不定なのは仕方ないとはいえちょっと気になります。

[root@dc1server /]# cat /tmp/consul.log
executed script: Sat Jun 27 06:14:37 UTC 2015
executed script: Sat Jun 27 06:14:42 UTC 2015

reloadしても1回以上実行されます。

[root@dc1server /]# consul reload
Configuration reload triggered
[root@dc1server /]# cat /tmp/consul.log
executed script: Sat Jun 27 06:14:37 UTC 2015
executed script: Sat Jun 27 06:14:42 UTC 2015
executed script: Sat Jun 27 06:15:23 UTC 2015 # 増えた
executed script: Sat Jun 27 06:15:23 UTC 2015 # 増えた

同じことを実行しても、発動が1回だけのときもあります。
これがよく分からない…。

[root@dc1server /]# consul reload
Configuration reload triggered
[root@dc1server /]# cat /tmp/consul.log
executed script: Sat Jun 27 06:14:37 UTC 2015
executed script: Sat Jun 27 06:14:42 UTC 2015
executed script: Sat Jun 27 06:15:23 UTC 2015
executed script: Sat Jun 27 06:15:23 UTC 2015
executed script: Sat Jun 27 06:15:48 UTC 2015 # 増えた

これは本来の動作ですが、サービスをダウンさせても発動します。
(ここではサービス監視対象のファイルを削除しています)

[root@dc1server /]# consul exec -node dc1client1 "rm -f /tmp/testfile"
==> dc1client1: finished with exit code 0
1 / 1 node(s) completed / acknowledged
[root@dc1server /]# consul exec "ls -l /tmp/testfile"
    dc1server: -rw-r--r-- 1 root root 0 Jun 27 04:34 /tmp/testfile
    dc1server:
==> dc1server: finished with exit code 0
    dc1client1: ls: cannot access /tmp/testfile: No such file or directory
    dc1client1:
    dc1client2: -rw-r--r-- 1 root root 0 Jun 27 04:34 /tmp/testfile
    dc1client2:
==> dc1client1: finished with exit code 2
==> dc1client2: finished with exit code 0
3 / 3 node(s) completed / acknowledged
[root@dc1server /]# cat /tmp/consul.log
executed script: Sat Jun 27 06:14:37 UTC 2015
executed script: Sat Jun 27 06:14:42 UTC 2015
executed script: Sat Jun 27 06:15:23 UTC 2015
executed script: Sat Jun 27 06:15:23 UTC 2015
executed script: Sat Jun 27 06:15:48 UTC 2015
executed script: Sat Jun 27 06:23:42 UTC 2015 # 増えた

サービスを復旧させても発動します。
(ここではサービス監視対象のファイルを作っています)

[root@dc1server /]# consul exec -node dc1client1 "touch /tmp/testfile"
==> dc1client1: finished with exit code 0
1 / 1 node(s) completed / acknowledged
[root@dc1server /]# consul exec "ls -l /tmp/testfile"
    dc1server: -rw-r--r-- 1 root root 0 Jun 27 04:34 /tmp/testfile
    dc1server:
==> dc1server: finished with exit code 0
    dc1client1: -rw-r--r-- 1 root root 0 Jun 27 06:25 /tmp/testfile
    dc1client1:
    dc1client2: -rw-r--r-- 1 root root 0 Jun 27 04:34 /tmp/testfile
    dc1client2:
==> dc1client2: finished with exit code 0
==> dc1client1: finished with exit code 0
3 / 3 node(s) completed / acknowledged
[root@dc1server /]# cat /tmp/consul.log
executed script: Sat Jun 27 06:14:37 UTC 2015
executed script: Sat Jun 27 06:14:42 UTC 2015
executed script: Sat Jun 27 06:15:23 UTC 2015
executed script: Sat Jun 27 06:15:23 UTC 2015
executed script: Sat Jun 27 06:15:48 UTC 2015
executed script: Sat Jun 27 06:23:42 UTC 2015
executed script: Sat Jun 27 06:25:32 UTC 2015 # 増えた

Service機能の1つであるDNSは、想定通り3つ返しています。

[root@dc1server /]# dig @127.0.0.1 -p 8600 file-check.service.consul. ANY
(snip)

;; QUESTION SECTION:
;file-check.service.consul. IN  ANY

;; ANSWER SECTION:
file-check.service.consul. 0    IN  A   172.17.0.34
file-check.service.consul. 0    IN  A   172.17.0.36
file-check.service.consul. 0    IN  A   172.17.0.32

(snip)

まとめ

consulのservice機能自体はかなり便利です。特に生きているノードに対してのみレコードを返すようなDNSは、いろいろと応用が効きそうです。

一方、Serviceと組み合わせたwatch機能はかなり使いづらい印象を受けました。

  • Serviceのdown/upに関係なく発動する
  • configのreload時にも発動する
  • 1回発動するとは限らない。何回発動するかも分からない(自分だけかも)

watch機能は、何回実行しても問題ないような処理に限ったほうがよさそうだという印象です。configの入れ替えなどでしょうか。ただ、サービスのダウン時、アップ時に処理を分けたいと思うことは多いと思われますので、今のままだとスクリプトで処理を分けなければならず、ちょっと使いづらいです。特にreload時に勝手に発動するのは、できればコントロールさせて欲しい…。

以下でも話題になっています。
Reloading Consul re-runs all watch commands every time. · Issue #571 · hashicorp/consul · GitHub

あと今回は触れませんでしたが、checkと連動するときも注意が必要です。 「このcheck」という指定ができないので、checkを複数種類登録しており、かついずれかのcheckの状態が変更されると、どのcheckだったとしてもwatchが発動します。 基本的に、watchはserviceに紐づくものなので、checkもserviceに紐付けることが前提になりそうです。