Consul 服务发现与配置中心集群部署实战

一、概述

Consul 是 HashiCorp 公司推出的一款开源工具,主要用于解决分布式系统中的服务发现、配置管理和健康检查问题。在现代微服务架构中,Consul 已成为服务网格基础设施的核心组件之一。

核心特性

  • 服务发现:支持 DNS 和 HTTP 两种方式的服务注册与发现
  • 健康检查:自动检测服务健康状态,实现故障转移
  • 键值存储:提供分布式 KV 存储,用于配置管理
  • 多数据中心:支持跨数据中心的服务发现和数据同步
  • 服务网格:内置 Connect 功能,提供服务间安全通信

适用场景

  • 微服务架构中的服务注册与发现
  • 动态配置管理与分发
  • 服务健康监控与自动故障转移
  • 多数据中心服务路由

二、架构设计

2.1 核心组件

组件 说明
Server 存储集群状态,参与 Raft 共识,建议 3 或 5 节点奇数部署
Client 转发请求到 Server,参与服务注册和健康检查
Agent 运行在每台主机上的守护进程,可以是 Server 或 Client 模式

2.2 推荐架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
                 ┌─────────────┐
│ Load │
│ Balancer │
└──────┬──────┘

┌──────────────────┼──────────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ Consul │ │ Consul │ │ Consul │
│ Server 1│◄─────►│ Server 2│◄─────►│ Server 3│
│ (Raft) │ │ (Raft) │ │ (Raft) │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└─────────────────┼─────────────────┘

┌─────────────────┼─────────────────┐
│ │ │
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
│ Consul │ │ Consul │ │ Consul │
│ Client 1│ │ Client 2│ │ Client N│
└─────────┘ └─────────┘ └─────────┘

三、环境准备

3.1 系统要求

  • 操作系统:Linux (Ubuntu 20.04+/CentOS 7+)
  • CPU:2 核以上
  • 内存:2GB 以上 (Server 节点建议 4GB+)
  • 磁盘:SSD 推荐,用于 Raft 日志存储
  • 网络:节点间低延迟通信

3.2 节点规划

节点 IP 地址 角色 说明
consul-01 192.168.1.101 Server Raft 节点 1
consul-02 192.168.1.102 Server Raft 节点 2
consul-03 192.168.1.103 Server Raft 节点 3
consul-04 192.168.1.104 Client 应用节点
consul-05 192.168.1.105 Client 应用节点

3.3 防火墙配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 开放 Consul 所需端口
# 8300: Server RPC
# 8301: Serf LAN (TCP/UDP)
# 8302: Serf WAN (TCP/UDP)
# 8500: HTTP API
# 8501: HTTPS API
# 8600: DNS (TCP/UDP)

sudo ufw allow 8300/tcp
sudo ufw allow 8301/tcp
sudo ufw allow 8301/udp
sudo ufw allow 8302/tcp
sudo ufw allow 8302/udp
sudo ufw allow 8500/tcp
sudo ufw allow 8501/tcp
sudo ufw allow 8600/tcp
sudo ufw allow 8600/udp

四、安装部署

4.1 下载并安装 Consul

1
2
3
4
5
6
7
8
9
# 所有节点执行
CONSUL_VERSION="1.18.0"
wget https://releases.hashicorp.com/consul/${CONSUL_VERSION}/consul_${CONSUL_VERSION}_linux_amd64.zip
unzip consul_${CONSUL_VERSION}_linux_amd64.zip
sudo mv consul /usr/local/bin/
sudo chmod +x /usr/local/bin/consul

# 验证安装
consul --version

4.2 创建系统用户和目录

1
2
3
4
5
6
7
# 所有节点执行
sudo useradd --system --shell /bin/false consul
sudo mkdir -p /etc/consul.d
sudo mkdir -p /opt/consul/data
sudo mkdir -p /opt/consul/config
sudo chown -R consul:consul /opt/consul
sudo chown -R consul:consul /etc/consul.d

4.3 Server 节点配置

在 consul-01、consul-02、consul-03 上创建配置文件 /etc/consul.d/consul.hcl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 节点基本信息
node_name = "consul-server-1" # 各节点修改为 consul-server-2/3
datacenter = "dc1"
data_dir = "/opt/consul/data"
log_level = "INFO"

# 网络配置
bind_addr = "0.0.0.0"
client_addr = "0.0.0.0"

# 端口配置
ports {
http = 8500
https = 8501
grpc = 8502
dns = 8600
}

