hugo-teek is loading...

2、Envoy动态配置

最后更新于:

Envoy动态配置

image-20231031073218798

本节我们将学习 Envoy 的核心 - 动态配置的使用。

目录

image-20231102130218966

[toc]

本节实战

实战名称
🚩 实战:Envoy动态配置-EDS-2023.10.31(测试成功)
🚩 实战:基于 API 的动态配置-2023.11.2(测试成功)

1、基于文件的动态配置

Envoy 除了支持静态配置之外,还支持动态配置,而且动态配置也是 Envoy 重点关注的功能,本节我们将学习如何将 Envoy 静态配置转换为动态配置,从而允许 Envoy 自动更新

==Envoy 动态配置==

前面的章节中,我们都是直接使用的静态配置,但是当我们需要更改配置的时候就比较麻烦了,需要重启 Envoy 代理才会生效。要解决这个问题,我们可以将静态配置更改成动态配置,当我们使用动态配置的时候,更改了配置,Envoy 将会自动去重新加载配置。

Envoy 支持不同的模块进行动态配置,可配置的有如下几个 API(统称为 xDS):

  • EDS:端点发现服务(EDS)可以让 Envoy 自动发现上游集群的成员,这使得我们可以动态添加或者删除处理流量请求的服务。
  • CDS:集群发现服务(CDS)可以让 Envoy 通过该机制自动发现在路由过程中使用的上游集群。
  • RDS:路由发现服务(RDS)可以让 Envoy 在运行时自动发现 HTTP 连接管理过滤器的整个路由配置,这可以让我们来完成诸如动态更改流量分配或者蓝绿发布之类的功能
  • VHDS:虚拟主机发现服务(VHDS)允许根据需要与路由配置本身分开请求属于路由配置的虚拟主机。该 API 通常用于路由配置中有大量虚拟主机的部署中。
  • SRDS:作用域路由发现服务(SRDS)允许将路由表分解为多个部分。该 API 通常用于具有大量路由表的 HTTP 路由部署中。
  • LDS:监听器发现服务(LDS)可以让 Envoy 在运行时自动发现整个监听器。
  • SDS:密钥发现服务(SDS)可以让 Envoy 自动发现监听器的加密密钥(证书、私钥等)以及证书校验逻辑(受信任的根证书、吊销等)。
  • RTDS:运行时发现服务 (RTDS) API 允许通过 xDS API 获取运行时层。这可以通过文件系统层进行补充或改善。
  • ECDS:扩展配置发现服务 (ECDS) API 允许独立于侦听器提供扩展配置(例如 HTTP 过滤器配置)。当构建更适合与主控制平面分离的系统(例如 WAF、故障测试等)时,这非常有用。
  • ADS:EDS、CDS 等都是单独的服务,具有不同的 REST/gRPC 服务名称,例如 StreamListenersStreamSecrets。对于希望强制资源按照不同类型的顺序到达 Envoy 的用户来说,有聚合的 xDS,这是一个单独的 gRPC 服务,在一个 gRPC 流中携带所有资源类型。(ADS 只支持 gRPC)。

动态资源,是指由 Envoy 通过 xDS 协议发现所需要的各项配置的机制,相关的配置信息保存于称之为管理服务器(Management Server )的主机上,经由 xDS API 向外暴露;下面是一个纯动态资源的基础配置框架。

1{
2  "lds_config": "{...}",
3  "cds_config": "{...}",
4  "ads_config": "{...}"
5}

xDS API 为 Envoy 提供了资源的动态配置机制,它也被称为 Data Plane API

img

Envoy 支持三种类型的配置信息的动态发现机制,相关的发现服务及其相应的 API 联合起来 称为 xDS API

  • 基于文件系统发现:指定要监视的文件系统路径

  • 通过查询一到多个管理服务器发现:通过 DiscoveryRequest 协议报文发送请求,并要求服务方以 DiscoveryResponse 协议报文进行响应

    • gRPC 服务:启动 gRPC
    • REST 服务:轮询 REST-JSON URL

v3 版本的 xDS 支持如下几种资源类型:

  • envoy.config.listener.v3.Listener
  • envoy.config.route.v3.RouteConfiguration
  • envoy.config.route.v3.ScopedRouteConfiguration
  • envoy.config.route.v3.VirtualHost
  • envoy.config.cluster.v3.Cluster
  • envoy.config.endpoint.v3.ClusterLoadAssignment
  • envoy.extensions.transport_sockets.tls.v3.Secret
  • envoy.service.runtime.v3.Runtime

Envoy 对 xDS API 的管理由后端服务器实现,包括 LDS、CDS、RDS、SRDS(Scoped Route)、VHDS (Virtual Host)、EDS、SDS、RTDS(Runtime )等。

  • 所有这些 API 都提供了最终的一致性,并且彼此间不存在相互影响;
  • 部分更高级别的操作(例如执行服务的 A/B 部署)需要进行排序以防止流量被丢弃,因此,基于一个管理服务器提供多类 API 时还需要使用聚合发现服务(ADS )API
    • ADS API 允许所有其他 API 通过来自单个管理服务器的单个 gRPC 双向流进行编组,从而允许对操作进行确定性排序

==🚩 实战:Envoy动态配置-2023.10.31(测试成功)==

接下来我们先更改配置来使用 EDS,让 Envoy 根据配置文件的数据来动态添加节点。

Cluster ID

实验环境:

1envoyproxy/envoy:v1.28.0
2docker 20.10.21-ce(具有docker环境)

实验软件:

链接:https://pan.baidu.com/s/13XKNt060XYDZU_79sjhCVQ?pwd=0820 提取码:0820 2023.10.31-实战:Envoy动态配置-EDS-2023.10.31(测试成功)

image-20231102122725855

实验步骤:

1graph LR
2	A[实战步骤] -->B(1️⃣ 定义一个基本的 Envoy 配置文件)
3	A[实战步骤] -->C(2️⃣ 加一个 node 节点让 Envoy 来识别并应用这一个唯一的配置)
4    A[实战步骤] -->D(3️⃣ EDS配置)
5    A[实战步骤] -->E(4️⃣ 创建eds)
6    A[实战步骤] -->F(5️⃣ 启动 Envoy 代理)
7    A[实战步骤] -->G(6️⃣ 启动两个 HTTP 服务来作为上游服务器)
8    A[实战步骤] -->H(7️⃣ 测试)
9    A[实战步骤] -->I(8️⃣ CDS配置)

⚠️ 情况清空之前的测试环境:

image-20231031091611741

1#这里之前创建好了2个http服务,这里就不删除了,继续使用。
2[root@docker 3.Envoy]#docker inspect 162418c8b220|grep IPAddress
3            "SecondaryIPAddresses": null,
4            "IPAddress": "172.17.0.4",
5                    "IPAddress": "172.17.0.4",
6[root@docker 3.Envoy]#docker inspect 9c9a986cb9ae|grep IPAddress
7            "SecondaryIPAddresses": null,
8            "IPAddress": "172.17.0.3",
9                    "IPAddress": "172.17.0.3",

