1 - XDS API中的LDS概述

介绍Envoy的XDS API中的LDS

Listener

Listener Filter

LDS介绍

LDS是Listener Discovery Service的首字母缩写。

监听器发现服务(LDS)是一个可选的 API,Envoy 将调用它来动态获取监听器。Envoy 将协调 API 响应,并根据需要添加、修改或删除已知的监听器。

监听器更新的语义如下:

  • 每个监听器必须有一个独特的名字。如果没有提供名称,Envoy 将创建一个 UUID。要动态更新的监听器,管理服务必须提供监听器的唯一名称。
  • 当一个监听器被添加,在参与连接处理之前,会先进入“预热”阶段。例如,如果监听器引用 RDS 配置,那么在监听器迁移到 “active” 之前,将会解析并提取该配置。
  • 监听器一旦创建,实际上就会保持不变。因此,更新监听器时,会创建一个全新的监听器(使用相同的侦听套接字)。新增加的监听者都会通过上面所描述的相同“预热”过程。
  • 当更新或删除监听器时,旧的监听器将被置于 “draining(逐出)” 状态,就像整个服务重新启动时一样。监听器移除之后,该监听器所拥有的连接,经过一段时间优雅地关闭(如果可能的话)剩余的连接。逐出时间通过 --drain-time-s 选项设置。

注意: 任何在 Envoy 配置中静态定义的监听器都不能通过 LDS API 进行修改或删除。

2 - xDS中Listener的概念

xDS中Listener的概念

2.1 - [译]Envoy中的Listener

翻译Envoy中的Listener介绍内容

https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/listeners/listeners

Listeners

The Envoy configuration supports any number of listeners within a single process. Generally we recommend running a single Envoy per machine regardless of the number of configured listeners. This allows for easier operation and a single source of statistics. Envoy supports both TCP and UDP listeners.

Envoy 支持单个进程中配置任意数量的监听器。通常情况下,部署 Envoy 的数量与监听器数量无关,建议每台机器部署一个 Envoy 即可。这使得操作会更加简便,而且每台机器只有一个监控数据来源。Envoy 同时支持 TCP 和 UDP 监听器。

TCP

Each listener is independently configured with some number filter chains, where an individual chain is selected based on its match criteria. An individual filter chain is composed of one or more network level (L3/L4) filters. When a new connection is received on a listener, the appropriate filter chain is selected, and the configured connection local filter stack is instantiated and begins processing subsequent events. The generic listener architecture is used to perform the vast majority of different proxy tasks that Envoy is used for (e.g., rate limiting, TLS client authentication, HTTP connection management, MongoDB sniffing, raw TCP proxy, etc.).

每个监听器都独立配置了多个 过滤器链,其中根据其 匹配条件 选择某个过滤器链。 一个独立的过滤器链由一个或多个网络层(L3/L4) 过滤器 组成。 当监听器上接收到新连接时,会选择适当的过滤器链,接着实例化配置的本地筛选器堆栈和处理后续事件。 通用监听器系统架构通常用于处理各不相同的代理任务,例如 Envoy 用于( 限速、TLS 客户端身份验证、HTTP 连接管理、MongoDB 嗅探、原始 TCP 代理 等)。

Listeners are optionally also configured with some number of listener filters. These filters are processed before the network level filters, and have the opportunity to manipulate the connection metadata, usually to influence how the connection is processed by later filters or clusters.

监听器还可以选择配置一些 监听过滤器。 这些过滤器在网络层过滤器之前处理,并且有机会去操作连接元数据,这样通常是为了影响后续过滤器或集群如何处理连接。

Listeners can also be fetched dynamically via the listener discovery service (LDS).

还可以通过 监听器发现服务 (LDS) 动态获取监听器。

UDP

Envoy also supports UDP listeners and specifically UDP listener filters. UDP listener filters are instantiated once per worker and are global to that worker. Each listener filter processes each UDP datagram that is received by the worker listening on the port. In practice, UDP listeners are configured with the SO_REUSEPORT kernel option which will cause the kernel to consistently hash each UDP 4-tuple to the same worker. This allows a UDP listener filter to be “session” oriented if it so desires. A built-in example of this functionality is the UDP proxy listener filter.

