文档
目标
用 Envoy 搭建反向代理,实现流量分割(金丝雀发布):90% 流量到 v1,10% 到 v2。演示 L7 路由、加权分流的完整配置。
完整代码
架构
Browser → Envoy(:10000) ──90%──→ backend-v1(:8081)
──10%──→ backend-v2(:8082)
1. 后端服务 v1(Python)
# backend_v1.py
from http.server import HTTPServer, BaseHTTPRequestHandler
import os
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(b'{"version":"v1","message":"This is stable version"}')
HTTPServer(("0.0.0.0", 8081), Handler).serve_forever()
2. 后端服务 v2(Python)
# backend_v2.py
from http.server import HTTPServer, BaseHTTPRequestHandler
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(b'{"version":"v2","message":"This is canary version"}')
HTTPServer(("0.0.0.0", 8082), Handler).serve_forever()
3. Envoy 配置(envoy-canary.yaml)
static_resources:
listeners:
- name: main_listener
address:
socket_address: { address: 0.0.0.0, port_value: 10000 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress
route_config:
name: canary_routes
virtual_hosts:
- name: app
domains: ["*"]
routes:
# 精确匹配:/health 走 v1
- match: { path: "/health" }
route:
cluster: backend_v1
# 前缀匹配 + 超时配置
- match: { prefix: "/" }
route:
weighted_clusters:
clusters:
- name: backend_v1
weight: 90
- name: backend_v2
weight: 10
total_weight: 100
retry_policy:
retry_on: "5xx"
num_retries: 2
per_try_timeout: 1s
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: backend_v1
type: STRICT_DNS
connect_timeout: 2s
load_assignment:
cluster_name: backend_v1
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: 127.0.0.1, port_value: 8081 }
# 异常检测(熔断)
circuit_breakers:
thresholds:
- priority: DEFAULT
max_connections: 100
max_pending_requests: 100
max_requests: 100
max_retries: 10
health_checks:
- timeout: 1s
interval: 5s
unhealthy_threshold: 3
healthy_threshold: 1
http_health_check:
path: "/health"
- name: backend_v2
type: STRICT_DNS
connect_timeout: 2s
load_assignment:
cluster_name: backend_v2
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: 127.0.0.1, port_value: 8082 }
circuit_breakers:
thresholds:
- priority: DEFAULT
max_connections: 100
max_pending_requests: 100
max_requests: 100
max_retries: 10
4. 管理接口配置
# admin 接口(添加到 envoy-canary.yaml 顶层)
admin:
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
运行步骤
# 1. 启动后端服务
python backend_v1.py &
python backend_v2.py &
# 2. 启动 Envoy
envoy -c envoy-canary.yaml
# 3. 验证流量分割
for i in {1..20}; do curl -s http://localhost:10000/api; done | sort | uniq -c
# 预期: 约 18 次 v1, 2 次 v2
# 4. 查看 Envoy 管理接口
curl http://localhost:9901/stats | grep cluster.backend_v1
curl http://localhost:9901/clusters
curl http://localhost:9901/config_dump
# 5. 健康检查
curl http://localhost:10000/health
预期输出
$ for i in {1..20}; do curl -s http://localhost:10000/api; done | sort | uniq -c
18 {"version":"v1","message":"This is stable version"}
2 {"version":"v2","message":"This is canary version"}
# 管理接口
$ curl http://localhost:9901/clusters
# backend_v1::observability_name::backend_v1
# backend_v2::observability_name::backend_v2
关键点
weighted_clusters实现加权流量分割,零代码金丝雀发布retry_policy配置自动重试,retry_on: 5xx只在服务端错误时重试circuit_breakers防止连接池耗尽health_checks自动剔除不健康实例- Admin 接口提供运行时诊断能力