# Server 模式配置
server = true
bootstrap_expect = 3 # 期望的 Server 节点数

# 集群发现配置
retry_join = [
"192.168.1.101",
"192.168.1.102",
"192.168.1.103"
]

# UI 界面启用
ui_config {
enabled = true
}

# ACL 配置(生产环境建议启用)
acl {
enabled = true
default_policy = "deny"
enable_token_persistence = true
}

# 服务网格配置
connect {
enabled = true
}

4.4 Client 节点配置

在 consul-04、consul-05 上创建配置文件 /etc/consul.d/consul.hcl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 节点基本信息
node_name = "consul-client-1" # 各节点修改
datacenter = "dc1"
data_dir = "/opt/consul/data"
log_level = "INFO"

# 网络配置
bind_addr = "0.0.0.0"
client_addr = "0.0.0.0"

# 端口配置
ports {
http = 8500
dns = 8600
}

# Client 模式配置
server = false

# 集群发现配置
retry_join = [
"192.168.1.101",
"192.168.1.102",
"192.168.1.103"
]

# ACL 配置
acl {
enabled = true
tokens {
agent = "your-agent-token"
default = "your-default-token"
}
}

4.5 创建 systemd 服务文件

所有节点创建 /etc/systemd/system/consul.service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[Unit]
Description=Consul
Documentation=https://www.consul.io/docs/
Requires=network-online.target
After=network-online.target

[Service]
Type=notify
User=consul
Group=consul
ExecStart=/usr/local/bin/consul agent -config-dir=/etc/consul.d
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
KillSignal=SIGTERM
Restart=on-failure
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

4.6 启动 Consul 服务

1
2
3
4
5
6
7
# 所有节点执行
sudo systemctl daemon-reload
sudo systemctl enable consul
sudo systemctl start consul

# 检查状态
sudo systemctl status consul

五、集群验证

5.1 检查集群成员

1
2
3
4
5
6
7
8
9
10
# 在任意节点执行
consul members

# 输出示例:
# Node Status Type Build Protocol DC Segment
# consul-server-1 alive server 1.18.0 2 dc1 <default>
# consul-server-2 alive server 1.18.0 2 dc1 <default>
# consul-server-3 alive server 1.18.0 2 dc1 <default>
# consul-client-1 alive client 1.18.0 2 dc1 <default>
# consul-client-2 alive client 1.18.0 2 dc1 <default>

5.2 检查 Raft 状态

1
2
3
4
# 在 Server 节点执行
consul operator raft list-peers

# 输出应显示 3 个 voter 节点

5.3 访问 Web UI

浏览器访问:http://192.168.1.101:8500

六、服务注册与发现

6.1 通过配置文件注册服务

在 Client 节点创建服务定义 /etc/consul.d/services/web-service.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"service": {
"name": "web-api",
"id": "web-api-1",
"port": 8080,
"address": "192.168.1.104",
"tags": ["production", "v1"],
"meta": {
"version": "1.0.0",
"environment": "prod"
},
"check": {
"id": "web-api-health",
"name": "HTTP Health Check",
"http": "http://localhost:8080/health",
"interval": "10s",
"timeout": "5s",
"deregister_critical_service_after": "30s"
}
}
}

重启 Consul 使配置生效:

1
sudo systemctl reload consul

6.2 通过 API 注册服务

1
2
3
4
5
6
7
8
# 注册服务
curl --request PUT \
--data @service.json \
http://localhost:8500/v1/agent/service/register

# 注销服务
curl --request PUT \
http://localhost:8500/v1/agent/service/deregister/web-api-1

6.3 服务发现查询

1
2
3
4
5
6
7
8
# HTTP API 查询
curl http://localhost:8500/v1/catalog/service/web-api

# DNS 查询
dig @127.0.0.1 -p 8600 web-api.service.consul

# 带标签查询
dig @127.0.0.1 -p 8600 production.web-api.service.consul

七、键值存储配置管理

7.1 存储配置

1
2
3
4
5
6
7
8
# 写入配置
consul kv put config/database/host "db.example.com"
consul kv put config/database/port "5432"
consul kv put config/database/user "app_user"
consul kv put config/database/password "secret123"

# 批量写入 JSON
echo '{"timeout": 30, "retries": 3}' | consul kv put config/app/settings

7.2 读取配置

1
2
3
4
5
6
7
8
# 读取单个键
consul kv get config/database/host