Envoy 还支持 UDP 监听器和 UDP 监听过滤器 。 每个工作线程都会实例化一次 UDP 监听过滤器,并且 UDP 监听过滤器对于工作线程来讲是全局可见的。 每个工作线程监听端口接收到的 UDP 数据报文由监听过滤器处理。 实际上,UDP 监听器配置有一个 SO_REUSEPORT 内核选项,这将导致内核会将属于同一个 UDP 四个元组的 UDP 报文分配给同一个工作线程。 这就允许 UDP 监听过滤器在需要时可以打开会话保持功能。 这个功能的一个内置示例就是 UDP 代理 监听过滤器。

参考文档

3 - xDS中Listener Filter的概念

xDS中Listener Filter的概念

3.1 - [译]Envoy中的Listener Filter

翻译Envoy中的Listener Filter介绍内容

https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/listeners/listener_filters

As discussed in the listener section, listener filters may be used to manipulate connection metadata. The main purpose of listener filters is to make adding further system integration functions easier by not requiring changes to Envoy core functionality, and also make interaction between multiple such features more explicit.

如 监听器 一节所述, 监听器过滤器可以用于操纵连接元数据。 监听器过滤器的主要目的是更方便地添加系统集成功能,而无需更改 Envoy 核心功能,并使多个此类功能之间的交互更加明确。

The API for listener filters is relatively simple since ultimately these filters operate on newly accepted sockets. Filters in the chain can stop and subsequently continue iteration to further filters. This allows for more complex scenarios such as calling a rate limiting service, etc. Envoy already includes several listener filters that are documented in this architecture overview as well as the configuration reference.

监听器过滤器的 API 相对简单,因为最终这些过滤器是在新接收的套接字上操作的。可停止链中的过滤器并继续执行后续的过滤器。这允许去运作更复杂的业务场景,例如调用 限速服务 等。 Envoy 包含多个监听器过滤器,这些过滤器在架构概述以及 配置参考 中都有记录。

参考文档

3.2 - [译]Envoy中的Listener Filter Chain

翻译Envoy中的Listener Filter Chain介绍内容

https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/listeners/network_filter_chain

As discussed in the listener section, network level (L3/L4) filters form the core of Envoy connection handling.

正如在 Listener 部分所讨论的,网络级(L3/L4)过滤器构成了Envoy连接处理的核心。

The network filters are chained in a ordered list known as filter chain. Each listener has multiple filter chains and an optional default filter chain. associated with each filter chain. If the best match filter chain cannot be found, the default filter chain will be chosen to serve the request. If the default filter chain is not supplied, the connection will be closed.

网络过滤器在一个有序的列表中被链起来,称为过滤器链。每个监听器都有多个过滤器链和一个与每个过滤器链相关的可选默认过滤器链。如果找不到最佳匹配的过滤链,将选择默认的过滤链来处理请求。如果没有提供默认的过滤链,连接将被关闭。

Filter chain only update

Filter chains can be updated independently. Upon listener config update, if the listener manager determines that the listener update is a filter chain only update, the listener update will be executed by adding, updating and removing filter chains. The connections owned by these destroying filter chains will be drained as described in listener drain.

过滤链可以独立更新。在 Listener 配置更新时,如果 listener 管理器确定 listener 更新只是更新过滤链,listener 更新将通过添加、更新和删除过滤链来执行。这些破坏的过滤链所拥有的连接将被逐出,如 listener drain 中所描述的那样。

If the new filter chain and the old filter chain is protobuf message equivalent, the corresponding filter chain runtime info survives. The connections owned by the survived filter chains remain open.

如果新的过滤链和旧的过滤链是 protobuf 消息等价的,那么相应的过滤链运行时信息就会存活。存活的过滤链所拥有的连接保持打开。

Not all the listener config updates can be executed by filter chain update. For example, if the listener metadata is updated within the new listener config, the new metadata must be picked up by the new filter chains. In this case, the entire listener is drained and updated.

并非所有的 listener 配置更新都可以通过过滤链更新来执行。例如,如果 listener 元数据在新的 listener 配置中被更新,新的元数据必须被新的过滤链所接收。在这种情况下,整个 listener 会被逐出并更新。

3.3 - [译]Envoy中的Network (L3/L4) filters

翻译Envoy中的Network (L3/L4) filters介绍内容

