Envoy 配置及策略

Envoy 的配置使用

https://www.envoyproxy.io/docs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 启动一个 nginx 环境
docker pull nginx
docker run -dit --name=web nginx
docker exec -it web bash
/# echo 111 > /usr/share/nginx/html/index.html
/# exit
docker inspect web | grep -i ipaddress
# 172.17.0.2


# 启动 envoy
docker pull envoyproxy/envoy:latest

# 先将下面的 envoy 配置文件写了再启动
docker run -d -p 10000:10000 -v /root/envoy.yaml:/etc/envoy/envoy.yaml --name myenvoy envoyproxy/envoy:latest
# 关键是在于写 envoy 的配置文件 envoy.yaml
docker logs myenvoy

#修改hosts
vim /etc/hosts
192.168.26.23<本级IP> bb.yuan.cc bb

# 客户端测试, envoy设置了: domains: [bb.yuan.cc] #只转发此条
curl bb.yuan.cc bb:10000
#没有返回
curl -H "Host: bb.yuan.cc" bb.yuan.cc bb:10000
#返回111

Envoy配置文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
listen -- 监听器
1.我监听的地址
2.过滤链
filter1
路由: 转发到哪里
virtual_hosts
只转发什么
转发到哪里 --> 由后面的 cluster 来定义
filter2
filter3
#envoyproxy.io/docs/envoy/v1.19.1/api-v3/config/filter/filter
cluster
转发规则
endpoints
--指定了我的后端地址

vim envoy.yaml 比较老旧的写法了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 127.0.0.1, port_value: 9901 } #定义管理

static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 10000 } #要监听的地址
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
# extensions.filters.network.http_connection_manager.v3.HttpConnectionManager 为具体值,type.googleapis.com/envoy为固定前缀
config:
stat_prefix: ingress_http
codec_type: AUTO #都允许
#codec_type: HTTP2 #只允许HTTP2协议访问,(如果是访问nginx容器,要先开启nginx的http2)
#access_log: #添加访问日志
#- name: envoy.file_access_log
# config:
# path: "/tmp/aa.log"
route_config:
name: myroute1
virtual_hosts:
- name: local_service
domains: ["*"] #都允许
#domains: [bb.yuan.cc] #只转发此条
routes:
- match: { prefix: "/" }
#- match: { prefix: "/demo1" } #只匹配 相对目录 的 demo1 目录
route: { cluster: some_service } #可以自定义名字
#- name: local_service2
# domains: ["cc.yuan.cc"]
# routes:
# - match: { prefix: "/" }
# route: { cluster: some_service2 }
http_filters:
#- name: envoy.router #旧的写法,快被废弃了
- name: envoy.filters.http.router
clusters:
- name: some_service #与上面route对应
connect_timeout: 0.25s
type: STATIC
#type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
hosts: [ #指定后端地址
#{ socket_address: { address: 192.168.26.23, port_value: 808 }},
{ socket_address: { address: 172.17.0.2, port_value: 80 }}

]
#- name: some_service2 #与上面route对应
# connect_timeout: 0.25s
# type: STATIC
# dns_lookup_family: V4_ONLY
# lb_policy: ROUND_ROBIN
# hosts: [
# { socket_address: { address: 172.17.0.4, port_value: 80 }}
# ]

Filter的写法语法1

name: 指定使用哪个过滤器

config:

​ 参数1:值1

​ 参数2:值2

​ 。。。

这里选择什么参数,要看name里选择的什么参数要根据所选择的过滤器来判定

和http相关的,一般选择 HTTP connection manager。

https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/filter/filter里找参数

name的位置应该写envoy.filters.network.http_connection_manager

http_connection_manager 常见的参数包括:

codec_type – 可选值为AUTO(默认)、HTTP1、

HTTP2

stat_prefix

route_config

http_filters

access_log

Filter的写法语法2

name: 指定使用哪个过滤器

typed_config:

​ “@type”: type.googleapis.com/envoy.过滤器的具体值

​ 参数1:值1

​ 参数2:值2

​ 。。。

这里选择什么参数,要看name里选择的什么参数要根据所选择的过滤器来判定