# 读取所有键
consul kv get -recurse config/

# JSON 格式输出
consul kv get -format=json config/database/host

7.3 配置变更监控

使用 Consul Template 实现配置动态更新:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 安装 consul-template
wget https://releases.hashicorp.com/consul-template/0.39.0/consul-template_0.39.0_linux_amd64.zip
unzip consul-template_0.39.0_linux_amd64.zip
sudo mv consul-template /usr/local/bin/

# 创建模板文件
cat > /etc/consul-template/templates/app.conf.ctmpl << 'EOF'
database_host = {{ key "config/database/host" }}
database_port = {{ key "config/database/port" }}
EOF

# 运行 consul-template
consul-template \
-consul-addr="127.0.0.1:8500" \
-template="/etc/consul-template/templates/app.conf.ctmpl:/etc/app/app.conf:systemctl restart app"

八、健康检查配置

8.1 HTTP 健康检查

1
2
3
4
5
6
7
8
9
10
11
{
"check": {
"id": "api-health",
"name": "API Health Check",
"http": "http://localhost:8080/health",
"method": "GET",
"interval": "10s",
"timeout": "5s",
"deregister_critical_service_after": "1m"
}
}

8.2 TCP 健康检查

1
2
3
4
5
6
7
8
9
{
"check": {
"id": "db-health",
"name": "Database TCP Check",
"tcp": "localhost:5432",
"interval": "10s",
"timeout": "3s"
}
}

8.3 脚本健康检查

1
2
3
4
5
6
7
8
9
{
"check": {
"id": "disk-check",
"name": "Disk Space Check",
"args": ["/usr/local/bin/check_disk.sh"],
"interval": "30s",
"timeout": "10s"
}
}

8.4 TTL 健康检查

1
2
3
4
5
6
7
8
9
10
11
12
{
"check": {
"id": "app-heartbeat",
"name": "Application Heartbeat",
"ttl": "30s",
"notes": "Application must report health every 30 seconds"
}
}

# 应用端报告健康状态
curl --request PUT \
http://localhost:8500/v1/agent/check/pass/app-heartbeat

九、ACL 安全配置

9.1 初始化 ACL 系统

1
2
3
4
5
6
7
8
9
10
# 生成 bootstrap token
consul acl bootstrap

# 输出示例:
# SecretID: 8d7c8f3a-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# AccessorID: 9e8d9f4b-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# Description: Bootstrap Token
# Local: false
# CreateTime: 2026-03-17T16:00:00.000Z
# Policies: 00000000-0000-0000-0000-000000000001 (global-management)

9.2 创建策略

1
2
3
4
5
6
7
8
9
10
11
# 创建只读策略
consul acl policy create \
-name "read-only" \
-description "Read-only access" \
-rules @read-only.hcl

# read-only.hcl 内容:
# agent_prefix "" { policy = "read" }
# node_prefix "" { policy = "read" }
# service_prefix "" { policy = "read" }
# kv_prefix "" { policy = "read" }

9.3 创建 Token

1
2
3
4
5
6
7
8
# 创建服务注册 token
consul acl token create \
-description "Web API Service Token" \
-policy-name "read-only" \
-service-identity "web-api"

# 在应用中使用 token
export CONSUL_HTTP_TOKEN="your-token-here"

十、多数据中心配置

10.1 配置 WAN 联合

在两个数据中心的 Server 节点上互相添加 WAN 连接:

1
2
3
4
5
# 在 dc1 的 Server 上执行
consul join -wan 192.168.2.101

# 在 dc2 的 Server 上执行
consul join -wan 192.168.1.101

10.2 跨数据中心服务发现

1
2
3
4
5
# 查询特定数据中心的服务
curl http://localhost:8500/v1/catalog/service/web-api?dc=dc2

# DNS 查询
dig @127.0.0.1 -p 8600 web-api.service.dc2.consul

十一、监控与告警

11.1 Prometheus 集成

1
2
3
4
5
6
7
8
9
10
11
# Consul 自带 Prometheus metrics
curl http://localhost:8500/v1/agent/metrics?format=prometheus

# Prometheus 配置
scrape_configs:
- job_name: 'consul'
static_configs:
- targets: ['192.168.1.101:8500']
metrics_path: '/v1/agent/metrics'
params:
format: ['prometheus']

11.2 关键监控指标