https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/listeners/network_filters

As discussed in the listener section, network level (L3/L4) filters form the core of Envoy connection handling. The filter API allows for different sets of filters to be mixed and matched and attached to a given listener. There are three different types of network filters:

正如在 listener 部分所讨论的,网络级(L3/L4)过滤器构成了Envoy连接处理的核心。过滤器API允许混合和匹配不同的过滤器集合,并附加到给定的监听器。有三种不同类型的网络过滤器:

  • Read: Read filters are invoked when Envoy receives data from a downstream connection.
  • Write: Write filters are invoked when Envoy is about to send data to a downstream connection.
  • Read/Write: Read/Write filters are invoked both when Envoy receives data from a downstream connection and when it is about to send data to a downstream connection.
  • :当Envoy收到来自下游连接的数据时,会调用读过滤器。

  • :写过滤器在Envoy收到下游连接的数据时被调用。当Envoy要向下游连接发送数据时,会调用写过滤器。

  • 读/写:读/写过滤器在Envoy从下游连接接收数据和即将向下游连接发送数据时都会被调用。

The API for network level filters is relatively simple since ultimately the filters operate on raw bytes and a small number of connection events (e.g., TLS handshake complete, connection disconnected locally or remotely, etc.). Filters in the chain can stop and subsequently continue iteration to further filters. This allows for more complex scenarios such as calling a rate limiting service, etc. Network level filters can also share state (static and dynamic) among themselves within the context of a single downstream connection. Refer to data sharing between filters for more details. Envoy already includes several network level filters that are documented in this architecture overview as well as the configuration reference.

网络级过滤器的API相对简单,因为最终过滤器操作的是原始字节和少量的连接事件(例如,TLS握手完成,连接在本地或远程断开,等等)。链上的过滤器可以停止,随后继续迭代到更多的过滤器。这允许更复杂的场景,如调用速率限制服务等。网络级过滤器也可以在单个下游连接的范围内相互共享状态(静态和动态)。更多细节请参考过滤器之间的数据共享。Envoy已经包含了几个网络级过滤器,在这个架构概述以及配置参考中都有记录。

4 - xDS中LDS API的定义和实现

xDS中Listener API的定义和实现

4.1 - LDS API的概述

介绍LDS API的服务定义和参数说明

LDS服务定义

LDS的服务定义如下:

https://github.com/envoyproxy/envoy/blob/main/api/envoy/service/listener/v3/lds.proto

service ListenerDiscoveryService {
  option (envoy.annotations.resource).type = "envoy.config.listener.v3.Listener";

  rpc DeltaListeners(stream discovery.v3.DeltaDiscoveryRequest)
      returns (stream discovery.v3.DeltaDiscoveryResponse) {
  }

  rpc StreamListeners(stream discovery.v3.DiscoveryRequest)
      returns (stream discovery.v3.DiscoveryResponse) {
  }

  rpc FetchListeners(discovery.v3.DiscoveryRequest) returns (discovery.v3.DiscoveryResponse) {
    option (google.api.http).post = "/v3/discovery:listeners";
    option (google.api.http).body = "*";
  }
}

请求参数

对于 DeltaDiscoveryRequest 和 DiscoveryRequest,请求参数中的 type_url 字段的取值是 “type.googleapis.com/envoy.config.listener.v3.Listener” (或者隐含)。

应答参数

对于 DiscoveryResponse 和 DeltaDiscoveryResponse,返回的资源类型被抽象为 google.protobuf.Any ,对于LDS返回的实际是 Listener 这个消息体,定义在 api/envoy/config/listener/v3/listener.proto 文件中:

package envoy.config.listener.v3;

message Listener {

  string name = 1;

  core.v3.Address address = 2 [(validate.rules).message = {required: true}];


  repeated FilterChain filter_chains = 3;

  repeated ListenerFilter listener_filters = 9;

  ......
}

详细的字段定义请见后续的详细解说。

4.2 - LDS API中的Listener配置

LDS API中的Listener配置

Listener配置

Listener 的配置详细定义在 xDS API 中 Linsenter 的 proto 定义文件中,地址如下:

https://github.com/envoyproxy/envoy/blob/main/api/envoy/config/listener/v3/listener.proto#L39

