2025-01-02 10:46:09 +08:00

586 lines
22 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Consul
![](../images/Consul/consul-architecture.png)
上图是官网提供的一个事例系统图图中的Server是consul服务端高可用集群Client是consul客户端。consul客户端不保存数据客户端将接收到的请求转发给响应的Server端。Server之间通过局域网或广域网通信实现数据一致性。每个Server或Client都是一个consul agent。
Consul集群间使用了GOSSIP协议通信和raft一致性算法。上面这张图涉及到了很多术语
- Agent——agent是一直运行在Consul集群中每个成员上的守护进程。通过运行consul agent来启动。agent可以运行在client或者server模式。指定节点作为client或者server是非常简单的除非有其他agent实例。所有的agent都能运行DNS或者HTTP接口并负责运行时检查和保持服务同步。
- Client——一个Client是一个转发所有RPC到server的代理。这个client是相对无状态的。client唯一执行的后台活动是加入LAN gossip池。这有一个最低的资源开销并且仅消耗少量的网络带宽。
- Server——一个server是一个有一组扩展功能的代理这些功能包括参与Raft选举维护集群状态响应RPC查询与其他数据中心交互WAN gossip和转发查询给leader或者远程数据中心。
- DataCenter——虽然数据中心的定义是显而易见的但是有一些细微的细节必须考虑。例如在EC2中多个可用区域被认为组成一个数据中心。我们定义数据中心为一个私有的低延迟和高带宽的一个网络环境。这不包括访问公共网络但是对于我们而言同一个EC2中的多个可用区域可以被认为是一个数据中心的一部分。
- Consensus——一致性使用Consensus来表明就leader选举和事务的顺序达成一致。为了以容错方式达成一致一般有超过半数一致则可以认为整体一致。Consul使用Raft实现一致性进行leader选举在consul中的使用bootstrap时可以进行自选其他server加入进来后bootstrap就可以取消。
- Gossip——Consul建立在Serf的基础之上它提供了一个用于多播目的的完整的gossip协议。Serf提供成员关系故障检测和事件广播。Serf是去中心化的服务发现和编制的解决方案节点失败侦测与发现具有容错、轻量、高可用的特点。
- LAN Gossip——它包含所有位于同一个局域网或者数据中心的所有节点。
- WAN Gossip——它只包含Server。这些server主要分布在不同的数据中心并且通常通过因特网或者广域网通信。
- RPC——远程过程调用。这是一个允许client请求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。
这使得数据中心之间只有一个很低的耦合,但是由于故障检测,连接缓存和复用,跨数据中心的请求都是相对快速和可靠的。
### Consul集群安装环境
此处启动的是单实例多端口,如果你是多实例,请自行更改相关配置
| 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 |
#### 二进制安装Consul 1.7.7
配置为systemd启动
```bash
# 下载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
```
#### 创建Server{1-3}配置文件
```bash
# 生成密钥
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
```
#### 启动服务
```bash
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只能执行一次.`
```bash
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。
```bash
# 环境变量
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}'
```
#### 将Consul日志加入Syslog
此处为可选项如果你需要单独将日志输出到ELK那么此项配置非常有必要因为默认的日志都打到syslog中了。
```bash
# 创建目录&赋权
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/目录下的数据,重启服务即可。`
#### Prometheus集成Consul
```bash
# 基于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动态配置服务
```bash
# 安装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 # 把标准输出和标准错误重定向到syslogsyslog的默认级别是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环境下的监控需求。