前言

Prometheus 基于 Consul 的服务发现完全指南:从原理到实战

        在云原生与微服务架构中,服务的动态伸缩、弹性部署已成为常态。面对频繁变化的实例 IP 和端口,无论是静态配置还是基于文件的服务发现,都显得力不从心——前者需要频繁修改配置并重启,后者仍需手动维护目标文件。

        Consul 服务发现正是为解决这一痛点而生。 Consul 作为专业的服务注册中心,让服务实例自动注册、自动下线,Prometheus 通过 Consul API 实时感知服务变化,实现监控目标的全自动动态管理

        本文将从零开始,系统讲解 Consul 服务发现的完整工作流程——安装部署、服务注册、Prometheus 配置、脚本自动化以及服务下线管理,并明确标注每个操作涉及的文件及其作用。

一、Consul 服务发现与其他方式的对比

1.1 不同服务发现方式的差异

        在开始之前,我们先来理解 Consul 服务发现与其他方式的核心区别:

特性 静态配置 文件服务发现 Consul 服务发现
工作方式 手动编辑 prometheus.yml 手动维护 JSON/YAML 文件 服务自动注册到 Consul,无需手动改配置
服务自动注册/下线 ❌ 不支持 ❌ 不支持 ✅ 支持
是否需要重启 Prometheus ✅ 需要 ❌ 不需要 ❌ 不需要
实时性 无变化 依赖刷新间隔 实时同步 Consul 健康状态
使用场景 小型固定环境 小型测试环境 生产环境、微服务、Docker、K8s、大规模监控平台

1.2 适用场景

        Consul 服务发现特别适合以下场景:

  1. 微服务架构:服务实例频繁扩缩容,需要自动发现新实例并移除已下线的实例

  2. Docker/Kubernetes 环境:容器动态启停,IP 频繁变化

  3. 多云/混合云环境:跨云平台统一服务注册与发现

  4. 大规模监控平台:监控目标数量大、变化频繁,手动维护不可行

1.3 核心工作流程

        Consul 服务发现的整体工作流程如下:

text

┌─────────────┐    ①注册服务    ┌──────────────────┐    ②查询服务列表   ┌─────────────┐
│  Exporter   │ ───────────────▶ │     Consul       │ ◀───────────────── │  Prometheus │
│  /业务服务  │   (HTTP API)     │   (注册中心)      │   (consul_sd)     │   (9090)    │
└─────────────┘                  └──────────────────┘                   └─────────────┘
       │                                  │                                    │
       │                                  │                                    │
       └──────────────────────────────────┴────────────────────────────────────┘
                                        ③ Prometheus 周期性拉取服务列表,
                                          自动生成监控目标并采集指标[reference:10]

二、环境准备

项目 说明
操作系统 Linux(CentOS 7/8 或 Ubuntu 20.04+)
Consul 待安装,默认端口 8500
Prometheus 已安装并正常运行(参考本系列之前的文章)
Node Exporter 已安装并运行(用于演示服务注册)

三、Consul 安装

3.1 方式一:二进制安装(推荐生产环境)

步骤一:下载 Consul 二进制包

bash

# 下载 Consul(以 v1.15.0 为例)
wget https://releases.hashicorp.com/consul/1.15.0/consul_1.15.0_linux_amd64.zip

# 解压
unzip consul_1.15.0_linux_amd64.zip

# 移动到系统路径
sudo mv consul /usr/local/bin/

该文件的作用/usr/local/bin/consul 是 Consul 的可执行二进制文件,用于启动 Consul 服务和管理 Consul 集群。

步骤二:验证安装

bash

consul --version

步骤三:创建专用系统用户

bash

sudo useradd --no-create-home --shell /bin/false consul

步骤四:创建配置文件

操作文件/etc/consul.d/consul.hcl(Consul 核心配置文件)

bash

sudo mkdir -p /etc/consul.d
sudo tee /etc/consul.d/consul.hcl <<'EOF'
# 数据存储目录
data_dir = "/opt/consul"

# 绑定地址(生产环境改为实际 IP)
bind_addr = "0.0.0.0"

# 客户端地址(允许外部访问 UI 和 API)
client_addr = "0.0.0.0"

# 数据中心名称
datacenter = "dc1"

# 启用 UI 界面
ui = true

# 服务注册配置文件目录
config_entries {
  config_dir = "/etc/consul.d/services"
}
EOF

该文件的作用:定义 Consul 的核心运行参数,包括数据存储路径、网络绑定地址、是否启用 UI 界面等。