Json格式

Listerner配置的JSON格式如下所示:

{
  "name": "...",
  "address": "{...}",
  "stat_prefix": "...",
  "filter_chains": [],
  "use_original_dst": "{...}",
  "default_filter_chain": "{...}",
  "per_connection_buffer_limit_bytes": "{...}",
  "metadata": "{...}",
  "drain_type": "...",
  "listener_filters": [],
  "listener_filters_timeout": "{...}",
  "continue_on_listener_filters_timeout": "...",
  "transparent": "{...}",
  "freebind": "{...}",
  "socket_options": [],
  "tcp_fast_open_queue_length": "{...}",
  "traffic_direction": "...",
  "udp_listener_config": "{...}",
  "api_listener": "{...}",
  "connection_balance_config": "{...}",
  "reuse_port": "...",
  "enable_reuse_port": "{...}",
  "access_log": [],
  "tcp_backlog_size": "{...}",
  "bind_to_port": "{...}"
}

proto格式

proto 文件定义如下:

message Listener {
  option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.Listener";

  string name = 1;

  core.v3.Address address = 2 [(validate.rules).message = {required: true}];

  string stat_prefix = 28;

  repeated FilterChain filter_chains = 3;

  google.protobuf.BoolValue use_original_dst = 4;

  FilterChain default_filter_chain = 25;

  google.protobuf.UInt32Value per_connection_buffer_limit_bytes = 5
      [(udpa.annotations.security).configure_for_untrusted_downstream = true];

  core.v3.Metadata metadata = 6;

  DrainType drain_type = 8;

  repeated ListenerFilter listener_filters = 9;

  google.protobuf.Duration listener_filters_timeout = 15;

  bool continue_on_listener_filters_timeout = 17;

  google.protobuf.BoolValue transparent = 10;

  google.protobuf.BoolValue freebind = 11;

  repeated core.v3.SocketOption socket_options = 13;

  google.protobuf.UInt32Value tcp_fast_open_queue_length = 12;

  core.v3.TrafficDirection traffic_direction = 16;

  UdpListenerConfig udp_listener_config = 18;

  ApiListener api_listener = 19;

  ConnectionBalanceConfig connection_balance_config = 20;

  google.protobuf.BoolValue enable_reuse_port = 29;

  repeated accesslog.v3.AccessLog access_log = 22;

  google.protobuf.UInt32Value tcp_backlog_size = 24;

  google.protobuf.BoolValue bind_to_port = 26;
}

Listener字段说明

具体字段的说明:

字段 格式 说明
name string 该监听器的唯一名称。如果没有提供名称,Envoy将为监听器分配一个内部UUID。如果监听器要通过LDS动态更新或删除,必须提供唯一的名字。
address core.v3.Address, REQUIRED 听众应该收听的地址。一般来说,这个地址必须是唯一的,不过这要由操作系统的绑定规则决定。例如,多个监听器可以在Linux上监听端口0,因为实际的端口将由操作系统分配。
stat_prefix string 可选的前缀,用于监听器的统计信息。如果为空,统计信息将以 listener.<address as string> 为根。如果非空,统计信息将以listener.<stat_prefix>为根。
filter_chains FilterChain, REQUIRED 考虑用于这个监听器的过滤链列表。最符合 FilterChainMatch 条件的 FilterChain 将用于连接。
use_original_dst google.protobuf.BoolValue 如果使用iptables重定向连接,代理接收连接的端口可能与原始目标地址不同。当这个标志被设置为 “true” 时,监听器会将重定向的连接交给与原始目标地址相关的监听器。如果没有与原始目标地址相关联的监听器,连接将由接收它的监听器处理。默认为false。
default_filter_chain FilterChain 如果没有一个过滤器链相匹配,则为默认过滤器链。如果没有提供默认的过滤链,连接将被关闭。在这个字段中,过滤链的匹配被忽略。
per_connection_buffer_limit_bytes UInt32Value 对监听器新建连接的读写缓冲区大小的软限制。如果未指定,则使用实现定义的默认值(1MiB)。
metadata core.v3.Metadata 监听器元数据
drain_type DrainType 在监听器范围内执行的逐出类型。
listener_filters ListenerFilter[] Listener 过滤器有机会操作和增加连接元数据,例如在连接过滤器链匹配中使用。这些过滤器会在任何过滤器链之前运行。顺序很重要,因为过滤器是在监听器接受套接字后,在创建连接前,按顺序处理的。当监听器套接字地址中的协议是UDP时,可以指定UDP监听器过滤器。UDP监听器目前只支持一个过滤器。
listener_filters_timeout google.protobuf.Duration 等待所有监听器过滤器完成操作的超时时间。如果达到超时,接受的套接字将被关闭,而不创建连接,除非continue_on_listener_filters_timeout被设置为true。指定0来禁用超时。如果不指定,将使用默认的15s超时。
continue_on_listener_filters_timeout bool 当监听器过滤器超时时,是否应该创建连接。默认为false。
transparent google.protobuf.BoolValue 监听器是否应该被设置为透明套接字。

当这个标志设置为 “true “时,连接可以使用iptables TPROXY目标重定向到监听器,在这种情况下,接受的连接会保留原来的源地址和目的地址以及端口。这个标志应该与 original_dst 监听器过滤器结合使用,以标记连接的本地地址为 “restored”。这可以用来把每个重定向的连接移交给与该连接的目的地址相关的另一个监听器。没有使用TPROXY的套接字的直接连接无法与使用TPROXY重定向的连接区分开来,因此会被当作重定向的连接。当这个标志被设置为false时,监听器的套接字会被明确地重置为非透明的。设置这个标志需要Envoy以CAP_NET_ADMIN能力运行。当这个标志没有设置时(默认),套接字不会被修改,也就是说,透明选项既不会被设置也不会被重置。
freebind google.protobuf.BoolValue 监听器是否应设置 IP_FREEBIND 套接字选项。 当此标志设置为true时,可以将监听器绑定到未在运行Envoy的系统上配置的IP地址。 当此标志设置为false时,套接字上的选项 IP_FREEBIND 被禁用。 如果未设置此标志(默认值),则不会修改套接字,即既未启用也未禁用该选项。
socket_options core.v3.SocketOption Envoy源代码或预编译二进制文件中可能不存在的其他套接字选项。
tcp_fast_open_queue_length UInt32Value 监听器是否应接受 TCP Fast Open(TFO)连接。 当此标志设置为大于0的值时,将在套接字上启用选项TCP_FASTOPEN,其队列长度为指定大小(请参阅RFC7413中的详细信息)。 当此标志设置为0时,套接字上禁用选项TCP_FASTOPEN。 如果未设置此标志(默认值),则不会修改套接字,即既未启用也未禁用该选项。
traffic_direction core.v3.TrafficDirection 指定流量相对于本地 envoy 的预期方向。对于使用原始目的地过滤器的 listener 来说,这个属性在Windows下是必需的,见原始目的地
udp_listener_config UdpListenerConfig 如果协议中的监听器套接字地址的协议是UDP,这个字段指定UDP监听器的具体配置。
api_listener ApiListener 用于表示一个API监听器,在非代理客户端中使用。暴露给非代理应用程序的API类型取决于API监听器的类型。当这个字段被设置时,除了名字之外,其他字段都不应该被设置。
connection_balance_config ConnectionBalanceConfig 监听器的连接平衡器配置,目前只适用于TCP监听器。如果没有指定配置,Envoy将不会尝试在工作线程之间平衡活动连接。

在这种情况下,监听器X通过在X中设置use_original_dst,在Y1和Y2中设置bind_to_port为false,将所有连接重定向到监听器Y1和Y2,建议禁用监听器X中的平衡配置,以避免平衡的成本,并启用Y1和Y2中的平衡配置,在工作者之间平衡连接。
reuse_port bool 弃用。请使用 enable_reuse_port
enable_reuse_port google.protobuf.BoolValue 当这个标志被设置为 “true” 时,监听器会设置SO_REUSEPORT套接字选项,为每个工作线程创建一个套接字。这使得在连接数较多的情况下,入站连接在工作线程之间大致均匀分布。当这个标志被设置为false时,所有工作线程共享一个套接字。这个字段的默认值是true。
access_log accesslog.v3.AccessLog[] 该监听器发出的访问日志的配置。
tcp_backlog_size google.protobuf.UInt32Value tcp 监听器的待处理连接队列可以增长的最大长度。如果没有提供net.core.somaxconn的值,在Linux上将会使用,否则将使用128。
bind_to_port google.protobuf.BoolValue 监听器是否应该与端口绑定。不绑定的监听器只能接收从其他设置use_original_dst为true的监听器重定向的连接。默认为true。

