与 HashiCorp Consul 集成
HashiCorp Consul 维护一个记录服务实例及其健康状态的服务目录。通过服务发现,APISIX 可以监视在 Consul 服务名称下注册的健康实例,并将其用作动态上游节点。
本指南将启动一个 Consul 服务器和两个示例服务,为这两个服务注册健康检查,并配置 APISIX 发现健康实例并在它们之间进行负载均衡。
本教程在同一 Docker 网络中运行 APISIX、Consul 和示例服务。生产部署应使用 APISIX 实例可以访问的地址。
如果所有服务都在 Kubernetes 中运行,通常不需要 Consul,因为 Kubernetes 可以通过 Service 和 DNS 提供服务发现。

前置条件
启动 Consul
在 APISIX 快速入门网络中启动一个 Consul 服务器。端口 8500 绑定到环回接口,以供本地访问 API:
docker run \
--name consul \
-d \
-p 127.0.0.1:8500:8500 \
--network apisix-quickstart-net \
hashicorp/consul:2.0.3 \
consul agent \
-server \
-bootstrap-expect=1 \
-node=consul-server \
-client 0.0.0.0 \
-log-level info \
-data-dir=/consul/data
Consul Agent 会监听容器内的所有接口,使 APISIX 能够访问它;发布到主机的端口则仅限环回接口访问。
此单服务器开发配置仅用于本地测试。准备生产 Consul 集群时,请遵循 HashiCorp 的部署指南。
启动示例 Web 服务
在 APISIX 快速入门网络中启动两个 NGINX 服务。每个服务返回不同的响应,以便观察负载均衡效果。
创建 web1.conf:
cat > web1.conf <<'EOF'
events {
worker_connections 1024;
}
http {
access_log off;
server {
listen 80;
location / {
return 200 "Application 1 is running";
}
}
}
EOF
创建 web2.conf:
cat > web2.conf <<'EOF'
events {
worker_connections 1024;
}
http {
access_log off;
server {
listen 80;
location / {
return 200 "Application 2 is running";
}
}
}
EOF
启动 web1:
docker run -d \
--name web1 \
--network apisix-quickstart-net \
-v "$(pwd)/web1.conf:/etc/nginx/nginx.conf:ro" \
nginx:1.30.4-alpine
启动 web2:
docker run -d \
--name web2 \
--network apisix-quickstart-net \
-v "$(pwd)/web2.conf:/etc/nginx/nginx.conf:ro" \
nginx:1.30.4-alpine
在 Consul 中注册服务
保存 APISIX 快速入门网络中服务容器的地址:
export WEB1_IP="$(
docker inspect \
--format '{{(index .NetworkSettings.Networks "apisix-quickstart-net").IPAddress}}' \
web1
)"
export WEB2_IP="$(
docker inspect \
--format '{{(index .NetworkSettings.Networks "apisix-quickstart-net").IPAddress}}' \
web2
)"
将 web1 注册为 svc-a 的第一个实例。HTTP 检查让 Consul 仅在 NGINX 正常响应时将该实例报告为健康:
curl "http://127.0.0.1:8500/v1/agent/service/register" -X PUT \
-H "Content-Type: application/json" \
--data-binary @- <<EOF
{
"ID": "svc-a1",
"Name": "svc-a",
"Address": "$WEB1_IP",
"Port": 80,
"Check": {
"HTTP": "http://$WEB1_IP/",
"Interval": "5s",
"Timeout": "2s"
}
}
EOF
将 web2 注册为第二个实例:
curl "http://127.0.0.1:8500/v1/agent/service/register" -X PUT \
-H "Content-Type: application/json" \
--data-binary @- <<EOF
{
"ID": "svc-a2",
"Name": "svc-a",
"Address": "$WEB2_IP",
"Port": 80,
"Check": {
"HTTP": "http://$WEB2_IP/",
"Interval": "5s",
"Timeout": "2s"
}
}
EOF
❶ Address 和 Port:APISIX 用于所发现上游节点的网络位置。
❷ Check:Consul 每五秒运行一次的 HTTP 健康检查。APISIX 仅发现检查状态为通过的实例。
验证 Consul 报告的两个服务实例状态均为 passing:
curl "http://127.0.0.1:8500/v1/health/service/svc-a?passing=true" | \
jq '[.[] | {
ID: .Service.ID,
Address: .Service.Address,
Port: .Service.Port,
Status: .Checks[-1].Status
}]'
响应应包含 svc-a1 和 svc-a2 两个条目,且状态均为 passing。
将 Consul 连接到 APISIX
将 Consul 服务器添加到 APISIX 的 config.yaml 配置文件。该命令会移除 YAML 文档终止符、追加服务发现配置,然后恢复终止符:
docker exec -i apisix-quickstart sh -c \
'sed -i "/^\.\.\.$/d" /usr/local/apisix/conf/config.yaml &&
cat >> /usr/local/apisix/conf/config.yaml' <<'EOF'
discovery:
consul:
servers:
- http://consul:8500
...
EOF
servers 数组 包含 Consul HTTP API 地址,APISIX 会监视这些地址上的服务和健康状态更新。
重新加载 APISIX 以使配置更改生效:
docker exec apisix-quickstart apisix reload
在 APISIX 中创建路由
创建一个路由,并将上游配置为使用 Consul 发现 svc-a 服务:
- Admin API
- ADC
通过 Admin API 创建路由:
curl -i "http://127.0.0.1:9180/apisix/admin/routes/consul-web-route" -X PUT \
--data-binary @- <<'EOF'
{
"uri": "/consul/web/*",
"upstream": {
"service_name": "svc-a",
"discovery_type": "consul",
"type": "roundrobin"
}
}
EOF
响应 HTTP/1.1 201 Created 表明路由已创建。
创建包含路由配置的 adc.yaml:
services:
- name: consul-web
routes:
- name: consul-web-route
uris:
- /consul/web/*
upstream:
service_name: svc-a
discovery_type: consul
type: roundrobin
将配置同步到 APISIX:
adc sync -f adc.yaml
验证服务发现
验证 APISIX 已发现两个服务实例:
curl -fsS "http://127.0.0.1:9090/v1/discovery/consul/dump" | \
jq --arg web1 "$WEB1_IP" --arg web2 "$WEB2_IP" -e '
([.services["svc-a"][] | select(.port == 80) | .host] | sort) ==
([$web1, $web2] | sort)
'
当发现的节点集合包含两个服务地址时,该命令返回 true。向路由发送多个请求:
for _ in $(seq 1 10); do
curl "http://127.0.0.1:9080/consul/web/"
echo
done
每个请求应返回以下响应之一。你可能会看到两种响应,且顺序可能不同:
Application 1 is running
Application 2 is running
停止 web1,验证 Consul 会从 APISIX 服务发现中移除不健康的实例:
docker stop web1
轮询 APISIX Control API,直到发现的 svc-a 节点集合中只包含 web2。该命令最多按一秒间隔尝试 20 次;如果服务发现未收敛,则以非零状态退出:
for _ in $(seq 1 20); do
nodes="$(curl --max-time 2 -fsS \
"http://127.0.0.1:9090/v1/discovery/consul/dump" | \
jq -r '.services["svc-a"] | map("\(.host):\(.port)") | join(",")')" || nodes=""
[ "$nodes" = "$WEB2_IP:80" ] && break
sleep 1
done
[ "$nodes" = "$WEB2_IP:80" ]
命令成功即确认 APISIX 已从发现的节点中移除 web1。再发送一个请求,验证流量到达 web2:
curl "http://127.0.0.1:9080/consul/web/"
响应应为:
Application 2 is running
验证后重新启动 web1:
docker start web1
后续步骤
使用服务发现 Control API 端点检查已发现的服务并排查注册中心更新问题。有关更多信息,请参阅 Control API 参考。
除 Consul 外,APISIX 还支持与 Eureka、Nacos 和其他服务发现平台集成。