envoy
Envoy
目录
envoy:是一个7层代理和L3/L4的服务总线,使用c++编写,envoy 单进程,多线程。
envoy 提供了服务网格的数据平面,istio 使用了envoy作为数据平面【istio-proxy】,自身又实现了服务网格的控制平面。
配置文件语法测试
envoy --mode validate -c envoy.yaml
BootStrap 配置文件
admin
位置:顶级配置段
/ready envoy的健康状态
/certs envoy 已加载的证书
/listeners envoy 已监听的监听器
admin:
address:
socket_address:
address: 127.0.0.1
port_value: 9901
node
位置:顶级配置段
node: # 使用xds动态配置服务时 node信息必须配置
id: test-01
cluster: test
layered_rumtime
位置:顶级配置段
layered_runtime:
layers:
- name admin
admin_layer: {}
static_resources
位置:顶级配置段
echo
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
filter_chains:
- filters:
- name: envoy.filters.network.echo
使用方式: nc 101.43.43.9 9999
tcp_proxy
位置: static_resources
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
filter_chains:
- filters:
- name: envoy.filters.network.tcp_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
stat_prefix: tcp
cluster: local_cluster
http_connection_manager
位置: static_resources
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 80 }
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: http
codec_type: AUTO
route_config:
name: local_route
virtual_hosts:
- name: loacl_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: mycluster
http_filters:
name: envoy.filtes.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
route
flowchart LR
subgraph routes
subgraph redirect
AA[schema_redirect]
BB[host_redirect]
CC[port_redirect]
DD[path_redirect]
EE[prefix_redirect]
end
subgraph direct_response
FF[status & body]
end
subgraph route
GG[cluster]
HH[weighted_cluser]
II[cluster_head]
JJ[timeout]
KK[retry_policy]
LL[rate_limits]
MM[prefix_rewrite]
NN[host_rewirte]
end
end
subgraph match
subgraph
A[prefix]
B[path]
C[safe_regex]
end
subgraph
D[headers]
E[request_parameters]
end
end
match ==> redirect
match ==> direct_response
match ==> route
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: / # prefix 、path 、safe_regex 、headers、request_parameters
route:
cluster: mycluster # cluster redirect direct_response weighted_cluster
路由规则定义
- route_config.routes[0].match.prefix
routes:
- match:
prefix: "/login" # 前缀匹配
route:
cluster: version1.0
- route_config.routes[0].match.path
routes:
- match:
path: "/static" #请求必须完全匹配 http://127.0.0.1/static
route:
cluster: version1.0
- route_config.routes[0].match.safe_regex
routes:
- match:
safe_regex:
goole_re2: {}
regex: "^list/[0-9]{,2}$" # http://127.0.0.1/list/1
route:
cluster: version1.0
- route_config.routes[0].match.headers
routes:
- match:
prefix: "/"
headers:
name: User-Agent
exact_macth: "chrome" # curl -H "User-Agent: Chrome" http://127.0.0.1
route:
cluster: version1.0
- route_config.routes[0].match.request_parameters
routes:
- match:
prefix: "/"
request_parameters:
name: name
exact: "AAA" # curl http://127.0.0.1/search?name=AAA
route:
cluster: version1.0
路由规则匹配
- route_config.routes[0].route.cluster
routes:
- match:
prefix: "/"
route:
cluster: version1.0
- route_config.routes[0].route.weighted_clusters
routes:
- match:
prefix: "/"
route:
weighted_clusters:
clusters:
- name: version1.0
weight: 10
- name: version2.0
weight: 90
total_weight: 100
runtime_key_prefix: weight_cluster
- route_config.routes[0].redirect
routes:
- match:
prefix: "/"
redirect:
https_redirect: true
port_redirect: 443
host_redirect: "www.baidu.com"
prefix_redirect: "/s?wd=news"
- route_config.routes[0].response
routes:
- match:
prefix: "/"
resopnse:
status: 200
body:
inline_string: "hello world"
#filename: /tmp/filename.txt
#inline_bytes: "b'hellp world'"
流量迁移
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: /
runtime_fraction:
default_value:
numerator: 100
denominator: HUNDER
runtime_key: traffic_shift
route:
cluster: mycluster_v1
- match:
prefix: /
route:
cluster: mycluster_v2
流量分割
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: /
route:
weighted_cluster:
clusters:
- name: mycluster_v1
weight: 10
- name: mycluster_v2
weight: 90
total_weight: 100
runtime_key_prefix: routing.traffic_split.demoapp
流量镜像
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: /
route:
cluster: version1.0
request_mirrors_polices:
cluster: version2.0
runtime_fracton:
default_value:
numerator: 10
denominator: HUNDRED
runtime_key: traffic_mirrors
故障注入
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
perfix: "/"
route:
cluster: version1.0
http_filters:
- name: envoy.filters.http.fault
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
max_active_faults: 100
abort:
http_status: 503
header_abort: {}
percentage:
numerator: 10
denominator: HUNDRED #10% 的流量返回 5xx
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
perfix: "/"
route:
cluster: version1.0
http_filters:
- name: envoy.filters.http.fault
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
max_active_faults: 100
delay:
header_delay: {}
percentage:
numerator: 100 #100% 的流量进行延迟
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
perfix: "/"
route:
cluster: version1.0
http_filters:
- name: envoy.filters.http.fault
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
max_active_faults: 100
response_rate_limit:
header_limit: {}
percentage:
numerator: 100 #100% 的流量进行限制
限速
超时和重试
route_config:
name: local_route
vitual_hosts:
- name: local_service
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: version1.0
timeout: 1s # 连接cluster超时时长1s
retry_policy:
retry_on: "5xx"
num_retries: 3
cluster
clusters:
- name: mycluster #集群的唯一名称,当为提供alt_stat_name时该名称被引用到统计信息中
alt_stat_name: mycluster # 统计信息中标记该集群
connect_timeout: 1s
lb_policy: ROUND_ROBIN # least_request ring_hash random maglev cluster_provided
type: STATIC # strict_dns logical_dns ends
load_assignment:
cluster_name: mycluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 0.0.0.0
port_value: 80
调度策略
- wrr
clusters:
- name: mycluster
connect_timeout: 1s
lb_policy: ROUND_ROBIN
type: STATIC
load_assignment:
cluster_name: mycluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 80
load_balacing_weight: 10
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 8080
load_balacing_weight: 90
- wlr
clusters:
- name: mycluster
connect_timeout: 1s
lb_policy: LEAST_REQUEST
least_request_lb_config:
choice_count: 2
type: STATIC
load_assignment:
cluster_name: mycluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 80
load_balacing_weight: 10
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 8080
load_balacing_weight: 90
- ring_hash
route_config:
name: local_route
virtual_hosts:
- name: local_server
domains: ["*"]
routes:
- match:
prefix: "/"
route:
cluster: mycluster
hash_policy:
header:
header_name: User-Agent
# cookie:
# name:
# ttl:
# path:
connection_properties:
source_ip: true
# query_parameter:
# name:
# filter_state:
# 第一个条件匹配时终止hash_policy
terminal: true
clusters:
- name: mycluster
connect_timeout: 1s
lb_policy: RING_HASH
ring_hash_lb_config:
maximum_ring_size: 65535
minimum_ring_szie: 512
type: STATIC
load_assignment:
cluster_name: mycluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 80
load_balacing_weight: 10
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 8080
load_balacing_weight: 90
-
maglev
-
random
基于位置权重
static_resources:
clusters:
name: mycluster
connect_timeout: 1s
lb_policy: ROUND_ROBIN
type: STATIC
load_assignment:
cluster_name: mycluster
endpoints:
- locality:
region: cn-north-01
load_balancing_weight: 1
lb_endpoints:
- endpoint:
address:
socket_address: { address: 172.4.88.2, port_value: 80 }
- endpoint:
address:
socket_address: { address: 172.4.88.3, port_value: 80 }
- locality:
region: cn-north-02
load_balancing_weight: 2
lb_endpoints:
- endpoint:
address:
socket_address: { address: 172.4.88.4, port_value: 80 }
- endpoint:
address:
socket_address: { address: 172.4.88.5, port_value: 80 }
基于位置priority
clusters:
name: mycluster
connect_timeout: 1s
lb_policy: ROUND_ROBIN
type: STATIC
load_assignment:
cluster_name: mycluster
endpoints:
- locality:
region: cn-north-01
priority: 0 # 0 表示最高级别
lb_endpoints:
- endpoint:
address:
socket_address:
address:
port_value:
- locality:
region: cn-north-02
priority: 1 # 默认不会向这个节点调度
lb_endpoints:
- endpoint:
address:
socket_address:
address:
port_value:
超配因子
static_resources:
clusters:
name: mycluster
connect_timeout: 1s
lb_policy: ROUND_ROBIN
type: STATIC
load_assignment:
cluster_name: mycluster
#######################################################
policy:
overprovisioning_factor: 140 # 默认值 140
#######################################################
endpoints:
- locality:
region: cn-north-01
priority: 0
load_balancing_weight: 1
lb_endpoints:
- endpoint:
address:
socket_address: { address: 172.4.88.2, port_value: 80 }
- endpoint:
address:
socket_address: { address: 172.4.88.3, port_value: 80 }
- locality:
region: cn-north-02
priority: 1
load_balancing_weight: 2
lb_endpoints:
- endpoint:
address:
socket_address: { address: 172.4.88.4, port_value: 80 }
- endpoint:
address:
socket_address: { address: 172.4.88.5, port_value: 80 }
集群子集
clusters:
name: mycluster
connect_timeout: 1s
lb_policy: LEAST_REQUEST
type: STATIC
least_request_lb_config:
choice_count: 2
load_assignment:
cluster_name: mycluster
policy:
overprovisioning_factor: 140
endpoints:
- locality:
region: cn-north-01
priority: 0
lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 80
metadata:
filter_metadata:
envoy.lb:
version: "1.0"
stag: "dev"
lb_subset_config:
fallback_policy: DEFAULT_SUBSET
default_subset:
version: "1.0"
stag: "dev"
subset_selectors:
- keys: ["stage", "version"]
- keys: ["stage"]
- keys: ["version"]
主动健康检查和异常值检测
clusters:
- name: mycluster
connect_timeout: 1s
lb_policy: ROUND_ROBIN
type: STATIC # strict_dns logical_dns ends
load_assignment:
cluster_name: mycluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 0.0.0.0
port_value: 80
health_checks:
- timeout: 1s
interval: 5s
health_threshold: 2
unhealth_threshold: 2
http_health_check: # tcp_health_check: {} 空负载的tcp检测
path: /
expected_statuses:
start: 200
end: 399
outlier_detection
clusters:
- name: mycluster
connect_timeout: 1s
lb_policy: ROUND_ROBIN
type: STATIC # strict_dns logical_dns ends
load_assignment:
cluster_name: mycluster
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 0.0.0.0
port_value: 80
outlier_detection:
....
断路器
clusters:
circuit_breakers:
- thresholds:
max_connectons: 1
max_pending_requests: 1
max_retires: 3
tls
- 客户端验证服务端证书
- 客户端验证服务端证书,服务端验证客户端证书
# The following self-signed certificate pair is generated using:
# $ openssl req -x509 -newkey rsa:2048 -keyout front-proxy.key -out front-proxy.crt -days 3650 -nodes -subj '/CN=test.wed.com'
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
tls_certificates:
- certificate_chain:
filename: "/etc/envoy/certs/front-proxy.crt"
private_key:
filename: "/etc/envoy/certs/front-proxy.key"
日志
# 日志
access_log:
name: envoy.access_loggers.file
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.v3.FileAccessLog
path: "/dev/stdout"
log_format:
json_format: {"start": "[%START_TIME%] ", "method": "%REQ(:METHOD)%", "url": "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%", "protocol": "%PROTOCOL%", "status": "%RESPONSE_CODE%", "respflags": "%RESPONSE_FLAGS%", "bytes-received": "%BYTES_RECEIVED%", "bytes-sent": "%BYTES_SENT%", "duration": "%DURATION%", "upstream-service-time": "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%", "x-forwarded-for": "%REQ(X-FORWARDED-FOR)%", "user-agent": "%REQ(USER-AGENT)%", "request-id": "%REQ(X-REQUEST-ID)%", "authority": "%REQ(:AUTHORITY)%", "upstream-host": "%UPSTREAM_HOST%", "remote-ip": "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%"}
产生的日志格式
{
"respflags":"-",
"start":"[2022-08-16T06:22:14.549Z] ",
"request-id":"94f1f61e-906e-4025-aea1-8e59f11bbf0f",
"authority":"101.43.43.9:5000",
"upstream-host":"172.31.4.3:5000",
"method":"GET",
"upstream-service-time":"1",
"remote-ip":"113.97.31.62",
"status":200,
"bytes-received":0,
"x-forwarded-for":null,
"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.81 Safari/537.36 Edg/104.0.1293.47",
"url":"/",
"duration":2,
"bytes-sent":113,
"protocol":"HTTP/1.1"
}