WEBKT

Envoy 原生扩展开发指南:深入 API 与实践

33 0 0 0

为什么需要 Envoy 扩展?

Envoy 扩展类型

Envoy 扩展开发:HTTP Filter 示例

1. 开发环境准备

2. 创建 Filter 源码

3. 编译 Filter

4. 配置 Envoy 使用 Filter

5. 运行 Envoy

6. 测试 Filter

Envoy 扩展开发:其他注意事项

总结

Envoy 作为一款高性能、可扩展的代理,被广泛应用于服务网格和边缘代理场景。其强大的扩展性,允许开发者根据自身需求定制功能,满足各种复杂的应用场景。本文将深入探讨 Envoy 的原生扩展机制,带你了解如何利用 Envoy 提供的 API 进行自定义扩展开发,打造属于你自己的专属功能。

为什么需要 Envoy 扩展?

虽然 Envoy 本身已经提供了丰富的功能,但在实际应用中,你可能会遇到以下场景,需要通过扩展来满足需求:

  • 协议定制: 需要支持 Envoy 尚未原生支持的协议,例如一些私有协议或行业特定协议。
  • 自定义过滤: 在请求处理流程中添加自定义逻辑,例如实现特殊的认证、授权、限流、监控等。
  • 服务发现集成: 集成自定义的服务发现机制,例如 Consul、Etcd 或其他内部系统。
  • 访问日志定制: 以特定格式记录访问日志,或将日志发送到自定义的日志系统。
  • 指标定制: 收集自定义的性能指标,并将其暴露给监控系统。
  • Tracing 集成: 集成不同的 Tracing 系统,例如 Jaeger、Zipkin 或其他定制系统。

Envoy 扩展类型

Envoy 提供了多种扩展点,允许你在不同层面进行定制。主要扩展类型包括:

  1. Filters (过滤器): 这是最常用的扩展类型。Filters 位于 Envoy 的请求处理流水线中,可以对请求和响应进行各种操作,例如修改头部、修改 Body、进行路由决策、执行健康检查等。Filters 分为以下几种:
    • Listener Filters (监听器过滤器): 在 Listener 接收到连接后,但在创建网络 Filter 链之前执行。可用于实现 TLS 终结、连接重定向等。
    • Network Filters (网络过滤器): 在 Listener 接收到连接后,对连接上的原始数据流进行处理。可用于实现协议解析、流量整形等。
    • HTTP Filters (HTTP 过滤器): 在 Network Filter 处理完数据后,如果数据是 HTTP 协议,则会进入 HTTP Filter 链。HTTP Filters 可以对 HTTP 请求和响应进行更细粒度的操作。这是最常用,也是最强大的过滤器。
  2. Access Loggers (访问日志记录器): 用于记录请求的详细信息,例如请求时间、来源 IP、目标地址、请求头、响应码等。你可以自定义日志格式,或将日志发送到不同的后端系统。
  3. Tracers (追踪器): 用于实现分布式追踪,帮助你了解请求在整个系统中的调用链路。Envoy 支持集成多种 Tracing 系统。
  4. Health Checkers (健康检查器): 用于主动探测后端服务的健康状态。Envoy 支持多种健康检查方式,例如 HTTP、TCP 等。你可以自定义健康检查逻辑。
  5. Resource Monitors (资源监控器): 用于监控 Envoy 自身的资源使用情况,例如内存、CPU 等。当资源使用超过阈值时,可以触发告警或执行其他操作。
  6. Clusters (集群): 定义了一组提供相同服务的上游主机。Envoy 支持多种负载均衡算法和健康检查机制。你可以自定义集群的发现方式。
  7. Endpoints (端点): 集群中的单个上游主机实例。
  8. Listeners (监听器): 监听特定的端口,接收来自客户端的连接。你可以自定义监听器的配置,例如绑定的 IP 地址、端口、使用的协议等。
  9. Secrets Discovery Service (SDS): 用于动态获取 TLS 证书和其他机密信息。你可以集成自定义的 SDS 实现。
  10. **Runtime Configuration(运行时配置):**提供了一个动态修改Envoy配置的机制。

Envoy 扩展开发:HTTP Filter 示例

下面以 HTTP Filter 为例,详细介绍如何进行 Envoy 扩展开发。HTTP Filter 是最常用也是功能最强大的扩展类型。我们将创建一个简单的 HTTP Filter,用于在请求头中添加一个自定义字段 X-My-Custom-Header

1. 开发环境准备

  • 安装 Bazel: Envoy 使用 Bazel 作为构建系统。你需要安装 Bazel。
  • 获取 Envoy 源码: 从 GitHub 克隆 Envoy 源码。
  • C++编译器: 确保已安装支持C++14或者更高版本的编译器。

2. 创建 Filter 源码