==EDS配置==

1️⃣ 定义一个基本的 Envoy 配置文件

首先我们这里定义了一个基本的 Envoy 配置文件,如下所示:

 1# envoy.yaml
 2admin:
 3  access_log_path: /tmp/admin_access.log
 4  address:
 5    socket_address:
 6      address: 0.0.0.0
 7      port_value: 9901
 8
 9static_resources:
10  listeners:
11    - name: listener_0 # 监听器的名称
12      address:
13        socket_address:
14          address: 0.0.0.0 # 监听器的地址
15          port_value: 10000 # 监听器的端口
16
17      filter_chains:
18        - filters:
19            - name: envoy.filters.network.http_connection_manager
20              typed_config:
21                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
22                stat_prefix: ingress_http
23                access_log:
24                  - name: envoy.access_loggers.stdout
25                    typed_config:
26                      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
27                http_filters: # 定义http过滤器链
28                  - name: envoy.filters.http.router # 调用7层的路由过滤器
29                    typed_config:
30                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
31                route_config:
32                  name: local_route
33                  virtual_hosts:
34                    - name: backend
35                      domains: ["*"]
36                      routes:
37                        - match:
38                            prefix: "/"
39                          route:
40                            cluster: targetCluster

现在我们还没有配置 clusters 集群部分,这是因为我们要通过使用 EDS 来进行自动发现。

2️⃣ 加一个 node 节点让 Envoy 来识别并应用这一个唯一的配置

首先我们需要添加一个 node 节点让 Envoy 来识别并应用这一个唯一的配置,动态配置中 Envoy 实例需要有唯一的 id 标识。将下面的配置放置在配置文件的顶部区域:

1node:
2  id: envoy_eds_id
3  cluster: youdianzhishi_cluster

除了 idcluster 之外,我们还可以配置基于区域的一些位置信息来进行声明,比如 regionzonesub_zone 等。

EDS 配置

端点发现服务 EDS 是基于 gRPC 或 REST-JSON API 服务器的 xDS 管理服务器,Envoy 使用它来获取集群成员。集群成员在 Envoy 术语中称为“端点”。对于每个集群,Envoy 从发现服务获取端点,EDS 是首选的服务发现机制:

  • Envoy 明确了解每个上游主机(相对于通过 DNS 解析的负载均衡器进行路由),并且可以做出更智能的负载均衡决策。
  • 每个主机的发现 API 响应中携带的额外属性告知 Envoy 主机的负载均衡权重、金丝雀状态、区域等。这些附加属性由 Envoy 网格在负载均衡、统计收集等过程中全局使用。

3️⃣ EDS配置

接下来我们就可以来定义 EDS 配置了,可以来动态控制上游集群数据。在前面这部分的静态配置是这样的:

 1clusters:
 2  - name: targetCluster
 3    connect_timeout: 0.25s
 4    type: STRICT_DNS
 5    dns_lookup_family: V4_ONLY
 6    lb_policy: ROUND_ROBIN
 7    load_assignment:
 8      cluster_name: targetCluster
 9      endpoints:
10        - lb_endpoints:
11            - endpoint:
12                address:
13                  socket_address:
14                    address: 172.17.0.3
15                    port_value: 80
16            - endpoint:
17                address:
18                  socket_address:
19                    address: 172.17.0.4
20                    port_value: 80

现在我们将上面的静态配置转换成动态配置,首先需要转换为基于 EDSeds_cluster_config 属性,并将类型更改为 EDS,将下面的集群配置添加到 Envoy 配置的末尾:

 1clusters:
 2  - name: targetCluster
 3    connect_timeout: 0.25s
 4    lb_policy: ROUND_ROBIN
 5    type: EDS
 6    eds_cluster_config:
 7      service_name: localservices # 可选,代替集群的名称,提供给 EDS 服务
 8      eds_config: # 集群的 EDS 更新源配置
 9        path_config_source: # 本地文件配置源
10          path: "/etc/envoy/eds.yaml"
11          watched_directory: # 可选,监视目录中的文件更改
12            path: "/etc/envoy"

在上面的集群配置中我们设置了 type: EDS,表示这是一个基于 EDS 的集群配置,然后使用 eds_cluster_config 属性来定义 EDS 的配置信息,其中 service_name 属性是可选的,如果没有设置则使用集群的名称,这个属性是提供给 EDS 服务的,eds_config 属性定义了 EDS 更新源的配置,这里我们使用的是本地文件配置源,所以使用 path_config_source 属性来指定本地配置文件的路径,这里我们使用的是 /etc/envoy/eds.yaml 这个文件,这个文件将会被 Envoy 代理监视,当文件内容发生变化的时候,Envoy 将会自动更新配置。

此外还可以配置一个 watched_directory 属性来监视目录中的文件更改,当该目录中的文件被移动到时,该路径将被重新加载。这在某些部署场景中是必需的。比如如果我们使用 Kubernetes ConfigMap 来加载 xDS 资源,则可能会使用以下配置:

  • xds.yaml 存储在 ConfigMap 内。

  • 将 ConfigMap 挂载到 /config_map/xds

  • 配置路径 /config_map/xds/xds.yaml

  • 配置监视目录 /config_map/xds

上述配置将确保 Envoy 监视所属目录的移动,这是由于 Kubernetes 在原子更新期间管理 ConfigMap 符号链接的方式而必需的。

4️⃣ 创建eds

上游的服务器 192.168.215.3192.168.215.4 就将来自于 /etc/envoy/eds.yaml 这个文件,我们创建一个如下所示的 eds.yaml 文件,内容如下所示:

 1resources:
 2  - "@type": type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment
 3    cluster_name: localservices # 集群的名称,如果在集群 eds_cluster_config 中指定,这将是 service_name 值。
 4    endpoints:
 5      - lb_endpoints:
 6          - endpoint:
 7              address:
 8                socket_address:
 9                  address: 172.17.0.3
10                  port_value: 80

上面我们暂时只定义了 192.168.215.3 这一个端点。该配置文件是以 DiscoveryResponse 的格式提供响应实例的。

5️⃣ 启动 Envoy 代理

image-20231031092114846

现在配置完成后,我们可以启动 Envoy 代理来进行测试。执行下面的命令启动 Envoy 容器:

1$ docker run --name=proxy-eds -d \
2    -p 9901:9901 \
3    -p 80:10000 \
4    -v $(pwd)/manifests/3.Envoy:/etc/envoy \
5    envoyproxy/envoy:v1.28.0
1$ docker run --name=proxy-eds -d \
2    -p 9901:9901 \
3    -p 80:10000 \
4    -v $(pwd)/3.Envoy:/etc/envoy \
5    envoyproxy/envoy:v1.28.0

