4. Envoy 代理基础与配置
在 Service Mesh 中,Envoy 是数据面的核心代理。无论是 Istio 的 sidecar 模式,还是独立部署的边缘代理,流量最终都要经过 Envoy 完成转发、路由、负载均衡、熔断和可观测性采集。理解 Envoy 的配置模型,是掌握云原生流量治理的关键一步。本节从 Envoy 的核心概念出发,逐步展开监听器、集群、路由三大配置支柱,并通过静态配置与动态配置的对比实战,帮助读者建立完整的配置认知。
一、Envoy 的核心概念与配置模型
Envoy 的配置围绕几个核心对象展开:Listener(监听器)负责在指定地址和端口上接收连接;Cluster(集群)定义一组逻辑上等价的上游主机,并承载负载均衡、健康检查等策略;Route(路由)决定请求如何从监听器匹配到具体集群;Filter(过滤器)则在连接或请求处理链中插入具体能力,如 HTTP 连接管理、限流、鉴权等。这些对象通过 Bootstrap 引导配置串联起来,形成一棵从入口到出口的配置树。
Envoy 的配置分为静态配置和动态配置两类。静态配置在启动时一次性加载,适合结构稳定、变更不频繁的场景;动态配置通过 xDS 协议从控制面(如 Istio 的 Pilot、自研的 xDS Server)实时下发,支持监听器、集群、路由、端点等资源的增量更新,是 Service Mesh 实现动态流量治理的基础。
二、监听器:流量的入口
监听器是 Envoy 接收流量的第一站。一个监听器至少包含监听地址、端口、协议类型和过滤器链。在 HTTP 场景中,通常使用 envoy.filters.network.http_connection_manager 作为网络过滤器,它负责解析 HTTP 协议、执行路由匹配,并将请求交给后续的 HTTP 过滤器链。
下面是一个静态配置中的监听器示例,监听 0.0.0.0:8080,并将所有请求交给名为 local_route 的路由配置:
static_resources:
listeners:
- name: main_listener
address:
socket_address:
address: 0.0.0.0
port_value: 8080
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_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: service_cluster }
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
这里的关键点在于:route_config 可以直接内联在监听器中(静态路由),也可以通过 rds 字段引用外部路由配置(动态路由)。当使用 RDS 时,监听器只保留一个占位配置,实际路由规则由控制面动态推送。
三、集群:上游主机的逻辑分组
集群定义了一组提供相同服务的上游主机。Envoy 支持多种服务发现方式:静态 IP 列表、DNS 解析、以及通过 EDS 动态获取端点。集群配置中最重要的参数包括负载均衡算法、健康检查、连接池和熔断阈值。
以下是一个静态集群配置示例,使用轮询负载均衡,并配置了主动健康检查:
clusters:
- name: service_cluster
connect_timeout: 2s
type: STATIC
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: service_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 10.0.0.1
port_value: 8080
- endpoint:
address:
socket_address:
address: 10.0.0.2
port_value: 8080
health_checks:
- timeout: 1s
interval: 5s
unhealthy_threshold: 2
healthy_threshold: 2
http_health_check:
path: /healthz
当 type 设为 STATIC 时,端点列表固定不变;若设为 EDS,则端点由控制面通过 EDS 协议动态推送,适合 Pod IP 频繁变化的 Kubernetes 环境。健康检查的 unhealthy_threshold 和 healthy_threshold 决定了主机状态切换的灵敏度,生产环境中需要根据服务特性调整。
四、路由:请求到集群的匹配规则
路由配置决定了请求如何被匹配并转发到目标集群。Envoy 的路由匹配支持前缀、精确路径、正则表达式、请求头、查询参数等多种条件。匹配顺序从上到下,第一个命中的路由生效。路由还可以配置重定向、重写、超时、重试等策略。
一个典型的路由配置如下,将 /api/v1 前缀的请求转发到 v1_cluster,其余请求转发到 default_cluster:
route_config:
name: local_route
virtual_hosts:
- name: backend
domains: ["*"]
routes:
- match:
prefix: "/api/v1"
route:
cluster: v1_cluster
timeout: 3s
retry_policy:
retry_on: "5xx"
num_retries: 2
- match:
prefix: "/"
route:
cluster: default_cluster
注意 domains 字段用于匹配 Host 头,"*" 表示匹配所有域名。在生产环境中,通常会根据域名或路径前缀划分不同的虚拟主机,实现多租户或灰度发布。
五、静态配置与动态配置的对比实战
静态配置适合快速验证和稳定拓扑,动态配置适合频繁变更的云原生环境。两者的核心差异在于:静态配置在启动时加载,变更需要重启 Envoy;动态配置通过 xDS 协议实时推送,支持增量更新和 ACK/NACK 确认机制。
| 对比维度 | 静态配置 | 动态配置(xDS) |
|---|---|---|
| 加载时机 | 启动时一次性加载 | 运行时按需推送 |
| 变更方式 | 修改 YAML 后重启 | 控制面推送增量更新 |
| 适用场景 | 固定拓扑、边缘代理 | Kubernetes、Service Mesh |
| 端点发现 | STATIC / DNS | EDS 动态端点 |
| 配置一致性 | 人工保证 | 控制面统一管理 |
在实际操作中,可以先使用静态配置验证 Envoy 的基本转发能力,再逐步迁移到动态配置。例如,在 Kubernetes 中部署 Istio 时,Envoy sidecar 的 Bootstrap 配置只包含最小化的静态部分(如 xDS 服务器地址、节点元数据),其余监听器、集群、路由全部由 Pilot 动态下发。这种设计使得 Envoy 可以快速启动,并在控制面就绪后立即获取完整配置。
envoy --mode validate -c config.yaml 验证静态配置的语法正确性。对于动态配置,可以通过 Envoy 的管理接口 /config_dump 查看当前生效的完整配置,通过 /clusters 查看集群健康状态,通过 /stats 观察请求计数和延迟分布。