3、Envoy使用案例
Envoy使用案例

目录
[toc]
本节实战
| 实战名称 |
|---|
| 🚩 实战:前端代理-2023.11.2(测试成功) |
| 🚩 实战:流量镜像-2023.11.4(测试成功) |
| 🚩 实战:故障注入过滤器-2023.11.4(测试成功) |
| 🚩 实战:MySQL 过滤器-2023.11.4(测试成功) |
| 🚩 实战:Golang HTTP 过滤器-2023.11.4(测试成功) |
前言
前面我们已经学习了 Envoy 的基础知识,接下来我们就可以来学习如何使用 Envoy 来进行流量管理了。Envoy 作为一个高性能的边缘和内部代理,可以用于许多不同的场景。在本节中,我们将介绍 Envoy 的流量管理功能,包括路由、负载平衡、故障转移、故障注入、速率限制和等方面。
这些案例都位于 Envoy 官方代码仓库中的 examples 目录下,我们可以在这里找到各种使用案例。
所以我们可以先 Clone 一份 Envoy 的代码仓库到本地,然后在本地的 examples 目录下面找到对应的案例进行学习。
1$ git clone https://github.com/envoyproxy/envoy.git

1、流量拆分
Envoy 的路由器可以将流量拆分到跨两个或多个上游集群的虚拟主机中的路由,有两种常见的用例。
- 版本升级: 一条路由的流量逐渐从一个集群转移到另一个集群。
- A/B 测试: 同时测试同一服务的两个或多个版本,路由的流量必须在运行同一服务的不同版本的集群之间分配。
1.两个上游之间的流量转移
路由配置中的运行时对象决定选择特定路由的概率。通过使用 runtime_fraction 配置,可以逐渐将虚拟主机中特定路由的流量从一个群集转移到另一个群集。比如以下示例配置,其中在 Envoy 配置文件中声明了名为 helloworld 的服务的两个版本 helloworld_v1 和 helloworld_v2。
1virtual_hosts:
2 - name: www2
3 domains:
4 - "*"
5 routes:
6 - match:
7 prefix: /
8 runtime_fraction: # 额外匹配指定的运行时键值,每次评估匹配路径时,它必需低于此字段指示的匹配百分比;支持渐进式修改;
9 default_value:
10 numerator: 50
11 denominator: HUNDRED
12 runtime_key: routing.traffic_shift.helloworld
13 route:
14 cluster: helloworld_v1
15 - match:
16 prefix: /
17 route:
18 cluster: helloworld_v2
Envoy 使用首个匹配策略来匹配路由。如果路由具有 runtime_fraction 对象,则将基于 runtime_fraction 值额外匹配请求(如果未指定值,则为默认值)。上面的配置中我们可以看到在第一条路由中指定了 runtime_fraction 对象,可以通过更改 runtime_fraction 值来实现流量转移。
首先,将 routing.traffic_shift.helloworld 设置为 100,这样对于 helloworld 虚拟主机的所有请求,都将与 v1 路由匹配,并由 helloworld_v1 集群提供服务。
要开始转移流量到 helloworld_v2 集群,将 routing.traffic_shift.helloworld 的值设置为 0 < x < 100。例如设置为 90,此时到 helloworld 虚拟主机的每 10 个请求中有 1 个请求将与 v1 路由不匹配,并将进入 v2 路由。
逐渐减少 routing.traffic_shift.helloworld 的值以便更大比例的请求与 v2 路由匹配。
当 routing.traffic_shift.helloworld 的值设置为 0 时,没有到 helloworld 虚拟主机的请求与 v1 路由匹配。所有流量此时会进入 v2 路由,由 helloworld_v2 集群提供服务。
2.跨多个上游的流量拆分
现在我们有三个(v1、v2 和 v3)而不是两个版本。可以使用 weighted_clusters 选项可以用来指定每个上游集群的权重来在三个版本之间平均分配流量(比如 33%、33%、34%)。
与前面的示例不同,一个路由条目就够了。路由中的 weighted_clusters 配置块可用于指定多个上游集群以及每个上游集群的权重。
1virtual_hosts:
2 - name: www2
3 domains:
4 - "*"
5 routes:
6 - match: { prefix: / }
7 route:
8 weighted_clusters:
9 runtime_key_prefix: routing.traffic_split.helloworld
10 clusters:
11 - name: helloworld_v1
12 weight: 33
13 - name: helloworld_v2
14 weight: 33
15 - name: helloworld_v3
16 weight: 34
默认情况下,权重的和必须等于 100。然后就可以通过运行时变量
routing.traffic_split.helloworld.helloworld_v1、
routing.traffic_split.helloworld.helloworld_v2 和
routing.traffic_split.helloworld.helloworld_v3 对每个集群的权重进行动态地调整。
2、前端代理
==🚩 实战:前端代理-2023.11.2(测试成功)==
实验环境:
1Docker Compose version v2.23.0
2docker 20.10.21-ce(具有docker环境)
实验软件:
链接:https://pan.baidu.com/s/1RB2YMVeNDkX18YFQQ1suZg?pwd=0820
提取码:0820
2023.11.4-Day4-2023.10.30-Envoy使用案例

实验步骤:
1graph LR
2 A[实战步骤] -->B(1️⃣ 拉取测试demo)
3 A[实战步骤] -->C(2️⃣ 熟悉demo)
4 A[实战步骤] -->D(3️⃣ 启动服务)
5 A[实战步骤] -->E(4️⃣ 测试)
6 A[实战步骤] -->F(5️⃣ 测试 Envoy 的负载均衡功能)
这些案例大部分都是基于官方提供的一个 Front proxy 来进行演示的,该示例可以使用 Docker Compose 进行管理,其将部署一个前置 Envoy 和几个后端服务(简单的 aiohttp 应用程序),如下图所示:

所有传入请求都通过前端 Envoy 进行路由,前端 Envoy 充当位于 envoymesh 网络边缘的反向代理。 Docker Compose 将端口 8080、8443 和 8001 三个端口,分别处理对服务的 HTTP、HTTPS 调用和对 /admin 的请求,docker-compose.yml 文件内容如下所示:
1services:
2 front-envoy:
3 build:
4 context: .
5 dockerfile: ../shared/envoy/Dockerfile
6 depends_on:
7 service-envoy-1:
8 condition: service_healthy
9 service-envoy-2:
10 condition: service_healthy
11 ports:
12 - "${PORT_PROXY:-8080}:8080"
13 - "${PORT_HTTPS:-8443}:8443"
14 - "${PORT_STATS:-8001}:8001"
15
16 service-envoy-1:
17 build:
18 context: .
19 dockerfile: ../shared/envoy/Dockerfile
20 target: envoy-admin
21 args:
22 ENVOY_CONFIG: ./service-envoy.yaml
23 ENVOY_ADMIN_PORT: 8001
24 depends_on:
25 service1:
26 condition: service_healthy
27
28 service1:
29 build:
30 context: ../shared/python
31 target: aiohttp-tracing-service2
32 environment:
33 - SERVICE_NAME=1
34
35 service-envoy-2:
36 build:
37 context: .
38 dockerfile: ../shared/envoy/Dockerfile
39 target: envoy-admin
40 args:
41 ENVOY_ADMIN_PORT: 8001
42 ENVOY_CONFIG: ./service-envoy-2.yaml
43
44 depends_on:
45 service2:
46 condition: service_healthy
47
48 service2:
49 build:
50 context: ../shared/python
51 target: aiohttp-tracing-service2
52 environment:
53 - SERVICE_NAME=2
Front Envoy 路由到服务容器的所有流量实际上都被路由到 Service Envoy 上,对应的 envoy.yaml 配置如下所示:
1# envoy.yaml
2static_resources:
3 listeners:
4 - address:
5 socket_address:
6 address: 0.0.0.0
7 port_value: 8080
8 filter_chains:
9 - filters:
10 - name: envoy.filters.network.http_connection_manager
11 typed_config:
12 "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
13 codec_type: AUTO
14 stat_prefix: ingress_http
15 route_config:
16 name: local_route
17 virtual_hosts:
18 - name: backend
19 domains:
20 - "*"
21 routes:
22 - match:
23 prefix: "/service/1"
24 route:
25 cluster: service1-envoy
26 - match:
27 prefix: "/service/2"
28 route:
29 cluster: service2-envoy
30 http_filters:
31 - name: envoy.filters.http.router
32 typed_config:
33 "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
34
35 - address:
36 socket_address:
37 address: 0.0.0.0
38 port_value: 8443
39 filter_chains:
40 - filters:
41 - name: envoy.filters.network.http_connection_manager
42 typed_config:
43 "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
44 codec_type: AUTO
45 stat_prefix: ingress_http
46 route_config:
47 name: local_route
48 virtual_hosts:
49 - name: backend
50 domains:
51 - "*"
52 routes:
53 - match:
54 prefix: "/service/1"
55 route:
56 cluster: service1-envoy
57 - match:
58 prefix: "/service/2"
59 route:
60 cluster: service2-envoy
61 http_filters:
62 - name: envoy.filters.http.router
63 typed_config:
64 "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
65
66 transport_socket:
67 name: envoy.transport_sockets.tls
68 typed_config:
69 "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
70 common_tls_context:
71 tls_certificates:
72 # The following self-signed certificate pair is generated using:
73 # $ openssl req -x509 -newkey rsa:2048 -keyout a/front-proxy-key.pem -out a/front-proxy-crt.pem -days 3650 -nodes -subj '/CN=front-envoy'
74 #
75 # Instead of feeding it as an inline_string, certificate pair can also be fed to Envoy
76 # via filename. Reference: https://envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#config-core-v3-datasource.
77 #
78 # Or in a dynamic configuration scenario, certificate pair can be fetched remotely via
79 # Secret Discovery Service (SDS). Reference: https://envoyproxy.io/docs/envoy/latest/configuration/security/secret.
80 - certificate_chain:
81 inline_string: |
82 -----BEGIN CERTIFICATE-----
83 MIICqDCCAZACCQCquzpHNpqBcDANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtm
84 cm9udC1lbnZveTAeFw0yMDA3MDgwMTMxNDZaFw0zMDA3MDYwMTMxNDZaMBYxFDAS
85 BgNVBAMMC2Zyb250LWVudm95MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
86 AQEAthnYkqVQBX+Wg7aQWyCCb87hBce1hAFhbRM8Y9dQTqxoMXZiA2n8G089hUou
87 oQpEdJgitXVS6YMFPFUUWfwcqxYAynLK4X5im26Yfa1eO8La8sZUS+4Bjao1gF5/
88 VJxSEo2yZ7fFBo8M4E44ZehIIocipCRS+YZehFs6dmHoq/MGvh2eAHIa+O9xssPt
89 ofFcQMR8rwBHVbKy484O10tNCouX4yUkyQXqCRy6HRu7kSjOjNKSGtjfG+h5M8bh
90 10W7ZrsJ1hWhzBulSaMZaUY3vh5ngpws1JATQVSK1Jm/dmMRciwlTK7KfzgxHlSX
91 58ENpS7yPTISkEICcLbXkkKGEQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCmj6Hg
92 vwOxWz0xu+6fSfRL6PGJUGq6wghCfUvjfwZ7zppDUqU47fk+yqPIOzuGZMdAqi7N
93 v1DXkeO4A3hnMD22Rlqt25vfogAaZVToBeQxCPd/ALBLFrvLUFYuSlS3zXSBpQqQ
94 Ny2IKFYsMllz5RSROONHBjaJOn5OwqenJ91MPmTAG7ujXKN6INSBM0PjX9Jy4Xb9
95 zT+I85jRDQHnTFce1WICBDCYidTIvJtdSSokGSuy4/xyxAAc/BpZAfOjBQ4G1QRe
96 9XwOi790LyNUYFJVyeOvNJwveloWuPLHb9idmY5YABwikUY6QNcXwyHTbRCkPB2I
97 m+/R4XnmL4cKQ+5Z
98 -----END CERTIFICATE-----
99 private_key:
100 inline_string: |
101 -----BEGIN PRIVATE KEY-----
102 MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2GdiSpVAFf5aD
103 tpBbIIJvzuEFx7WEAWFtEzxj11BOrGgxdmIDafwbTz2FSi6hCkR0mCK1dVLpgwU8
104 VRRZ/ByrFgDKcsrhfmKbbph9rV47wtryxlRL7gGNqjWAXn9UnFISjbJnt8UGjwzg
105 Tjhl6EgihyKkJFL5hl6EWzp2Yeir8wa+HZ4Achr473Gyw+2h8VxAxHyvAEdVsrLj
106 zg7XS00Ki5fjJSTJBeoJHLodG7uRKM6M0pIa2N8b6HkzxuHXRbtmuwnWFaHMG6VJ
107 oxlpRje+HmeCnCzUkBNBVIrUmb92YxFyLCVMrsp/ODEeVJfnwQ2lLvI9MhKQQgJw
108 tteSQoYRAgMBAAECggEAeDGdEkYNCGQLe8pvg8Z0ccoSGpeTxpqGrNEKhjfi6NrB
109 NwyVav10iq4FxEmPd3nobzDPkAftfvWc6hKaCT7vyTkPspCMOsQJ39/ixOk+jqFx
110 lNa1YxyoZ9IV2DIHR1iaj2Z5gB367PZUoGTgstrbafbaNY9IOSyojCIO935ubbcx
111 DWwL24XAf51ez6sXnI8V5tXmrFlNXhbhJdH8iIxNyM45HrnlUlOk0lCK4gmLJjy9
112 10IS2H2Wh3M5zsTpihH1JvM56oAH1ahrhMXs/rVFXXkg50yD1KV+HQiEbglYKUxO
113 eMYtfaY9i2CuLwhDnWp3oxP3HfgQQhD09OEN3e0IlQKBgQDZ/3poG9TiMZSjfKqL
114 xnCABMXGVQsfFWNC8THoW6RRx5Rqi8q08yJrmhCu32YKvccsOljDQJQQJdQO1g09
115 e/adJmCnTrqxNtjPkX9txV23Lp6Ak7emjiQ5ICu7iWxrcO3zf7hmKtj7z+av8sjO
116 mDI7NkX5vnlE74nztBEjp3eC0wKBgQDV2GeJV028RW3b/QyP3Gwmax2+cKLR9PKR
117 nJnmO5bxAT0nQ3xuJEAqMIss/Rfb/macWc2N/6CWJCRT6a2vgy6xBW+bqG6RdQMB
118 xEZXFZl+sSKhXPkc5Wjb4lQ14YWyRPrTjMlwez3k4UolIJhJmwl+D7OkMRrOUERO
119 EtUvc7odCwKBgBi+nhdZKWXveM7B5N3uzXBKmmRz3MpPdC/yDtcwJ8u8msUpTv4R
120 JxQNrd0bsIqBli0YBmFLYEMg+BwjAee7vXeDFq+HCTv6XMva2RsNryCO4yD3I359
121 XfE6DJzB8ZOUgv4Dvluie3TB2Y6ZQV/p+LGt7G13yG4hvofyJYvlg3RPAoGAcjDg
122 +OH5zLN2eqah8qBN0CYa9/rFt0AJ19+7/smLTJ7QvQq4g0gwS1couplcCEnNGWiK
123 72y1n/ckvvplmPeAE19HveMvR9UoCeV5ej86fACy8V/oVpnaaLBvL2aCMjPLjPP9
124 DWeCIZp8MV86cvOrGfngf6kJG2qZTueXl4NAuwkCgYEArKkhlZVXjwBoVvtHYmN2
125 o+F6cGMlRJTLhNc391WApsgDZfTZSdeJsBsvvzS/Nc0burrufJg0wYioTlpReSy4
126 ohhtprnQQAddfjHP7rh2LGt+irFzhdXXQ1ybGaGM9D764KUNCXLuwdly0vzXU4HU
127 q5sGxGrC1RECGB5Zwx2S2ZY=
128 -----END PRIVATE KEY-----
129
130 clusters:
131 - name: service1-envoy
132 type: STRICT_DNS
133 lb_policy: ROUND_ROBIN
134 load_assignment:
135 cluster_name: service1-envoy
136 endpoints:
137 - lb_endpoints:
138 - endpoint:
139 address:
140 socket_address:
141 address: service-envoy-1
142 port_value: 8000
143 - name: service2-envoy
144 type: STRICT_DNS
145 lb_policy: ROUND_ROBIN
146 load_assignment:
147 cluster_name: service2-envoy
148 endpoints:
149 - lb_endpoints:
150 - endpoint:
151 address:
152 socket_address:
153 address: service-envoy-2
154 port_value: 8000
155admin:
156 address:
157 socket_address:
158 address: 0.0.0.0
159 port_value: 8001
160
161layered_runtime: # 用于设置 Envoy 的运行时参数
162 layers:
163 - name: static_layer_0
164 static_layer: # 静态层,用于设置 Envoy 的运行时参数
165 envoy:
166 resource_limits:
167 listener:
168 example_listener_name:
169 connection_limit: 10000
上面的配置文件我们可以看到 Envoy 中定义了两个 Listener,分别监听 8080 和 8443 端口,分别对应 http 和 https 请求,我们可以看到 8443 这个监听器配置了 TLS 证书,这个证书是自签名的。然后根据路由规则,将匹配路由 /service/1 的请求路由到 service1-envoy 这个集群中,将匹配路由 /service/2 的请求路由到 service2-envoy 这个集群中。
这两个集群分别对应了 service-envoy-1 和 service-envoy-2 这两个后端服务,需要注意的是这里的两个后端服务并不是最终的 aiohttp 应用程序,而是 aiohttp 应用前面的 Service Envoy 代理,这样所有的请求都会先经过 Envoy 代理,然后再路由到最终的 aiohttp 应用程序中。
下面是 service1 这个服务前面的 Envoy 代理的配置文件:
1# service-envoy.yaml
2static_resources:
3 listeners:
4 - address:
5 socket_address:
6 address: 0.0.0.0
7 port_value: 8000
8 filter_chains:
9 - filters:
10 - name: envoy.filters.network.http_connection_manager
11 typed_config:
12 "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
13 codec_type: AUTO
14 stat_prefix: service_envoy_1
15 route_config:
16 name: local_route
17 virtual_hosts:
18 - name: backend
19 domains:
20 - "*"
21 routes:
22 - match:
23 prefix: "/service/1"
24 route:
25 cluster: service1
26 http_filters:
27 - name: envoy.filters.http.router
28 typed_config:
29 "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
30
31 clusters:
32 - name: service1
33 type: STRICT_DNS
34 lb_policy: ROUND_ROBIN
35 load_assignment:
36 cluster_name: service1
37 endpoints:
38 - lb_endpoints:
39 - endpoint:
40 address:
41 socket_address:
42 address: service1
43 port_value: 8080
44admin:
45 address:
46 socket_address:
47 address: 0.0.0.0
48 port_value: 8001
我们可以看到收到的请求都会被路由到 service1 这个集群中,这个集群对应的是 service1 这个服务,这个服务就是一个 真正的后端 aiohttp 应用程序了,Service Envoy 相当于充当应用程序的 Sidecar,这样所有请求均由 Envoy 处理,然后有效路由到您的服务。
🍀
下面我们路由到 examples/front-proxy 目录,然后使用 Docker Compose 启动这个案例:
这个是要安装docker-compose的。
1$ pwd
2/Users/cnych/Documents/course/istio/manifests/envoy/examples/front-proxy
3$ docker-compose up --build -d
4#docker compose up --build -d
5$ docker-compose ps
6NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
7front-proxy-front-envoy-1 front-proxy-front-envoy "/docker-entrypoint.sh /usr/local/bin/envoy -c /etc/envoy.yaml" front-envoy About a minute ago Up 35 seconds 0.0.0.0:8001->8001/tcp, :::8001->8001/tcp, 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp, 0.0.0.0:8443->8443/tcp, :::8443->8443/tcp, 10000/tcp
8front-proxy-service-envoy-1-1 front-proxy-service-envoy-1 "/docker-entrypoint.sh /usr/local/bin/envoy -c /etc/envoy.yaml" service-envoy-1 About a minute ago Up 37 seconds (healthy) 10000/tcp
9front-proxy-service-envoy-2-1 front-proxy-service-envoy-2 "/docker-entrypoint.sh /usr/local/bin/envoy -c /etc/envoy.yaml" service-envoy-2 About a minute ago Up 37 seconds (healthy) 10000/tcp
10front-proxy-service1-1 front-proxy-service1 "python3 /code/service.py" service1 About a minute ago Up 38 seconds (healthy)
11front-proxy-service2-1 front-proxy-service2 "python3 /code/service.py" service2 About a minute ago Up 38 seconds (healthy)
在使用docker-compose启动的时候报错了:。。。
汇总踩坑如下:
11.要升级docker-compse版本新一点
22.要手动拉取2个镜像才行
⚠️ 注意:
安装docker compose出问题了。。。
老师当时测试都是没问题的。
- 报错现象

