hugo-teek is loading...

3、Envoy使用案例

最后更新于:

Envoy使用案例

image-20231102072134362

目录

[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

image-20231102201943144

1、流量拆分

Envoy 的路由器可以将流量拆分到跨两个或多个上游集群的虚拟主机中的路由,有两种常见的用例。

    1. 版本升级: 一条路由的流量逐渐从一个集群转移到另一个集群。
    1. A/B 测试: 同时测试同一服务的两个或多个版本,路由的流量必须在运行同一服务的不同版本的集群之间分配。

1.两个上游之间的流量转移

路由配置中的运行时对象决定选择特定路由的概率。通过使用 runtime_fraction 配置,可以逐渐将虚拟主机中特定路由的流量从一个群集转移到另一个群集。比如以下示例配置,其中在 Envoy 配置文件中声明了名为 helloworld 的服务的两个版本 helloworld_v1helloworld_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使用案例

image-20231104065901821

实验步骤:

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 应用程序),如下图所示:

img

所有传入请求都通过前端 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-1service-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出问题了。。。

老师当时测试都是没问题的。

  • 报错现象

image-20231102220259226

  • 当前环境(自己之前的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

image-20231104061627564

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

image-20231102220514084

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

image-20231104061714263

  • 自己再次测试

image-20231104061312821

==这次就可以了,估计还是和自己的docker-compose版本有关。==

  • 拉取报错了:。。。

第一次拉取失败:。。。

image-20231104062011684

第2次拉取失败:。。。

image-20231104062031410

估计还是自己linux虚机无法访问外网导致的。。。

  • 自己pc是可以科学上网的的。

image-20231104062201769

image-20231104062320880

image-20231104062423609

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虚机里配置了终端代理后,再次测试看下现象

image-20231104062502684

image-20231104062700799

不行呀。。。。

  • 这个镜像有问题。。。
1[service2 python-base 1/3] FROM docker.io/library/python:3.11.5-slim-bullseye@sha256:9f35f3a6420693c209c11bba63dcf103d88e47ebe0b205336b5168c122967edf 

可以单独拉取成功的:

image-20231104063048386

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

image-20231104063216230

image-20231104063527921

  • 重启了机器后,再次测试。。。

怎么还一直卡在这里呀。。。。

image-20231104064145494

image-20231104064309689

  • 再次拉取镜像:

image-20231104064530391

  • 终于拉启动好了:

image-20231104064641654


🍀

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

img

image-20231104065051832

🍀

启动完成后,我们现在可以通过前端代理向两个服务发送请求来测试 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使用案例

image-20231104065901821

实验步骤:

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

🍀

image-20231103062452126

这里的演示应用一共包含 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 集群:

img

对于路径 /service/2 的请求将根据 x-mirror-cluster 标头的存在和值进行动态镜像。此路径的所有请求都会转发到 service2 集群,并且还会镜像到标头中指定的集群。

例如,如果我们发送带有头信息 x-mirror-cluster: service2-mirror 的请求,则该请求将被镜像转发到 service2-mirror 集群。

另外需要注意 Envoy 只会将从主集群接收到的响应返回给客户端。比如我们这里来自 service1service2 集群的响应将会发送给客户端。而来自 service1-mirrorservice2-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)

image-20231104075828305

🍀

现在让我们向 envoy-front-proxy 服务发送一个请求,该服务将请求转发到 service1,并将请求镜像发送到服 service1-mirror

1$ curl localhost:10000/service/1
2Hello from behind Envoy (service 1)!

然后我们可以分别查看 service1service1-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

正常情况下这两个服务都将接收到请求。 img

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

image-20231104080236953

image-20231104080146595

🍀

如果在对 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 中并没有。

image-20231104080609998

🍀

接下来我们再发送一个请求,这次我们将请求发送到 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)!

请求后查看这两个服务的日志来验证请求是否已被镜像:

img

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

image-20231104080646911

🍀

停掉测试容器:

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使用案例

