Envoy配置使用
Envoy配置使用
Envoy代理有两个常见用途。一是用作服务代理(sidecar),二是用作网关。
用作sidecar时,Envoy是一个位于服务旁边的四层或七层的应用代理,可以生成指标、应用策略和控制流量。
用作API网关时,Envoy作为一个“前置代理”接受inbound流量,核对请求中的信息并将其定向到目的地。本文的例子将演示如何使用Envoy作为前置代理。我们将编写一个静态配置,返回例如HTTP和IPv4等不会改变的静态数据。正如你将在本例中看到的那样,这一用途很简单,适合处理几乎不变化的信息。
envoy基本请求流程
- listener:与端口绑定并监听到达网关的inbound请求,listener 的监听地址是互斥的,两个 listener 不能监听同一个 socket 地址
- filter chain:请求被listener接受进入Envoy后应当被如何处理,它由一些filter组成,filter决定请求能否被传递到下一个filter或发生短路。filter chains是network filter,可以有多组。
- Route:请求通过所有filter后,route将会将请求定向到正确的服务
编写yaml文件
#声明静态资源
static_resources:
listeners:
- 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
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains:
- "*"
routes:
- match:
prefix: "/service/1"
route:
cluster: service1
- match:
prefix: "/service/2"
route:
cluster: service2
http_filters:
- name: envoy.filters.http.router
typed_config: {}
clusters: #设置集群
- name: service1
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
http2_protocol_options: {}
load_assignment:
cluster_name: service1
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 10.244.1.1
port_value: 8000
- name: service2
connect_timeout: 0.25s
type: strict_dns
lb_policy: round_robin
http2_protocol_options: {}
load_assignment:
cluster_name: service2
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: service2
port_value: 8000
admin:
access_log_path: "/dev/null"
address:
socket_address:
address: 0.0.0.0
port_value: 8001
envoy动态配置方法
Listener、Cluster等除了在配置文件中静态配置,还可以从控制平面动态获取。下发动态配置的服务叫做控制平面,它的地址以cluster的形式在配置文件中静态配置
,然后在dynamic_resources
中引用这个cluster。可以动态下发的配置主要有:CDS、LDS、EDS、RDS、SDS,其中只有CDS和LDS的发现地址是在dynamic_resources中指定的。
配置文件中使用同样ID和Cluster的envoy才会接受这个控制平面下发的配置。
基于文件方式
基于文件的方式需要在envoy容器中指定xDS的配置文件路径,envoy将使用inotify来监视文件系统的更改,并在更新时解析文件中的DiscoveryResponse原型。
node:
id: id_1
cluster: test
dynamic_resources:
cds_config:
path: /var/lib/envoy/cds.yaml
lds_config:
path: /var/lib/envoy/lds.yaml
admin:
access_log_path: "/dev/null"
address:
socket_address:
address: 0.0.0.0
port_value: 19000
其中cds_config和las_config内容和静态配置方式内容一样:
#cds内容
resources:
- "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
name: example_proxy_cluster
connect_timeout: 1s
type: strict_dns
http2_protocol_options: {}
load_assignment:
cluster_name: example_proxy_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: service1
port_value: 8080
-----
#lds内容
resources:
- "@type": type.googleapis.com/envoy.config.listener.v3.Listener
name: listener_0
address:
socket_address:
address: 0.0.0.0
port_value: 10001
filter_chains:
- filters:
name: envoy.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
stat_prefix: ingress_http
http_filters:
- name: envoy.router
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: example_proxy_cluster
使用这种方式,虽说可以动态修改envoy路由,但仍需要手动更改xds配置文件,并且每次修改后需要重新启动envoy才能刷新。
基于控制平面方式
用XDS下发配置
首先在配置文件中静态配置控制平面的地址,然后在cds_config和lds_config中引用前面配置的xds_cluster。
dynamic_resources:
cds_config:
api_config_source:
api_type: GRPC
grpc_services:
envoy_grpc:
cluster_name: xds_cluster
lds_config:
api_config_source:
api_type: GRPC
grpc_services:
envoy_grpc:
cluster_name: xds_cluster
用ADS下发配置
Cds_config和las_config是分开的,这意味着cluster和listener配置可以从不同的控制平面获取,这样会遇到配置不同步的问题,即时他们用的是同一个控制平面也可能因为到达次序不同而不同步。譬如 listenerA 中使用了 clusterA,但是 listenerA 的配置可能在 clusterA 之前下发到 envoy ,使 envoy 认为 listenerA 使用了一个不存在的 clusterA。
ADS 支持所有类型动态配置的下发,并且会处理配置间的依赖,保证配置的下发顺序,是优先选用的配置发现方法,实现原理见配置下发协议的说明 xDS REST and gRPC protocol。
node:
cluster: test-cluster
id: test-id
dynamic_resources:
ads_config:
api_type: GRPC
transport_api_version: V3
grpc_services:
- envoy_grpc:
cluster_name: xds_cluster
cds_config:
resource_api_version: V3
ads: {}
lds_config:
resource_api_version: V3
ads: {}
static_resources:
clusters:
- connect_timeout: 1s
type: strict_dns
http2_protocol_options: {}
name: xds_cluster
load_assignment:
cluster_name: xds_cluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: go-control-plane
port_value: 18000
admin:
access_log_path: /dev/null
address:
socket_address:
address: 0.0.0.0
port_value: 19000
envoy 的 lds/cds/rds/sds/eds
dynamic_resources 配置中只有 lds_config、cds_config 和 ads_config,分别对应 listenter、cluster 和聚合发现。但可以动态下发的配置不只有 listener 和 cluster。
cluster 中的 endpoint、tls 用到的 secret、HttpConnectionManager 中用到 route 也可以动态下发,对应的发现服务分别是 eds、sds、rds。这些发现服务不在 dynamic_resources 中配置,而是独立配置或者在用到它们的 filter 中配置。
控制平面实现
Go-control-plane的基本用法
go-control-plane 是一个框架,提供了配置下发接口,在它的基础上根据自己的需要开发其它功能。
动态配置是关联到 envoy 的 ,每个 envoy 的动态配置都要单独维护。
在 envoy 的配置文件中有一段 node 配置,标注了当前 envoy 所属的 cluster 和 id,envoy 只接受使用同样的 cluster 和 id 的动态配置,使用 go-control-plane 实现的控制平面要为每个 envoy 实例维护一份配置:
node := &core.Node{
Id: "envoy-64.58",
Cluster: "test",
}
node_config := &NodeConfig{
node: node,
endpoints: []cache.Resource{}, //[]*api_v2.ClusterLoadAssignment
clusters: []cache.Resource{}, //[]*api_v2.Cluster
routes: []cache.Resource{}, //[]*api_v2.RouteConfiguration
listeners: []cache.Resource{}, //[]*api_v2.Listener
}
Go-control-plane中filter定义与下发
Listener是envoy中最复杂的配置,其中filter又是Listerner中最繁琐的。从 socket 中收取的请求先经过 listener_filters 处理,然后再由 filter_chains 处理,前者包含的 filter 称为 listener filter,后者包含的 filter 称为 network filter。因为 listener_filters 先起作用,因此它可以修改请求的信息,从而影响 filter_chains 的匹配。filter一共有以下几大类:
Listener filters
Network filters
HTTP filters
Thrift filters
Common access log types
Common fault injection types
Dubbo filters
Filter 是填充在 listener 中作为 listener 配置下发的,listener 在 go-control-plane/envoy/api/v2/lds.pb.go中定义,filter 的接口在 envoy/api/v2/listener/listener.pb.go 中定义,filter 的实现在 go-control-plane/envoy/config/filter/ 中