在 Envoy 源码目录下创建一个新的目录,例如 source/extensions/filters/http/my_custom_filter

在该目录下创建三个文件:

  • my_custom_filter.h: 定义 Filter 的类。
#ifndef EXTENSIONS_FILTERS_HTTP_MY_CUSTOM_FILTER_MY_CUSTOM_FILTER_H_
#define EXTENSIONS_FILTERS_HTTP_MY_CUSTOM_FILTER_MY_CUSTOM_FILTER_H_
#include "envoy/http/filter.h"
namespace Envoy {
namespace Extensions {
namespace HttpFilters {
namespace MyCustomFilter {
class MyCustomFilter : public Http::PassThroughFilter {
public:
MyCustomFilter() = default;
Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& headers,
bool end_stream) override;
};
} // namespace MyCustomFilter
} // namespace HttpFilters
} // namespace Extensions
} // namespace Envoy
#endif // EXTENSIONS_FILTERS_HTTP_MY_CUSTOM_FILTER_MY_CUSTOM_FILTER_H_
  • my_custom_filter.cc: 实现 Filter 的逻辑。
#include "source/extensions/filters/http/my_custom_filter/my_custom_filter.h"
#include "envoy/http/header_map.h"
namespace Envoy {
namespace Extensions {
namespace HttpFilters {
namespace MyCustomFilter {
Http::FilterHeadersStatus MyCustomFilter::decodeHeaders(Http::RequestHeaderMap& headers,
bool /*end_stream*/) {
headers.addCopy("x-my-custom-header", "My Custom Value");
return Http::FilterHeadersStatus::Continue;
}
} // namespace MyCustomFilter
} // namespace HttpFilters
} // namespace Extensions
} // namespace Envoy
  • BUILD: Bazel 构建文件。
load("@envoy//bazel:envoy_build_system.bzl", "envoy_cc_extension", "envoy_extension_config")
envoy_cc_extension(
name = "my_custom_filter_lib",
srcs = [
"my_custom_filter.cc",
],
hdrs = [
"my_custom_filter.h",
],
deps = [
"//include/envoy/http:filter_interface",
"//source/common/common:minimal_logger_lib",
],
)
envoy_extension_config(
name = "my_custom_filter",
category = "envoy.filters.http",
type_urls = ["type.googleapis.com/envoy.extensions.filters.http.my_custom_filter.v3.MyCustomFilter"],
config_discovery = False,
config_inline = True,
deps = [":my_custom_filter_lib"],
)

3. 编译 Filter

在 Envoy 源码根目录下执行以下命令:

bazel build //source/extensions/filters/http/my_custom_filter:my_custom_filter_lib

编译成功后,会生成一个 .so 文件,这就是我们的 Filter 库。

4. 配置 Envoy 使用 Filter

修改 Envoy 的配置文件,添加 Filter 配置:

static_resources:
listeners:
- 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_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: service_google
http_filters:
- name: envoy.extensions.filters.http.my_custom_filter
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.my_custom_filter.v3.MyCustomFilter
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: service_google
connect_timeout: 0.25s
type: LOGICAL_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: service_google
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: www.google.com
port_value: 80

http_filters 部分,添加了 envoy.extensions.filters.http.my_custom_filter,并指定了 typed_config

5. 运行 Envoy

使用修改后的配置文件启动 Envoy。

6. 测试 Filter

向 Envoy 发送请求,你会发现响应头中包含了 x-my-custom-header: My Custom Value

Envoy 扩展开发:其他注意事项

  • 线程模型: Envoy 是多线程的,Filter 代码必须是线程安全的。
  • 内存管理: Envoy 使用引用计数来管理内存,你需要正确地处理对象的生命周期,避免内存泄漏。
  • 性能优化: Filter 的性能对 Envoy 的整体性能有很大影响。在开发 Filter 时,要注意性能优化,避免不必要的开销。
  • API版本控制: Envoy API 使用 protobuf 进行版本控制。 确保使用与 Envoy 版本兼容的 API。
  • 测试: 编写单元测试和集成测试, 确保Filter功能的正确性和稳定性。

总结

Envoy 的扩展机制为开发者提供了强大的定制能力。通过原生扩展,你可以实现各种自定义功能,满足复杂的应用场景需求。本文以 HTTP Filter 为例,介绍了 Envoy 扩展开发的基本流程。希望本文能够帮助你入门 Envoy 扩展开发,打造出更强大、更灵活的代理解决方案。 除了HTTP Filter, 理解其他类型的Filter, 以及 Filter Chain 的工作原理也至关重要。 深入学习 Envoy 官方文档和示例代码, 是掌握 Envoy 扩展开发的最佳途径。

技术老炮儿 Envoy扩展开发服务网格

评论点评

打赏赞助
sponsor

感谢您的支持让我们更好的前行

分享

QRcode

https://www.webkt.com/article/8191