和http相关的,一般选择 HTTP connection manager。

https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/filter/filter 里找参数

name的位置应该写envoy.filters.network.http_connection_manager

@type的值到文档里找具体的值

vim envoy.yaml 现在的写法有所改动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 127.0.0.1, port_value: 9901 } #定义管理

static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 10000 } #要监听的地址
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
# extensions.filters.network.http_connection_manager.v3.HttpConnectionManager 为具体值,type.googleapis.com/envoy为固定前缀
#config:
stat_prefix: ingress_http
codec_type: AUTO #都允许
route_config:
name: myroute1
virtual_hosts:
- name: local_service
domains: ["*"] #都允许
#domains: [bb.yuan.cc] #只转发此条
routes:
- match: { prefix: "/" }
route: { cluster: some_service }
http_filters:
- name: envoy.filters.http.router
clusters:
- name: some_service #与上面route对应
connect_timeout: 0.25s
type: STATIC
#type: LOGICAL_DNS
dns_lookup_family: V4_ONLY
lb_policy: ROUND_ROBIN
#hosts: [
# { socket_address: { address: 172.17.0.2, port_value: 80 }}
#]
load_assignment:
cluster_name: some_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 172.17.0.2
port_value: 80
#- endpoint:
# address:
# socket_address:
# address: 172.17.0.4
# port_value: 80

使用 lua

vim envoy.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 127.0.0.1, port_value: 9901 } #定义管理
static_resources:
listeners:
- name: main
address:
socket_address:
address: 0.0.0.0 #要监听的地址
port_value: 10000
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
# extensions.filters.network.http_connection_manager.v3.HttpConnectionManager 为具体值,type.googleapis.com/envoy为固定前缀
#config:
stat_prefix: ingress_http
codec_type: AUTO #都允许
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains:
- "*"
routes:
- match:
prefix: "/"
route:
cluster: some_service
http_filters:
- name: envoy.filters.http.lua #修改为 lua
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
#inline_code:
inlineCode: |
function envoy_on_response(response_handle)
response_handle:headers():add("X-User-Header","===X====")
end
- name: envoy.filters.http.router
typed_config: {}
clusters:
- name: some_service #与上面route对应
connect_timeout: 0.25s
type: STATIC_DNS #static
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: some_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 172.17.0.2
port_value: 80

EnvoyFilter

EnvoyFilter用来自定义 Istio Pilot 生成的 Envoy 配置。使用 EnvoyFilter 可以修改某些

envoy的字段,添加特定的过滤器,甚至添加全新的监听器、集群等。必须谨慎使用此功能

1
2
3
4
5
6
7
8
9
10
11
12
docker ps | grep pod1
#k8s_istio_proxy_pod1_ns1 #sidecar
#k8s_pod1_pod1_ns1 #业务容器,nginx

docker top 713f7358dbf8 #sidecar 的 conternerId
#运行了两个主要的进程
# /usr/local/bin/pilot-agent proxy sidecar ...
# /usr/local/bin/envoy -c etc/istio/proxy/envpy-rev0.json #envoy 的配置文件有两种,静态|动态

#查看 envoyFilter
kubectl get envoyFilter
#No resources found in ns1 namespace

workloadSelector: 用于指定作用在谁

configPatches:用于配置补丁,下面的属性包括3个大类

- apply_To: 应用到谁

match:指定匹配规则

patch:新的规则

applyTo: 给哪个位置打补丁,可用的值包括

​ INVALID

​ LISTENER #将补丁应用到监听器

​ FILTER_CHAIN #将补丁应用到过滤器链

​ NETWORK_FILTER #将补丁应用到网络过滤器链

​ HTTP_FILTER #将补丁应用到HTTP过滤器链

​ ROUTE_CONFIGURATION

​ VIRTUAL_HOST

​ HTTP_ROUTE

​ CLUSTER

match:

​ context: SIDECAT_OUTBOUNT/SIDECAR_INBOUNT/GATEWAY(弃用)

​ listener:

​ name: 格式为ip:端口

​ portNumber:

​ filterChain:

​ filter:

​ name: 这4行用于定义过滤器

​ 格式为 envoy.filters.network.http_connection_manager

patch:

​ operation: 操作的意思,对应值有

​ MERG

​ ADD

​ REMOVE

​ INSERT_BEFOR

​ INSERT_AFTER

value

举个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
mkdir chap6 && cd chap6
kubectl get pods -n istio-system -l istio=ingressgateway
#istio-ingressgateway-5h354d356-jdmc4

vim ef1.yaml

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: lua-filter
namespace: istio-system #指定命名空间
spec:
workloadSelector:
labels:
istio: ingressgateway
configPatches:
- applyTo: HTTP_FILTER
match:
context: GATEWAY
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE #插入过滤器
value:
name: envoy.filters.http.lua #插入此过滤器
type_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |
function envoy_on_response(response_handle)
response_handle:headers():add("X-User-Header","===X===")
end

# 启动 envoyFilter
kubectl apply -f ef1.yaml
kubectl get envoyFilter -n istio-system
#lua-filter
curl -I aa.yuan.cc
# x-user-header: ===X=== #改变了标题的报文信息


-----------------------------------------------------------


kubectl delete -f ef1.yaml
vim ef2.yaml #阿里云提供的一个demo,用此作些修改

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: addheader-into-ingressgateway
namespace: istio-system #指定命名空间
spec:
workloadSelector:
# select by label in the same namespace
labels:
istio: ingressgateway
configPatches:
# The Envoy config you want to modify
- applyTo: HTTP_FILTER
match:
context: GATEWAY
proxy:
proxyVersion: '^1\.10.*' #改为自己 istio 的版本
listener:
filterChain:
filter:
name: "envoy.filters.network.http_connection_manager"
subFilter:
name: "envoy.filters.http.router"
patch:
operation: INSERT_BEFORE #插入过滤器
value: # lua filter specification
name: envoy.filters.http.lua #插入此过滤器
type_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |-
function envoy_on_response(response_handle)
function hasFrameAncestors(rh)
s = rh:headers():get("Content-Security-Policy");
delimiter = ";";
defined = false;
for match in (s..delimiter):gmatch("(.-)"..delimiter) do
match = match:gsub("%s+", "");
if match:sub(1,15)=="frame-ancestors" then
return true;
end
end
return false;
end
if not response_handle:headers():get("Content-Security-Policy") then
csp = "frame-ancestors none;";
response_handle:headers():add("Content-Security-Policy", csp);
elseif response_handle:headers():get("Content-Security-Policy") then
if not hasFrameAncestors(response_handle) then
csp = response_handle:headers():get("Content-Security-Policy");
csp = csp .. ";frame-ancestors none;";
response_handle:headers():replace("Content-Security-Policy", csp);
end
end
if not response_handle:headers():get("X-Frame-Options") then
response_handle:headers():add("X-Frame-Options", "deny");
end
if not response_handle:headers():get("X-XSS-Protection") then
response_handle:headers():add("X-XSS-Protection", "1; mode=block");
end
if not response_handle:headers():get("X-Content-Type-Options") then
response_handle:headers():add("X-Content-Type-Options", "nosniff");
end
if not response_handle:headers():get("Referrer-Policy") then
response_handle:headers():add("Referrer-Policy", "no-referrer");
end
if not response_handle:headers():get("X-Download-Options") then
response_handle:headers():add("X-Download-Options", "noopen");
end
if not response_handle:headers():get("X-DNS-Prefetch-Control") then
response_handle:headers():add("X-DNS-Prefetch-Control", "off");
end
if not response_handle:headers():get("Feature-Policy") then
response_handle:headers():add("Feature-Policy",
"camera 'none';"..
"microphone 'none';"..
"geolocation 'none';"..
"encrypted-media 'none';"..
"payment 'none';"..
"speaker 'none';"..
"usb 'none';")..
end
if response_handle:headers():get("X-Powered-By") then
response_handle:headers():remove("X-Powered-By");
end
end

# 应用 ef2
kubectl apply -f ef2.yaml
# 测试
curl -I aa.yuan.cc
# 加入了对应的信息