本章节会对consul的架构与配置作全面讲解。html
上图是官网提供的一个事例系统图,图中的Server是consul服务端高可用集群,Client是consul客户端。consul客户端不保存数据,客户端将接收到的请求转发给响应的Server端。Server之间经过局域网或广域网通讯实现数据一致性。每一个Server或Client都是一个consul agent。node
Consul集群间使用了GOSSIP协议通讯和raft一致性算法。上面这张图涉及到了不少术语:python
Agent——agent是一直运行在Consul集群中每一个成员上的守护进程。经过运行consul agent来启动。agent能够运行在client或者server模式。指定节点做为client或者server是很是简单的,除非有其余agent实例。全部的agent都能运行DNS或者HTTP接口,并负责运行时检查和保持服务同步。mysql
Client——一个Client是一个转发全部RPC到server的代理。这个client是相对无状态的。client惟一执行的后台活动是加入LAN gossip池。这有一个最低的资源开销而且仅消耗少许的网络带宽。linux
Server——一个server是一个有一组扩展功能的代理,这些功能包括参与Raft选举,维护集群状态,响应RPC查询,与其余数据中心交互WAN gossip和转发查询给leader或者远程数据中心。nginx
DataCenter——虽然数据中心的定义是显而易见的,可是有一些细微的细节必须考虑。例如,在EC2中,多个可用区域被认为组成一个数据中心。咱们定义数据中心为一个私有的,低延迟和高带宽的一个网络环境。这不包括访问公共网络,可是对于咱们而言,同一个EC2中的多个可用区域能够被认为是一个数据中心的一部分。web
Consensus——一致性,使用Consensus来代表就leader选举和事务的顺序达成一致。为了以容错方式达成一致,通常有超过半数一致则能够认为总体一致。Consul使用Raft实现一致性,进行leader选举,在consul中的使用bootstrap时,能够进行自选,其余server加入进来后bootstrap就能够取消。redis
Gossip——Consul创建在Serf的基础之上,它提供了一个用于多播目的的完整的gossip协议。Serf提供成员关系,故障检测和事件广播。Serf是去中心化的服务发现和编制的解决方案,节点失败侦测与发现,具备容错、轻量、高可用的特色。算法
LAN Gossip——它包含全部位于同一个局域网或者数据中心的全部节点。sql
WAN Gossip——它只包含Server。这些server主要分布在不一样的数据中心而且一般经过因特网或者广域网通讯。
在每一个数据中心,client和server是混合的。通常建议有3-5台server。这是基于有故障状况下的可用性和性能之间的权衡结果,由于越多的机器加入达成共识越慢。然而,并不限制client的数量,它们能够很容易的扩展到数千或者数万台。
同一个数据中心的全部节点都必须加入gossip协议。这意味着gossip协议包含一个给定数据中心的全部节点。这服务于几个目的:第一,不须要在client上配置server地址。发现都是自动完成的。第二,检测节点故障的工做不是放在server上,而是分布式的。这使的故障检测相比心跳机制有更高的可扩展性。第三:它用来做为一个消息层来通知事件,好比leader选举发生时。
每一个数据中心的server都是Raft节点集合的一部分。这意味着它们一块儿工做并选出一个leader,一个有额外工做的server。leader负责处理全部的查询和事务。做为一致性协议的一部分,事务也必须被复制到全部其余的节点。由于这一要求,当一个非leader得server收到一个RPC请求时,它将请求转发给集群leader。
server节点也做为WAN gossip Pool的一部分。这个Pool不一样于LAN Pool,由于它是为了优化互联网更高的延迟,而且它只包含其余Consul server节点。这个Pool的目的是为了容许数据中心可以以low-touch的方式发现彼此。这使得一个新的数据中心能够很容易的加入现存的WAN gossip。由于server都运行在这个pool中,它也支持跨数据中心请求。当一个server收到来自另外一个数据中心的请求时,它随即转发给正确数据中心一个server。该server再转发给本地leader。
这使得数据中心之间只有一个很低的耦合,可是因为故障检测,链接缓存和复用,跨数据中心的请求都是相对快速和可靠的。
此处启动的是单实例多端口,若是你是多实例,请自行更改相关配置
ServerName | IP Addr & Port | Consul Roles |
---|---|---|
server1 | 192.168.1.153:8500 | Server1 |
server2 | 192.168.1.154:8500 | Server2 |
server3 | 192.168.1.155:8500 | Server3 |
node-exporter | 192.168.1.151:9100 | Node-Exporter |
配置为systemd启动, Docker方式部署连接(http://www.javashuo.com/article/p-cfcuqobl-ey.html)
# 下载consul CONSUL_VERSION='1.7.7' wget https://releases.hashicorp.com/consul/${CONSUL_VERSION}/consul_${CONSUL_VERSION}_linux_amd64.zip # 解压安装 unzip consul_${CONSUL_VERSION}_linux_amd64.zip chown root:root consul mv consul /usr/local/bin/ consul --version # 启用自动补全 consul -autocomplete-install complete -C /usr/local/bin/consul consul # 建立用户和目录 useradd -M -s /sbin/nologin consul mkdir -p /data/consul/server/{data,config} chown -R consul.consul /data/consul/ # 配置Systemd # consul-server1 cat > /lib/systemd/system/consul-server1.service << EOF [Unit] Description="consul server1" Requires=network-online.target After=network-online.target [Service] User=consul Group=consul ExecStart=/usr/local/bin/consul agent -config-dir=/data/consul/server/config ExecReload=/usr/local/bin/consul reload KillMode=process Restart=on-failure LimitNOFILE=65536 [Install] WantedBy=multi-user.target EOF # consul-server2 cat > /lib/systemd/system/consul-server2.service << EOF [Unit] Description="consul server2" Requires=network-online.target After=network-online.target [Service] User=consul Group=consul ExecStart=/usr/local/bin/consul agent -config-dir=/data/consul/server/config ExecReload=/usr/local/bin/consul reload KillMode=process Restart=on-failure LimitNOFILE=65536 [Install] WantedBy=multi-user.target EOF # consul-server3 cat > /lib/systemd/system/consul-server3.service << EOF [Unit] Description="consul server3" Requires=network-online.target After=network-online.target [Service] User=consul Group=consul ExecStart=/usr/local/bin/consul agent -config-dir=/data/consul/server/config ExecReload=/usr/local/bin/consul reload KillMode=process Restart=on-failure LimitNOFILE=65536 [Install] WantedBy=multi-user.target EOF
# 生成密钥 CONSUL_KEY=`consul keygen` # node_id 必定不能够重复,server name能够随便定义 # 建立server1配置文件 cat > /data/consul/server/config/config.json << EOF { "datacenter": "prometheus", "bind_addr":"192.168.1.153", "log_level": "INFO", "node_id":"09d82408-bc4f-49e0-1111-61ef1d4842f7", "node_name": "server1", "data_dir":"/data/consul/server/data", "server": true, "bootstrap_expect": 3, "encrypt": "${CONSUL_KEY}", "ui":true, "client_addr":"0.0.0.0", "retry_join":["192.168.1.153:8301","192.168.1.154:8301","192.168.1.155:8301"], "ports": { "http": 8500, "dns": 8600, "serf_lan":8301, "serf_wan":8302, "server":8300, "grpc":8400 }, "acl": { "enabled": true, "default_policy": "deny", "down_policy": "extend-cache", "tokens":{ "master":"${CONSUL_HTTP_TOKEN}", "agent":"${CONSUL_HTTP_TOKEN}" } } } EOF # 建立server2配置文件 cat > /data/consul/server/config/config.json << EOF { "datacenter": "prometheus", "bind_addr":"192.168.1.154", "log_level": "INFO", "node_id":"613ccd6e-68d1-3bbd-2222-3cbc450f019d", "node_name": "server2", "data_dir":"/data/consul/server/data", "server": true, "bootstrap_expect": 3, "encrypt": "${CONSUL_KEY}", "ui":true, "client_addr":"0.0.0.0", "retry_join":["192.168.1.153:8301","192.168.1.154:8301","192.168.1.155:8301"], "ports": { "http": 8500, "dns": 8600, "serf_lan":8301, "serf_wan":8302, "server":8300, "grpc":8400 }, "acl": { "enabled": true, "default_policy": "deny", "down_policy": "extend-cache", "tokens":{ "master":"${CONSUL_HTTP_TOKEN}", "agent":"${CONSUL_HTTP_TOKEN}" } } } EOF # 建立server3配置文件 cat > /data/consul/server/config/config.json << EOF { "datacenter": "prometheus", "bind_addr":"192.168.1.155", "log_level": "INFO", "node_id":"d8a09ffd-7ccb-84bd-3333-8d8b7a01951e", "node_name": "server3", "data_dir":"/data/consul/server/data", "server": true, "bootstrap_expect": 3, "encrypt": "${CONSUL_KEY}", "ui":true, "client_addr":"0.0.0.0", "retry_join":["192.168.1.153:8301","192.168.1.154:8301","192.168.1.155:8301"], "ports": { "http": 8500, "dns": 8600, "serf_lan":8301, "serf_wan":8302, "server":8300, "grpc":8400 }, "acl": { "enabled": true, "default_policy": "deny", "down_policy": "extend-cache", "tokens":{ "master":"${CONSUL_HTTP_TOKEN}", "agent":"${CONSUL_HTTP_TOKEN}" } } } EOF
systemctl enable consul-server1 && systemctl start consul-server1 systemctl enable consul-server2 && systemctl start consul-server2 systemctl enable consul-server3 && systemctl start consul-server3 systemctl status consul-server1
生成http_acl_token,写入config.jso中的tokens数组中的master与agent。注意,consul acl bootstrap只能执行一次.
consul acl bootstrap AccessorID: ae4f5026-73e7-ff56-548c-3ae0fc76022f SecretID: 08ad8862-f702-eb26-0276-d8255b11267e Description: Bootstrap Token (Global Management) Local: false Create Time: 2020-09-02 23:25:47.533701389 +0800 CST Policies: 00000000-0000-0000-0000-000000000001 - global-management AccessorID: ae4f5026-73e7-ff56-548c-3ae0fc76022f SecretID: 08ad8862-f702-eb26-0276-d8255b11267e export CONSUL_HTTP_TOKEN='your_token'
返回空节点是正常的,由于开启了ACL,因此访问的时候须要加入token,若是CONSUL_HTTP_TOKEN
变量已经加入profile,不须要在指定token。
# 环境变量 cat >> /etc/profile << EOF export CONSUL_HTTP_TOKEN='08ad8862-f702-eb26-0276-d8255b11267e' EOF # consul members --token='08ad8862-f702-eb26-0276-d8255b11267e' Node Address Status Type Build Protocol DC Segment server1 192.168.1.153:8301 alive server 1.7.7 2 prometheus <all> server2 192.168.1.154:8301 alive server 1.7.7 2 prometheus <all> server3 192.168.1.155:8301 alive server 1.7.7 2 prometheus <all> # 验证集群UI 在页面http://127.0.0.1:8500/ui/prometheus/acls/tokens 输入配置中的 master token,再刷新界面能够在services和nodes中查看到信息 # 验证API,经过在header中增长x-consul-token则可返回节点列表 curl http://127.0.0.1:8500/v1/catalog/nodes -H 'x-consul-token: ${CONSUL_HTTP_TOKEN}'
此处为可选项,若是你须要单独将日志输出到ELK,那么此项配置很是有必要,由于默认的日志都打到syslog中了。
# 建立目录&赋权 mkdir -p /var/log/consul/ chown -R syslog.syslog /var/log/consul/ # 建立日志配置文件 cat >/etc/rsyslog.d/consul.conf <<EOF local0.* /var/log/consul/consul.log EOF # 修改默认配置文件中的如下内容 vim /etc/rsyslog.d/50-default.conf # 变动前 *.*;auth,authpriv.none -/var/log/syslog # 变动后 *.*;auth,authpriv.none,local0.none -/var/log/syslog # 重启rsyslog让配置生效。 $ systemctl restart rsyslog # 建立日志轮循规则 $ cat >/etc/logrotate.d/consul <<EOF /var/log/consul/*log { missingok compress notifempty daily rotate 5 create 0600 root root } EOF # 在Systemd启动脚本中加入`-syslog`参数 sed -i 's@ExecStart=/usr/local/bin/consul agent@ExecStart=/usr/local/bin/consul agent -syslog@g' /lib/systemd/system/consul-server{1..3}.service # 重启服务 systemctl daemon-reload && systemctl restart consul-server1 systemctl daemon-reload && systemctl restart consul-server2 systemctl daemon-reload && systemctl restart consul-server3 # 查看输出日志,对于加入ELK的配置就不过多描述了,若是想了解,加入咱们的qq群与微信群咨询相关解决方案。 tail -f /var/log/consul/consul.log
FAQ : 若是集群加入失败 或 提示:Error retrieving members: Unexpected response code: 403 (ACL not found),toekn格式不对,须要从新检查集群节点tokens配置,格式为:'55eca91c-b5f7-e82d-7777-dba7637e8888',而后删除/data/consul/server{1..3}/data/目录下的数据,重启服务便可。
# 基于AWS EC2 REDIS 发现规则 cat >> /data/prometheus/conf/prometheus.yml <<EOF - job_name: 'ec2_exporter' consul_sd_configs: - server: 172.26.42.229:8500 token: '${CONSUL_HTTP_TOKEN}' services: ['node_exporter'] relabel_configs: - source_labels: [__address__] regex: 172.26.42.229:8300 action: drop - source_labels: [__meta_consul_tags] regex: ".*,prod,.*" replacement: prod action: replace target_label: env - job_name: 'redis_exporter' consul_sd_configs: - server: 172.26.42.229:28500 token: '${CONSUL_HTTP_TOKEN}' services: ['redis_exporter'] relabel_configs: - source_labels: [__address__] regex: 172.26.42.229:28300 action: drop - source_labels: [__meta_consul_tags] regex: ".*,prod,.*" replacement: prod action: replace target_label: env - job_name: 'mysql_exporter' consul_sd_configs: - server: 172.26.42.229:38500 token: '${CONSUL_HTTP_TOKEN}' services: ['mysql_exporter'] relabel_configs: - source_labels: [__address__] regex: 172.26.42.229:38300 action: drop - source_labels: [__meta_consul_tags] regex: ".*,prod,.*" replacement: prod action: replace target_label: env EOF # registered nginx01 service to consul1 , ID为惟一标识,用于删除,Name就是consul中service字段的发现关键字,tag能够依据本身的需求relableing。 curl -H "x-consul-token: ${CONSUL_HTTP_TOKEN}" -X PUT -d '{"ID": "node_exporter01", "Name": "node_exporter", "Address": "192.168.1.220", "Port": 9100, "Tags": ["prod"], "EnableTagOverride": false}' \ http://192.168.1.153:8500/v1/agent/service/register # registered redis01 to consul2 curl -H "x-consul-token: ${CONSUL_HTTP_TOKEN}" -X PUT -d '{"ID": "redis_exporter01", "Name": "redis_exporter", "Address": "172.26.42.229", "Port": 9121, "Tags": ["prod"], "EnableTagOverride": false}' \ http://192.168.1.153:8500/v1/agent/service/register # registered mysql01 to consul2 curl -H "x-consul-token: ${CONSUL_HTTP_TOKEN}" -X PUT -d '{"ID": "mysql_exporter01", "Name": "mysql_exporter", "Address": "172.26.42.229", "Port": 9105, "Tags": ["prod"], "EnableTagOverride": false}' \ http://192.168.1.153:8500/v1/agent/service/register # delete nginx01 service curl -X PUT -H "x-consul-token: ${CONSUL_HTTP_TOKEN}" http://192.168.1.153:8500/v1/agent/service/deregister/node_exporter01 # delete redis01 service curl -X PUT -H "x-consul-token: ${CONSUL_HTTP_TOKEN}" http://192.168.1.153:8500/v1/agent/service/deregister/redis_exporter01 # delete mysql_exporter01 service curl -X PUT -H "x-consul-token: ${CONSUL_HTTP_TOKEN}" http://192.168.1.153:8500/v1/agent/service/deregister/mysql_exporter01
# 安装Consul-template 下载地址:https://releases.hashicorp.com/consul-template/ wget https://releases.hashicorp.com/consul-template/0.22.0/consul-template_0.22.0_linux_amd64.zip unzip consul-template_0.22.0_linux_amd64.zip mv consul-template /usr/local/bin/ # 查看版本 consul-template -v consul-template v0.22.0 (6cae10fe) #经常使用参数的做用: -consul-auth=<username[:password]> # 设置基本的认证用户名和密码。 -consul-addr=<address> # 设置Consul实例的地址。 -max-stale=<duration> # 查询过时的最大频率,默认是1s。 -dedup # 启用重复数据删除,当许多consul template实例渲染一个模板的时候能够下降consul的负载。 -consul-ssl # 使用https链接Consul。 -consul-ssl-verify # 经过SSL链接的时候检查证书。 -consul-ssl-cert # SSL客户端证书发送给服务器。 -consul-ssl-key # 客户端认证时使用的SSL/TLS私钥。 -consul-ssl-ca-cert # 验证服务器的CA证书列表。 -consul-token=<token> # 设置Consul API的token。 -syslog # 把标准输出和标准错误重定向到syslog,syslog的默认级别是local0。 -syslog-facility=<facility> # 设置syslog级别,默认是local0,必须和-syslog配合使用。 -template=<template> # 增长一个须要监控的模板,格式是:'templatePath:outputPath(:command)',多个模板则能够设置屡次。 -wait=<duration> # 当呈现一个新的模板到系统和触发一个命令的时候,等待的最大最小时间。若是最大值被忽略,默认是最小值的4倍。 -retry=<duration> # 当在和consul api交互的返回值是error的时候,等待的时间,默认是5s。 -config=<path> # 配置文件或者配置目录的路径。 -pid-file=<path> # PID文件的路径。 -log-level=<level> # 设置日志级别,能够是"debug","info", "warn" (default), and "err"。 -dry # Dump生成的模板到标准输出,不会生成到磁盘。 -once # 运行consul-template一次后退出,不以守护进程运行 # 在conf目录下建立1个nginx.json的配置文件 cat >> /data/consul/server1/config/nginx.json <<EOF { "service":{ "name":"nginx", "tags":[ "web" ], "port":80, "check":{ "http":"http://127.0.0.1:80", "interval":"10s" }, "token":"233b604b-b92e-48c8-a253-5f11514e4b50" } } EOF # 热加载配置文件 consul reload # 验证服务是否注册成功 curl -H "x-consul-token: ${CONSUL_HTTP_TOKEN}" http://172.26.42.229:8500/v1/catalog/service/nginx | python -m json.tool [ { "Address": "192.168.1.153", "CreateIndex": 21233, "Datacenter": "prometheus", "ID": "09d82408-bc4f-49e0-4208-61ef1d4842f7", "ModifyIndex": 21233, "Node": "server1", "NodeMeta": { "consul-network-segment": "" }, "ServiceAddress": "", "ServiceConnect": {}, "ServiceEnableTagOverride": false, "ServiceID": "nginx", "ServiceKind": "", "ServiceMeta": {}, "ServiceName": "nginx", "ServicePort": 80, "ServiceProxy": { "MeshGateway": {} }, "ServiceTags": [ "web" ], "ServiceWeights": { "Passing": 1, "Warning": 1 }, "TaggedAddresses": { "lan": "192.168.1.153", "wan": "192.168.1.155" } } ] # 建立模板 cat > tmpltest.ctmpl << EOF {{range services}} {{.Name}} {{range .Tags}} {{.}}{{end}} {{end}} EOF # 调用模板渲染 consul-template -consul-addr 192.168.1.153:8500 -template "/data/consul/consul-template/conf/tmpltest.ctmpl:result" -once # 查看模板渲染的输出结果,返回的结果:consul是系统自带的服务,nginx是刚才注册的服务,Tags是web cat result consul nginx web # 建立nginx模板文件 cat >> /data/consul/consul-template/conf/nginx.conf.ctmpl << EOF {{range services}} {{$name := .Name}} {{$service := service .Name}} upstream {{$name}} { zone upstream-{{$name}} 64k; {{range $service}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1; {{else}}server 127.0.0.1:65535; # force a 502{{end}} } {{end}} server { listen 80 default_server; location / { root /usr/share/nginx/html/; index index.html; } location /stub_status { stub_status; } {{range services}} {{$name := .Name}} location /{{$name}} { proxy_pass http://{{$name}}; } {{end}} } EOF # 调用模板文件生成Nginx配置文件 consul-template -consul-addr 192.168.1.153:8500 -template "/data/consul/consul-template/conf/nginx.conf.ctmpl:nginx.conf" -once # 为了更加安全,token从环境变量里读取,使用CONSUL_TOKEN和VAULT_TOKEN。强烈建议你不要把token放到未加密的文本配置文件中。 # 建立一个nginx.hcl文件 cat >> nginx.hcl << EOF consul { address = "192.168.1.153:8500" } template { source = "/data/consul/consul-template/conf/nginx.conf.ctmpl" destination = "/etc/nginx/conf/conf.d/default.conf" command = "service nginx reload" } EOF # 执行渲染命令 consul-template -config "nginx.hcl:test.out" # 同时渲染多个template并放出后台启动 cat > consul_temp.sh << EOF #!/bin/bash #prom cd /data/consul/consul-template/ && nohup /usr/local/bin/consul-template -config=/data/consul/consul-template/hcl_conf/ & 2>&1 EOF
相比于直接使用静态配置和基于文件发现,是不利于云环境以及k8s环境的,由于咱们大多时候更多监控对象都是动态的。所以,经过服务发现,使得Prometheus相比于其余传统监控解决方案更适用于云以及k8s环境下的监控需求。