用etcd和CoreDNS来实现Prometheus的服务发现
首先
这篇文章是2017年Prometheus购物节的第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
核心DNS
由于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或其他方式来将其作为守护进程运行,就可以了。
DNS配置
当etcd和CoreDNS准备就绪时,您将能够获取DNS记录。只需在运行CoreDNS的服务器上可以执行dig命令即可。
$ 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,因此省略此部分设置。
将NS记录注册到CoreDNS
CoreDNS的etcd后端默认将SOA记录的目标设置为ns.dns子域名。
将ns记录设置为ns.dns.prom.local.。
$ 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的记录。
将SRV记录注册到CoreDNS的etcd客户端
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集群。
出口方面的设定
在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之前启动exporter,并在停止之后将信息注册到etcd中的Wrap脚本被调用。这是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系等等的方式进行水平分片的配置也是可能的。
最后
以上是在Bare Metal环境中使用动态SD的一个例子。在该例中,我们假设使用systemd进行操作,但是如果存在混合了旧环境(如CentOS 6)的情况,也可以使用Upstart来实现类似的操作。
我认为通过将监控带入到Prometheus中,即使在裸金属环境中,也可以实现在k8s中容易完成的功能,这样可以更容易地构建一个适合迁移到k8s的环境。
进行自我反省
在验证过程中我注意到一个问题,由于DNS缓存的原因,可能会导致Prometheus的更新稍微有点慢… 如果发生这种情况,Prometheus最好直接向CoreDNS查询名称…