指标 说明 告警阈值
consul_raft_fsm_pending Raft 待处理命令数 > 100
consul_runtime_total_alloc_bytes 内存分配总量 持续增长
consul_serf_members 集群成员数 < 期望值
consul_http_request_duration HTTP 请求延迟 P99 > 1s

11.3 告警规则示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
groups:
- name: consul
rules:
- alert: ConsulServerDown
expr: consul_serf_members{type="server"} < 3
for: 1m
annotations:
summary: "Consul Server 节点宕机"

- alert: ConsulRaftLeaderMissing
expr: consul_raft_state{state="leader"} == 0
for: 1m
annotations:
summary: "Consul Raft 集群无 Leader"

十二、备份与恢复

12.1 快照备份

1
2
3
4
5
6
7
# 创建快照
consul snapshot save backup.snap \
-http-addr=127.0.0.1:8500 \
-token=$CONSUL_HTTP_TOKEN

# 查看快照信息
consul snapshot inspect backup.snap

12.2 快照恢复

1
2
3
4
# 恢复快照(会重启 Consul)
consul snapshot restore backup.snap \
-http-addr=127.0.0.1:8500 \
-token=$CONSUL_HTTP_TOKEN

12.3 自动化备份脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
# /usr/local/bin/consul-backup.sh

BACKUP_DIR="/opt/consul/backups"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=7

mkdir -p $BACKUP_DIR

consul snapshot save ${BACKUP_DIR}/consul_${DATE}.snap \
-http-addr=127.0.0.1:8500 \
-token=$CONSUL_HTTP_TOKEN

# 清理旧备份
find $BACKUP_DIR -name "consul_*.snap" -mtime +$RETENTION_DAYS -delete

十三、性能调优

13.1 Raft 性能优化

1
2
3
4
# 在 Server 节点配置中调整
performance {
raft_multiplier = 1 # 默认 1,降低可提高响应速度但增加负载
}

13.2 内存优化

1
2
3
4
5
# 限制 Go GC 触发阈值
export GOGC=50

# systemd 配置中添加
Environment="GOGC=50"

13.3 网络优化

1
2
3
4
5
6
7
8
# 调整 Serf 配置
serf_lan_config {
memberlist_config {
gossip_interval = "200ms"
probe_interval = "500ms"
probe_timeout = "250ms"
}
}

十四、故障排查

14.1 常见问题

问题 1:节点无法加入集群

1
2
3
4
5
6
7
8
# 检查网络连通性
consul members -detailed

# 检查日志
journalctl -u consul -f

# 验证端口开放
nc -zv 192.168.1.101 8301

问题 2:Raft 集群无法选举 Leader

1
2
3
4
5
# 检查 Raft 状态
consul operator raft list-peers

# 检查 Server 节点数量是否为奇数
# 确保 bootstrap_expect 配置正确

问题 3:服务注册后无法发现

1
2
3
4
5
# 检查服务状态
consul catalog services

# 检查健康检查状态
curl http://localhost:8500/v1/health/service/web-api

14.2 调试模式

1
2
3
4
5
# 以调试模式启动
consul agent -dev -log-level=debug

# 启用 HTTP 调试端点
curl http://localhost:8500/debug/pprof/goroutine?debug=2

十五、最佳实践

15.1 部署建议

  1. Server 节点数量:始终使用奇数(3 或 5),避免脑裂
  2. 节点分布:跨可用区部署,提高容灾能力
  3. 存储介质:使用 SSD 存储 Raft 日志
  4. 网络隔离:Server 节点间使用独立网络

15.2 安全建议

  1. 启用 ACL:生产环境必须启用 ACL
  2. 启用 TLS:节点间通信加密
  3. 最小权限:为不同服务分配最小必要权限
  4. 定期轮换:定期轮换 Token 和证书

15.3 运维建议

  1. 监控告警:配置关键指标监控
  2. 定期备份:自动化快照备份
  3. 版本管理:灰度升级,避免同时升级所有节点
  4. 文档维护:维护集群拓扑和配置文档

十六、总结

Consul 作为成熟的服务发现和配置管理工具,在现代云原生架构中扮演着重要角色。通过本文的部署实践,您可以构建一个高可用、易维护的 Consul 集群,为微服务架构提供可靠的基础设施支撑。

关键要点:

  • Server 节点采用 3 或 5 节点奇数部署
  • 启用 ACL 和 TLS 保障安全
  • 配置合理的健康检查机制
  • 建立完善的监控和备份体系
  • 遵循最小权限原则分配 Token

参考文档: