一、Consul 介绍
Consul 是基于 GO 语言开发的开源工具,主要面向分布式,服务化的系统提供服务注册、服务发现和配置管理的功能。Consul 提供服务注册/发现、健康检查、Key/Value存储、多数据中心和分布式一致性保证等功能。
在没有使用 consul 服务自动发现的时候,我们需要频繁对 Prometheus 配置文件进行修改,无疑给运维人员带来很大的负担。引入consul之后,只需要在consul中维护监控组件配置,prometheus就能够动态发现配置了。
Prometheus 支持的多种服务发现机制
#Prometheus数据源的配置主要分为静态配置和动态发现, 常用的为以下几类:
1)static_configs: #静态服务发现
2)file_sd_configs: #文件服务发现
3)dns_sd_configs: DNS #服务发现
4)kubernetes_sd_configs: #Kubernetes 服务发现
5)consul_sd_configs: Consul #服务发现
...
#在监控kubernetes的应用场景中,频繁更新的pod,svc,等等资源配置应该是最能体现Prometheus监控目标自动发现服务的好处
二、环境、软件准备
本次演示环境,我是在虚拟机上安装 Linux 系统来执行操作,以下是安装的软件及版本:
- Oracle VirtualBox: 5.1.20 r114628 (Qt5.6.2)
- System: CentOS Linux release 7.3.1611 (Core)
- Docker: 18.06.1-ce
- Prometheus: v2.11.1
- Consul: 1.6.1
注意:这里为了方便启动 Prometheus、Consul服务,我使用 Docker 方式启动,所以本机需要安装好 Docker 环境,这里忽略 Docker 的安装过程。其中 Prometheus 安装配置,可以参照之前文章 Prometheus 监控报警系统 AlertManager 之邮件告警,这里着重介绍一下如何启动并配置 Consul 并配置 Prometheus 基于 Consul 实现自动服务发现。
三、Consul 安装配置
Consul 安装很方便,官网 提供各个系统版本二进制安装包,解压安装即可,同时也可以通过 Docker 来快速安装。
3.1、安装
yum安装
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum -y install consul
源码安装
以 Linux 系统为例,源码安装并以开发模式启动一个单节点,下载最新版二进制安装包,解压启动即可。
$ wget https://releases.hashicorp.com/consul/1.6.1/consul_1.6.1_linux_amd64.zip
$ unzip consul_1.5.3_linux_amd64.zip
#数据持久化
mkdir -p /app/consul/data
#启动命令
$ nohup consul agent -server -data-dir=/app/consul/data -node=agent-one -bind=172.21.1.11 -bootstrap-expect=1 -client=0.0.0.0 -ui > /app/consul/consul.log 2>&1 &
cat << EOF > /etc/systemd/system/consul.service
[Unit]
Description="HashiCorp Consul - A service mesh solution"
Documentation=https://www.consul.io/
Requires=network-online.target
After=network-online.target
ConditionFileNotEmpty=/etc/consul.d/consul.hcl
[Service]
EnvironmentFile=-/etc/consul.d/consul.env
User=consul
Group=consul
ExecStart=/usr/bin/consul agent -config-dir=/etc/consul.d/
ExecReload=/bin/kill --signal HUP $MAINPID
KillMode=process
KillSignal=SIGTERM
Restart=on-failure
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF
Docker 安装
使用 Docker 启动 Consul 单节点服务,直接获取最新版官方镜像 consul:latest 命令如下:
$ docker run -d -p 8500:8500 --restart=always --name=consul consul:latest agent -server -bootstrap -ui -node=1 -client='0.0.0.0'
- agent: 表示启动 Agent 进程。
- server: 表示启动 Consul Server 模式
- client: 表示启动 Consul Cilent 模式。
- bootstrap: 表示这个节点是 Server-Leader ,每个数据中心只能运行一台服务器。技术角度上讲 Leader 是通过 Raft 算法选举的,但是集群第一次启动时需要一个引导 Leader,在引导群集后,建议不要使用此标志。
- ui: 表示启动 Web UI 管理器,默认开放端口 8500,所以上面使用 Docker 命令把 8500 端口对外开放。
- node: 节点的名称,集群中必须是唯一的,默认是该节点的主机名。
- client: consul服务侦听地址,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1所以不对外提供服务,如果你要对外提供服务改成0.0.0.0
- join: 表示加入到某一个集群中去。 如:-json=192.168.0.11。
3.2、配置
我们将 keygen 保存到一个单独的文件中,以便在丢失 consul 配置文件时进行备份
consul keygen > /etc/consul.d/consul.keygen
要配置 consul,我们将编辑 /etc/consul.d/consul.hcl 并添加以下配置:
datacenter = "marcsg"
bootstrap_expect = 1
server = true
data_dir = "/opt/consul"
log_level = "INFO"
client_addr = "0.0.0.0"
bind_addr = "172.21.1.11" #多网卡需指定
node_name = "consul"
leave_on_terminate = true
rejoin_after_leave = true
connect{
enabled = true
}
ui_config{
enabled = true
}
encrypt = "3EY9MGe2a1ElUNrsl5E6rHAtJEL7lqe+1CDZAyY8yTU="
- datacenter: 将确定我们的数据中心名称,必须与我们的客户相同。
- bootstrap_expect: 预期的领事服务器数量。
- server: 将其设置为 true 将使我们的 consul 服务作为服务器运行,而不是作为客户端或代理运行。
- data_dir: consul 的默认数据目录,它存储一些持久服务器值。
- log_level: 在运行 consul 的命令时我们将如何处理日志。
- client_addr: 我们的客户地址,如果我们想要更多地保护它,我们可以使用 - 子网划分或只允许来自确定的 ip 的连接。
- bind_addr: 我们的服务器ip地址,如果只使用一个网卡则不需要
- node_name: 我们的领事节点名称,如果未定义,它将使用机器 - 主机名。
- leave_on_terminate: 终止实例时离开集群
- rejoin_after_leave: 离开前加入集群
- connect: 允许网状连接。
- ui_config: 基于Web的用户界面。
- encrypt: 我们之前生成的consul 密钥。
3.3、启动
# Change consul directories permissions
chown -R consul:consul /opt/consul
chown -R consul:consul /etc/consul.d
# Enable consul service
systemctl enable consul.service
systemctl start consul.service
systemctl status consul.service
现在,如果我们去http://172.21.1.11:8500
我们可以访问 consul 的 web ui 并查看我们的上/下服务,目前它只是 consul 服务器本身
四、API 注册服务到 Consul
接下来,我们要注册服务到 Consul 中,可以通过其提供的 API 标准接口来添加。consul主要是添加和删除命令,都是使用接口调用
#删除
$ curl -X PUT http://172.21.1.11:8500/v1/agent/service/deregister/node-exporter-172.21.1.22
#添加(以node:172.21.1.21 为例)
$ curl -X PUT -d '{"id": "node-exporter","name": "node-exporter-172.21.1.21","address": "172.21.1.21","port":"9100","tags": ["test"],"checks": [{"http": "http://172.21.1.21:9100/","interval": "5s"}]}' http://172.21.1.11:8500/v1/agent/service/register
执行完毕后,刷新一下 Consul Web 控制台页面,可以看到成功注册到 Consul 中。
批量添加可以使用下面脚本:
##hosts文件格式
node01 172.21.1.21
node02 172.21.1.22
$ cat registry.sh # 脚本内容如下
#!/bin/bash
while read host_name host_addr
do
curl -X PUT -d '{"id": "'${host_name}'","name": "node-exporter","address": "'${host_addr}'","port":9100,"tags": ["dam"],"checks": [{"http": "http://'${host_addr}':9100/","interval": "15s"}]}' http://172.21.1.11:8500/v1/agent/service/register
done < hosts
五、配置 Prometheus 实现自动服务发现
现在 Consul 服务已经启动完毕,并成功注册了一个服务,接下来,我们需要配置 Prometheus 来使用 Consul 自动服务发现,目的就是能够将上边添加的服务自动发现到 Prometheus 的 Targets 中,增加 prometheus.yml 配置如下:
$ cat /usr/local/prometheus/prometheus.yml
#类似下面格式 这个server为consul的地址,根据标签匹配组
- job_name: 'consul-prometheus'
consul_sd_configs:
- server: '172.21.1.11:8500'
services: [node-exporter]
#复杂一点,需要正则表达式
- job_name: dam-exporter
honor_labels: true
metrics_path: /metrics
scheme: http
consul_sd_configs:
- server: 172.21.1.11:8500
services: [node-exporter]
relabel_configs:
- source_labels: ['__meta_consul_tags']
target_label: 'product'
- source_labels: ['__meta_consul_dc']
target_label: 'idc'
- source_labels: ['product']
regex: ",node-exporter,"
action: keep
说明一下:这里需要使用 consul_sd_configs 来配置使用 Consul 服务发现类型,server 为 Consul 的服务地址,这里跟上边要对应上。 配置完毕后,重启 Prometheus 服务,此时可以通过 Prometheus UI 页面的 Targets 下查看是否配置成功。
可以看到,在 Targets 中能够成功的自动发现 Consul 中的 Services 信息,后期需要添加新的 Targets 时,只需要通过 API 往 Consul 中注册服务即可,Prometheus 就能自动发现该服务,是不是很方便。
不过,我们会发现有如下几个问题:
会发现 Prometheus 同时加载出来了默认服务 consul,这个是不需要的。
默认只显示 job 及 instance 两个标签,其他标签都默认属于 before relabeling 下,有些必要的服务信息,也想要在标签中展示,该如何操作呢?
如果需要自定义一些标签,例如 team、group、project 等关键分组信息,方便后边 alertmanager 进行告警规则匹配,该如何处理呢?
所有 Consul 中注册的 Service 都会默认加载到 Prometheus 下配置的 consul_prometheus 组,如果有多种类型的 exporter,如何在 Prometheus 中配置分配给指定类型的组,方便直观的区别它们?
以上问题,我们可以通过 Prometheus 配置中的 relabel_configs 参数来解决。
六、配置 relabel_configs 实现自定义标签及分类
我们先来普及一下 relabel_configs 的功能, Prometheus 允许用户在采集任务设置中,通过 relabel_configs 来添加自定义的 Relabeling 的额过程,来对标签进行指定规则的重写。 Prometheus 加载 Targets 后,这些 Targets 会自动包含一些默认的标签,Target 以 __ 作为前置的标签是在系统内部使用的,这些标签不会被写入到样本数据中。眼尖的会发现,每次增加 Target 时会自动增加一个 instance 标签,而 instance 标签的内容刚好对应 Target 实例的 __address__ 值,这是因为实际上 Prometheus 内部做了一次标签重写处理,默认 __address__ 标签设置为 <host>:<port> 地址,经过标签重写后,默认会自动将该值设置为 instance 标签,所以我们能够在页面看到该标签。
详细 relabel_configs 配置及说明可以参考 relabel_config 官网说明,这里我简单列举一下里面每个 relabel_action 的作用,方便下边演示。
replace: 根据 regex 的配置匹配 source_labels 标签的值(注意:多个 source_label 的值会按照 separator 进行拼接),并且将匹配到的值写入到 target_label 当中,如果有多个匹配组,则可以使用 ${1}, ${2} 确定写入的内容。如果没匹配到任何内容则不对 target_label 进行重新, 默认为 replace。
keep: 丢弃 source_labels 的值中没有匹配到 regex 正则表达式内容的 Target 实例
drop: 丢弃 source_labels 的值中匹配到 regex 正则表达式内容的 Target 实例
hashmod: 将 target_label 设置为关联的 source_label 的哈希模块
labelmap: 根据 regex 去匹配 Target 实例所有标签的名称(注意是名称),并且将捕获到的内容作为为新的标签名称,regex 匹配到标签的的值作为新标签的值
labeldrop: 对 Target 标签进行过滤,会移除匹配过滤条件的所有标签
labelkeep: 对 Target 标签进行过滤,会移除不匹配过滤条件的所有标签
接下来,我们来挨个处理上述问题。
问题一,我们可以配置 relabel_configs 来实现标签过滤,只加载符合规则的服务。以上边为例,可以通过过滤 __meta_consul_tags 标签为 test 的服务,relabel_config 向 Consul 注册服务的时候,只加载匹配 regex 表达式的标签的服务到自己的配置文件。修改 prometheus.yml 配置如下:
...
- job_name: 'consul-prometheus'
consul_sd_configs:
- server: '172.30.12.167:8500'
services: []
relabel_configs:
- source_labels: [__meta_consul_tags]
regex: .*test.*
action: keep
解释下,这里的 relabel_configs 配置作用为丢弃源标签中 __meta_consul_tags 不包含 test 标签的服务,__meta_consul_tags 对应到 Consul 服务中的值为 "tags": ["test"],默认 consul 服务是不带该标签的,从而实现过滤。重启 Prometheus 可以看到现在只获取了 node-exporter-172.30.12.167 这个服务了。
问题二和问题三可以归为一类,就是将系统默认标签或者用户自定义标签转换成可视化标签,方便查看及后续 Alertmanager 进行告警规则匹配分组。不过要实现给服务添加自定义标签,我们还得做一下修改,就是在注册服务时,将自定义标签信息添加到 Meta Data 数据中,具体可以参考 [这里](Consul Service - Agent HTTP API) 官网说明,下边来演示一下如何操作。
新建 consul-0.json 如下:
$ vim consul-0.json
{
"ID": "node-exporter",
"Name": "node-exporter-172.30.12.167",
"Tags": [
"test"
],
"Address": "172.30.12.167",
"Port": 9100,
"Meta": {
"app": "spring-boot",
"team": "appgroup",
"project": "bigdata"
},
"EnableTagOverride": false,
"Check": {
"HTTP": "http://172.30.12.167:9100/metrics",
"Interval": "10s"
},
"Weights": {
"Passing": 10,
"Warning": 1
}
}
说明一下:该 Json 文件为要注册的服务信息,同时往 Meta 信息中添加了 app=spring-boot,team=appgroup,project=bigdata 三组标签,目的就是为了方便告警分组使用。执行如下命令进行注册:
$ curl --request PUT --data @consul-0.json http://172.30.12.167:8500/v1/agent/service/register?replace-existing-checks=1
参数:
- replace-existing-checks:对请求进行检查,删除没有健康检查的部分。以URL方式提供。
- Name:指定服务名称,必选。
- ID:指定服务ID,如果未指定,默认为服务名称。
- Tags:指定标记,用于筛选。
- Address:指定服务的地址。
- Port:指定服务的端口。
- Meta:指定 KV 元数据。
- Weights:指定服务的权重。
- Check:指定健康检测。具体设置请参考健康检测部分。
注册完毕,通过 Consul Web 管理页面可以查看到已注册成功,并且包含了 Meta 信息。
然后修改 prometheus.yml 配置如下:
...
- job_name: 'consul-prometheus'
consul_sd_configs:
- server: '172.30.12.167:8500'
services: []
relabel_configs:
- source_labels: [__meta_consul_tags]
regex: .*test.*
action: keep
- regex: __meta_consul_service_metadata_(.+)
action: labelmap
解释一下,增加的配置作用为匹配 __meta_consul_service_metadata_ 开头的标签,将捕获到的内容作为新的标签名称,匹配到标签的的值作为新标签的值,而我们刚添加的三个自定义标签,系统会自动添加 __meta_consul_service_metadata_app=spring-boot、__meta_consul_service_metadata_team=appgroup、__meta_consul_service_metadata_project=bigdata 三个标签,经过 relabel 后,Prometheus 将会新增 app=spring-boot、team=appgroup、project=bigdata 三个标签。重启 Prometheus 服务,可以看到新增了对应了三个自定义标签。
问题四,将自动发现的服务进行分类,本质上跟上边的处理方式一致,可以添加自定义的标签方式,通过标签来区分,二可以通过服务 Tag 来进行匹配来创建不同的类型 exporter 分组。这里我以第二种为例,通过给每个服务标记不同的 Tag,然后通过 relabel_configs 来进行匹配区分。我们来更新一下原 node-exporter-172.30.12.167 服务标签,同时注册一个其他类型 exporter 的服务如下:
$ vim consul-1.json
{
"ID": "node-exporter",
"Name": "node-exporter-172.30.12.167",
"Tags": [
"node-exporter"
],
"Address": "172.30.12.167",
"Port": 9100,
"Meta": {
"app": "spring-boot",
"team": "appgroup",
"project": "bigdata"
},
"EnableTagOverride": false,
"Check": {
"HTTP": "http://172.30.12.167:9100/metrics",
"Interval": "10s"
},
"Weights": {
"Passing": 10,
"Warning": 1
}
}
# 更新注册服务
$ curl --request PUT --data @consul-1.json http://172.30.12.167:8500/v1/agent/service/register?replace-existing-checks=1
$ vim consul-2.json
{
"ID": "cadvisor-exporter",
"Name": "cadvisor-exporter-172.30.12.167",
"Tags": [
"cadvisor-exporter"
],
"Address": "172.30.12.167",
"Port": 8080,
"Meta": {
"app": "docker",
"team": "cloudgroup",
"project": "docker-service"
},
"EnableTagOverride": false,
"Check": {
"HTTP": "http://172.30.12.167:8080/metrics",
"Interval": "10s"
},
"Weights": {
"Passing": 10,
"Warning": 1
}
}
# 注册服务
$ curl --request PUT --data @consul-2.json http://172.30.12.167:8500/v1/agent/service/register?replace-existing-checks=1
说明一下,我们更新了原 node-exporter-172.30.12.167 服务的标签为 node-exporter,同时注册一个新类型 cadvisor-exporter-172.30.12.167 服务,并设置标签为 cadvisor-exporter,以示区别。注册完毕,通过 Consul Web 控制台可以看到成功注册了这两个服务。
最后,我们修改 prometheus.yml 配置如下:
...
- job_name: 'consul-node-exporter'
consul_sd_configs:
- server: '172.30.12.167:8500'
services: []
relabel_configs:
- source_labels: [__meta_consul_tags]
regex: .*node-exporter.*
action: keep
- regex: __meta_consul_service_metadata_(.+)
action: labelmap
- job_name: 'consul-cadvisor-exproter'
consul_sd_configs:
- server: '172.30.12.167:8500'
services: []
relabel_configs:
- source_labels: [__meta_consul_tags]
regex: .*cadvisor-exporter.*
action: keep
- regex: __meta_consul_service_metadata_(.+)
action: labelmap
这里需要根据每种类型的 exporter 新增一个关联 job,同时 relabel_configs 中配置以 Tag 来做匹配区分。重启 Prometheus 服务,可以看到服务已经按照类型分类了,方便查看。
备份还原导入导出
备份与还原
需要备份的主要有两类数据:consul相关的配置文件、consul的服务器状态,采用下面的脚本备份就可以了:
ts=$(date +%Y%m%d%H%M%S)
# 备份配置文件
tar -czpf consul_config_$ts.tar.gz /etc/consul/config.json /etc/consul/consul.d
# 备份consul的服务器状态,注意由于该consul开启了ACL,执行consul snapshot save时必须带Management Token
# 关于consul ACL token的说明见上一篇"consul安全加固"
consul snapshot save --http-addr=http://172.21.1.11:8500 -token=b3a9bca3-6e8e-9678-ea35-ccb8fb272d42 consul_state_$ts.snap
# 查看一下生成的consul服务器状态文件
consul snapshot inspect consul_state_$ts.snap
最后将生成的consul_config_xxx.tar.gz
、consul_state_xxx.snap
拷贝到其它服务器妥善存储。
还原也比较简单,采用下面的脚本就可以了:
# 还原配置文件
tar -xzpf consul_config_20180521145032.tar.gz -C /
# 还原consul服务器状态
consul snapshot restore --http-addr=http://172.21.1.11:8500 -token=b3a9bca3-6e8e-9678-ea35-ccb8fb272d42 consul_state_20180521145032.snap
KV存储的导入导出
consul直接提供命令对KV里存储的数据进行导入导出,如下:
$ ts=$(date +%Y%m%d%H%M%S)
# 导出所有kv键值对,注意最后一个参数是导出键值对的前缀,为空字符串说明要导出所有
$ consul kv export --http-addr=http://172.21.1.11:8500 -token=b3a9bca3-6e8e-9678-ea35-ccb8fb272d42 '' > consul_kv_$ts.json
# 查看下导出的json文件格式
$ cat consul_kv_$ts.json
[
{
"key": "xxxxxx",
"flags": 0,
"value": "yyyyyy"
},
{
"key": "xxxxxx2",
"flags": 0,
"value": "eyJ2ZXJzaW9uX3RpbWVzdGFtcCI6IC0xfQ=="
},
]
发现是每个键值对都是json数值中一项,其中key为键值对Key的名称,value为键值对Value的base64编码,使用base64 -d
命令编码就可以看到原始的value值,如:
$ echo 'eyJ2ZXJzaW9uX3RpbWVzdGFtcCI6IC0xfQ==' | base64 -d
{"version_timestamp": -1}
导入就更简单了:
consul kv import --http-addr=http://172.21.1.11:8500 -token=b3a9bca3-6e8e-9678-ea35-ccb8fb272d42 @consul_kv_20180521150322.json
参考链接:https://blog.csdn.net/aixiaoyang168/article/details/103022342