image-20231031092306861

完整配置文件如下:(以下代码测试正常)

envoy.yaml

 1# envoy.yaml
 2node:
 3  id: envoy_eds_id
 4  cluster: youdianzhishi_cluster
 5  
 6admin:
 7  access_log_path: /tmp/admin_access.log
 8  address:
 9    socket_address:
10      address: 0.0.0.0
11      port_value: 9901
12
13static_resources:
14  listeners:
15    - name: listener_0 # 监听器的名称
16      address:
17        socket_address:
18          address: 0.0.0.0 # 监听器的地址
19          port_value: 10000 # 监听器的端口
20
21      filter_chains:
22        - filters:
23            - name: envoy.filters.network.http_connection_manager
24              typed_config:
25                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
26                stat_prefix: ingress_http
27                access_log:
28                  - name: envoy.access_loggers.stdout
29                    typed_config:
30                      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
31                http_filters: # 定义http过滤器链
32                  - name: envoy.filters.http.router # 调用7层的路由过滤器
33                    typed_config:
34                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
35                route_config:
36                  name: local_route
37                  virtual_hosts:
38                    - name: backend
39                      domains: ["*"]
40                      routes:
41                        - match:
42                            prefix: "/"
43                          route:
44                            cluster: targetCluster
45
46  clusters:
47  - name: targetCluster
48    connect_timeout: 0.25s
49    lb_policy: ROUND_ROBIN
50    type: EDS
51    eds_cluster_config:
52      service_name: localservices # 可选,代替集群的名称,提供给 EDS 服务
53      eds_config: # 集群的 EDS 更新源配置
54        path_config_source: # 本地文件配置源
55          path: "/etc/envoy/eds.yaml"
56          watched_directory: # 可选,监视目录中的文件更改
57            path: "/etc/envoy"

eds.yaml

 1resources:
 2  - "@type": type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment
 3    cluster_name: localservices # 集群的名称,如果在集群 eds_cluster_config 中指定,这将是 service_name 值。
 4    endpoints:
 5      - lb_endpoints:
 6          - endpoint:
 7              address:
 8                socket_address:
 9                  address: 172.17.0.3
10                  port_value: 80
11          # - endpoint:
12          #     address:
13          #       socket_address:
14          #         address: 172.17.0.4
15          #         port_value: 80                  

6️⃣ 启动两个 HTTP 服务来作为上游服务器

然后同样和前面一样运行两个 HTTP 服务来作为上游服务器:

1$ docker run -d cnych/docker-http-server; docker run -d cnych/docker-http-server;
2$ docker ps
3CONTAINER ID   IMAGE                      COMMAND                  CREATED              STATUS          PORTS                                                                                NAMES
44ee790db09db   cnych/docker-http-server   "/app"                   3 seconds ago        Up 3 seconds    80/tcp                                                                               fervent_khorana
5f9456b56f1ff   cnych/docker-http-server   "/app"                   4 seconds ago        Up 3 seconds    80/tcp                                                                               wonderful_carson
6f9ce95dcc434   envoyproxy/envoy:v1.28.0   "/docker-entrypoint.…"   About a minute ago   Up 44 seconds   0.0.0.0:9901->9901/tcp, :::9901->9901/tcp, 0.0.0.0:80->10000/tcp, :::80->10000/tcp   proxy-eds

7️⃣ 测试

根据上面的 EDS 配置,Envoy 将把所有的流量都发送到 172.17.0.3 这一个节点上去,我们可以使用 curl localhost 来测试下:

1[root@docker ~]#curl localhost
2<h1>This request was processed by host: 9c9a986cb9ae</h1>
3[root@docker ~]#curl localhost
4<h1>This request was processed by host: 9c9a986cb9ae</h1>
5[root@docker ~]#curl localhost
6<h1>This request was processed by host: 9c9a986cb9ae</h1>

可以看到可以正常得到响应,而且都是由 9c9a986cb9ae 这个容器来处理的请求。现在我们来尝试更新上面的 EDS 配置添加上另外的一个节点,观察 Envoy 代理是否会自动生效。

由于我们这里使用的是 EDS 动态配置,所以当我们要扩展上游服务的时候,只需要将新的端点添加到上面我们指定的 eds.yaml 配置文件中即可,然后 Envoy 就会自动将新添加的端点包含进来。用上面同样的方式添加 172.17.0.4 这个端点,eds.yaml 内容如下所示:

 1resources:
 2  - "@type": type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment
 3    cluster_name: localservices # 集群的名称,如果在集群 eds_cluster_config 中指定,这将是 service_name 值。
 4    endpoints:
 5      - lb_endpoints:
 6          - endpoint:
 7              address:
 8                socket_address:
 9                  address: 172.17.0.3
10                  port_value: 80
11          - endpoint:
12              address:
13                socket_address:
14                  address: 172.17.0.4
15                  port_value: 80                  

更新后,正常情况下 Envoy 就会自动重新加载配置并将新的端点添加到负载均衡中去,这个时候我们再来访问代理:

1[root@docker ~]#curl localhost
2<h1>This request was processed by host: 9c9a986cb9ae</h1>
3[root@docker ~]#curl localhost
4<h1>This request was processed by host: 162418c8b220</h1>
5[root@docker ~]#curl localhost
6<h1>This request was processed by host: 162418c8b220</h1>
7[root@docker ~]#curl localhost
8<h1>This request was processed by host: 9c9a986cb9ae</h1>

可以看到已经可以自动访问到另外的端点去了。

我在测试阶段发现在 Mac 系统下面并没有自动热加载,在 Linux 系统下面是可以正常重新加载的。


==CDS 配置==

现在已经配置好了 EDS,接下来我们就可以去扩大上游集群的规模了,如果我们想要能够动态添加新的域名和集群,就需要实现集群发现服务(CDS)API,在下面的示例中,我们将配置集群发现服务(CDS)和监听器发现服务(LDS)来进行动态配置。

1️⃣ 创建cds.yaml

创建一个名为 cds.yaml 的文件来配置集群服务发现的数据,文件内容如下所示:

 1resources:
 2  - "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
 3    name: targetCluster
 4    connect_timeout: 0.25s
 5    lb_policy: ROUND_ROBIN
 6    type: EDS
 7    eds_cluster_config:
 8      service_name: localservices
 9      eds_config:
10        path: /etc/envoy/eds.yaml

2️⃣ 创建lds.yaml

此外,还需要创建一个名为 lds.yaml 的文件来放置监听器的配置,文件内容如下所示:

 1resources:
 2  - "@type": type.googleapis.com/envoy.config.listener.v3.Listener
 3    name: listener_0 # 监听器的名称
 4    address:
 5      socket_address:
 6        address: 0.0.0.0 # 监听器的地址
 7        port_value: 10000 # 监听器的端口
 8
 9    filter_chains:
