Prometheus監控神器-服務發現篇(三)

本章節會對consul的架構與配置作全面講解。html

Consul架構

image

上圖是官網提供的一個事例系統圖,圖中的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主要分佈在不一樣的數據中心而且一般經過因特網或者廣域網通訊。

  • 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啓動, 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

建立Server{1-3}配置文件

# 生成密鑰
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}'

將Consul日誌加入Syslog

此處爲可選項,若是你須要單獨將日誌輸出到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/目錄下的數據,重啓服務便可。

Prometheus集成Consul

# 基於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動態配置服務

# 安裝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環境下的監控需求。

相關文章
相關標籤/搜索