转载自:https://cloud.tencent.com/developer/article/1611091

1、Consul 介绍

Consul 是基于 GO 语言开发的开源工具,主要面向分布式,服务化的系统提供服务注册、服务发现和配置管理的功能。Consul 提供服务注册/发现、健康检查、Key/Value存储、多数据中心和分布式一致性保证等功能。Prometheus 通过 Consul 可以很方便的实现服务自动发现和维护,同时 Consul 支持分布式集群部署,将大大提高了稳定性,通过 Prometheus 跟 Consul 集群二者结合起来,能够高效的进行数据维护同时保证系统稳定。

2、环境、软件准备

本次演示环境,我是在虚拟机上安装 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,我使用 Docker 方式启动,所以本机需要安装好 Docker 环境,这里忽略 Docker 的安装过程。其中 Prometheus 安装配置,可以参照之前文章 Prometheus 监控报警系统 AlertManager 之邮件告警,这里着重介绍一下如何配置 Consul 分布式集群,以及使用 nginx 来负载均衡 Consul 集群,最后分别验证配置 Prometheus 基于 Consul 集群来实现自动服务发现。

3、Consul 分布式集群搭建

Consul 单机安装很方便,官网 提供各个系统版本二进制安装包,解压安装即可,可以参照之前文章 Prometheus 通过 consul 实现自动服务发现 文章来安装。这里我们要搭建 Consul 分布式集群,既然是分布式集群,那么肯定至少得部署到三台机器上,组成一个集群,苦于手上没有那么多的机器,我们只能在一台机器上部署三个 Consul 服务来模拟 “分布式” 集群,Consul 默认以 client 方式启动,这里我们采用 Server 方式来启动实例,通过不同的端口来区分不同的服务,集群实例如下:

  • 172.30.12.100:8500 node1 leader
  • 172.30.12.100:8510 node2 follower
  • 172.30.12.100:8520 node2 follower

下载最新版二进制安装包,解压后并拷贝到 /usr/local/bin 目录下

$ cd /root/prometheus/consul
$ wget https://releases.hashicorp.com/consul/1.6.1/consul_1.6.1_linux_amd64.zip
$ unzip consul_1.6.1_linux_amd64.zip
$ mv consul /usr/local/bin

集群启动三个实例,这里因为在一台机器上,直接使用 consul anget -server -bootstrap-expect=3 -data-dir=xxx...命令来启动,稍显麻烦且不直观,这里我们采用配置文件的方式分别启动实例。配置 node1 实例,新建配置文件 consul01.json 如下 :

{
"datacenter": "dc1",
"data_dir": "/root/prometheus/consul/consul01",
"log_level": "INFO",
"server": true,
"node_name": "node1",
"ui": true,
"bind_addr": "172.30.12.100",
"client_addr": "0.0.0.0",
"advertise_addr": "172.30.12.100",
"bootstrap_expect": 3,
"ports":{
"http": 8500,
"dns": 8600,
"server": 8300,
"serf_lan": 8301,
"serf_wan": 8302
}
}

说明一下参数:

  • datacenter:数据中心名称
  • data_dir:数据存放本地目录
  • log_level:输出的日志级别
  • server:以 server 身份启动实例,不指定默认为 client
  • node_name:节点名称,集群中每个 node 名称不能重复,默认情况使用节点 hostname
  • ui:指定是否可以访问 UI 界面
  • bind_addr:监听的 IP 地址,指 Consul 监听的地址,该地址必须能够被集群中的所有节点访问,默认监听 0.0.0.0
  • client_addr:客户端监听地址,0.0.0.0 表示所有网段都可以访问
  • advertise_addr:集群广播地址
  • bootstrap_expect:集群要求的最少成员数量
  • ports:该参数详细配置各个服务端口,如果想指定其他端口,可以修改这里。

后台启动一下 node1 Consul 服务,执行如下命令启动:

nohup consul agent -config-dir=consul01.json > ./consul01.log 2>&1 &

查看服务启动日志会发现如下输出:

ootstrap_expect > 0: expecting 3 servers
==> Starting Consul agent...
Version: 'v1.6.1'
Node ID: '18450af8-64a3-aa0f-2a6c-4c2fc6e35a4b'
Node name: 'node1'
Datacenter: 'dc1' (Segment: '<all>')
Server: true (Bootstrap: false)
Client Addr: [0.0.0.0] (HTTP: 8500, HTTPS: -1, gRPC: -1, DNS: 8600)
Cluster Addr: 172.30.12.100 (LAN: 8301, WAN: 8302)
Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false, Auto-Encrypt-TLS: false ==> Log data will now stream in as it occurs: 2020/03/30 17:03:18 [INFO] raft: Initial configuration (index=0): []
2020/03/30 17:03:18 [INFO] raft: Node at 172.30.12.100:8300 [Follower] entering Follower state (Leader: "")
2020/03/30 17:03:18 [INFO] serf: EventMemberJoin: node1.dc1 172.30.12.100
2020/03/30 17:03:18 [INFO] serf: EventMemberJoin: node1 172.30.12.100
2020/03/30 17:03:18 [INFO] agent: Started DNS server 0.0.0.0:8600 (udp)
2020/03/30 17:03:18 [INFO] consul: Handled member-join event for server "node1.dc1" in area "wan"
2020/03/30 17:03:18 [INFO] consul: Adding LAN server node1 (Addr: tcp/172.30.12.100:8300) (DC: dc1)
2020/03/30 17:03:18 [INFO] agent: Started DNS server 0.0.0.0:8600 (tcp)
2020/03/30 17:03:18 [INFO] agent: Started HTTP server on [::]:8500 (tcp)
2020/03/30 17:03:18 [INFO] agent: started state syncer
==> Consul agent running!
==> Newer Consul version available: 1.7.2 (currently running: 1.6.1)
2020/03/30 17:03:23 [WARN] raft: no known peers, aborting election
2020/03/30 17:03:25 [ERR] agent: failed to sync remote state: No cluster leader

我们会看到类似 [ERR] agent: failed to sync remote state: No cluster leader 这样的报错,这是因为目前还没有任何其他实例加入,无法构成一个集群。接下来,按照上边的配置,启动第二个实例 node2,并加入到 node1 集群中,新建配置文件 consul02.json 如下 :

{
"datacenter": "dc1",
"data_dir": "/root/prometheus/consul/consul02",
"log_level": "INFO",
"server": true,
"node_name": "node2",
"ui": true,
"bind_addr": "172.30.12.100",
"client_addr": "0.0.0.0",
"advertise_addr": "172.30.12.100",
"bootstrap_expect": 3,
"ports":{
"http": 8510,
"dns": 8610,
"server": 8310,
"serf_lan": 8311,
"serf_wan": 8312
}
}

注意:由于这里是一台服务器上启动了多个实例,所以必须修改各个服务端口号,否则会报错,这里新启动的 Consul 服务端口为 8510。启动 node2 Consul 服务,并加入到 node1 Consul 服务中组成集群,启动命令如下:

nohup consul agent -config-dir=consul02.json -join 172.30.12.100:8301 > ./consul02.log 2>&1 &

启动完毕后,此时会发现 node1 的日志输出中会打印如下日志:

    2020/03/30 17:14:54 [INFO] serf: EventMemberJoin: node2 172.30.12.100
2020/03/30 17:14:54 [INFO] consul: Adding LAN server node2 (Addr: tcp/172.30.12.100:8310) (DC: dc1)
2020/03/30 17:14:54 [INFO] serf: EventMemberJoin: node2.dc1 172.30.12.100
2020/03/30 17:14:54 [INFO] consul: Handled member-join event for server "node2.dc1" in area "wan"

可以看到 node2 成功加入到 node1 集群,不过接下来它还会一直报错 agent: failed to sync remote state: No cluster leader,这是为什么?日志明明已经显示 node2 成功加入了,怎么还一直报错呢?这是因为我们创建时指定了 bootstrap_expect3,那么就必须至少存在 3 个实例才能组成该 Consul 集群。那么,依照以上步骤,继续启动 node3 Consul 服务并添加到 node1 集群中,新建配置文件 consul03.json 如下:

{
"datacenter": "dc1",
"data_dir": "/root/prometheus/consul/consul03",
"log_level": "INFO",
"server": true,
"node_name": "node3",
"ui": true,
"bind_addr": "172.30.12.100",
"client_addr": "0.0.0.0",
"advertise_addr": "172.30.12.100",
"bootstrap_expect": 3,
"ports":{
"http": 8520,
"dns": 8620,
"server": 8320,
"serf_lan": 8321,
"serf_wan": 8322
}
}

启动 node3 Consul 实例命令如下:

nohup consul agent -config-dir=consul03.json -join 172.30.12.100:8301 > ./consul03.log 2>&1 &

此时,我们会发现 node1 日志输出中会打印如下日志:

    2020/03/30 17:24:39 [INFO] serf: EventMemberJoin: node3 172.30.12.100