10      - filters:
11          - name: envoy.filters.network.http_connection_manager
12            typed_config:
13              "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
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              http_filters: # 定义http过滤器链
20                - name: envoy.filters.http.router # 调用7层的路由过滤器
21                  typed_config:
22                    "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
23              route_config:
24                name: local_route
25                virtual_hosts:
26                  - name: backend
27                    domains: ["*"]
28                    routes:
29                      - match:
30                          prefix: "/"
31                        route:
32                          cluster: targetCluster

仔细观察可以发现 cds.yamllds.yaml 配置文件的内容基本上和之前的静态配置文件一致的。我们这里只是将集群和监听器拆分到外部文件中去,这个时候我们需要修改 Envoy 的配置来引用这些文件,我们可以通过将 static_resources 更改为 dynamic_resources 来进行配置。

3️⃣ 创建envoy-dynamic.yaml

重新新建一个 Envoy 配置文件,命名为 envoy-dynamic.yaml,内容如下所示:

 1# envoy-dynamic.yaml
 2node:
 3  id: envoy_eds_id
 4  cluster: youdianzhishi_cluster
 5admin:
 6  access_log_path: "/dev/null"
 7  address:
 8    socket_address:
 9      address: 0.0.0.0
10      port_value: 9901
11dynamic_resources: # 动态配置
12  lds_config:
13    path: "/etc/envoy/lds.yaml"
14  cds_config:
15    path: "/etc/envoy/cds.yaml"

4️⃣启动envoy代理

然后使用上面的配置文件重新启动一个新的 Envoy 代理,命令如下所示:

1$ docker run --name=proxy-xds -d \
2    -p 9901:9901 \
3    -p 80:10000 \
4    -v $(pwd)/manifests/3.Envoy:/etc/envoy \
5    -v $(pwd)/manifests/3.Envoy/envoy-dynamic.yaml:/etc/envoy/envoy.yaml \
6    envoyproxy/envoy:v1.28.0

在启动之前,记得删除前面的那个envoy代理:

1[root@docker ~]#docker ps
2CONTAINER ID   IMAGE                      COMMAND                  CREATED        STATUS        PORTS                                                                                NAMES
390805be51f74   envoyproxy/envoy:v1.28.0   "/docker-entrypoint.…"   22 hours ago   Up 22 hours   0.0.0.0:9901->9901/tcp, :::9901->9901/tcp, 0.0.0.0:80->10000/tcp, :::80->10000/tcp   proxy-eds
4162418c8b220   cnych/docker-http-server   "/app"                   2 days ago     Up 2 days     80/tcp                                                                               priceless_raman
59c9a986cb9ae   cnych/docker-http-server   "/app"                   2 days ago     Up 2 days     80/tcp                                                                               optimistic_banach
6[root@docker ~]#docker rm -f proxy-eds
7proxy-eds

自己本次命令:

1docker run --name=proxy-xds -d \
2    -p 9901:9901 \
3    -p 80:10000 \
4    -v $(pwd)/3.Envoy:/etc/envoy \
5    -v $(pwd)/3.Envoy/envoy-dynamic.yaml:/etc/envoy/envoy.yaml \
6    envoyproxy/envoy:v1.28.0

启动完成:

 1[root@docker ~]#docker run --name=proxy-xds -d \
 2>     -p 9901:9901 \
 3>     -p 80:10000 \
 4>     -v $(pwd)/3.Envoy:/etc/envoy \
 5>     -v $(pwd)/3.Envoy/envoy-dynamic.yaml:/etc/envoy/envoy.yaml \
 6>     envoyproxy/envoy:v1.28.0
 790bf2c8c5fc7ba4399b2e2cc2d887c2b7c37646c696b075bc3ff2fb9c467aa3f
 8[root@docker ~]#docker ps -l
 9CONTAINER ID   IMAGE                      COMMAND                  CREATED         STATUS         PORTS                                                                                NAMES
1090bf2c8c5fc7   envoyproxy/envoy:v1.28.0   "/docker-entrypoint.…"   6 seconds ago   Up 5 seconds   0.0.0.0:9901->9901/tcp, :::9901->9901/tcp, 0.0.0.0:80->10000/tcp, :::80->10000/tcp   proxy-xds
11[root@docker ~]#

5️⃣ 测试

启动完成后,同样可以访问 Envoy 代理来测试是否生效了:

1[root@docker ~]#curl localhost
2<h1>This request was processed by host: 162418c8b220</h1>
3[root@docker ~]#curl localhost
4<h1>This request was processed by host: 9c9a986cb9ae</h1>
5[root@docker ~]#curl localhost
6<h1>This request was processed by host: 9c9a986cb9ae</h1>
7[root@docker ~]#curl localhost
8<h1>This request was processed by host: 162418c8b220</h1>
1[root@docker ~]#docker ps
2CONTAINER ID   IMAGE                      COMMAND                  CREATED              STATUS              PORTS                                                                                NAMES
390bf2c8c5fc7   envoyproxy/envoy:v1.28.0   "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:9901->9901/tcp, :::9901->9901/tcp, 0.0.0.0:80->10000/tcp, :::80->10000/tcp   proxy-xds
4162418c8b220   cnych/docker-http-server   "/app"                   2 days ago           Up 2 days           80/tcp                                                                               priceless_raman
59c9a986cb9ae   cnych/docker-http-server   "/app"                   2 days ago           Up 2 days           80/tcp                                                                               optimistic_banach

🍀 添加一个新的集群newTargetCluster

现在我们再基于上面配置的 CDSLDSEDS 的配置来动态添加一个新的集群。比如添加一个名为 newTargetCluster 的集群,内容如下所示:

 1# cds.yaml
 2resources:
 3  - "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
 4    name: targetCluster
 5    connect_timeout: 0.25s
 6    lb_policy: ROUND_ROBIN
 7    type: EDS
 8    eds_cluster_config:
 9      service_name: localservices
10      eds_config:
11        path: /etc/envoy/eds.yaml
12  - "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
13    name: newTargetCluster
14    connect_timeout: 0.25s
15    lb_policy: ROUND_ROBIN
16    type: EDS
17    eds_cluster_config:
18      service_name: localservices
19      eds_config:
20        path: /etc/envoy/eds-1.yaml

🍀 创建eds-1.yaml

上面我们新增了一个新的集群,对应的 eds_config 配置文件是 eds-1.yaml,所以我们同样需要去创建该文件去配置新的端点服务数据,内容如下所示:

 1resources:
 2  - "@type": type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment
 3    cluster_name: localservices # 集群的名称,如果在集群 eds_cluster_config 中指定,这将是 service_name 值。
 4    endpoints:
 5      - lb_endpoints:
 6          - endpoint:
 7              address:
 8                socket_address:
 9                  address: 172.17.0.5
10                  port_value: 80
11          - endpoint:
12              address:
13                socket_address:
14                  address: 172.17.0.6
15                  port_value: 80

🍀