步骤五:创建 Systemd 服务文件

操作文件/etc/systemd/system/consul.service

bash

sudo tee /etc/systemd/system/consul.service <<'EOF'
[Unit]
Description=Consul Service Discovery
After=network.target

[Service]
User=consul
Group=consul
Type=simple
ExecStart=/usr/local/bin/consul agent -config-dir=/etc/consul.d
ExecReload=/bin/kill -HUP $MAINPID
Restart=always

[Install]
WantedBy=multi-user.target
EOF

该文件的作用:将 Consul 注册为 Systemd 服务,实现开机自启和进程守护。

步骤六:启动 Consul

bash

# 创建数据目录
sudo mkdir -p /opt/consul
sudo chown consul:consul /opt/consul

# 重新加载 systemd
sudo systemctl daemon-reload

# 启动 Consul
sudo systemctl start consul

# 设置开机自启
sudo systemctl enable consul

# 查看状态
sudo systemctl status consul

步骤七:验证 Consul

bash

# 查看 Consul 集群成员
consul members

# 通过浏览器访问 Consul UI
# http://<服务器IP>:8500

Consul 默认监听 8500 端口,提供服务注册、发现和 UI 访问。

步骤八:配置防火墙

bash

# CentOS 7
sudo firewall-cmd --permanent --add-port=8500/tcp
sudo firewall-cmd --reload

# Ubuntu
sudo ufw allow 8500/tcp

3.2 方式二:Docker 安装(推荐快速体验)

操作文件docker-compose.yml

yaml

version: '3'
services:
  consul:
    image: hashicorp/consul:latest
    container_name: consul
    restart: always
    ports:
      - "8500:8500"
    volumes:
      - ./consul/data:/consul/data
      - ./consul/config:/consul/config
    command: agent -server -bootstrap-expect=1 -ui -client=0.0.0.0

启动:

bash

docker-compose up -d

或直接使用 Docker 命令:

bash

docker run -d --name consul -p 8500:8500 hashicorp/consul agent -dev -client=0.0.0.0

注意-dev 模式仅适用于开发测试环境,生产环境请使用完整的集群配置。

四、Consul HTTP API 访问方式

Consul 提供了完善的 RESTful HTTP API,用于服务注册、查询和管理。

4.1 API 端点概览

API 端点 方法 说明
/v1/agent/service/register PUT 注册服务到本地 Agent
/v1/agent/service/deregister/:service_id PUT 从本地 Agent 注销服务
/v1/catalog/services GET 获取所有已注册的服务列表
/v1/health/service/:service_name GET 获取指定服务的健康实例列表
/v1/kv/:key GET/PUT/DELETE 键值存储操作

4.2 基础 API 测试

bash

# 查看 Consul 集群状态
curl http://localhost:8500/v1/agent/self

# 查看所有已注册的服务
curl http://localhost:8500/v1/catalog/services

# 查看所有节点
curl http://localhost:8500/v1/catalog/nodes

五、通过 API 注册服务到 Consul

5.1 临时注册(测试用)

通过 curl 直接向 Consul API 发送注册请求:

bash

curl -X PUT \
  -H "Content-Type: application/json" \
  -d '{
    "ID": "node_exporter-1",
    "Name": "node_exporter",
    "Tags": ["prometheus", "node"],
    "Address": "192.168.1.101",
    "Port": 9100,
    "Check": {
      "HTTP": "http://192.168.1.101:9100/metrics",
      "Interval": "10s",
      "Timeout": "3s"
    }
  }' \
  http://localhost:8500/v1/agent/service/register

该命令的作用:将一个 Node Exporter 实例注册到 Consul,并配置健康检查。Consul 会定期检查 /metrics 端点是否可达,如果不可达则标记该服务为不健康。

5.2 持久化注册(推荐)

将服务定义写入 JSON 文件,通过 Consul 的配置目录自动加载。

操作文件/etc/consul.d/services/node_exporter.json

json

{
  "service": {
    "id": "node_exporter-192.168.1.101",
    "name": "node_exporter",
    "tags": ["prometheus", "node", "production"],
    "address": "192.168.1.101",
    "port": 9100,
    "check": {
      "http": "http://192.168.1.101:9100/metrics",
      "interval": "10s",
      "timeout": "3s",
      "deregister_critical_service_after": "30s"
    }
  }
}

该文件的作用:定义服务注册的完整信息,包括服务 ID、名称、标签、地址、端口和健康检查配置。Consul 启动时会自动加载 config_entries.config_dir 目录下的所有服务定义文件。

重新加载配置

bash

# 重载 Consul 配置(不重启服务)
consul reload

# 或使用 systemctl
sudo systemctl reload consul

5.3 注册多个 Exporter

操作文件/etc/consul.d/services/mysql_exporter.json

json

{
  "service": {
    "id": "mysql_exporter-192.168.1.101",
    "name": "mysql_exporter",
    "tags": ["prometheus", "mysql", "production"],
    "address": "192.168.1.101",
    "port": 9104,
    "check": {
      "http": "http://192.168.1.101:9104/metrics",
      "interval": "10s",
      "timeout": "3s"
    }
  }
}

操作文件/etc/consul.d/services/redis_exporter.json

json

{
  "service": {
    "id": "redis_exporter-192.168.1.101",
    "name": "redis_exporter",
    "tags": ["prometheus", "redis", "production"],
    "address": "192.168.1.101",
    "port": 9121,
    "check": {
      "http": "http://192.168.1.101:9121/metrics",
      "interval": "10s",
      "timeout": "3s"
    }
  }
}

六、配置 Prometheus 对接 Consul

6.1 修改 Prometheus 配置文件

操作文件/etc/prometheus/prometheus.yml

在 scrape_configs 部分添加 Consul 服务发现配置:

yaml

scrape_configs:
  # ... 其他 job 配置 ...

  # ============================================
  # 基于 Consul 的服务发现
  # ============================================
  - job_name: 'consul_services'
    consul_sd_configs:
      # Consul 服务器地址[reference:26]
      - server: 'localhost:8500'
        # 可选:按标签过滤服务[reference:27]
        tags:
          - 'prometheus'
        # 刷新间隔[reference:28]
        refresh_interval: 30s
    # 重标签配置:将 Consul 元数据转换为 Prometheus 标签[reference:29]
    relabel_configs:
      # 使用 Consul 中的服务名作为 job 标签
      - source_labels: [__meta_consul_service]
        target_label: job
      # 使用服务地址作为 instance 标签
      - source_labels: [__meta_consul_service_address]
        target_label: instance
      # 保留 Consul 中的服务标签
      - source_labels: [__meta_consul_tags]
        target_label: consul_tags
      # 仅抓取健康的服务实例
      - source_labels: [__meta_consul_service_health]
        regex: passing
        action: keep

配置项说明

配置项 说明
server Consul 服务器的地址和端口
tags 可选,只发现带有指定标签的服务
refresh_interval 从 Consul 刷新目标列表的频率
relabel_configs 将 Consul 元数据标签转换为 Prometheus 标签

该文件的作用:定义 Prometheus 如何从 Consul 获取监控目标。consul_sd_configs 告诉 Prometheus 去哪个 Consul 服务器查询服务列表,relabel_configs 负责将 Consul 返回的元数据转换为 Prometheus 可用的标签。

6.2 更多配置示例

按服务名过滤

yaml

consul_sd_configs:
  - server: 'localhost:8500'
    services: ['node_exporter', 'mysql_exporter']  # 只发现指定服务

使用 Consul 的元数据标签

Consul 会为每个服务生成以下元数据标签:

元数据标签 说明
__meta_consul_service 服务名称
__meta_consul_service_address 服务地址
__meta_consul_service_port 服务端口
__meta_consul_tags 服务标签列表
__meta_consul_service_id 服务 ID
__meta_consul_service_health 服务健康状态

6.3 使配置生效

bash

# 检查配置语法
promtool check config /etc/prometheus/prometheus.yml

# 热加载配置(推荐,不中断服务)
sudo systemctl reload prometheus

# 或使用 API 热加载(需启用 --web.enable-lifecycle)
curl -X POST http://localhost:9090/-/reload[reference:37]

6.4 验证服务发现

  1. 访问 http://<Prometheus_IP>:9090/targets,查看 consul_services 作业下的目标

  2. 访问 http://<Prometheus_IP>:9090/service-discovery,查看 Consul 发现的所有目标

  3. 在 Consul UI(http://<Consul_IP>:8500)中查看已注册的服务

七、创建自动注册脚本

在生产环境中,通常需要编写脚本实现服务的自动注册与注销。

7.1 Shell 注册脚本

操作文件/opt/scripts/register_to_consul.sh

bash

#!/bin/bash
# 功能:将服务注册到 Consul
# 用法:./register_to_consul.sh <service_name> <service_port> <service_ip>

SERVICE_NAME=${1:-"node_exporter"}
SERVICE_PORT=${2:-9100}
SERVICE_IP=${3:-$(hostname -I | awk '{print $1}')}
CONSUL_URL="http://localhost:8500/v1/agent/service/register"

# 构建服务注册 JSON
SERVICE_JSON=$(cat <<EOF
{
  "ID": "${SERVICE_NAME}-${SERVICE_IP}",
  "Name": "${SERVICE_NAME}",
  "Tags": ["prometheus", "production"],
  "Address": "${SERVICE_IP}",
  "Port": ${SERVICE_PORT},
  "Check": {
    "HTTP": "http://${SERVICE_IP}:${SERVICE_PORT}/metrics",
    "Interval": "10s",
    "Timeout": "3s",
    "DeregisterCriticalServiceAfter": "30s"
  }
}
EOF
)

# 发送注册请求
curl -X PUT -H "Content-Type: application/json" -d "${SERVICE_JSON}" ${CONSUL_URL}

if [ $? -eq 0 ]; then
    echo "Service ${SERVICE_NAME} registered successfully at ${SERVICE_IP}:${SERVICE_PORT}"
else
    echo "Failed to register service ${SERVICE_NAME}"
    exit 1
fi

该文件的作用:通过脚本自动将指定服务注册到 Consul,支持传入服务名、端口和 IP 参数。

使用示例

bash

chmod +x /opt/scripts/register_to_consul.sh

# 注册 Node Exporter
./register_to_consul.sh node_exporter 9100 192.168.1.101

# 注册 MySQL Exporter
./register_to_consul.sh mysql_exporter 9104 192.168.1.101

7.2 Python 注册脚本

操作文件/opt/scripts/register_to_consul.py

python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 功能:通过 Python 将服务注册到 Consul

import json
import requests
import socket
import sys

CONSUL_URL = "http://localhost:8500/v1/agent/service/register"

def register_service(service_name, service_port, service_ip=None):
    """注册服务到 Consul"""
    if service_ip is None:
        service_ip = socket.gethostbyname(socket.gethostname())
    
    service_id = f"{service_name}-{service_ip}"
    
    payload = {
        "ID": service_id,
        "Name": service_name,
        "Tags": ["prometheus", "production"],
        "Address": service_ip,
        "Port": service_port,
        "Check": {
            "HTTP": f"http://{service_ip}:{service_port}/metrics",
            "Interval": "10s",
            "Timeout": "3s",
            "DeregisterCriticalServiceAfter": "30s"
        }
    }
    
    response = requests.put(
        CONSUL_URL,
        data=json.dumps(payload),
        headers={"Content-Type": "application/json"}
    )
    
    if response.status_code == 200:
        print(f"✅ Service {service_name} registered at {service_ip}:{service_port}")
    else:
        print(f"❌ Failed to register: {response.text}")
        sys.exit(1)

if __name__ == "__main__":
    if len(sys.argv) < 3:
        print("Usage: python3 register_to_consul.py <service_name> <port> [ip]")
        sys.exit(1)
    
    service_name = sys.argv[1]
    service_port = int(sys.argv[2])
    service_ip = sys.argv[3] if len(sys.argv) > 3 else None
    
    register_service(service_name, service_port, service_ip)

该文件的作用:Python 版本的服务注册脚本,功能与 Shell 版本相同,适合集成到 Python 应用或运维平台中。

使用示例

bash

python3 /opt/scripts/register_to_consul.py node_exporter 9100 192.168.1.101

7.3 服务发现脚本(查询已注册服务)

操作文件/opt/scripts/discover_services.sh

bash

#!/bin/bash
# 功能:查询 Consul 中已注册的服务列表

curl -s http://localhost:8500/v1/catalog/services | jq '.'

该文件的作用:快速查询 Consul 中所有已注册的服务,用于验证注册是否成功。

八、Consul 删除/注销服务

8.1 通过 API 删除服务

bash

# 删除指定服务(通过服务 ID)
curl -X PUT http://localhost:8500/v1/agent/service/deregister/<service_id>

# 示例:删除 node_exporter
curl -X PUT http://localhost:8500/v1/agent/service/deregister/node_exporter-192.168.1.101

8.2 通过 Consul 命令删除

bash

# 使用 consul 命令注销服务[reference:38]
consul services deregister /etc/consul.d/services/node_exporter.json

8.3 删除脚本

操作文件/opt/scripts/deregister_from_consul.sh

bash

#!/bin/bash
# 功能:从 Consul 注销服务
# 用法:./deregister_from_consul.sh <service_id>

SERVICE_ID=${1}
CONSUL_URL="http://localhost:8500/v1/agent/service/deregister/${SERVICE_ID}"

if [ -z "${SERVICE_ID}" ]; then
    echo "Usage: $0 <service_id>"
    echo "Example: $0 node_exporter-192.168.1.101"
    exit 1
fi

curl -X PUT ${CONSUL_URL}

if [ $? -eq 0 ]; then
    echo "Service ${SERVICE_ID} deregistered successfully"
else
    echo "Failed to deregister service ${SERVICE_ID}"
    exit 1
fi

该文件的作用:通过脚本快速注销 Consul 中的服务,适用于服务下线或维护场景。

使用示例

bash

chmod +x /opt/scripts/deregister_from_consul.sh
./deregister_from_consul.sh node_exporter-192.168.1.101

8.4 服务退出时自动注销

在生产环境中,服务进程退出时应自动从 Consul 注销,避免产生“僵尸服务”。

在服务的停止脚本中添加:

bash

# 在服务停止时执行
curl -X PUT http://localhost:8500/v1/agent/service/deregister/node_exporter-192.168.1.101

九、ConsulManager 简介

在生产环境中,手动编写 JSON 文件或 curl 命令来管理服务注册既繁琐又容易出错。ConsulManager 正是为解决这一问题而生的 Web 管理工具。

9.1 什么是 ConsulManager

ConsulManager 是一个使用 Flask + Vue 开发的 Consul Web 管理工具,比官方自带的 Web UI 实现了更多的功能。它弥补了 Consul 官方 UI 对 Services 管理的不足。

主要功能

  1. Consul Web Manager:支持 Services 的增删改查、批量删除,直观查看服务实例信息和健康状态,便捷配置 Tags、Meta 和健康检查

  2. ECS Manager:支持同步阿里云、腾讯云、华为云、AWS 的 ECS 主机信息到 Consul,实现 Prometheus 监控目标的自动发现

  3. Blackbox Manager:基于 Blackbox Exporter 实现站点与接口监控,通过 Web 界面即可对监控目标增删改查,支持批量删除和分类管理

9.2 部署方式

使用 Docker Compose 一键部署

bash

# 一键安装脚本
curl -s https://starsl.cn/static/img/all_install.sh | sudo bash

安装路径为 /opt/tensuns。安装完成后,通过浏览器访问 http://<服务器IP>:1026 即可登录 ConsulManager 管理界面。

使用 ConsulManager 的优势

不用写 JSON、不用重启 Consul,批量增删、改标签、改健康检查等等,一切都可以在 Web 界面上完成。

十、操作文件速查表

文件路径 作用
/usr/local/bin/consul Consul 可执行二进制文件
/etc/consul.d/consul.hcl Consul 核心配置文件
/etc/consul.d/services/*.json 服务注册定义文件目录
/etc/systemd/system/consul.service Consul Systemd 服务文件
/opt/consul/ Consul 数据存储目录
/etc/prometheus/prometheus.yml Prometheus 主配置文件,添加 consul_sd_configs
/opt/scripts/register_to_consul.sh Shell 服务注册脚本
/opt/scripts/register_to_consul.py Python 服务注册脚本
/opt/scripts/deregister_from_consul.sh Shell 服务注销脚本
/opt/scripts/discover_services.sh 服务查询脚本

十一、总结

本文系统介绍了 Prometheus 基于 Consul 的服务发现的完整知识体系:

  1. 与其他方式的区别:Consul 服务发现实现了服务自动注册与下线,无需手动维护配置文件,是生产环境和大规模监控的首选方案

  2. 适用场景:微服务架构、容器环境、多云环境、大规模监控平台

  3. 安装部署:支持二进制安装(生产推荐)和 Docker 安装(快速体验)

  4. Consul HTTP API:提供了完整的 RESTful API,支持服务注册、查询、注销等操作

  5. 服务注册:支持通过 API 临时注册和 JSON 文件持久化注册两种方式

  6. Prometheus 配置:通过 consul_sd_configs 对接 Consul,实现监控目标的自动发现

  7. 脚本自动化:提供了 Shell 和 Python 两种注册/注销脚本,便于集成到自动化运维体系

  8. ConsulManager:Web 管理工具,无需写 JSON 和重启 Consul,即可在界面上完成服务的增删改查

一句话总结:Consul 服务发现让 Prometheus 的监控目标管理从“手动维护”进化到“全自动感知”——服务注册到 Consul 即被 Prometheus 自动发现并开始监控,服务下线即自动停止抓取,全程无需人工干预。

更多推荐