4.3 - LDS API中的Filter配置

LDS API中的Filter配置

Listener Filter的配置详细定义在 xDS API 中 Linsenter Components 的 proto 定义文件中,地址如下:

https://github.com/envoyproxy/envoy/blob/main/api/envoy/config/listener/v3/listener_components.proto#L28

Json格式

Listerner Filter配置的JSON格式如下所示:

{
  "name": "...",
  "typed_config": "{...}"
}

proto格式

proto 文件定义如下:

message Filter {

  string name = 1 [(validate.rules).string = {min_len: 1}];

  oneof config_type {

    google.protobuf.Any typed_config = 4;

    core.v3.ExtensionConfigSource config_discovery = 5;
  }
}

Listener字段说明

具体字段的说明:

字段 格式 说明
name string 要实例化的过滤器的名称。该名称必须符合支持的过滤器
typed_config google.protobuf.Any 过滤器的具体配置,取决于正在实例化的过滤器。参见支持的过滤器的进一步的文档。
config_discovery core.v3.ExtensionConfigSource 扩展配置发现服务的配置源指定器。在失败和没有默认配置的情况下,监听器会关闭连接。

如果是通过 typed_config 来配置 filter,则 name 必须是已经被支持的 filter,具体目前支持的filter列表见:

https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/network_filters/network_filters#config-network-filters

4.4 - LDS API中的Filter Chain配置

LDS API中的Filter Chain配置

Filter Chain

过滤器链包裹着一组匹配判据,一个选项TLS上下文,一组过滤器,以及其他各种参数。

Listener Filter Chain的配置详细定义在 xDS API 中 Linsenter Components 的 proto 定义文件中,地址如下:

https://github.com/envoyproxy/envoy/blob/main/api/envoy/config/listener/v3/listener_components.proto#L201

Json格式

Listerner Filter Chain配置的JSON格式如下所示:

{
  "filter_chain_match": "{...}",
  "filters": [],
  "use_proxy_proto": "{...}",
  "transport_socket": "{...}",
  "transport_socket_connect_timeout": "{...}"
}

proto格式

proto 文件定义如下:

message FilterChain {
  option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.listener.FilterChain";

  FilterChainMatch filter_chain_match = 1;

  repeated Filter filters = 3;

  google.protobuf.BoolValue use_proxy_proto = 4
      [deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];

  core.v3.Metadata metadata = 5;

  core.v3.TransportSocket transport_socket = 6;

  google.protobuf.Duration transport_socket_connect_timeout = 9;

  string name = 7;

  OnDemandConfiguration on_demand_configuration = 8;
}

字段说明

具体字段的说明:

字段 格式 说明
filter_chain_match FilterChainMatch 匹配连接到该过滤链时使用的判据。
filters Filter 一个单独的网络过滤器的列表,它构成了与监听器建立的连接的过滤器链。顺序很重要,因为过滤器会随着连接事件的发生按顺序处理。注意:如果过滤器列表为空,连接将默认关闭。
use_proxy_proto google.protobuf.BoolValue 监听器是否应该在新连接上期待一个PROXY协议V1头。如果该选项被启用,监听器将假定连接的远程地址是头中指定的地址。包括AWS ELB在内的一些负载均衡器支持这个选项。如果该选项不存在或设置为false,Envoy将使用连接的物理对等地址作为远程地址。

这个字段已经废弃了。可以明确地添加PROXY协议监听器过滤器来代替。
metadata core.v3.Metadata 过滤链元数据
transport_socket core.v3.TransportSocket 可选的自定义传输套接字实现,用于下游连接。要设置TLS,在typed_config中设置一个名称为envoy.transport_sockets.tls的传输套接字和DownstreamTlsContext。如果没有指定传输套接字的配置,新的连接将用纯文本建立。
transport_socket_connect_timeout google.protobuf.Duration 如果存在并且不为零,允许传入的连接完成任何传输套接字协商的时间量。如果这个时间在传输报告连接建立之前过期,连接将被立即关闭。