这个时候新的集群添加上了,但是还没有任何路由来使用这个新集群,我们可以在 lds.yaml 中去配置,将之前配置的 targetCluster 替换成 newTargetCluster

image-20231101073225574

🍀 创建2个http服务

当然同样我们这里还需要运行两个简单的 HTTP 服务来作为上游服务提供服务,执行如下所示的命令:

1docker run -d cnych/docker-http-server; docker run -d cnych/docker-http-server;

创建后:

 1[root@docker ~]#docker run -d cnych/docker-http-server; docker run -d cnych/docker-http-server;
 2cd162927bd5b776435a62149ac5b7d51493db19a3e25853b80296b68d65dda1d
 3abf164fca7b95b23ab211eccc8d76c7ccb8a400add5c78737b2da77446abba87
 4[root@docker ~]#docker ps
 5CONTAINER ID   IMAGE                      COMMAND                  CREATED         STATUS         PORTS                                                                                NAMES
 6abf164fca7b9   cnych/docker-http-server   "/app"                   4 seconds ago   Up 2 seconds   80/tcp                                                                               nifty_greider
 7cd162927bd5b   cnych/docker-http-server   "/app"                   5 seconds ago   Up 3 seconds   80/tcp                                                                               distracted_nash
 890bf2c8c5fc7   envoyproxy/envoy:v1.28.0   "/docker-entrypoint.…"   4 minutes ago   Up 4 minutes   0.0.0.0:9901->9901/tcp, :::9901->9901/tcp, 0.0.0.0:80->10000/tcp, :::80->10000/tcp   proxy-xds
 9162418c8b220   cnych/docker-http-server   "/app"                   2 days ago      Up 2 days      80/tcp                                                                               priceless_raman
109c9a986cb9ae   cnych/docker-http-server   "/app"                   2 days ago      Up 2 days      80/tcp                                                                               optimistic_banach
11d83dbc25e4da   kindest/node:v1.25.3       "/usr/local/bin/entr…"   7 months ago    Up 2 days                                                                                           demo-worker2
128e32056c89da   kindest/node:v1.25.3       "/usr/local/bin/entr…"   7 months ago    Up 2 days                                                                                           demo-worker
13bf4947c5578a   kindest/node:v1.25.3       "/usr/local/bin/entr…"   7 months ago    Up 2 days      127.0.0.1:39911->6443/tcp                                                            demo-control-plane

查看当前2个http服务的容器ip:

1[root@docker ~]#docker inspect abf164fca7b9|grep IPAddress
2            "SecondaryIPAddresses": null,
3            "IPAddress": "172.17.0.6",
4                    "IPAddress": "172.17.0.6",
5[root@docker ~]#docker inspect cd162927bd5b|grep IPAddress
6            "SecondaryIPAddresses": null,
7            "IPAddress": "172.17.0.5",
8                    "IPAddress": "172.17.0.5",

🍀 测试

这个时候 Envoy 应该就会自动重新加载并添加新的集群,我们同样可以执行 curl localhost 命令来验证:

1$ curl localhost
2<h1>This request was processed by host: 5f43efcb9432</h1>
3$ curl localhost
4<h1>This request was processed by host: 4986b39d716f</h1>

可以看到已经变成了新的两个端点数据了,证明我们这里基于文件的 xDS 动态配置已经生效了。

⚠️ 注意:

==这里现象不符。。。==

自己测试:

我这里已经改成了新的集群名称了:

image-20231101074616057

但是测试,还是无法自动生效。。。

image-20231101074712215

必须要重启下envoy代理,才能生效:。。。

 1[root@docker 3.Envoy]#docker restart proxy-xds
 2proxy-xds
 3[root@docker 3.Envoy]#curl  localhost
 4<h1>This request was processed by host: abf164fca7b9</h1>
 5[root@docker 3.Envoy]#curl  localhost
 6<h1>This request was processed by host: abf164fca7b9</h1>
 7[root@docker 3.Envoy]#curl  localhost
 8<h1>This request was processed by host: cd162927bd5b</h1>
 9[root@docker 3.Envoy]#curl  localhost
10<h1>This request was processed by host: cd162927bd5b</h1>

待提问老师。


测试过程:

结论:

以上eds是可以自动热更新的,但是lds里面集群名称修改后,还是需要重启envoy代理的,具体的哪种资源可以实现热更新,需特别注意。这里仅仅按文档把实验现象做出来即可。

==问题:==

image-20231101075237442

image-20231101075522609

阳总,在《Envoy-动态配置》这一节课程里,做基于文件的动态配置-CDS配置时,将lds.yaml 中配置的 targetCluster 替换成 newTargetCluster后,使用curl localhost测试发现不能自动生效,还需要重启envoy代理才行。做了2次现象都是一样的,这个可以帮看下吗?(我当前环境是winodws pc里vmworkstation里开的centos虚机)

==老师回答==

image-20231101193732496

7a6ddbc437c0cedd84e4c5145e71dd0

==再次测试==

2023年11月1日测试

当前环境:

image-20231101194027261

从这里开始测试:

image-20231101194104688

==再次测试,发现还是有问题:。。。==

envoy容器里的/etc/envoy/lds.yaml、cds.yaml、eds-1.yaml都生效了,但是通过curl测试访问依旧无法从新的2个端点获取流量。。。

image-20231101194834004

 1[root@docker 3.Envoy]#docker exec d4b2533ed7a5 cat /etc/envoy/envoy-dynamic.yaml
 2# envoy-dynamic.yaml
 3node:
 4  id: envoy_eds_id
 5  cluster: youdianzhishi_cluster
 6admin:
 7  access_log_path: "/dev/null"
 8  address:
 9    socket_address:
10      address: 0.0.0.0
11      port_value: 9901
12dynamic_resources: # 动态配置
13  lds_config:
14    path: "/etc/envoy/lds.yaml"
15  cds_config:
16    path: "/etc/envoy/cds.yaml"[root@docker 3.Envoy]#docker exec d4b2533ed7a5 cat /etc/envoy/lds.yaml
17resources:
18  - "@type": type.googleapis.com/envoy.config.listener.v3.Listener
19    name: listener_0 # 监听器的名称
20    address:
21      socket_address:
22        address: 0.0.0.0 # 监听器的地址
23        port_value: 10000 # 监听器的端口
24
25    filter_chains:
26      - filters:
27          - name: envoy.filters.network.http_connection_manager
28            typed_config:
29              "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
30              stat_prefix: ingress_http
31              access_log:
32                - name: envoy.access_loggers.stdout
33                  typed_config:
34                    "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
35              http_filters: # 定义http过滤器链
36                - name: envoy.filters.http.router # 调用7层的路由过滤器
37                  typed_config:
38                    "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
39              route_config:
40                name: local_route
41                virtual_hosts:
42                  - name: backend
43                    domains: ["*"]
44                    routes:
45                      - match:
46                          prefix: "/"
47                        route:
48                          cluster: newTargetCluster
49[root@docker 3.Envoy]#docker exec d4b2533ed7a5 cat /etc/envoy/cds.yaml
50resources:
51  - "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
52    name: targetCluster
53    connect_timeout: 0.25s
54    lb_policy: ROUND_ROBIN
55    type: EDS
56    eds_cluster_config:
57      service_name: localservices
58      eds_config:
59        path: /etc/envoy/eds.yaml
60
61  - "@type": type.googleapis.com/envoy.config.cluster.v3.Cluster
62    name: newTargetCluster
63    connect_timeout: 0.25s
64    lb_policy: ROUND_ROBIN
65    type: EDS
66    eds_cluster_config:
67      service_name: localservices
68      eds_config:
69        path: /etc/envoy/eds-1.yaml
70[root@docker 3.Envoy]#docker exec d4b2533ed7a5 cat /etc/envoy/eds-1.yaml
71resources:
72  - "@type": type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment
73    cluster_name: localservices # 集群的名称,如果在集群 eds_cluster_config 中指定,这将是 service_name 值。
74    endpoints:
75      - lb_endpoints:
76          - endpoint:
77              address:
78                socket_address:
79                  address: 172.17.0.5
80                  port_value: 80
81          - endpoint:
82              address:
83                socket_address:
84                  address: 172.17.0.6
85                  port_value: 80
86[root@docker 3.Envoy]#

必须要重启才可以:。。。

 1[root@docker 3.Envoy]#docker restart proxy-xds
 2proxy-xds
 3[root@docker 3.Envoy]#curl localhost
 4<h1>This request was processed by host: cd162927bd5b</h1>
 5[root@docker 3.Envoy]#curl localhost
 6<h1>This request was processed by host: abf164fca7b9</h1>
 7[root@docker 3.Envoy]#curl localhost
 8<h1>This request was processed by host: abf164fca7b9</h1>
 9[root@docker 3.Envoy]#curl localhost
10<h1>This request was processed by host: cd162927bd5b</h1>
11[root@docker 3.Envoy]#

需再次问老师。。。

==老师回答==

image-20231102121809671

闭环。


测试结束。😘

2、基于 API 的动态配置

平时项目里可以遇到的方式。

当在 Envoy 配置中定义了上游集群后,Envoy 需要知道如何解析集群成员,这就是服务发现。**端点发现服务(EDS)**是 Envoy 基于 gRPC 或者用来获取集群成员的 REST-JSON API 服务的 xDS 管理服务。在本节我们将学习如何使用 REST-JSON API 来配置端点的自动发现。

在前面的章节中,我们使用文件来定义了静态和动态配置,在这里我们将介绍另外一种方式来进行动态配置:API 动态配置

Envoy 项目在 JavaGolang 中都提供了 EDS 和其他服务发现的 gRPC 实现参考。

image-20231102060712843

==🚩 实战:基于 API 的动态配置-2023.11.2(测试成功)==

接下来我们将更改配置来使用 EDS,从而允许基于来自 REST-JSON API 服务的数据进行动态添加节点。

实验环境:

1envoyproxy/envoy:v1.28.0
2docker 20.10.21-ce(具有docker环境)
3python 3.6.8

实验软件:

链接:https://pan.baidu.com/s/1eKu-M5YvrUfmHe2cl8U6SQ?pwd=0820 提取码:0820 2023.11.2-实战:基于 API 的动态配置-2023.11.2(测试成功)

image-20231102124408735

实验步骤:

  1. 提供一个初始配置 envoy.yaml
  2. 添加一个 EDS 类型的集群配置,并在 eds_config 中配置使用 REST API
  3. 定义 xds_cluster 的解析方式,这里我们可以使用静态配置
  4. 启动一个 Envoy 代理实例来进行测试
  5. 启动一个上游端点服务
  6. 测试
  7. 启动 EDS 服务,使用 python 实现的一个 REST-JSON 的管理服务
  8. curl post数据提交
  9. 测试
  10. 在上游集群中运行更多的节点,并调用 API 来进行动态注册
  11. 测试

EDS 配置

🍀

下面是提供的一个 Envoy 配置的初始配置 envoy.yaml,文件内容如下所示:

 1# envoy.yaml
 2admin:
 3  access_log_path: /tmp/admin_access.log
 4  address:
 5    socket_address:
 6      address: 0.0.0.0
 7      port_value: 9901
 8
 9static_resources:
10  listeners:
11    - name: listener_0 # 监听器的名称
12      address:
13        socket_address:
14          address: 0.0.0.0 # 监听器的地址
15          port_value: 10000 # 监听器的端口
16
17      filter_chains:
18        - filters:
19            - name: envoy.filters.network.http_connection_manager
20              typed_config:
21                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
22                stat_prefix: ingress_http
23                access_log:
24                  - name: envoy.access_loggers.stdout
25                    typed_config:
26                      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
27                http_filters: # 定义http过滤器链
28                  - name: envoy.filters.http.router # 调用7层的路由过滤器
29                    typed_config:
30                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
31                route_config:
32                  name: local_route
33                  virtual_hosts:
34                    - name: backend
35                      domains: ["*"]
36                      routes:
37                        - match:
38                            prefix: "/"
39                          route:
40                            cluster: targetCluster

🍀

接下来需要添加一个 EDS 类型的集群配置,并在 eds_config 中配置使用 REST API:

 1clusters:
 2  - name: targetCluster
 3    type: EDS
 4    connect_timeout: 0.25s
 5    eds_cluster_config:
 6      service_name: myservice
 7      eds_config:
 8        resource_api_version: V3 # xDS资源的API版本,支持 AUTO、V2、V3,如果未指定,默认为 v2。
 9        api_config_source: # api_config_source的数据来自于 xDS API Server,即 Management Server。
10          api_type: REST
11          cluster_names: [xds_cluster] # 该字段只用于REST,cluster_names 的集群必须是静态定义的,其类型不能是EDS。
12          transport_api_version: V3
13          refresh_delay: 5s

上面配置中我们使用 api_config_source 来使用 REST API 的配置,其中 api_type 属性指定了使用 REST API,cluster_names 属性指定了使用 xds_cluster 这个集群来获取数据,refresh_delay 属性指定了刷新间隔时间,这里我们设置为 5 秒。

image-20231102061311497

image-20231102061435708

DELTA_GRPC是增量更新的,而GRPC是全量更新的。

🍀

然后需要定义 xds_cluster 的解析方式,这里我们可以使用静态配置:

 1  - name: xds_cluster
 2    type: STATIC
 3    connect_timeout: 0.25s
 4    load_assignment:
 5      cluster_name: xds_cluster
 6      endpoints:
 7        - lb_endpoints:
 8            - endpoint:
 9                address:
10                  socket_address:
11                    address: 192.168.0.112
12                    port_value: 8080  