2020/03/30 17:24:39 [INFO] consul: Adding LAN server node3 (Addr: tcp/172.30.12.100:8320) (DC: dc1)
2020/03/30 17:24:39 [INFO] consul: Found expected number of peers, attempting bootstrap: 172.30.12.100:8300,172.30.12.100:8310,172.30.12.100:8320
2020/03/30 17:24:39 [INFO] serf: EventMemberJoin: node3.dc1 172.30.12.100
2020/03/30 17:24:39 [INFO] consul: Handled member-join event for server "node3.dc1" in area "wan"
2020/03/30 17:24:40 [WARN] raft: Heartbeat timeout from "" reached, starting election
2020/03/30 17:24:40 [INFO] raft: Node at 172.30.12.100:8300 [Candidate] entering Candidate state in term 2
2020/03/30 17:24:40 [INFO] raft: Election won. Tally: 2
2020/03/30 17:24:40 [INFO] raft: Node at 172.30.12.100:8300 [Leader] entering Leader state
2020/03/30 17:24:40 [INFO] raft: Added peer b7212be5-7d33-a5b6-0ca8-522f05ab9eeb, starting replication
2020/03/30 17:24:40 [INFO] raft: Added peer 0afe6fcb-3a07-e443-3802-f822ae9df422, starting replication
2020/03/30 17:24:40 [INFO] consul: cluster leadership acquired
2020/03/30 17:24:40 [INFO] consul: New leader elected: node1
2020/03/30 17:24:40 [WARN] raft: AppendEntries to {Voter 0afe6fcb-3a07-e443-3802-f822ae9df422 172.30.12.100:8320} rejected, sending older logs (next: 1)
2020/03/30 17:24:40 [INFO] raft: pipelining replication to peer {Voter 0afe6fcb-3a07-e443-3802-f822ae9df422 172.30.12.100:8320}
2020/03/30 17:24:40 [WARN] raft: AppendEntries to {Voter b7212be5-7d33-a5b6-0ca8-522f05ab9eeb 172.30.12.100:8310} rejected, sending older logs (next: 1)
2020/03/30 17:24:40 [INFO] raft: pipelining replication to peer {Voter b7212be5-7d33-a5b6-0ca8-522f05ab9eeb 172.30.12.100:8310}
2020/03/30 17:24:40 [INFO] consul: member 'node1' joined, marking health alive
2020/03/30 17:24:40 [INFO] consul: member 'node2' joined, marking health alive
2020/03/30 17:24:40 [INFO] consul: member 'node3' joined, marking health alive
2020/03/30 17:24:42 [INFO] agent: Synced node info

node3 成功加入到 node1 集群,整个集群已选出 node1 作为新的 Leader,此时集群状态为 health,那么整个 “分布式” 集群就搭建完毕了。此时,浏览器访问以下任意一个 http://127.0.0.1:8500http://127.0.0.1:8510http://127.0.0.1:8520 地址,均可打开 Consul Web 管理页面。

我们也可以通过命令行查看集群状态、以及集群成员状态。

# 查看集群状态
$ consul operator raft list-peers
Node ID Address State Voter RaftProtocol
node1 18450af8-64a3-aa0f-2a6c-4c2fc6e35a4b 172.30.12.100:8300 leader true 3
node2 b7212be5-7d33-a5b6-0ca8-522f05ab9eeb 172.30.12.100:8310 follower true 3
node3 0afe6fcb-3a07-e443-3802-f822ae9df422 172.30.12.100:8320 follower true 3
# 查看集群成员状态
$ consul members
Node Address Status Type Build Protocol DC Segment
node1 172.30.12.100:8301 alive server 1.6.1 2 dc1 <all>
node2 172.30.12.100:8311 alive server 1.6.1 2 dc1 <all>
node3 172.30.12.100:8321 alive server 1.6.1 2 dc1 <all>

4、配置 Prometheus 实现自动服务发现

接下来,我们配置 Prometheus 来使用 Consul 集群来实现自动服务发现,目的就是能够将添加的服务自动发现到 Prometheus 的 Targets 中,详细配置说明可以参考之前文章 Prometheus 通过 consul 实现自动服务发现 中的配置,在修改 Prometheus 配置之前,我们需要往 Consul 集群中注册一些数据。首先,我们注册一个 node-exporter-172.30.12.100 的服务,新建 consul-1.json 如下:

{
"ID": "node-exporter",
"Name": "node-exporter-172.30.12.100",
"Tags": [
"node-exporter"
],
"Address": "172.30.12.100",
"Port": 9100,
"Meta": {
"app": "spring-boot",
"team": "appgroup",
"project": "bigdata"
},
"EnableTagOverride": false,
"Check": {
"HTTP": "http://172.30.12.100:9100/metrics",
"Interval": "10s"
},
"Weights": {
"Passing": 10,
"Warning": 1
}
} # 调用 API 注册服务
$ curl --request PUT --data @consul-1.json http://172.30.12.100:8500/v1/agent/service/register?replace-existing-checks=1