FilterChainMatch

指定为 Listener 选择特定过滤链的匹配判据。

为了选择一个过滤链,它的所有判据必须被传入的连接满足,其属性由网络堆栈和/或监听器过滤器设置。

以下顺序适用:

  • 目的地端口。
  • 目的地IP地址。
  • 服务器名称(例如:TLS协议的SNI)。
  • 传输协议。
  • 应用协议(例如:TLS协议的ALPN)。
  • 直接连接的源IP地址(这只有在使用覆盖源地址的监听器过滤器时才会与源IP地址不同,如代理协议监听器过滤器)。
  • 源类型(例如,任何,本地或外部网络)。
  • 源IP地址。
  • 源端口

对于允许范围或通配符的标准,将使用任何配置的过滤链中与传入连接相匹配的最具体的值(例如,对于SNI www.example.com,最具体的匹配将是www.example.com,然后是*.example.com,然后是*.com,然后是任何没有server_names要求的过滤链)。

用另一种方式来推理过滤链的匹配。假设存在N个过滤链。使用上述8个步骤对过滤链集进行修剪。在每个步骤中,与属性最具体匹配的过滤链继续进入下一个步骤。监听器保证在所有的步骤之后最多剩下1个过滤链。

例如:

对于目的端口,指定传入流量的目的端口的过滤链是最具体的匹配。如果没有一个过滤链指定确切的目的端口,那么不指定端口的过滤链是最具体的匹配。指定错误端口的过滤链永远不可能成为最具体的匹配。

Listener Filter Chain Match的配置详细定义在 xDS API 中 Linsenter Components 的 proto 定义文件中,地址如下:

https://github.com/envoyproxy/envoy/blob/main/api/envoy/config/listener/v3/listener_components.proto#L97

Json格式

Listerner Filter Chain Match配置的JSON格式如下所示:

{
  "destination_port": "{...}",
  "prefix_ranges": [],
  "direct_source_prefix_ranges": [],
  "source_type": "...",
  "source_prefix_ranges": [],
  "source_ports": [],
  "server_names": [],
  "transport_protocol": "...",
  "application_protocols": []
}

proto格式

proto 文件定义如下:

message FilterChainMatch {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.api.v2.listener.FilterChainMatch";

  google.protobuf.UInt32Value destination_port = 8 [(validate.rules).uint32 = {lte: 65535 gte: 1}];

  repeated core.v3.CidrRange prefix_ranges = 3;

  string address_suffix = 4;

  google.protobuf.UInt32Value suffix_len = 5;

  repeated core.v3.CidrRange direct_source_prefix_ranges = 13;

  ConnectionSourceType source_type = 12 [(validate.rules).enum = {defined_only: true}];

  repeated core.v3.CidrRange source_prefix_ranges = 6;

  repeated uint32 source_ports = 7
      [(validate.rules).repeated = {items {uint32 {lte: 65535 gte: 1}}}];

  repeated string server_names = 11;

  string transport_protocol = 9;

  repeated string application_protocols = 10;
}

字段说明

具体字段的说明:

字段 格式 说明
destination_port google.protobuf.UInt32Value 当监听器上设置use_original_dst时,在确定过滤链匹配时要考虑的可选目标端口。
prefix_ranges core.v3.CidrRange[] 如果非空,则是一个IP地址和前缀长度,以便在监听器被绑定到0.0.0.0/::或指定use_original_dst时匹配地址。
direct_source_prefix_ranges core.v3.CidrRange[] 如果下游连接的直接连接源IP地址包含在至少一个指定的子网中,则满足该条件。如果没有指定参数或者列表为空,直接连接的源IP地址将被忽略。
source_type ConnectionSourceType 指定连接源IP匹配类型。可以是任何,本地或外部网络。
source_prefix_ranges core.v3.CidrRange[] 如果下游连接的源IP地址包含在至少一个指定的子网中,则满足该条件。如果没有指定参数或列表为空,则源IP地址被忽略。
source_ports uint32[] 如果下游连接的源端口包含在至少一个指定的端口中,则满足该条件。如果没有指定该参数,源端口将被忽略。
server_names string[] 如果非空,则是一个服务器名称的列表(例如TLS协议的SNI),在确定过滤器链匹配时要考虑。这些值将与新连接的服务器名称进行比较,当被一个监听器过滤器检测到时。

