用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を使って監視対象追加

整体形象

整体就像这个样子。

Promtheus.png

准备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查询名称…

bannerAds