Consul を Prometheus と連携させてみる
前回まで Prometheus による監視や、Alertmanager によるアラート通知などを書いてきた。
ただ設定ファイルを見ると分かる通り、監視対象のノードが増える度に手動で設定ファイルに追記していくのはとても面倒。自動化したい。 幸いにも Prometheus には監視対象を連携システムから取得するための機能が豊富にある。 今回は Consul と連携してノードが増える度に自動で監視対象も増やせるようにする。
サーバとエージェントを同じノードで動かすのは無理のようなので Consul server と Consul agent は別ノードにインストールします。 前回に引き続いてこんな構成になってます。
- 監視サーバ(ホスト名:promhost)
- Prometheus server, Alertmanager, node_exporter, Consul server
- 監視対象のサーバ(ホスト名:targethost)
- node_exporter, Consul agent
Consul とは?
散々解説はあると思うのでそちらで(詳しい解説ができないだけ)。 以下は素晴らしい連載記事。
あと公式の Getting Started も分かりやすくていい。
自分の理解だと
- サーバ・クライアント型
- KVS 機能を持っていて以下の情報等を格納している
- サーバに接続しているノード一覧の情報
- どんなサービスがどこで稼働しているか(サービスディスカバリ)
- サービスの検出のために監視機能はあるがアラート機能はない
サービスディスカバリによって得たノード一覧とかの情報を KVS に蓄えているので、 それを Prometheus に渡してアラートはそいつにやってやろうみたいなノリです(実際は Prometheus から情報を Pull するので逆ですが)。
Consul のインストール
Consul のバイナリは Prometheus と違い GitHub の releases には置いてない(ソースコードのみ)。 公式サイトのダウンロードページからダウンロードしてくる。 zip で配布されているので、Linux 上で展開するなら unzip をインストールする必要があるかもしれない。
$ sudo yum install unzip # なければインストール $ curl -LO https://releases.hashicorp.com/consul/0.9.0/consul_0.9.0_linux_amd64.zip $ unzip consul_0.9.0_linux_amd64.zip
展開すると consul というバイナリが一つだけカレントディレクトリに展開される。
これを /opt/consul/consul
としてインストールする。
$ sudo mkdir /opt/consul $ sudo mv consul /opt/consul/ $ sudo chmod 755 /opt/consul $ sudo chown -R root:root /opt/consul
バイナリのインストール終わり。 このバイナリ単体でサーバとエージェント両方兼ねている。 ちなみにインストールの簡単さから想像できる通り Consul も Go 製。
あとは systemd で起動できるように設定ファイルを作る。
Consul エージェント用
エージェント用のノードにインストールするファイル。 まだエージェントとクライアントの違いが分かってない… ともかくまずは設定ファイル用ディレクトリを作っておく。
$ sudo mkdir /etc/consul.d
次に設定ファイルを作る。
/etc/systemd/system/consul-agent.service
[Unit] Description=Consul Agent After=network.target [Service] Type=simple EnvironmentFile=-/etc/default/consul-agent ExecStart=/opt/consul/consul agent $OPTIONS PrivateTmp=true [Install] WantedBy=multi-user.target
/etc/default/consul-agent
-data-dir
はデータディレクトリ。
-node
は Consul クラスタ上で重複しない名前。自分はホスト名を設定した(これ後でエージェントごとにインストールする時自動生成したいなぁ)。
-config-dir
は設定ファイル用のディレクトリ。
-join
は Consul サーバのIPアドレスかホスト名。
OPTIONS="-data-dir=/var/lib/consul-agent -node=targethost -config-dir=/etc/consul.d/ -join=promhost"
ちなみに -node
に指定する値を $(hostname)
にしたらまんま $(hostname)
ってノード名で追加されてしまった。
systemd の EnvironmentFile に指定するのってシェルスクリプトじゃないのね…(SysVinit ならいけたような?)
OPTIONS="-data-dir=/var/lib/consul-agent -node=$(hostname) -config-dir=/etc/consul.d/ -join=promhost"
で、こんな感じになった。
$ sudo /opt/consul/consul members Node Address Status Type Build Protocol DC promhost xxx.xxx.xxx.xxx:8301 alive server 0.9.0 2 dc1 $(hostname) zzz.zzz.zzz.zzz:8301 alive client 0.9.0 2 dc1
ノード名修正したら今度はこんな風になった。 Status が failed になってるけど一覧から削除されてない。
Node Address Status Type Build Protocol DC $(hostname) xxx.xxx.xxx.xxx:8301 failed client 0.9.0 2 dc1 promhost yyy.yyy.yyy.yyy:8301 alive server 0.9.0 2 dc1 targethost xxx.xxx.xxx.xxx:8301 alive client 0.9.0 2 dc1
こういう時は consul force-leave
を行うと left 状態にはできる(failed と left の違いはこちら)。
ただそれでも一覧からは削除されない。
$ sudo /opt/consul/consul force-leave '$(hostname)' $ sudo /opt/consul/consul members Node Address Status Type Build Protocol DC $(hostname) xxx.xxx.xxx.xxx:8301 left client 0.9.0 2 dc1 promhost yyy.yyy.yyy.yyy:8301 alive server 0.9.0 2 dc1 targethost xxx.xxx.xxx.xxx:8301 alive client 0.9.0 2 dc1
公式サイトによると、
Q: Are failed or left nodes ever removed?
To prevent an accumulation of dead nodes (nodes in either failed or left states), Consul will automatically remove dead nodes out of the catalog. This process is called reaping. This is currently done on a configurable interval of 72 hours. Reaping is similar to leaving, causing all associated services to be deregistered. Changing the reap interval for aesthetic reasons to trim the number of failed or left nodes is not advised (nodes in the failed or left state do not cause any additional burden on Consul).
72時間ごとに failed や left になったノードを一覧から削除する reaping と呼ばれる処理が実行されるとのこと。
一覧に残ってて見た目上気になるからこの間隔を変えるのは推奨されないとまで書いてある。
というわけで気にしないことにする。
ただ consul-server を再起動したら $(hostname)
がいなくなってたので、もしかしたら再起動すると自動的に reaping が行われるのかもしれない。
- systemd で起動
$ sudo systemctl daemon-reload $ sudo systemctl enable consul-agent # 今回は検証のためなので自分の環境ではやらなかった $ sudo systemctl start consul-agent
Consul サーバ用
サーバ用のノードにインストールするファイル。
/etc/systemd/system/consul-server.service
[Unit] Description=Consul Server After=network.target [Service] Type=simple EnvironmentFile=-/etc/default/consul-server ExecStart=/opt/consul/consul agent -server $OPTIONS PrivateTmp=true [Install] WantedBy=multi-user.target
/etc/default/consul-server
-data-dir
はデータディレクトリ。
-bootstrap-expect
は Consul サーバの数。
ネットワークインターフェースが複数ある環境では -bind=IPアドレス
も付けないといけないらしいです。
ちなみにサーバー側のサービス定義も公開するならエージェントと同じく -config-dir=/etc/consul.d/
を付ければ良い。
サービス定義の設定ファイルに関しては後述。
OPTIONS="-bootstrap-expect=1 -data-dir=/var/lib/consul-server"
- systemd で起動
$ sudo systemctl daemon-reload $ sudo systemctl enable consul-server # 今回は検証のためなので自分の環境ではやらなかった $ sudo systemctl start consul-server
Consul サービス設定
※サービス設定は多分 Prometheus で監視するならいらない。理由は後述。
先ほど空の /etc/consul.d
ディレクトリを作っておいたが、その中に Web サーバなどのサービス用の設定ファイルを作っていく。
サーバ側で管理するんじゃなくノード側に自分を監視する設定を置くのは新鮮。
あと設定ファイルが JSON なのも割と新鮮。
以下は第6回の記事からの引用。
/etc/consul.d/web.json
{ "service": { "name": "web", "tags": [ "nginx" ], "port": 80, "check": { "script": "curl http://127.0.0.1:80/consul.html >/dev/null 2>&1", "interval": "10s", "timeout": "5s" } } }
今回のために nginx 用意するのもだるかったので前回インストールした node_exporter が HTTP でメトリクス情報を公開してるので、
それを監視することにする(というか Prometheus はここを監視してるのですでにアラートは行く状態になってるけど、今回はテストなので)。
テストのつもりで追加しましたが、Prometheus に監視させるために必要でした。理由は後述。
設定ファイルはこんな感じ。
/etc/consul.d/node_exporter.json
{ "service": { "name": "node_exporter", "tags": ["node_exporter"], "port": 9100 } }
まだ詳しく分かってないけどこれでサービスの定義はできる。 監視もするなら
{ "service": { "name": "node_exporter", "tags": ["node_exporter"], "port": 9100, "check": { "script": "curl http://targethost:9100 >/dev/null 2>&1", "interval": "10s" } } }
みたいにするって Getting Started でも書いてあったんだけど動かなかった。
ちなみに失敗した際のログ
$ sudo systemctl status -l consul-agent.service ● consul-agent.service - Consul Agent Loaded: loaded (/etc/systemd/system/consul-agent.service; disabled; vendor preset: disabled) Active: failed (Result: exit-code) since 日 2017-07-30 18:39:58 JST; 1s ago Process: 4575 ExecStart=/opt/consul/consul agent $OPTIONS (code=exited, status=1/FAILURE) Main PID: 4575 (code=exited, status=1/FAILURE) 7月 30 18:39:58 targethost consul[4555]: 2017/07/30 18:39:58 [INFO] Exit code: 0 7月 30 18:39:58 targethost systemd[1]: Started Consul Agent. 7月 30 18:39:58 targethost systemd[1]: Starting Consul Agent... 7月 30 18:39:58 targethost consul[4575]: ==> Starting Consul agent... 7月 30 18:39:58 targethost consul[4575]: ==> Error starting agent: Failed to register service '': Check types that exec scripts are disabled on this agent 7月 30 18:39:58 targethost systemd[1]: consul-agent.service: main process exited, code=exited, status=1/FAILURE 7月 30 18:39:58 targethost systemd[1]: Unit consul-agent.service entered failed state. 7月 30 18:39:58 targethost systemd[1]: consul-agent.service failed.
まぁ監視は Prometheus でやるからいいか、って思ったのでとりあえず今回はやらないことにした。
ちなみに無事設定がうまくいったらサーバ側で以下のコマンドで node_exporter がいるのを確認できるはずです。
$ sudo /opt/consul/consul catalog services consul node_exporter
Prometheus との連携
で、上でサービスの定義とか書いてみたんだけど、ぶっちゃけ Prometheus で監視するためには必要ない。
なぜかというと Prometheus としては exporter が動いてるノード一覧を取得することが目的なので、サービスが定義されていなくても大丈夫(のはず)。
ただオプションで監視対象のサービスを Prometheus で絞り込むことはできる(参照:/scrape_configs/consul_sd_config/services
)。
…と思ってたんですが、どうやら監視対象はサービスで決まる様子。 つまり services で絞り込んでやらないとデフォルトで提供される consul のサービスを見に行ってしまう(8300 は consul が RPC に使うポートなので Prometheus に見に行ってもらっても困るんですが…)。 ということで上記で定義した node_exporter で絞り込むことにする。つまりこう。
scrape_configs: - job_name: 'consul_sd_configs' consul_sd_configs: - server: 'localhost:8500' services: - 'node_exporter' # node_exporter というタグを持つサービスのみ監視
監視対象のホスト名を表示する
そのままだと http://<prometheus host>/targets
に表示されるノードは IP アドレスで表示される。
またアラートが来た時も同じ。
IP アドレスだとパッと見どのノードなのか分かりづらい。 なので代わりにホスト名で表示する。
Controlling the instance label | Robust Perception
この記事を参考に書いた Consul 用の設定は以下の通り。
relabel_configs: - source_labels: [__meta_consul_node] regex: '(.*)' target_label: __address__ replacement: '${1}:9100' - source_labels: [__meta_consul_node] target_label: instance
…と思ったんだけどこれだとポートが 9100 固定になっている。 それ以外のポートで動作させたり、この記事で書いたように複数の exporter を同じノード上で動作させることができない。 というわけで以下の設定になった。
relabel_configs: - source_labels: [__meta_consul_node, __meta_consul_service_port] separator: ':' target_label: __address__ - source_labels: [__meta_consul_node] target_label: instance
これでちゃんと Consul エージェント側で定義したポートを見に行ってくれる。
Prometheus が監視しにいく URL を見る方法は?
http://<Prometheus>/targets
で見れる。
監視対象のポートが違うんだけど…
先ほどエージェント側に置いた /etc/consul.d/node_exporter.json
のファイルの port をチェックすること。
Consul が公開しているサービスの情報
curl http://<Consul server>:8500/v1/catalog/service/<service>
で見れる(例:
$ curl http://<Consul server>:8500/v1/catalog/service/node_exporter | jq .
Consul が使うポート
参考に Consul が使うポートをこちらの記事から引用。
機能 | TCP/UDP | ポート | 説明 |
---|---|---|---|
Server RPC | TCP | 8300 | Server が他の Agent からRPCのリクエストを受け付ける |
Serf LAN | TCP & UDP | 8301 | LAN用のゴシッププロトコル。全 Agent 同士が使う |
Serf WAN | TCP & UDP | 8302 | WAN用のゴシッププロトコル。Server 同士が使う |
CLI RPC | TCP | 8400 | consulコマンド実行時にローカルの Agent との通信に使われる |
HTTP API | TCP | 8500 | Client が HTTP リクエストを受け付ける |
DNS | TCP & UDP | 8600 | Agent が DNSクエリを受け付ける |
雑感
最近 Go 製のツールを構築してく中で思ったのは、Go 製のツールってあえて明示的に設定ファイルを指定する必要があったり、 暗黙的に色々参照したりしない傾向があるような気がする(サンプル数少ないけど)。 Go の文化なのかな。