赞
踩
本文基于 envoy 1.21.0 (latest)
1 过滤器介绍
从 socket 中收取的请求先经过 listener_filters 处理,然后再由 filter_chains 处理,前者包含的 filter 称为 listener filter,后者包含的 filter 称为 network filter。因为 listener_filters 先起作用,因此它可以修改请求的信息,从而影响 filter_chains 的匹配。
1.1 过滤器简述
监听器过滤器
可以在加入 listener 的 listener_filter 字段中的 listener filter。 这些 filter 的主要作用是检测协议、解析协议,通过它们解析出的信息被用于匹配 filter_chains 中的 filter。
例如:
envoy.listener.http_inspector:判断应用层的数据是否使用 HTTP 协议,如果是,续继判断 HTTP 协议的版本号(HTTP 1.0、HTTP 1.1、HTTP 2)。
envoy.listener.original_src:用于透明代理,让 uptream 看到的是请求端的 IP,双方均感知不到 envoy 的存在。
envoy.listener.original_dst: 用来读取 socket 的配置项 SO_ORIGINAL_DST,用该 filter 获取报文的原始目地地址。
envoy.listener.proxy_protocol:解析代理协议,用该 filter 可以解析出真实的源 IP。
envoy.listener.tls_inspector: 用来判断是否使用 TLS 协议,如果是 TLS 协议,解析出 Server Name、Negotiation 信息,解析出来的信息用于 FilterChain 的匹配。
network 过滤器
操作原始字节。允许混合不同的过滤器组合,并匹配和附加到给定的监听器。
网络过滤器在一个有序的列表中被链起来(过滤器栈),称为过滤器链。每个监听器都有多个过滤器链和一个可选默认过滤器链。如果找不到最佳匹配的过滤链,将选择默认的过滤链来处理请求。如果没有提供默认的过滤链,连接将被关闭。
参考:https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/network_filters/network_filters
例如:
envoy.filters.network.mysql_proxy:能够解析 mysql 的通信协议,需要和 [TCP proxy][] 一起使用。
配置文件
filter_chains:
envoy.http_connection_manager:专门处理 http 协议的 network filter,内部又实现了 http filter。因为 http 最经常使用的协议,对代理功能需求也非常多样, HTTP connection manager 本身是一个比较复杂的 network filter,在 envoy 文档中被单独列出:HTTP connection 。 proto message 字段参考 连接管理器.proto 。
1.2 network filter chain 配置
说明:envoy 中每一个资源对象的参数配置都是通过 protobuf 来定义的。
监听器配置
过滤链配置定义,这里指 网络过滤器链,
listener.FilterChain
{
“filter_chain_match”: “{…}”,
“tls_context”: “{…}”,
“filters”: [],
“use_proxy_proto”: “{…}”,
“transport_socket”: “{…}”
}
过滤器链包裹着一组匹配判据,一个选项TLS上下文,一组过滤器,以及其他各种参数。
具体字段的说明:
FilterChainMatch 配置定义
指定为 Listener 选择特定过滤链的匹配判据。
为了选择一个过滤链,它的所有判据必须被传入的连接满足,其属性由网络堆栈和/或监听器过滤器设置。
以下顺序适用:
服务器名称将与所有通配符域名进行匹配,即www.example.com,然后是*.example.com,然后是*.com。
注意,不支持部分通配符,像*w.example.com这样的值是无效的。
transport_protocol
string
如果非空,在确定过滤器链匹配时要考虑的传输协议。这个值将与新连接的传输协议进行比较,当它被一个监听器过滤器检测到时。
建议的值包括:
raw_buffer - 默认值,在没有检测到传输协议时使用。
tls - 当检测到TLS协议时由envoy.filters.listener.tls_inspector设置。
application_protocols
string[]
如果非空,则是一个应用协议的列表(例如,TLS协议的ALPN),在确定过滤器链的匹配时要考虑。这些值将与新连接的应用协议进行比较,当被一个监听器过滤器检测到时。
建议的值包括。
http/1.1 - 由 envoy. filters.listener.tls_inspector 设置。
h2 - 由 envoy.filters.listener.tls_inspector 设置。
// source/server/listener_manager_impl.cc 创建 ListenerImpl,ListenerImpl 做 bind 操作
bool ListenerManagerImpl::addOrUpdateListener(const envoy::config::listener::v3::Listener& config,
const std::string& version_info, bool added_via_api) {
//…
return addOrUpdateListenerInternal(config, version_info, added_via_api, name);
//…
}
bool ListenerManagerImpl::addOrUpdateListenerInternal(
const envoy::config::listener::v3::Listener& config, const std::string& version_info,
bool added_via_api, const std::string& name) {
//…
ListenerImplPtr new_listener = nullptr;
//…
ENVOY_LOG(debug, “use full listener update path for listener name={} hash={}”, name, hash);
new_listener =
std::make_unique(config, version_info, *this, name, added_via_api,
workers_started_, hash, server_.options().concurrency());
//…
}
主要目的:解析配置文件中的 listeners , 以构造对应的 ListenerImpl 。
message Listener {
string name = 1;
core.v3.Address address = 2 [(validate.rules).message = {required: true}];
repeated FilterChain filter_chains = 3;
FilterChain default_filter_chain = 25;
repeated ListenerFilter listener_filters = 9;
// …
}
参考 https://cloudnative.to/envoy/api-v3/config/listener/v3/listener.proto.html
各种过滤器:https://cloudnative.to/envoy/api-v3/config/filter/filter.html#
HttpConnectionManager参考https://cloudnative.to/envoy/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto.html
void FilterChainManagerImpl::addFilterChains(
absl::Span<const envoy::config::listener::v3::FilterChain* const> filter_chain_span,
const envoy::config::listener::v3::FilterChain* default_filter_chain,
FilterChainFactoryBuilder& filter_chain_factory_builder,
FilterChainFactoryContextCreator& context_creator) {
Cleanup cleanup(this { origin_ = absl::nullopt; });
absl::node_hash_map<envoy::config::listener::v3::FilterChainMatch, std::string, MessageUtil,
MessageUtil>
filter_chains;
uint32_t new_filter_chain_size = 0;
for (const auto& filter_chain : filter_chain_span) {
const auto& filter_chain_match = filter_chain->filter_chain_match();
if (!filter_chain_match.address_suffix().empty() || filter_chain_match.has_suffix_len()) {
throw EnvoyException(fmt::format("error adding listener ‘{}’: filter chain ‘{}’ contains "
“unimplemented fields”,
address_->asString(), filter_chain->name()));
}
const auto& matching_iter = filter_chains.find(filter_chain_match);
if (matching_iter != filter_chains.end()) {
throw EnvoyException(fmt::format("error adding listener ‘{}’: filter chain ‘{}’ has "
“the same matching rules defined as ‘{}’”,
address_->asString(), filter_chain->name(),
matching_iter->second));
}
filter_chains.insert({filter_chain_match, filter_chain->name()});
auto createAddressVector = [](const auto& prefix_ranges) -> std::vector<std::string> {
std::vector<std::string> ips;
ips.reserve(prefix_ranges.size());
for (const auto& ip : prefix_ranges) {
const auto& cidr_range = Network::Address::CidrRange::create(ip);
ips.push_back(cidr_range.asString());
}
return ips;
};
// Validate IP addresses.
std::vector<std::string> destination_ips =
createAddressVector(filter_chain_match.prefix_ranges());
std::vector<std::string> source_ips =
createAddressVector(filter_chain_match.source_prefix_ranges());
std::vector<std::string> direct_source_ips =
createAddressVector(filter_chain_match.direct_source_prefix_ranges());
std::vector<std::string> server_names;
// Reject partial wildcards, we don't match on them.
for (const auto& server_name : filter_chain_match.server_names()) {
if (server_name.find('*') != std::string::npos && !isWildcardServerName(server_name)) {
throw EnvoyException(
fmt::format("error adding listener '{}': partial wildcards are not supported in "
"\"server_names\"",
address_->asString()));
}
server_names.push_back(absl::AsciiStrToLower(server_name));
}
// Reuse created filter chain if possible.
// FilterChainManager maintains the lifetime of FilterChainFactoryContext
// ListenerImpl maintains the dependencies of FilterChainFactoryContext
auto filter_chain_impl = findExistingFilterChain(*filter_chain);
if (filter_chain_impl == nullptr) {
filter_chain_impl =
filter_chain_factory_builder.buildFilterChain(*filter_chain, context_creator);
++new_filter_chain_size;
}
addFilterChainForDestinationPorts(
destination_ports_map_,
PROTOBUF_GET_WRAPPED_OR_DEFAULT(filter_chain_match, destination_port, 0), destination_ips,
server_names, filter_chain_match.transport_protocol(),
filter_chain_match.application_protocols(), direct_source_ips,
filter_chain_match.source_type(), source_ips, filter_chain_match.source_ports(),
filter_chain_impl);
fc_contexts_[*filter_chain] = filter_chain_impl;
}
convertIPsToTries();
copyOrRebuildDefaultFilterChain(default_filter_chain, filter_chain_factory_builder,
context_creator);
ENVOY_LOG(debug, “new fc_contexts has {} filter chains, including {} newly built”,
fc_contexts_.size(), new_filter_chain_size);
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。