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/ 中