服务器名称将与所有通配符域名进行匹配,即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 设置。

4.5 - LDS API中的Listener Filter配置

LDS API中的Listener Filter配置

Listener Filter的配置详细定义在 xDS API 中 Linsenter Components 的 proto 定义文件中,地址如下:

https://github.com/envoyproxy/envoy/blob/main/api/envoy/config/listener/v3/listener_components.proto#L336

Json格式

Listerner Filter Chain配置的JSON格式如下所示:

{
  "name": "...",
  "typed_config": "{...}",
  "filter_disabled": "{...}"
}

proto格式

proto 文件定义如下:

message ListenerFilter {
  option (udpa.annotations.versioning).previous_message_type =
      "envoy.api.v2.listener.ListenerFilter";

  string name = 1 [(validate.rules).string = {min_len: 1}];

  oneof config_type {
    google.protobuf.Any typed_config = 3;
  }

  ListenerFilterChainMatchPredicate filter_disabled = 4;
}

字段说明

具体字段的说明:

字段 格式 说明
name string 要实例化的过滤器的名称。该名称必须符合支持的过滤器。
typed_config google.protobuf.Any 过滤器的具体配置,取决于正在实例化的过滤器。参见支持的过滤器的进一步文件。
filter_disabled ListenerFilterChainMatchPredicate 用于禁用过滤器的可选匹配谓词。当这个字段为空时,过滤器被启用。更多例子见ListenerFilterChainMatchPredicate。

如果是通过 typed_config 来配置 filter,则 name 必须是已经被支持的 filter,具体目前支持的filter列表见:

https://www.envoyproxy.io/docs/envoy/latest/configuration/listeners/listener_filters/listener_filters#config-listener-filters

5 - xDS中LDS的版本演进

xDS中LDS API的版本演进

5.1 - LDS版本演进

介绍LDS在各个版本中的演进

LDS定义

LDS v1

TODO:LDS v1的定义在哪里?

LDS v2

https://github.com/envoyproxy/envoy/blob/master/api/envoy/api/v2/lds.proto

// Envoy实例在启动时发起一个RPC,以发现监听器列表。
// 更新是通过LDS服务器的流式传输的,包括所有监听器的完整更新。
// 监听器不再存在时,现有的连接将被允许剔除。
service ListenerDiscoveryService {
  option (envoy.annotations.resource).type = "envoy.api.v2.Listener";

  rpc DeltaListeners(stream DeltaDiscoveryRequest) returns (stream DeltaDiscoveryResponse) {
  }

  rpc StreamListeners(stream DiscoveryRequest) returns (stream DiscoveryResponse) {
  }

  rpc FetchListeners(DiscoveryRequest) returns (DiscoveryResponse) {
    option (google.api.http).post = "/v2/discovery:listeners";
    option (google.api.http).body = "*";
  }
}

LDS v3

https://github.com/envoyproxy/envoy/blob/main/api/envoy/service/listener/v3/lds.proto

// Envoy实例在启动时发起一个RPC,以发现监听器列表。
// 更新是通过LDS服务器的流式传输的,包括所有监听器的完整更新。
// 监听器不再存在时,现有的连接将被允许剔除。
service ListenerDiscoveryService {
  option (envoy.annotations.resource).type = "envoy.config.listener.v3.Listener";

  rpc DeltaListeners(stream discovery.v3.DeltaDiscoveryRequest)
      returns (stream discovery.v3.DeltaDiscoveryResponse) {
  }

  rpc StreamListeners(stream discovery.v3.DiscoveryRequest)
      returns (stream discovery.v3.DiscoveryResponse) {
  }

  rpc FetchListeners(discovery.v3.DiscoveryRequest) returns (discovery.v3.DiscoveryResponse) {
    option (google.api.http).post = "/v3/discovery:listeners";
    option (google.api.http).body = "*";
  }
}

和 LDS v2 API相比:

  1. option type 从 envoy.api.v2.Listener 修改为 envoy.config.listener.v3.Listener
  2. 各种message定义都增加了 discovery.v3 的前缀

相关消息体的定义

DeltaDiscoveryRequest