image-20231102062543207

🍀

完整代码

 1# envoy.yaml
 2node:
 3  id: envoy_eds_id
 4  cluster: youdianzhishi_cluster
 5
 6admin:
 7  access_log_path: /tmp/admin_access.log
 8  address:
 9    socket_address:
10      address: 0.0.0.0
11      port_value: 9901
12
13static_resources:
14  listeners:
15    - name: listener_0 # 监听器的名称
16      address:
17        socket_address:
18          address: 0.0.0.0 # 监听器的地址
19          port_value: 10000 # 监听器的端口
20
21      filter_chains:
22        - filters:
23            - name: envoy.filters.network.http_connection_manager
24              typed_config:
25                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
26                stat_prefix: ingress_http
27                access_log:
28                  - name: envoy.access_loggers.stdout
29                    typed_config:
30                      "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog
31                http_filters: # 定义http过滤器链
32                  - name: envoy.filters.http.router # 调用7层的路由过滤器
33                    typed_config:
34                      "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
35                route_config:
36                  name: local_route
37                  virtual_hosts:
38                    - name: backend
39                      domains: ["*"]
40                      routes:
41                        - match:
42                            prefix: "/"
43                          route:
44                            cluster: targetCluster
45
46
47
48  clusters:
49  - name: targetCluster
50    type: EDS
51    connect_timeout: 0.25s
52    eds_cluster_config:
53      service_name: localservices
54      eds_config:
55        resource_api_version: V3 # xDS资源的API版本,支持 AUTO、V2、V3,如果未指定,默认为 v2。
56        api_config_source: # api_config_source的数据来自于 xDS API Server,即 Management Server。
57          api_type: REST
58          cluster_names: [xds_cluster] # 该字段只用于REST,cluster_names 的集群必须是静态定义的,其类型不能是EDS。
59          transport_api_version: V3
60          refresh_delay: 5s    
61
62  - name: xds_cluster
63    type: STATIC
64    connect_timeout: 0.25s
65    load_assignment:
66      cluster_name: xds_cluster
67      endpoints:
68        - lb_endpoints:
69            - endpoint:
70                address:
71                  socket_address:
72                    address: 172.29.9.65 #这个是本机的一个服务,这个服务是暂时不存在的,需要去监听/v3/discovery:endpoints, DiscoveryRequest, DiscoveryResponse
73                    port_value: 8080                        

🍀

记得清除前面的测试环境:

1[root@docker ~]#docker rm -f proxy-xds
2proxy-xds

然后同样启动一个 Envoy 代理实例来进行测试:

1$ docker run --name=api-eds -d \
2    -p 9901:9901 \
3    -p 80:10000 \
4    -v $(pwd)/manifests/4.Envoy:/etc/envoy \
5    envoyproxy/envoy:v1.28.0

自己代码:

1docker run --name=api-eds -d \
2    -p 9901:9901 \
3    -p 80:10000 \
4    -v $(pwd)/4.envoy:/etc/envoy \
5    envoyproxy/envoy:v1.28.0
1[root@docker ~]#docker run --name=api-eds -d \
2>     -p 9901:9901 \
3>     -p 80:10000 \
4>     -v $(pwd)/4.envoy:/etc/envoy \
5>     envoyproxy/envoy:v1.28.0
6a07e39f1a27b420f9fbbbba3729d222ea22b42cddcb4ec6056f6dc56a2e88443
7[root@docker ~]#docker ps
8CONTAINER ID   IMAGE                      COMMAND                  CREATED         STATUS         PORTS                                                                                NAMES
9a07e39f1a27b   envoyproxy/envoy:v1.28.0   "/docker-entrypoint.…"   4 seconds ago   Up 3 seconds   0.0.0.0:9901->9901/tcp, :::9901->9901/tcp, 0.0.0.0:80->10000/tcp, :::80->10000/tcp   api-eds

🍀

然后启动一个如下所示的上游端点服务:

1$ docker run -p 8081:8081 -d -e EDS_SERVER_PORT='8081' cnych/docker-http-server:v4
1[root@docker ~]#docker ps
2CONTAINER ID   IMAGE                         COMMAND                  CREATED         STATUS         PORTS                                                                                NAMES
3edbc120f9dd7   cnych/docker-http-server:v4   "python ./server.py"     7 seconds ago   Up 5 seconds   0.0.0.0:8081->8081/tcp, :::8081->8081/tcp                                            optimistic_gould
4a07e39f1a27b   envoyproxy/envoy:v1.28.0      "/docker-entrypoint.…"   2 minutes ago   Up 2 minutes   0.0.0.0:9901->9901/tcp, :::9901->9901/tcp, 0.0.0.0:80->10000/tcp, :::80->10000/tcp   api-eds

🍀

启动完成后我们可以使用如下命令来测试上游的端点服务:

1$ curl http://localhost:8081 -i
2HTTP/1.0 200 OK
3Content-Type: text/html; charset=utf-8
4Content-Length: 36
5Server: Werkzeug/0.15.4 Python/2.7.16
6Date: Fri, 27 Oct 2023 06:58:29 GMT
7
84caf19d5-6765-470b-a95c-a3615aea9796
1[root@docker ~]#curl http://localhost:8081 -i
2HTTP/1.0 200 OK
3Content-Type: text/html; charset=utf-8
4Content-Length: 36
5Server: Werkzeug/0.15.4 Python/2.7.16
6Date: Wed, 01 Nov 2023 22:46:23 GMT
7
8e87c78ce-78b1-4eae-8d0a-9bb8f86621bd[root@docker ~]#

🍀

现在我们启动了 Envoy 代理和上游的服务集群,但是由于我们这里启动的服务并不是 xds_cluster 中配置的服务,所以还没有连接它们。这个时候我们去查看 Envoy 代理得日志,可以看到如下所示的一些错误:

1$ docker logs -f api-eds
2[2023-10-27 08:43:48.964][1][warning][config] [source/extensions/config_subscription/rest/http_subscription_impl.cc:120] REST update for /v3/discovery:endpoints failed
3......

image-20231102064734647

🍀

启动 EDS 服务

为了让 Envoy 获取端点服务,我们需要启动 xds_cluster,我们这里将使用 python 实现的一个 REST-JSON 的管理服务,代码如下所示:

自己本地要有python环境。

我们安装一个flash包就行。

1pip3 install flask
 1# server.py
 2from flask import Flask, request, jsonify
 3import uuid
 4
 5app = Flask(__name__)
 6
 7# 存储 endpoints 的数据库
 8endpoints_db = {}
 9
