0x00 前言
Envoy 是一个开源的边缘服务代理,也是 Istio Service Mesh 默认的数据平面,专为云原生应用程序设计。与 HAProxy 以及 Nginx 等传统 Proxy 依赖静态配置文件来定义各种资源以及数据转发规则不同,Envoy 几乎所有配置都可以通过订阅来动态获取。对应的发现服务以及各种各样的 API 统称为 xDS
。Envoy 与 xDS
之间通过 Proto 约定请求和响应的数据模型,不同类型资源,对应的数据模型也不同。Envoy 因其设计理念 ** 一个为大型现代服务化架构设计的七层代理和通信总线 **,成为了云原生时代七层网关的最佳选择。
基础入门教程:
envoy 架构
Envoy 进程中运行着一系列 Inbound/Outbound 监听器(Listener),其中 Inbound 代理入站流量,Outbound 代理出站流量。Listener 的核心就是过滤器链(FilterChain),链中每个过滤器都能够控制流量的处理流程。Envoy 接收到请求后,会先走 FilterChain,通过各种 L3/L4/L7 Filter 对请求进行处理,然后再路由到指定的集群(Cluster),并通过负载均衡获取一个目标地址,最后再转发出去。其中每一个环节可以静态配置,也可以动态服务发现(即 xDS,包含了LDS/RDS/CDS/EDS/SDS等)
笔者理解,可以通过envoy配置出想要的转发模型
envoy简单部署及使用
0x01 envoy 配置(控制流程)
Envoy 使用 YAML
配置来控制代理的行为,可以通过静态/动态来配置。大概结构如下:
listen -- 监听器
1.监听的地址
2.过滤链
filter1
路由: 转发到哪里
virtual_hosts(route_config)
只转发什么
转发到哪里 --> 由后面的 cluster 来定义
filter2
filter3
# envoyproxy.io/docs/envoy/v1.28.0/api-v3/config/filter/filter
cluster
转发规则
endpoints
--指定了转到后端地址
当然,这只是最基础的配置,实际envoy可以有多种组合,甚至是Listener To Listener都可以
0x02 第一个例子:简单代理
本例子的功能:监听 10000
端口,将请求转发到 www.baidu.com:80
,配置文件 参考,下面简单分析下这个yaml文件:
1、需要在静态配置下面定义 Envoy 的监听器(Listener),监听器是 Envoy 监听请求的网络配置(如 IP 地址和端口)。这里设置监听 IP 地址为 0.0.0.0
,并在端口 10000
上进行监听
static_resources: #定义正在使用的接口配置,配置静态 API
listeners:
- name: listener_0 # 监听器的名称
address:
socket_address:
address: 0.0.0.0 # 监听器的地址
port_value: 10000 # 监听器的端口
2、通过 Envoy 监听传入的流量,下一步是定义如何处理这些请求。每个监听器都有一组过滤器(filters),并且不同的监听器可以具有一组不同的过滤器。过滤器是通过 filter_chains
来定义,每个过滤器的目的是找到传入请求的匹配项,以使其与目标地址进行匹配。写法如下:
name: 指定使用哪个过滤器
typed_config:
"@type": type.googleapis.com/envoy.过滤器的具体值 #@type 的值到文档里找具体的值
参数1:值1
参数2:值2
......
一般需要解决如下问题:
- 需要实现针对哪些流量处理?选择合适的filter(HTTP 相关的,一般选择
HTTP connection manager
,name 的位置应该写envoy.filters.network.http_connection_manager
) - 需要处理何种参数?设置该filter支持的处理参数,参数选择在此
参考本例配置(注释):
static_resources:
listeners:
- name: listener_0 # 监听器的名称
address:
socket_address:
address: 0.0.0.0 # 监听器的地址
port_value: 10000 # 监听器的端口
filter_chains: # 配置过滤器链
# 在此地址收到的任何请求都会通过这一系列过滤链发送。
- filters:
# 指定要使用哪个过滤器,下面是envoy内置的网络过滤器,如果请求是 HTTP 它将通过此 HTTP 过滤器
# 该过滤器将原始字节转换为HTTP级别的消息和事件(例如接收到的header、接收到的正文数据等)
# 它还处理所有HTTP连接和请求中常见的功能,例如访问日志记录、请求ID生成和跟踪、请求/响应头操作、路由表管理和统计信息。
- name: envoy.filters.network.http_connection_manager
typed_config:
# 需要配置下面的类型,启用 http_connection_manager
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
access_log: # 连接管理器发出的 HTTP 访问日志的配置
- name: envoy.access_loggers.stdout # 输出到stdout
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
http_filters: # 定义http过滤器链
- name: envoy.filters.http.router # 调用7层的路由过滤器
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"] # 要匹配的主机名列表,*表示匹配所有主机
routes:
- match:
prefix: "/" # 要匹配的 URL 前缀(这里为根路由)
route: # 路由规则,发送请求到 service_baidu 集群
host_rewrite_literal: www.baidu.com # 更改 HTTP 请求的入站 Host 头信息
cluster: service_baidu # 将要处理请求的集群名称,下面会有相应的实现
在上述配置中,过滤器使用了 envoy.filters.network.http_connection_manager
,这是为 HTTP 连接设计的一个内置过滤器,它的作用将原始字节转换为 HTTP 级别的消息和事件(例如接收到的 header、接收到的正文数据等),它还处理所有 HTTP 连接和请求中常见的功能,例如访问日志记录、请求 ID 生成和跟踪、请求/响应头操作、路由表管理和统计信息,该过滤器有如下常用参数:
stat_prefix
:为连接管理器发出统计信息时使用的一个前缀route_config
:路由配置,如果虚拟主机匹配上了则检查路由。在配置中,无论请求的主机域名是什么,route_config
都匹配所有传入的 HTTP 请求routes
:如果 URL 前缀匹配,则一组路由规则定义了下一步将发生的状况host_rewrite_literal
:更改 HTTP 请求的入站Host
头信息cluster
: 将要处理请求的集群名称,下面会有相应的实现http_filters
: 该过滤器允许 Envoy 在处理请求时去适应和修改请求
请求在filter匹配完成后,最后会到达 Clusters,本例中将主机定义为访问 HTTPS 的 www.baidu.com
域名,如果定义了多个主机,则 Envoy 将执行轮询(Round Robin)策略
clusters:
- name: service_baidu # 集群的名称,与上面的 router 中的 cluster 对应
type: LOGICAL_DNS # 用于解析集群(生成集群端点)时使用的服务发现类型,可用值有STATIC、STRICT_DNS 、LOGICAL_DNS、ORIGINAL_DST和EDS等
connect_timeout: 0.25s
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN # 负载均衡算法,支持ROUND_ROBIN、LEAST_REQUEST、RING_HASH、RANDOM、MAGLEV和CLUSTER_PROVIDED;
load_assignment: # 以前的 v2 版本的 hosts 字段废弃了,现在使用 load_assignment 来定义集群的成员,指定 STATIC、STRICT_DNS 或 LOGICAL_DNS 集群的成员需要设置此项。
cluster_name: service_baidu # 集群的名称
endpoints: # 需要进行负载均衡的端点列表
- lb_endpoints:
- endpoint:
address:
socket_address:
address: www.baidu.com
port_value: 443
transport_socket: # 用于与上游集群通信的传输层配置
name: envoy.transport_sockets.tls # tls 传输层
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
sni: www.baidu.com
完整配置文件 参考
部署此例子
docker logs -f --tail=200 cfb4ba22c969
配置流程解读
如何容易理解envoy配置?还是结合代理程序的流程来思考,作为一个代理,首先要能获取请求流量,通常是采用监听端口的方式实现;其次拿到请求数据后需要对其做处理,例如添加 Header
或校验某个 Header
字段的内容等,这里针对来源数据的层次不同,又可以分为 L3/L4/L7,然后将请求转发出去;转发这里又可以衍生出如果后端是一个集群,需要从中挑选一台机器,如何挑选又涉及到负载均衡等;所以,回看上面的yaml配置:
listener
:Envoy 的监听地址,真正干活的。Envoy 会暴露一个或多个 Listener 来监听客户端的请求filter
: 过滤器:在 Envoy 中指的是一些可插拔和可组合的逻辑处理层,是 Envoy 核心逻辑处理单元route_config
:路由规则配置,即将请求路由到后端的哪个集群cluster
:服务提供方集群,Envoy 通过服务发现定位集群成员并获取服务,具体路由到哪个集群成员由负载均衡策略决定
比如下图,规则的应用顺序是(HTTP):
listeners
–>filter_chains
–>http_connection_manager
–>http_filters
–>route_config
–>cluster
–>clusters
0x03 第二个例子:使用 SSL/TLS 保护流量
0x04 第三个例子:Nginx 迁移到 Envoy
Flow:Life of a Request
0x05 构建一个简单的XDS
本小节详细介绍下XDS机制
有关XDS的基础,可以参考此文XDS学习笔记
0x05 HTTP dynamic forward proxy
0x05 Envoy 的 Internal Listener 机制
socket 在操作系统内核接收网络数据,但 Envoy还支持一种用户空间 socket,即Internal Listener ,用于从该用户空间 socket接收数据包,envoy 叫做Internal Listener
Internal Listener 需要和一个 Cluster 一起使用,配置在 Cluster 中作为接收流量的 endpoint。如下所示:
0x06 其他例子
0x07 相关issue
- Envoy forward proxy - man in the middle with ssl termination
- TLS bumping: decrypting communications between internal and external services
0x08 总结
0x09 参考
- Envoy 架构及其在网易轻舟的落地实践
- Envoy 的架构与基本配置解析
- Learn Envoy Fundamentals
- Envoy 架构理解 – 理解 xDS/Listener/Cluster/Router/Filter
- Envoy 入门教程
- envoy proxy 调研笔记
- 动态转发代理
- Envoy 简单入门示例
- 为什么 Envoy Gateway 是云原生时代的七层网关?
- Envoy Gateway 指南:架构设计与开源贡献
- Envoy Gateway 首个正式开源版本介绍
- Envoy Gateway 指南:架构设计与开源贡献
- HCM upstream/downstream 事件驱动协作下的 HTTP 反向代理流程
- 动态转发代理
- TLS bumping in Envoy
- Istio Ambient 模式流量管理实现机制详解(一)
- req-resp-flow-timeline.drawio
- Envoy Proxy as Explicit proxy
- XDS核心概念
- XDS学习笔记
- Envoy xDS示例