然后,我们再注册一个 cadvisor-exporter-172.30.12.100 的服务,新建 consul-2.json 并执行如下命令:

{
"ID": "cadvisor-exporter",
"Name": "cadvisor-exporter-172.30.12.100",
"Tags": [
"cadvisor-exporter"
],
"Address": "172.30.12.100",
"Port": 8080,
"Meta": {
"app": "docker",
"team": "cloudgroup",
"project": "docker-service"
},
"EnableTagOverride": false,
"Check": {
"HTTP": "http://172.30.12.100:8080/metrics",
"Interval": "10s"
},
"Weights": {
"Passing": 10,
"Warning": 1
}
} # 调用 API 注册服务
$ curl --request PUT --data @consul-2.json http://172.30.12.100:8500/v1/agent/service/register?replace-existing-checks=1

注册完毕,通过 Consul Web 管理页面可以查看到两服务已注册成功。注意:这里需要启动 node-exporter 及 cadvisor-exporter,否则即使注册成功了,健康检测也不通过,在后边 Prometheus 上服务发现后状态也是不健康的,这里我就不在演示了,可以直接拿 Docker 启动二者即可。

接下来,我们修改 Prometheus 配置如下:

...
- job_name: 'consul-node-exporter'
consul_sd_configs:
- server: '172.30.12.100: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.100:8510'
services: []
- server: '172.30.12.100:8520'
services: []
relabel_configs:
- source_labels: [__meta_consul_tags]
regex: .*cadvisor-exporter.*
action: keep
- action: labelmap
regex: __meta_consul_service_metadata_(.+)
...

启动一下 Prometheus 服务,通过 web 界面看下 Target 中是否能够发现 Consul 中注册的服务。

可以看到,妥妥没有问题,这里 consul-node-exporter 我配置指向了 node1 Consul 服务地址,consul-cadvisor-exproter 配置指向了 node2、node3 Consul 服务,二者都能够正确发现之前注册的服务,因为 Consul 集群数据是保持同步的,无论连接哪一个节点,都能够获取到注册的服务信息,同理,我们也可以指定 consul_sd_configs 分别指向集群所有节点,这样即使某个节点挂掉,也不会影响 Prometheus 从 Consul 集群其他节点获取注册的服务,从而实现服务的高可用。

5、配置 nginx 负载均衡 Consul 集群

虽然我们可以将整个 Consul 集群 IP 添加到 Prometheus 的配置中,从而实现 Prometheus 从 Consul 集群获取注册的服务,实现服务的高可用,但是这里有个问题,如果 Consul 集群节点新增或者减少,那么 Prometheus 配置也得跟着修改了,这样不是很友好,我们可以在 Consul 集群前面使用 nginx 反向代理将请求负载均衡到后端 Consul 集群各节点服务上,这样 Prometheus 只需要配置代理地址即可,后期不需要更改了。

这里为了方便,nginx 也使用容器方式启动,新增配置文件 default.conf 如下:

upstream service_consul {
server 172.30.12.100:8500;
server 172.30.12.100:8510;
server 172.30.12.100:8520;
ip_hash;
} server {
listen 80;
server_name 172.30.12.100;
index index.html index.htm; #access_log /var/log/nginx/host.access.log main; location / {
add_header Access-Control-Allow-Origin *;
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://service_consul;
} access_log /var/log/consul.access.log;
error_log /var/log/consul.error.log; error_page 404 /404.html; error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

Docker 启动 nginx 服务,启动命令如下:

$ docker run --name nginx-consul -p 80:80 -v /root/prometheus/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro -d nginx

这里就没啥好说的了,启动完成后,可以浏览器访问一下 http://172.30.12.100/ui ,妥妥也是没有问题的。

最后,我们修改一下 Prometheus 配置文件,将 server 指向 172.30.12.100 即可,修改配置如下:

...
- job_name: 'consul-node-exporter'
consul_sd_configs:
- server: '172.30.12.100'
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.100'
services: []
relabel_configs:
- source_labels: [__meta_consul_tags]
regex: .*cadvisor-exporter.*
action: keep
- action: labelmap
regex: __meta_consul_service_metadata_(.+)
...

重启 prometheus 服务,验证也是妥妥没问题的。

