はじめに
この記事はprometheus Advent Calendar 2017の21日目の記事です。23日に投稿していますが。。。
監視対象の追加はサービスティスカバリ(sd)によって、動的にするのが良いです。PrometheusにはAWS, Azure, GCP, OpenStack, Kubernetesなど多種多様なプラットフォームのメタデータを元にsdすることができます。が、所謂ベアメタルと呼ばれる、物理マシン上のプロセスの監視追加をsdによって実現しようとすると、諸々仕組みを整える必要があります。
という事で、以下の仕組みを検証/構築してみたので、その共有になります。
- CoreDNSのetcdバックエンドの機能によってetcdの情報をベースとしてDNSサービスを提供
- 監視対象はexporterの起動に合わせて、etcdに自身の監視エンドポイントを登録
- Prometheusのdns_sdを使って監視対象追加
全体像
全体像こんな感じです。
CoreDNS / etcdクラスタの用意
etcdクラスタ
etcdクラスタの構築に関しては本筋では無いので、割愛します。
ぱっと見だと作るの難しそうなんですが、認証やTLS対応をしない場合は、結局リッスンするURLに関する設定やクラスタメンバの設定くらいなので、構築はそれほど難しくはないかと思います。
以下の記事が参考になります。
https://qiita.com/hana_shin/items/602f98bd9b153d22e50c
CoreDNS
CoreDNSはetcdクラスタと同じホストに同居させるので各CoreDNSはローカルのetcdを見るようにします。
prom.local {
etcd prom.local {
path /skydns
endpoint http://localhost:2379
}
errors
log
}
CoreDNSとはなんぞや?って方は手前味噌で恐縮ですが、以下の記事を参考にして頂ければ。
https://qiita.com/kanga/items/e74038f25d1f53ca6ade
coredns自体の起動は簡単です。
coredns -conf Corefile
とロードするCorefileを指定するだけで済みます。後はこれをSystemdなりなんなりでデーモン化すればOKです。
DNS設定
etcdとCoreDNSの準備が整ったらDNSレコードが引けるようになります。CoreDNSが動いているサーバ上でdigが引ければOKです。
$ dig -p 53 @localhost SOA prom.local +noall +answer
; <<>> DiG 9.10.2-P4 <<>> -p 53 @localhost SOA prom.local +noall +answer
; (1 server found)
;; global options: +cmd
prom.local. 300 IN SOA ns.dns.prom.local. hostmaster.prom.local. 1513948062 7200 1800 86400 30
DNSに各種レコードを追加していきます。
親の内部DNSでサブドメインを委譲
内部DNSのサブドメインprom
をCoreDNSに委譲します。この辺の設定は使ってる内部DNSに依存するので割愛します。
CoreDNSにNSレコードを登録
CoreDNSのetcdバックエンドはSOAレコードの向き先がデフォルトでns.dns
サブドメインに向いています。
ns.dns.prom.local.
にnsレコードを設定していきます。
$ etcdctl set /skydns/local/prom/dns/ns/ns1 '{"host":"192.168.0.1"}'
{"host":"192.168.0.1"}
$ etcdctl set /skydns/local/prom/dns/ns/ns2 '{"host":"192.168.0.2"}'
{"host":"192.168.0.2"}
$ etcdctl set /skydns/local/prom/dns/ns/ns3 '{"host":"192.168.0.3"}'
{"host":"192.168.0.3"}
ちなみにCoreDNSのetcdバックエンドの機能はSkyDNSと完全に同じです。etcdのスラッシュ区切りのパスの逆順がDNSのFQDNに対応しています。
設定に問題無ければ、委譲されたサブドメインでAレコードとNSレコードが引けるようになります。
$ dig -p 53 @localhost NS prom.local. +noall +answer
; <<>> DiG 9.10.2-P4 <<>> -p 53 @localhost NS prom.local. +noall +answer
; (1 server found)
;; global options: +cmd
prom.local. 300 IN NS ns1.ns.dns.prom.local.
prom.local. 300 IN NS ns2.ns.dns.prom.local.
prom.local. 300 IN NS ns3.ns.dns.prom.local.
$ dig -p 53 @localhost A prom.local. +noall +answer
; <<>> DiG 9.10.2-P4 <<>> -p 53 @localhost A prom.local. +noall +answer
; (1 server found)
;; global options: +cmd
prom.local. 300 IN A 192.168.0.1
prom.local. 300 IN A 192.168.0.2
prom.local. 300 IN A 192.168.0.3
ここまで準備が終われば、内部dns経由でprom.local
のレコードが引けるようになります。
CoreDNSにetcdクライアント用のSRVレコードを登録
etcdにはDNSのSRVレコードから接続エンドポイントを指定する機能があります。SRVレコードはあまり馴染みの無い方も多いと思いますが、Aレコードの情報にポートと負荷分散の情報を加えたようなDNSのレコードのタイプになります。
$ etcdctl --discovery-srv prom.local ls
このコマンドを打つと、_etcd-client-ssl._tcp.prom.local
あるいは_etcd-client._tcp.prom.local
のドメインからSRVレコードを探して、名前解決できた先にetcdclientとして接続しに行きます。
今回はetcdをtls化していないので、_etcd-client._tcp.prom.local
にレコードを追加していきます。etcdclientの接続先ポートの情報も付加します。
$ etcdctl set /skydns/local/prom/_tcp/_etcd-client/coreos-coredns01 '{"host":"192.168.0.1","port":2379}'
{"host":"192.168.0.1","port":2379}
$ etcdctl set /skydns/local/prom/_tcp/_etcd-client/coreos-coredns02 '{"host":"192.168.0.2","port":2379}'
{"host":"192.168.0.2","port":2379}
$ etcdctl set /skydns/local/prom/_tcp/_etcd-client/coreos-coredns03 '{"host":"192.168.0.3","port":2379}'
{"host":"192.168.0.3","port":2379}
SRVレコードが名前解決できるようになり、etcdctlからSRVレコード指定で接続が可能になります。
$ dig SRV _etcd-client._tcp.prom.local +noall +answer +additional
; <<>> DiG 9.10.2-P4 <<>> SRV _etcd-client._tcp.prom.local +noall +answer +additional
;; global options: +cmd
_etcd-client._tcp.prom.local. 300 IN SRV 10 33 2379 coreos-coredns02._etcd-client._tcp.prom.local.
_etcd-client._tcp.prom.local. 300 IN SRV 10 33 2379 coreos-coredns03._etcd-client._tcp.prom.local.
_etcd-client._tcp.prom.local. 300 IN SRV 10 33 2379 coreos-coredns01._etcd-client._tcp.prom.local.
coreos-coredns01._etcd-client._tcp.prom.local. 197 IN A 192.168.0.1
coreos-coredns02._etcd-client._tcp.prom.local. 300 IN A 192.168.0.2
coreos-coredns03._etcd-client._tcp.prom.local. 300 IN A 192.168.0.3
$ etcdctl --discovery-srv prom.local ls
/skydns
これにより各etcdクライアントはetcdクラスタを構成する具体的なホスト、あるいはロードバランサのVIPを意識せずにetcdに接続できるようになりました。
exporter側の設定
server01とserver02でnode_exporterを起動させて動的ディスカバリを実現させます。以下のようなSystemdのUnitファイルを用意します。
[Unit]
Description=promtheus node_exporter service
[Service]
Type=simple
Environment=EXPORTER_ADDRESS=192.168.1.1
Environment=EXPORTER_PORT=9100
Environment=ETCD_ENDPOINT=prom.local
Environment=ETCD_BASE_PATH=/skydns/local/prom
Environment=EXPORTER_TYPE=node
ExecStartPre=/usr/local/bin/register.sh set
ExecStart=/usr/bin/node_exporter
ExecStopPost=/usr/local/bin/register.sh rm
Restart=always
RestartSec=180s
[Install]
WantedBy=multi-user.target
ExecStartPreとExecStopPostでexprterを起動する前、停止した後にetcdに情報を登録するWrapスクリプトを呼んでいます。ラップスクリプトはこんな感じです。
#!/bin/bash
set -eu
subcommand="$1"
shift
case $subcommand in
set)
etcdctl --discovery-srv ${ETCD_ENDPOINT} set ${ETCD_BASE_PATH}/${EXPORTER_TYPE}/`hostname -s` \
"{\"host\":\"${EXPORTER_ADDRESS}\",\"port\":${EXPORTER_PORT}}"
;;
rm)
etcdctl --discovery-srv ${ETCD_ENDPOINT} rm ${ETCD_BASE_PATH}/${EXPORTER_TYPE}/`hostname -s`
;;
*)
echo "Please specify set or rm as argument."
;;
esac
EXPORTER_ADDRESSなどの号機間で異なる値は、なんらか構成管理ツールで埋め込む想定です。あとはexporterを起動すると、etcdに情報が登録されDNSで名前解決できるようになります。
$ systemctl start prom@node.service
$ dig @localhost SRV node.prom.local +noall +answer
; <<>> DiG 9.10.2-P4 <<>> @localhost SRV node.prom.local +noall +answer
; (1 server found)
;; global options: +cmd
node.prom.local. 300 IN SRV 10 50 9100 server01.node.prom.local.
node.prom.local. 300 IN SRV 10 50 9100 server02.node.prom.local.
Prometheusの設定
後はPromtheusにsdの設定を入れるだけです。
global:
scrape_interval: 15s
evaluation_interval: 30s
external_labels:
monitor: 'global-monitor'
rule_files:
- "/etc/prometheus/rule.d/*.rule"
scrape_configs:
- job_name: 'node_exporter'
scrape_interval: 10s
dns_sd_configs:
- names:
- "node.prom.local"
これでPrometheusを起動したら、先ほど起動したserver01とserver02が登録されています。
今回はnode_exporter
のみを監視対象に追加しましたが、node.prom.local
やmysql.prom.local
のように監視対象のミドル別に登録ドメインを変更する事も可能ですし、もっと手前でドメインを掘ってnode.a.prom.local
やnode.b.prom.local
のようにA系B系C系...と用意して水平シャーディングする構成にもする事が可能です。
おわりに
以上、ベアメタル環境での動的sdの一例でした。例ではsystemdを前提に進めましたがCentOS6など古い環境も混ざっている場合はUpstartでも同じような事ができると思います。
k8sで簡単にできる事を手間暇やって実現した感が否めないですが、ベアメタルでも監視をPrometheusに持っていくことで、よりk8sに移行しやすい環境を整える事ができるかな、と思います。
反省点
検証してて気付いたのですが、DNSキャッシュの問題でPrometheusの反映が若干遅れるかも。。。その場合Prometheusは直接CoreDNSに名前を聞きにいったほうが良さそうだなぁ。。。