- 当前环境(自己之前的docker-compse版本是v1.26.2)
1[root@docker front-proxy]#docker-compose --version
2docker-compose version 1.26.2, build eefe0d31
3
4docker-ce 20.10.21

- 奇怪,不知道是哪里出了问题。。。–> 感觉还是自己的docker compose有点问题。。。,可能自己docker compose版本太低了。。。

- 安装了新版本,还是不行。。。
1[root@docker front-proxy]#docker-compose --version
2Docker Compose version v2.23.0
- 提问

- 自己再次测试

==这次就可以了,估计还是和自己的docker-compose版本有关。==
- 拉取报错了:。。。
第一次拉取失败:。。。

第2次拉取失败:。。。

估计还是自己linux虚机无法访问外网导致的。。。
- 自己pc是可以科学上网的的。



export https_proxy=http://127.0.0.1:33210 http_proxy=http://127.0.0.1:33210 all_proxy=socks5://127.0.0.1:33211
- 在linux虚机里配置了终端代理后,再次测试看下现象


不行呀。。。。
- 这个镜像有问题。。。
1[service2 python-base 1/3] FROM docker.io/library/python:3.11.5-slim-bullseye@sha256:9f35f3a6420693c209c11bba63dcf103d88e47ebe0b205336b5168c122967edf
可以单独拉取成功的:

哦,这边可以正常下载了。。。


- 重启了机器后,再次测试。。。
怎么还一直卡在这里呀。。。。


- 再次拉取镜像:

- 终于拉启动好了:

🍀
执行命令后会启动 5 个容器,其中 3 个是 Envoy 代理,2 个是 aiohttp 应用程序:


🍀
启动完成后,我们现在可以通过前端代理向两个服务发送请求来测试 Envoy 的路由功能了,我们可以使用 curl 命令来测试:
service1
1[root@docker front-proxy]#curl -v localhost:8080/service/1
2* About to connect() to localhost port 8080 (#0)
3* Trying ::1...
4* Connected to localhost (::1) port 8080 (#0)
5> GET /service/1 HTTP/1.1
6> User-Agent: curl/7.29.0
7> Host: localhost:8080
8> Accept: */*
9>
10< HTTP/1.1 200 OK
11< content-type: text/plain; charset=utf-8
12< content-length: 79
13< date: Fri, 03 Nov 2023 22:51:21 GMT
14< server: envoy
15< x-envoy-upstream-service-time: 4
16<
17Hello from behind Envoy (service 1)! hostname 221f01bef482 resolved 172.19.0.3
18* Connection #0 to host localhost left intact
service2
1[root@docker front-proxy]#curl -v localhost:8080/service/2
2* About to connect() to localhost port 8080 (#0)
3* Trying ::1...
4* Connected to localhost (::1) port 8080 (#0)
5> GET /service/2 HTTP/1.1
6> User-Agent: curl/7.29.0
7> Host: localhost:8080
8> Accept: */*
9>
10< HTTP/1.1 200 OK
11< content-type: text/plain; charset=utf-8
12< content-length: 79
13< date: Fri, 03 Nov 2023 22:51:41 GMT
14< server: envoy
15< x-envoy-upstream-service-time: 4
16<
17Hello from behind Envoy (service 2)! hostname eb0e9d483971 resolved 172.19.0.2
18* Connection #0 to host localhost left intact
可以看到每个请求我们都是直接发送到 Front Envoy,然后 Front Envoy 再根据路由规则将请求路由到对应的 Service Envoy,然后再路由到最终的
aiohttp应用程序中的。
🍀
此外还可以使用 HTTPS 来调用 Envoy 后面的服务,例如调用 service1:
1[root@docker front-proxy]#curl https://localhost:8443/service/1 -k -v
2* About to connect() to localhost port 8443 (#0)
3* Trying ::1...
4* Connected to localhost (::1) port 8443 (#0)
5* Initializing NSS with certpath: sql:/etc/pki/nssdb
6* skipping SSL peer certificate verification
7* SSL connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
8* Server certificate:
9* subject: CN=front-envoy
10* start date: 7月 08 01:31:46 2020 GMT
11* expire date: 7月 06 01:31:46 2030 GMT
12* common name: front-envoy
13* issuer: CN=front-envoy
14> GET /service/1 HTTP/1.1
15> User-Agent: curl/7.29.0
16> Host: localhost:8443
17> Accept: */*
18>
19< HTTP/1.1 200 OK
20< content-type: text/plain; charset=utf-8
21< content-length: 79
22< date: Fri, 03 Nov 2023 22:52:35 GMT
23< server: envoy
24< x-envoy-upstream-service-time: 3
25<
26Hello from behind Envoy (service 1)! hostname 221f01bef482 resolved 172.19.0.3
27* Connection #0 to host localhost left intact
🍀
接下来我们还可以继续测试 Envoy 的负载均衡功能,我们可以将 service1 服务扩展到 3 个实例:
1[root@docker front-proxy]#docker-compose scale service1=3
2[+] Running 3/3
3 ✔ Container front-proxy-service1-1 Running 0.0s
4 ✔ Container front-proxy-service1-3 Started 0.0s
5 ✔ Container front-proxy-service1-2 Started 0.0s
🍀
然后我们多次向 service1 发送请求,前端 Envoy 将通过对三台 service1 机器进行轮询来对请求进行负载平衡:
1[root@docker front-proxy]#curl localhost:8080/service/1
2Hello from behind Envoy (service 1)! hostname 221f01bef482 resolved 172.19.0.3
3[root@docker front-proxy]#curl localhost:8080/service/1
4Hello from behind Envoy (service 1)! hostname 221f01bef482 resolved 172.19.0.3
5[root@docker front-proxy]#curl localhost:8080/service/1
6Hello from behind Envoy (service 1)! hostname 4f39d0e0afc7 resolved 172.19.0.7
7[root@docker front-proxy]#curl localhost:8080/service/1
8Hello from behind Envoy (service 1)! hostname f6699d0a5de9 resolved 172.19.0.8
9[root@docker front-proxy]#curl localhost:8080/service/1
10Hello from behind Envoy (service 1)! hostname 4f39d0e0afc7 resolved 172.19.0.7
11[root@docker front-proxy]#curl localhost:8080/service/1
12Hello from behind Envoy (service 1)! hostname f6699d0a5de9 resolved 172.19.0.8
13[root@docker front-proxy]#curl localhost:8080/service/1
14Hello from behind Envoy (service 1)! hostname 221f01bef482 resolved 172.19.0.3
🍀
测试完成后可以执行 docker-compose down 命令来停止所有容器。
1[root@docker front-proxy]#docker-compose down
2[+] Running 8/8
3 ✔ Container front-proxy-front-envoy-1 Removed 0.2s
4 ✔ Container front-proxy-service-envoy-2-1 Removed 0.2s
5 ✔ Container front-proxy-service-envoy-1-1 Removed 0.2s
6 ✔ Container front-proxy-service2-1 Removed 0.3s
7 ✔ Container front-proxy-service1-1 Removed 0.4s
8 ✔ Container front-proxy-service1-3 Removed 0.4s
9 ✔ Container front-proxy-service1-2 Removed 0.3s
10 ✔ Network front-proxy_default Removed 0.1s
11[root@docker front-proxy]#docker-compose ps
12NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
13[root@docker front-proxy]#docker ps
14CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
测试结束。😘
3、流量镜像
这里说的集群都是envoy集群。
流量镜像功能允许您将流量复制到另一个集群,而不会影响主要流量。这对于测试新版本的服务或将流量发送到另一个集群以进行分析非常有用。
==🚩 实战:流量镜像-2023.11.4(测试成功)==
实验环境:
1Docker Compose version v2.23.0
2docker 20.10.21-ce(具有docker环境)
实验软件:
链接:https://pan.baidu.com/s/1RB2YMVeNDkX18YFQQ1suZg?pwd=0820
提取码:0820
2023.11.4-Day4-2023.10.30-Envoy使用案例

实验步骤:
1graph LR
2 A[实战步骤] -->B(1️⃣ 拉取测试demo)
3 A[实战步骤] -->C(2️⃣ 熟悉demo)
4 A[实战步骤] -->D(3️⃣ 启动服务)
5 A[实战步骤] -->E(4️⃣ 测试流量镜像功能)
🍀

这里的演示应用一共包含 5 个容器,对应的 docker-compose.yml 文件内容如下所示:
1services:
2 envoy-front-proxy:
3 build:
4 context: .
5 dockerfile: ../shared/envoy/Dockerfile
6 ports:
7 - "${PORT_PROXY:-10000}:10000"
8 depends_on:
9 service1:
10 condition: service_healthy
11 service1-mirror:
12 condition: service_healthy
13 service2:
14 condition: service_healthy
15 service2-mirror:
16 condition: service_healthy
17
18 service1:
19 build:
20 context: ../shared/python
21 target: aiohttp-tracing-service
22 environment:
23 - SERVICE_NAME=1
24
25 service1-mirror:
26 build:
27 context: ../shared/python
28 target: aiohttp-tracing-service
29 environment:
30 - SERVICE_NAME=1
31
32 service2:
33 build:
34 context: ../shared/python
35 target: aiohttp-tracing-service
36 environment:
37 - SERVICE_NAME=2
38
39 service2-mirror:
40 build:
41 context: ../shared/python
42 target: aiohttp-tracing-service
43 environment:
44 - SERVICE_NAME=2
🍀
输入请求由 envoy-front-proxy 服务接收,路径为 /service/1 的请求被静态复制。每个请求由 service1 集群处理,并且额外转发到 service1-mirror 集群:

对于路径 /service/2 的请求将根据 x-mirror-cluster 标头的存在和值进行动态镜像。此路径的所有请求都会转发到 service2 集群,并且还会镜像到标头中指定的集群。
例如,如果我们发送带有头信息 x-mirror-cluster: service2-mirror 的请求,则该请求将被镜像转发到 service2-mirror 集群。
另外需要注意 Envoy 只会将从主集群接收到的响应返回给客户端。比如我们这里来自
service1和service2集群的响应将会发送给客户端。而来自service1-mirror或service2-mirror集群的响应则不会被发送回客户端。这也意味着在镜像集群中请求处理过程中的任何问题或延迟都不会影响客户端接收到的响应。
🍀
现在切换到 examples/route-mirror 目录,然后启动应用:
1# examples/route-mirror 路径
2$ docker-compose up --build -d
3$ docker compose ps
4NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
5route-mirror-envoy-front-proxy-1 route-mirror-envoy-front-proxy "/docker-entrypoint.sh /usr/local/bin/envoy -c /etc/envoy.yaml" envoy-front-proxy 6 seconds ago Up 4 seconds 0.0.0.0:10000->10000/tcp, :::10000->10000/tcp
6route-mirror-service1-1 route-mirror-service1 "python3 /code/service.py" service1 6 seconds ago Up 5 seconds (healthy)
7route-mirror-service1-mirror-1 route-mirror-service1-mirror "python3 /code/service.py" service1-mirror 6 seconds ago Up 5 seconds (healthy)
8route-mirror-service2-1 route-mirror-service2 "python3 /code/service.py" service2 6 seconds ago Up 5 seconds (healthy)
9route-mirror-service2-mirror-1 route-mirror-service2-mirror "python3 /code/service.py" service2-mirror 6 seconds ago Up 5 seconds (healthy)

🍀
现在让我们向 envoy-front-proxy 服务发送一个请求,该服务将请求转发到 service1,并将请求镜像发送到服 service1-mirror:
1$ curl localhost:10000/service/1
2Hello from behind Envoy (service 1)!
然后我们可以分别查看 service1 和 service1-mirror 服务的日志:
1$ docker-compose logs service1
2$ docker-compose logs service1-mirror
3
4或者:
5docker logs -f route-mirror-service1-1
6docker logs -f route-mirror-service1-mirror-1
正常情况下这两个服务都将接收到请求。

而且对于对 service1-mirror 服务的请求,Envoy 将 Host 头信息修改为在主机名中添加了 -shadow后缀。


🍀
如果在对 service2 的请求中没有指定 x-mirror-cluster,或者指定未知的集群,则该请求将不会被镜像,而是会以正常方式处理。
1$ curl localhost:10000/service/2
2Hello from behind Envoy (service 2)!
3$ curl --header "x-mirror-cluster: service2-mirror-non-existent" localhost:10000/service/2
4Hello from behind Envoy (service 2)!
我们可以查看日志来验证结果:
1$ docker compose logs service2
2route-mirror-service2-1 | DEBUG:asyncio:Using selector: EpollSelector
3route-mirror-service2-1 | ======== Running on http://0.0.0.0:8080 ========
4route-mirror-service2-1 | (Press CTRL+C to quit)
5route-mirror-service2-1 | Host: localhost:10000
6route-mirror-service2-1 | INFO:aiohttp.access:192.168.227.6 [30/Oct/2023:09:21:03 +0000] "GET /service/2 HTTP/1.1" 200 189 "-" "curl/7.87.0"
7route-mirror-service2-1 | Host: localhost:10000
8route-mirror-service2-1 | INFO:aiohttp.access:192.168.227.6 [30/Oct/2023:09:23:06 +0000] "GET /service/2 HTTP/1.1" 200 189 "-" "curl/7.87.0"
9route-mirror-service2-1 | Host: localhost:10000
10route-mirror-service2-1 | INFO:aiohttp.access:192.168.227.6 [30/Oct/2023:09:23:11 +0000] "GET /service/2 HTTP/1.1" 200 189 "-" "curl/7.87.0"
11$ docker compose logs service2-mirror
12route-mirror-service2-mirror-1 | DEBUG:asyncio:Using selector: EpollSelector
13route-mirror-service2-mirror-1 | ======== Running on http://0.0.0.0:8080 ========
14route-mirror-service2-mirror-1 | (Press CTRL+C to quit)
15route-mirror-service2-mirror-1 | Host: localhost-shadow:10000
16route-mirror-service2-mirror-1 | INFO:aiohttp.access:192.168.227.6 [30/Oct/2023:09:21:03 +0000] "GET /service/2 HTTP/1.1" 200 189 "-" "curl/7.87.0"
可以看到 service2 中有对应的请求日志,但是 service2-mirror 中并没有。

🍀
接下来我们再发送一个请求,这次我们将请求发送到 service2 服务,但是我们在请求头中添加了 x-mirror-cluster: service2-mirror 这个头信息,这样 Envoy 将会将请求镜像到 service2-mirror 集群:
1$ curl --header "x-mirror-cluster: service2-mirror" localhost:10000/service/2
2Hello from behind Envoy (service 2)!
请求后查看这两个服务的日志来验证请求是否已被镜像:

同样的对于对 service2-mirror 服务的请求,Envoy 将 Host 头信息修改为在主机名中添加了 -shadow后缀。

🍀
停掉测试容器:
1[root@docker route-mirror]#docker-compose down
2[+] Running 6/5
3 ? Container route-mirror-envoy-front-proxy-1 Removed 0.1s
4 ? Container route-mirror-service2-1 Removed 0.3s
5 ? Container route-mirror-service2-mirror-1 Removed 0.3s
6 ? Container route-mirror-service1-1 Removed 0.2s
7 ? Container route-mirror-service1-mirror-1 Removed 0.3s
8 ? Network route-mirror_default Removed 0.0s
测试完成。😘
4、故障注入过滤器
==🚩 实战:故障注入过滤器-2023.11.4(测试成功)==
实验环境:
1Docker Compose version v2.23.0
2docker 20.10.21-ce(具有docker环境)
实验软件:
链接:https://pan.baidu.com/s/1RB2YMVeNDkX18YFQQ1suZg?pwd=0820
提取码:0820
2023.11.4-Day4-2023.10.30-Envoy使用案例

实验步骤:
1graph LR
2 A[实战步骤] -->B(1️⃣ 拉取测试demo)
3 A[实战步骤] -->C(2️⃣ 熟悉demo)
4 A[实战步骤] -->D(3️⃣ 启动服务)
5 A[实战步骤] -->E(4️⃣ 故障注入过滤器)
这里我们可以使用 Envoy 的故障注入过滤器来模拟故障,例如模请求中止、失败以及延迟响应等,这样我们就可以测试服务的容错能力了。该功能主要利用 Envoy 的运行时支持来控制故障注入的能力。

🍀

这里我们的入口 Envoy 的配置如下所示:
1# envoy.yaml
2static_resources:
3 listeners:
4 - address:
5 socket_address:
6 address: 0.0.0.0
7 port_value: 9211
8 filter_chains:
9 - filters:
10 - name: envoy.filters.network.http_connection_manager
11 typed_config:
12 "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
13 codec_type: AUTO
14 stat_prefix: ingress_http
15 access_log:
16 - name: envoy.access_loggers.stdout
17 typed_config:
18 "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
19 route_config:
20 name: local_route
21 virtual_hosts:
22 - name: service
23 domains:
24 - "*"
25 routes:
26 - match:
27 prefix: /
28 route:
29 cluster: local_service
30 http_filters:
31 - name: envoy.filters.http.fault
32 typed_config:
33 "@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
34 abort:
35 http_status: 503
36 percentage:
37 numerator: 0
38 denominator: HUNDRED
39 delay:
40 fixed_delay: 3s
41 percentage:
42 numerator: 0
43 denominator: HUNDRED
44 - name: envoy.filters.http.router
45 typed_config:
46 "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
47 clusters:
48 - name: local_service
49 type: STRICT_DNS
50 lb_policy: ROUND_ROBIN
51 load_assignment:
52 cluster_name: local_service
53 endpoints:
54 - lb_endpoints:
55 - endpoint:
56 address:
57 socket_address:
58 address: backend
59 port_value: 80
60layered_runtime:
61 layers:
62 - name: disk_layer_0
63 disk_layer:
64 symlink_root: /srv/runtime/current
65 subdirectory: envoy
上面的配置文件中我们使用了一个 layered_runtime 属性,这个属性用于运行时配置提供程序的配置,这里我们使用了 disk_layer,这个参数用于设置 Envoy 的运行时参数存储在哪个目录下,这里我们设置为 /srv/runtime/current,子目录为 envoy,然后就可以这这个目录下面创建配置文件。
注意下环境:


奇怪:(没关系的,不影响测试效果。)


为了实现故障注入功能,我们这里需要添加一个 envoy.filters.http.fault 的过滤器,这个过滤器用于实现故障注入功能,我们可以通过 typed_config 属性来配置故障注入的功能,这里我们配置了 abort 和 delay 两个功能,abort 用于模拟请求中止,delay 用于模拟延迟响应,这两个参数至少需要配置一个。
1- name: envoy.filters.http.fault
2 typed_config:
3 "@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
4 abort:
5 http_status: 503
6 percentage:
7 numerator: 0
8 denominator: HUNDRED
9 delay:
10 fixed_delay: 3s
11 percentage:
12 numerator: 0 # 分子
13 denominator: HUNDRED # 分母
delay:如果指定了此参数,该过滤器将根据对象中的值注入延迟。fixed_delay:在向上游转发操作之前添加固定延迟,对于 HTTP / Mongo,指定的延迟将在发出新请求/操作之前注入。header_delay:故障延迟通过一个 HTTP 头部来控制(如果适用)。percentage:注入延迟的操作/连接/请求的百分比。
abort:如果指定,过滤器将根据对象中的值中止请求。http_status:用于中止 HTTP 请求的 HTTP 状态码。grpc_status:用于中止 gRPC 请求的 gRPC 状态码。header_abort:故障中止通过一个 HTTP 头部来控制(如果适用)。percentage:注入中止的操作/连接/请求的百分比。
另外需要注意如果存在以下运行时配置值,则故障过滤器的值会被覆盖。
fault.http.abort.abort_percentfault.http.abort.http_statusfault.http.delay.fixed_delay_percentfault.http.delay.fixed_duration_ms
我们这里就是通过 disk_layer 方式来配置运行时参数的,我们可以在 所以我们需要在 /srv/runtime/current/envoy 目录下添加配置来控制故障注入的功能。
🍀
下面我们来测试下故障注入的功能,我们路由到 examples/fault-injection 目录,然后使用 Docker Compose 启动这个案例:
1$ pwd
2/Users/cnych/Documents/course/istio/manifests/envoy/examples/fault-injection
3$ docker-compose up --build -d
4$ docker-compose ps
5NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
6fault-injection-backend-1 fault-injection-backend "gunicorn -b 0.0.0.0:80 httpbin:app -k gevent" backend 9 seconds ago Up 7 seconds 0.0.0.0:8080->80/tcp, :::8080->80/tcp
7fault-injection-envoy-1 fault-injection-envoy "/docker-entrypoint.sh /usr/local/bin/envoy -c /etc/envoy.yaml" envoy 9 seconds ago Up 7 seconds 0.0.0.0:9211->9211/tcp, :::9211->9211/tcp, 10000/tcp

🍀
启动后我们开始发送连续的 HTTP 请求,重新开一个终端窗口,然后执行下面的命令:
1# examples/fault-injection 目录下
2$ docker-compose exec envoy bash
3bash send_request.sh
这里的 send_request.sh 脚本我们将会向 Envoy 一直发送 HTTP 请求,Envoy 将请求转发到后端容器,直到我们手动停止脚本,脚本内容如下所示:
1#!/usr/bin/env bash
2set -ex
3
4while :; do
5 curl -v localhost:9211/status/200
6 sleep 1
7done

🍀
虽然我们已经在 Envoy 中配置了故障注入功能,但是现在我们还没有启用它,但是目前的配置的分子都为 0,所以我们的请求都是正常的,我们可以看到请求的状态码都是 200。
下面我们再开一个新的终端,通过以下命令,在运行时打开中断故障注入。
1# examples/fault-injection 目录下
2$ docker compose exec envoy bash
3$ bash enable_abort_fault_injection.sh
这里执行的 enable_abort_fault_injection.sh 脚本可以对 100%的请求进行 HTTP 中止,对应的内容如下所示:
1#!/usr/bin/env bash
2set -ex
3
4mkdir -p /srv/runtime/v1/envoy/fault/http/abort
5echo '100' > /srv/runtime/v1/envoy/fault/http/abort/abort_percent
6echo '503' > /srv/runtime/v1/envoy/fault/http/abort/http_status
7
8pushd /srv/runtime
9ln -s /srv/runtime/v1 new && mv -Tf new current
10popd
当我们执行了该脚本后前面一直发送的请求就会出现中断的情况,我们可以看到请求的状态码都是 503。
在容器里执行。



这是因为我们在 Envoy 中配置了故障注入功能,然后通过运行时配置将故障注入功能打开了,配置 abort_percent 为 100%,这样所有请求都会被中断了。
可以再次执行 disable_abort_fault_injection.sh 脚本来关闭中断功能。
1bash disable_abort_fault_injection.sh
该脚本实现也非常简单,只需要将上面的运行时配置文件删除即可,脚本内容如下所示:
1#!/usr/bin/env bash
2set -ex
3
4rm /srv/runtime/v1/envoy/fault/http/abort/abort_percent
5rm /srv/runtime/v1/envoy/fault/http/abort/http_status
6
7pushd /srv/runtime
8ln -s /srv/runtime/v1 new && mv -Tf new current
9popd
正常现在我们的请求就恢复正常的响应了。

🍀
用同样的方式我们还可以通过一下命令通过运行时打开延迟故障注入。
1# examples/fault-injection 目录下
2$ docker compose exec envoy bash
3$ bash enable_delay_fault_injection.sh
这里的 enable_delay_fault_injection.sh 脚本和前面一样,只是将 abort 改为了 delay,将 fixed_delay_percent 设置为 50,fixed_duration_ms 设置为 3000,表示 50% 的请求会被延迟 3 秒钟,脚本内容如下所示:
1#!/usr/bin/env bash
2set -ex
3
4mkdir -p /srv/runtime/v1/envoy/fault/http/delay
5echo '50' > /srv/runtime/v1/envoy/fault/http/delay/fixed_delay_percent
6echo '3000' > /srv/runtime/v1/envoy/fault/http/delay/fixed_duration_ms
7
8pushd /srv/runtime
9ln -s /srv/runtime/v1 new && mv -Tf new current
10popd
上面脚本执行后,可以看到所有请求的响应码都为 200,但是其中一半的请求将需要 3 秒钟才能完成。

同样要关闭延迟故障注入功能,只需要执行 disable_delay_fault_injection.sh 脚本即可
1bash disable_delay_fault_injection.sh
🍀
最后我们可以通过查看当前运行时文件系统来了解当前的运行时配置。
1$ tree /srv/runtime
2/srv/runtime
3|-- current -> /srv/runtime/v1
4`-- v1
5 `-- envoy
6 `-- fault
7 `-- http
8 |-- abort
9 `-- delay
10
117 directories, 0 files
到这里我们就验证了 Envoy 的故障注入功能。
🍀
终止docker-compose:
1[root@docker fault-injection]#docker-compose down
2[+] Running 3/2
3 ? Container fault-injection-backend-1 Removed 0.9s
4 ? Container fault-injection-envoy-1 Removed 0.1s
5 ? Network fault-injection_default Removed 0.0s
测试完成。😘
5、MySQL 过滤器
==🚩 实战:MySQL 过滤器-2023.11.4(测试成功)==
实验环境:
1Docker Compose version v2.23.0
2docker 20.10.21-ce(具有docker环境)
实验软件:
链接:https://pan.baidu.com/s/1RB2YMVeNDkX18YFQQ1suZg?pwd=0820
提取码:0820
2023.11.4-Day4-2023.10.30-Envoy使用案例

实验步骤:
1graph LR
2 A[实战步骤] -->B(1️⃣ 拉取测试demo)
3 A[实战步骤] -->C(2️⃣ 熟悉demo)
4 A[实战步骤] -->D(3️⃣ 启动服务)
5 A[实战步骤] -->E(4️⃣ MySQL 过滤器)
这里我们将来展示如何在 Envoy 代理中使用 MySQL 过滤器。Envoy 代理配置包括一个 MySQL 过滤器,用于解析查询并收集 MySQL 特定的指标。
🍀
首先切换到 examples/mysql 目录下面,然后启动服务:

1# examples/mysql 目录
2$ docker-compose up --build -d
3$ docker-compose ps
4NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
5mysql-mysql-1 mysql-mysql "docker-entrypoint.sh mysqld" mysql 14 seconds ago Up 13 seconds 3306/tcp, 33060/tcp
6mysql-proxy-1 mysql-proxy "/docker-entrypoint.sh /usr/local/bin/envoy -c /etc/envoy.yaml" proxy 14 seconds ago Up 13 seconds 0.0.0.0:8001->8001/tcp, :::8001->8001/tcp, 10000/tcp
记得要手动拉取2个镜像才行:
1docker pull docker.io/library/mysql:8.2.0@sha256:1773f3c7aa9522f0014d0ad2bbdaf597ea3b1643c64c8ccc2123c64afd8b82b1
2docker pull docker.io/envoyproxy/envoy:contrib-dev

这个应用中我们通过 Envoy 来代理 MySQL 的请求,然后我们可以通过 mysql 客户端来连接 Envoy 代理,然后执行一些命令,这些命令将会被 Envoy 代理转发到后端的 MySQL 服务。对应的 Envoy 配置如下所示:
1static_resources:
2 listeners:
3 - name: mysql_listener
4 address:
5 socket_address:
6 address: 0.0.0.0
7 port_value: 1999
8 filter_chains:
9 - filters:
10 - name: envoy.filters.network.mysql_proxy
11 typed_config:
12 "@type": type.googleapis.com/envoy.extensions.filters.network.mysql_proxy.v3.MySQLProxy
13 stat_prefix: egress_mysql
14 - name: envoy.filters.network.tcp_proxy
15 typed_config:
16 "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
17 stat_prefix: mysql_tcp
18 cluster: mysql_cluster
19
20 clusters:
21 - name: mysql_cluster
22 type: STRICT_DNS
23 load_assignment:
24 cluster_name: mysql_cluster
25 endpoints:
26 - lb_endpoints:
27 - endpoint:
28 address:
29 socket_address:
30 address: mysql
31 port_value: 3306
32
33admin:
34 address:
35 socket_address:
36 address: 0.0.0.0
37 port_value: 8001
由于 MySQL 服务是 TCP 协议了,所有我们现在配置的是全新的过滤器链,这里我们使用的是 envoy.filters.network.mysql_proxy 以及 envoy.filters.network.tcp_proxy 两个过滤器。
MySQL 代理过滤器解码 MySQL 客户端和服务器之间的网络协议。它解码载荷中的 SQL 查询,解码的信息被发出作为动态元数据,可以与访问日志过滤器结合使用,以获取有关访问表以及对每个表执行的操作的详细信息。它是一个透明的过滤器,所以不会影响客户端和服务器的正常进度。此外 MySQL 代理过滤器应与 TCP 代理过滤器链接在一起。
上面的配置就是通过 Envoy 的 1999 端口来接收 MySQL 的代理请求,然后转发给 mysql_cluster 集群下面配置的 mysql 后端服务。
🍀
下面我们来验证下 MySQL 代理过滤器的功能,我们可以通过 mysql 客户端来连接 Envoy 代理:
1$ docker run --rm -it --platform=linux/amd64 --network mysql_default mysql:5.7 mysql -h proxy -P 1999 -u root --skip-ssl
2# ......
3mysql> CREATE DATABASE test;
4Query OK, 1 row affected (0.00 sec)
5
6mysql> USE test;
7Database changed
8mysql> CREATE TABLE test ( text VARCHAR(255) );
9Query OK, 0 rows affected (0.01 sec)
10
11mysql> SELECT COUNT(*) FROM test;
12+----------+
13| COUNT(*) |
14+----------+
15| 0 |
16+----------+
171 row in set (0.01 sec)
18
19mysql> INSERT INTO test VALUES ('hello, world!');
20Query OK, 1 row affected (0.00 sec)
21
22mysql> SELECT COUNT(*) FROM test;
23+----------+
24| COUNT(*) |
25+----------+
26| 1 |
27+----------+
281 row in set (0.00 sec)
29
30mysql> exit
31Bye
🍀
然后我们可以检查下流量出口的数据统计:
1$ curl -s "http://localhost:8001/stats?filter=egress_mysql"
2mysql.egress_mysql.auth_switch_request: 1
3mysql.egress_mysql.decoder_errors: 0
4mysql.egress_mysql.login_attempts: 1
5mysql.egress_mysql.login_failures: 0
6mysql.egress_mysql.protocol_errors: 0
7mysql.egress_mysql.queries_parse_error: 2
8mysql.egress_mysql.queries_parsed: 7
9mysql.egress_mysql.sessions: 1
10mysql.egress_mysql.upgraded_to_ssl: 0
🍀
可以看到已经有相关的数据了。同样还可以查看下入口的 TCP 的统计数据:
1curl -s "http://localhost:8001/stats?filter=mysql_tcp"
2tcp.mysql_tcp.downstream_cx_no_route: 0
3tcp.mysql_tcp.downstream_cx_rx_bytes_buffered: 0
4tcp.mysql_tcp.downstream_cx_rx_bytes_total: 451
5tcp.mysql_tcp.downstream_cx_total: 1
6tcp.mysql_tcp.downstream_cx_tx_bytes_buffered: 0
7tcp.mysql_tcp.downstream_cx_tx_bytes_total: 679
8tcp.mysql_tcp.downstream_flow_control_paused_reading_total: 0
9tcp.mysql_tcp.downstream_flow_control_resumed_reading_total: 0
10tcp.mysql_tcp.idle_timeout: 0
11tcp.mysql_tcp.max_downstream_connection_duration: 0
12tcp.mysql_tcp.upstream_flush_active: 0
13tcp.mysql_tcp.upstream_flush_total: 0
这样我们就实现了通过 Envoy 来代理 MySQL 的请求。
🍀
停止docker-comose:
1[root@docker mysql]#docker-compose down
2[+] Running 3/2
3 ✔ Container mysql-proxy-1 Removed 0.1s
4 ✔ Container mysql-mysql-1 Removed 1.2s
5 ✔ Network mysql_default Removed 0.0s
测试结束。😘
6、Golang HTTP 过滤器
==🚩 实战:Golang HTTP 过滤器-2023.11.4(测试成功)==
实验环境:
1Docker Compose version v2.23.0
2docker 20.10.21-ce(具有docker环境)
实验软件:
链接:https://pan.baidu.com/s/1RB2YMVeNDkX18YFQQ1suZg?pwd=0820
提取码:0820
2023.11.4-Day4-2023.10.30-Envoy使用案例

实验步骤:
1graph LR
2 A[实战步骤] -->B(1️⃣ 拉取测试demo)
3 A[实战步骤] -->C(2️⃣ 熟悉demo)
4 A[实战步骤] -->D(3️⃣ 启动服务)
5 A[实战步骤] -->E(4️⃣ Golang HTTP 过滤器)
HTTP Golang 过滤器允许在请求和响应流期间运行 Golang,并简化了对 Envoy 的扩展。这个过滤器使用的 Go 插件可以独立于 Envoy 重新编译,这使得在不重新编译 Envoy 的情况下更新插件变得容易。
另外需要注意 Envoy 的 Go 插件必须实现 StreamFilter API。构建 Go 插件动态库时,必须使用与 Envoy 的 glibc 版本一致的 Go 版本。
下面我们就来演示下如何使用 Golang HTTP 过滤器,这里的示例将展示一个 Go 插件,它可以直接响应请求,并且还可以更新上游服务器提供的响应。
🍀
同样定位到 examples/golang-http 目录,首先构建 go 插件库:

1# examples/golang-http 目录
2$ docker-compose -f docker-compose-go.yaml run --rm go_plugin_compile

1docker pull docker.io/library/golang:1.21.3-bullseye@sha256:26c7537d6ac3827eb4638034d16edc64de57bb011c8cc8fe301ac13a6568f6f4
⚠️ 注意:
记得配置这个参数,否则可能下载不了go包:


编译后的库文件会出现在 lib 文件夹中。
1$ ls lib
2simple.so

🍀
然后接下来可以直接启动我们的服务:
1$ docker-compose up --build -d
2$ docker-compose ps
3NAME COMMAND SERVICE STATUS PORTS
4golang-http-helloworld_service-1 "python3 /code/servi…" helloworld_service running (healthy)
5golang-http-proxy-1 "/docker-entrypoint.…" proxy running 0.0.0.0:10000->10000/tcp, :::10000->10000/tcp
这里我们同样要重点了解下 Envoy 代理的配置文件:
1static_resources:
2 listeners:
3 - name: listener_0
4 address:
5 socket_address:
6 address: 0.0.0.0
7 port_value: 10000
8 filter_chains:
9 - filters:
10 - name: envoy.filters.network.http_connection_manager
11 typed_config:
12 "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
13 stat_prefix: ingress_http
14 http_filters:
15 - name: envoy.filters.http.golang
16 typed_config:
17 "@type": type.googleapis.com/envoy.extensions.filters.http.golang.v3alpha.Config
18 library_id: simple
19 library_path: "lib/simple.so"
20 plugin_name: simple
21 plugin_config:
22 "@type": type.googleapis.com/xds.type.v3.TypedStruct
23 value:
24 prefix_localreply_body: "Configured local reply from go"
25 - name: envoy.filters.http.router
26 typed_config:
27 "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
28 route_config:
29 name: local_route
30 virtual_hosts:
31 - name: local_service
32 domains: ["*"]
33 routes:
34 - match:
35 prefix: "/"
36 route:
37 cluster: helloworld_service_cluster
38 clusters:
39 - name: helloworld_service_cluster
40 type: STRICT_DNS
41 lb_policy: ROUND_ROBIN
42 load_assignment:
43 cluster_name: helloworld_service_cluster
44 endpoints:
45 - lb_endpoints:
46 - endpoint:
47 address:
48 socket_address:
49 address: helloworld_service
50 port_value: 8080
整体上和之前的配置文件差不多,会将所有的请求都转发到后端的 helloworld_service 服务,但是这里我们在 http_filters 中还添加了一个 envoy.filters.http.golang 过滤器,这个过滤器就是我们编译的 go 插件,这个过滤器的配置如下所示:
1- name: envoy.filters.http.golang
2 typed_config:
3 "@type": type.googleapis.com/envoy.extensions.filters.http.golang.v3alpha.Config
4 library_id: simple
5 library_path: "lib/simple.so"
6 plugin_name: simple
7 plugin_config:
8 "@type": type.googleapis.com/xds.type.v3.TypedStruct
9 value:
10 prefix_localreply_body: "Configured local reply from go"
这里我们配置了 go 插件的路径,然后还配置了 plugin_config,这个配置会传递给 go 插件,这里我们配置了 prefix_localreply_body,这个配置会在 go 插件中使用,我们可以在 go 插件中获取到这个配置,然后将其添加到响应体中。
🍀
下面我们可以使用 curl 命令来测试下 go 插件的功能:
1curl -v localhost:10000 2>&1

正常我们可以看到由 Go 插件添加的 rsp-header-from-go: bar-test 这个 Header 头信息。
🍀
然后我们再发出一个由上游处理并由 Go 插件更新的请求:
1$ curl localhost:10000/update_upstream_response 2>&1
2upstream response body updated by the simple plugin%
该请求的响应结果是由 Go 插件更新的。
🍀
最后我们使用自定义配置进行处理的 Go 插件进行请求。
1$ curl localhost:10000/localreply_by_config 2>&1
2Configured local reply from go, path: /localreply_by_config
得到的结果是由 Go 插件提供的包含 prefix_localreply_body 值的 body。

当然这些都是我们在插件里面去实现的,具体要实现什么样的功能完全取决于我们自己。
测试结束。😘
总结
我们这里只是挑选了几个过滤器来进行演示,实际上 Envoy 还有很多其他的过滤器,这里就不一一介绍了,如果想了解更多的过滤器可以参考 Envoy 官方文档 了解更多使用方式。
最重要的是我们要了解 Envoy 的过滤器的工作原理,了解 Envoy 的配置流程,这样我们才能更好的使用 Envoy。
关于我
我的博客主旨:
- 排版美观,语言精炼;
- 文档即手册,步骤明细,拒绝埋坑,提供源码;
- 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!
🍀 微信二维码 x2675263825 (舍得), qq:2675263825。

🍀 微信公众号 《云原生架构师实战》

🍀 个人博客站点


🍀 语雀
https://www.yuque.com/xyy-onlyone

🍀 csdn
https://blog.csdn.net/weixin_39246554?spm=1010.2135.3001.5421

🍀 知乎
https://www.zhihu.com/people/foryouone

最后
好了,关于本次就到这里了,感谢大家阅读,最后祝大家生活快乐,每天都过的有意义哦,我们下期见!