image-20231104065901821

实验步骤:

1graph LR
2	A[实战步骤] -->B(1️⃣ 拉取测试demo)
3	A[实战步骤] -->C(2️⃣ 熟悉demo)
4    A[实战步骤] -->D(3️⃣ 启动服务)
5    A[实战步骤] -->E(4️⃣ 故障注入过滤器)

这里我们可以使用 Envoy 的故障注入过滤器来模拟故障,例如模请求中止、失败以及延迟响应等,这样我们就可以测试服务的容错能力了。该功能主要利用 Envoy 的运行时支持来控制故障注入的能力。

image-20231104081217135

🍀

image-20231104081456653

这里我们的入口 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,然后就可以这这个目录下面创建配置文件。

注意下环境:

image-20231104082049265

image-20231104082106856

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

image-20231104081842398

image-20231104081921649

为了实现故障注入功能,我们这里需要添加一个 envoy.filters.http.fault 的过滤器,这个过滤器用于实现故障注入功能,我们可以通过 typed_config 属性来配置故障注入的功能,这里我们配置了 abortdelay 两个功能,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_percent
  • fault.http.abort.http_status
  • fault.http.delay.fixed_delay_percent
  • fault.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

image-20231104084031868

🍀

启动后我们开始发送连续的 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

image-20231104084145800

🍀

虽然我们已经在 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

在容器里执行。

image-20231104083620313

img

image-20231104084526671

这是因为我们在 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

正常现在我们的请求就恢复正常的响应了。

image-20231104084547673

🍀

用同样的方式我们还可以通过一下命令通过运行时打开延迟故障注入。

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 秒钟才能完成。

img

同样要关闭延迟故障注入功能,只需要执行 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使用案例

image-20231104065901821

实验步骤:

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 目录下面,然后启动服务:

image-20231104084948854

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

image-20231104095419918

这个应用中我们通过 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使用案例

image-20231104065901821

实验步骤:

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 插件库:

image-20231104101539685

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

image-20231104102031599

1docker pull docker.io/library/golang:1.21.3-bullseye@sha256:26c7537d6ac3827eb4638034d16edc64de57bb011c8cc8fe301ac13a6568f6f4

⚠️ 注意:

记得配置这个参数,否则可能下载不了go包:

image-20231104101838899

image-20231104101705741

编译后的库文件会出现在 lib 文件夹中。

1$ ls lib
2simple.so

image-20231104102948308

🍀

然后接下来可以直接启动我们的服务:

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

img

正常我们可以看到由 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。

img

当然这些都是我们在插件里面去实现的,具体要实现什么样的功能完全取决于我们自己。

测试结束。😘

总结

我们这里只是挑选了几个过滤器来进行演示,实际上 Envoy 还有很多其他的过滤器,这里就不一一介绍了,如果想了解更多的过滤器可以参考 Envoy 官方文档 了解更多使用方式。

最重要的是我们要了解 Envoy 的过滤器的工作原理,了解 Envoy 的配置流程,这样我们才能更好的使用 Envoy。

关于我

我的博客主旨:

  • 排版美观,语言精炼;
  • 文档即手册,步骤明细,拒绝埋坑,提供源码;
  • 本人实战文档都是亲测成功的,各位小伙伴在实际操作过程中如有什么疑问,可随时联系本人帮您解决问题,让我们一起进步!

🍀 微信二维码 x2675263825 (舍得), qq:2675263825。

image-20230107215114763

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

image-20230107215126971

🍀 个人博客站点

http://onedayxyy.cn/

image-20231021104335916

image-20231021104405837

🍀 语雀

https://www.yuque.com/xyy-onlyone

image-20231030124453217

🍀 csdn

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

image-20230107215149885

🍀 知乎

https://www.zhihu.com/people/foryouone

image-20230107215203185

最后

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

image-20231104104454932

推荐使用微信支付
微信支付二维码
推荐使用支付宝
支付宝二维码
最新文章

文档导航