Prometheus 通过 consul 分布式集群实现自动服务发现的更多相关文章

  1. 15、基于consul+consul-template+registrator+nginx实现自动服务发现

    一.架构图 二.组件介绍 1.Registrator Registrator:一个由Go语言编写的,针对docker使用的,通过检查本机容器进程在线或者停止运行状态,去注册服务的工具.所以我们要做的实 ...

  2. consul分布式集群搭建

    环境准备 三台机器: vm-a    10.200.110.90    centos7vm-b    10.200.110.91    centos7vm-c    10.200.110.93     ...

  3. consul分布式集群搭建&简单功能测试&故障恢复【h】

    环境准备五台机器: 操作系统 IP Ubuntu 16.04.3 LTS x86_64 192.168.1.185 Ubuntu 16.10 x86_64 192.168.3.152 Ubuntu 1 ...

  4. Redis Sentinel分布式集群

    helm部署Redis哨兵分布式集群 Redis Sentinel集群 介绍 Redis Sentinel集群是由若干Sentinel节点组成的分布式集群,可以实现故障发现.故障自动转移.配置中心和客 ...

  5. ElasticSearch 5学习(6)——分布式集群学习分享1

    在使用中我们把文档存入ElasticSearch,但是如果能够了解ElasticSearch内部是如何存储的,将会对我们学习ElasticSearch有很清晰的认识.本文中的所使用的ElasticSe ...

  6. Redis分布式集群几点说道

    原文地址:http://www.cnblogs.com/verrion/p/redis_structure_type_selection.html  Redis分布式集群几点说道 Redis数据量日益 ...

  7. MySQL分布式集群之MyCAT(转)

    原文地址:http://blog.itpub.net/29510932/viewspace-1664499/ 隔了好久,才想起来更新博客,最近倒腾的数据库从Oracle换成了MySQL,研究了一段时间 ...

  8. SolrCloud分布式集群部署步骤

    Solr及SolrCloud简介 Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口.用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成 ...

  9. redis高可用分布式集群

    一,高可用 高可用(High Availability),是当一台服务器停止服务后,对于业务及用户毫无影响. 停止服务的原因可能由于网卡.路由器.机房.CPU负载过高.内存溢出.自然灾害等不可预期的原 ...

随机推荐

  1. Scala的基础用法 和 Java相对应学习(二)变量、循环、语法

    一.配置相关环境 1.增加项目 在idea里面创建新的maven项目 2. 在pom文件中增加依赖 <?xml version="1.0" encoding="UT ...

  2. 倍增求RMQ

    RMQ,即区间最值查询,给定一个序列,求区间l-r的最大值.最小值. st表求RMQ,预处理On*logn,查询O1. 预处理: void init_rmq() { for(rll j=1;j< ...

  3. C#基础语法之-泛型

    泛型:一共7个知识点 1.引入泛型,延迟声明 2.如何声明和使用泛型 3.泛型的好处和原理 4.泛型类,泛型方法,泛型接口,泛型委托 5.泛型约束 6.协变,逆变 7.泛型缓存 一.为啥会出现泛型,有 ...

  4. Mybatis的使用(1)

    1:新建maven项目,file->project->maven 2:在建好的maven项目中,打开pom.xml文件,加入mybatis所需要的依赖: <!-- mybatis核心 ...

  5. Nginx Rewrite资源重定向

    # Rewrite功能配置 # Rewrite功能主要是实现了url重写 # 如:你输入www.jd123.com,你可以通过Rewrite让它重定向到www.jd.com # Rewrite的实现依 ...

  6. Spring源码 12 IOC refresh方法7

    本文章基于 Spring 5.3.15 Spring IOC 的核心是 AbstractApplicationContext 的 refresh 方法. 其中一共有 13 个主要方法,这里分析第 7 ...

  7. Git 使用技巧(一):合并分支

    在合并分支之前最好保证你所有的分支都是最新的,所以你可以使用 git pull origin branchName 来拉取远程仓库到本地仓库. 假如有一个 dev 分支需要合并到 master 分支中 ...

  8. Rust实战系列-基本语法

    本文是<Rust in action>学习总结系列的第二部分,更多内容请看已发布文章: 一.Rust实战系列-Rust介绍 " 主要介绍 Rust 的语法.基本类型和数据结构,通 ...

  9. 如何使用.NET 6的IHostedService和BackgroundService?

    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 本章是<定制ASP NET 6.0框架系列文章>的第七篇.本文内容和定 ...

  10. Mysql和Redis数据如何保持一致

    先阐明一下Mysql和Redis的关系:Mysql是数据库,用来持久化数据,一定程度上保证数据的可靠性:Redis是用来当缓存,用来提升数据访问的性能. 关于如何保证Mysql和Redis中的数据一致 ...