10@app.route('/endpoints', methods=['POST'])
11def add_endpoint():
12    data = request.get_json()
13    endpoint_id = str(uuid.uuid4())
14    endpoints_db[endpoint_id] = data
15    return jsonify({"id": endpoint_id}), 201
16
17
18@app.route('/v3/discovery:endpoints', methods=['POST'])
19def discovery_endpoints():
20    xds_response = {  # 构造 xDS v3 EDS 响应格式
21        "version_info": "0",
22        "resources": [
23            {"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
24             "cluster_name": "localservices",
25             "endpoints": [{"lb_endpoints": [{"endpoint": {"address": {"socket_address": endpoint}}}
26                                              for endpoint in endpoints_db.values()]}]
27             }
28        ],
29        "type_url": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment",
30        "nonce": "0"
31    }
32    return jsonify(xds_response)
33
34if __name__ == '__main__':
35    app.run(host="0.0.0.0", port=8080, debug=True)

上面的代码中我们使用 Flask 实现了一个 /v3/discovery:endpoints 的 POST 接口,这个是 Envoy 用来请求发现 Endpoints 端点的接口,需要注意的是该接口必须返回 DiscoveryResponse 协议格式的数据,我们这里就是组装一个 ClusterLoadAssignment

🍀

我们这里直接在本地启动(当然也可以打包成 Docker 镜像在容器中启动):

 1$ python server.py
 2 * Serving Flask app 'server'
 3 * Debug mode: on
 4WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 5 * Running on all addresses (0.0.0.0)
 6 * Running on http://127.0.0.1:8080
 7 * Running on http://192.168.0.112:8080
 8Press CTRL+C to quit
 9 * Restarting with stat
10 * Debugger is active!
11 * Debugger PIN: 131-555-179

image-20231102072538675

要注意前面配置的 xds_cluster 的地址和端口要和上面的服务一致,并要能够访问到。

🍀

然后我们就可以将上游的服务配置添加到 EDS 服务中去了,这样可以让 Envoy 来自动发现上游服务。上面的管理服务中我们定义了一个 /endpoints 的添加端点的接口,我们只需要将要添加的端点提交给这个接口即可,然后在发现接口里面会自动获取添加的端点,然后 Envoy 就可以动态感知到了。

1$ curl --location --request POST 'http://localhost:8080/endpoints' \
2--header 'Content-Type: application/json' \
3--data-raw '{
4    "address": "192.168.215.7",
5    "port_value": 8081
6}'
 1172.17.0.7
 2
 3$ curl --location --request POST 'http://localhost:8080/endpoints' \
 4--header 'Content-Type: application/json' \
 5--data-raw '{
 6    "address": "172.17.0.7",
 7    "port_value": 8081
 8}'
 9
10
11
12curl --location --request POST 'http://localhost:8080/endpoints' \
13--header 'Content-Type: application/json' \
14--data '{
15    "address": "172.17.0.7",
16    "port_value": 8081
17}'
18
19[root@docker 4.envoy]#curl --location --request POST 'http://localhost:8080/endpoints' \
20> --header 'Content-Type: application/json' \
21> --data '{
22>     "address": "172.17.0.7",
23>     "port_value": 8081
24> }'
25{
26  "id": "db8feebe-212e-4161-b5b5-d38217aa3afc"
27}
28[root@docker 4.envoy]#

image-20231102073730570

🍀

由于我们已经启动了上面注册的上游服务,所以现在我们可以通过 Envoy 代理访问到它了:

1$ curl -i http://localhost
2HTTP/1.1 200 OK
3content-type: text/html; charset=utf-8
4content-length: 36
5server: envoy
6date: Fri, 27 Oct 2023 09:02:07 GMT
7x-envoy-upstream-service-time: 8
8
94caf19d5-6765-470b-a95c-a3615aea9796
1[root@docker 4.envoy]#curl -i http://localhost
2HTTP/1.1 200 OK
3content-type: text/html; charset=utf-8
4content-length: 36
5server: envoy
6date: Wed, 01 Nov 2023 23:40:06 GMT
7x-envoy-upstream-service-time: 104
8
9e87c78ce-78b1-4eae-8d0a-9bb8f86621bd[root@docker 4.envoy]#

🍀

接下来我们在上游集群中运行更多的节点,并调用 API 来进行动态注册,使用如下所示的命令来向上游集群再添加 4 个节点:

1for i in 8082 8083 8084 8085
2  do
3    docker run -d -e EDS_SERVER_PORT=$i cnych/docker-http-server:v4;
4    sleep .5
5done

image-20231102074109199

 1#以下命令可以查看容器的ip及端口
 2docker inspect 6cb4f32ee6c9|grep IPAddress
 3docker inspect 103542d997c8|grep IPAddress
 4docker inspect c5712ed910e1|grep IPAddress
 5docker inspect 30caf646dc3f|grep IPAddress
 6
 7
 8docker inspect 6cb4f32ee6c9|grep 80
 9docker inspect 103542d997c8|grep 80
10docker inspect c5712ed910e1|grep 80
11docker inspect 30caf646dc3f|grep 80

🍀

然后将上面的 4 个节点注册到 EDS 服务上面去,同样使用如下所示的 API 接口调用:

 1curl --location --request POST 'http://localhost:8080/endpoints' \
 2--header 'Content-Type: application/json' \
 3--data '{
 4    "address": "172.17.0.8",
 5    "port_value": 8082
 6}'
 7
 8curl --location --request POST 'http://localhost:8080/endpoints' \
 9--header 'Content-Type: application/json' \
10--data '{
11    "address": "172.17.0.9",
12    "port_value": 8083
13}'
14
15curl --location --request POST 'http://localhost:8080/endpoints' \
16--header 'Content-Type: application/json' \
17--data '{
18    "address": "172.17.0.10",
19    "port_value": 8084
20}'
21
22curl --location --request POST 'http://localhost:8080/endpoints' \
23--header 'Content-Type: application/json' \
24--data '{
25    "address": "172.17.0.11",
26    "port_value": 8085
27}'

🍀

注册成功后,我们可以通过如下所示的命令来验证网络请求是否与注册的节点之间是均衡的:

1[root@docker 4.envoy]#while true; do curl http://localhost; sleep .5; printf '\n'; done
2e87c78ce-78b1-4eae-8d0a-9bb8f86621bd
3c7169919-a0c6-4a9a-9b2a-7b1c418ee802
443c3b18d-c36a-40a5-9e7c-4d69c0f2d750
5e87c78ce-78b1-4eae-8d0a-9bb8f86621bd
643c3b18d-c36a-40a5-9e7c-4d69c0f2d750
7bbb3c266-9615-4ae4-849f-b64641c3c8cf
8……

根据上面的输出结果可以看到每次请求的服务是不同的响应,我们一共注册了 5 个端点服务。

到这里我们就实现了基于 REST-JSON 方式的 EDS 动态配置了,当然在实际使用的时候,更多的时候会使用 gRPC 的方式来实现管理服务,这样可以实现流式的数据传输,更加高效,可以查看官方提供的 go-control-plane 示例了解如何实现

测试完成。😘

关于我

我的博客主旨:

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

🍀 微信二维码 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

最后

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

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

文档导航