【AICon】AI 基础设施、LLM运维、大模型训练与推理,一场会议,全方位涵盖! >>> 了解详情
写点什么

服务网格数据平面的关键:层层剖析 Envoy 配置

  • 2020-05-18
  • 本文字数:6613 字

    阅读完需:约 22 分钟

服务网格数据平面的关键:层层剖析Envoy配置

服务网格是微服务设置中的通信层,也就是说往返于每个服务的所有请求都通过网格。服务网格在微服务设置中也成为基础架构层,它能够让服务之间的通信变得安全可靠。关于 Service Mesh 的基础内容,我们已经在这篇文章中详细介绍过。


每一个服务都有自己的代理服务(sidecars),然后所有代理服务一起形成服务网格。Sidecars 处理服务之间的通信,也就是说所有的流量都会通过网格并且该透明层可以控制服务之间如何交互。


服务网格通过由 API 控制的组件提供可观察性、服务发现以及负载均衡等。


实际上,如果一个服务要调用另一个服务,它不会直接调用目标服务。而是先将请求路由到本地代理,然后代理再将该请求路由到目标服务。这一过程意味着服务实例不会和其他服务直接接触,仅与本地代理进行通信。



本地代理服务


根据 ThoughtWorks Technology Radar(这是一份半年度的文档,用于评估现有技术和新生技术的风险和收益)指出,“服务网格提供一致的发现、安全性、跟踪(tracing)、监控以及故障处理,而无需共享资源(如 API 网关或 ESB)。一个十分典型的用例是轻量的反向代理进程会与每个服务进程或单独的容器一起部署。”


当谈到服务网格时,不可避免谈到的是“sidecar”——可用于每个服务实例的代理。每个 sidecar 负责管理一个服务的一个实例。我们将在本文中进一步详细讨论 sidecar。

服务网格可以交付什么?


服务网格可以交付的功能


当前,越来越多的企业和组织开始转向微服务架构。这样的企业需要服务网格所提供的上述功能。解耦库的使用或自定义代码的方法无疑是赢家。

为什么使用 Envoy?

Envoy 不是构建一个服务网格的唯一选择,市面上还有其他的代理如 Nginx、Traefik 等。我之所以选择 Envoy,这个用 C++编写的高性能代理,是因为我更喜欢 Envoy 的轻量、强大的路由,及其提供的可观察性和可扩展性。


让我们首先构建 1 个包含 3 个服务的服务网格设置,这是我们正在尝试构建的架构:



sidecar 代理的服务设置

Front Envoy

在我们的设置中 Front Envoy 是一个边缘代理,我们通常在其中执行 TLS 终止、身份验证、生成请求头等操作。


我们来看看 Front Envoy 配置:


---admin:  access_log_path: "/tmp/admin_access.log"  address:     socket_address:       address: "127.0.0.1"      port_value: 9901static_resources:   listeners:    -       name: "http_listener"      address:         socket_address:           address: "0.0.0.0"          port_value: 80      filter_chains:          filters:             -               name: "envoy.http_connection_manager"              config:                stat_prefix: "ingress"                route_config:                   name: "local_route"                  virtual_hosts:                     -                       name: "http-route"                      domains:                         - "*"                      routes:                         -                           match:                             prefix: "/"                          route:                            cluster: "service_a"                http_filters:                  -                     name: "envoy.router"  clusters:    -       name: "service_a"      connect_timeout: "0.25s"      type: "strict_dns"      lb_policy: "ROUND_ROBIN"      hosts:        -           socket_address:             address: "service_a_envoy"            port_value: 8786
复制代码


Envoy 配置主要由以下部分组成:


1、 监听器(Listener)


2、 路由


3、 集群


4、 端点

监听器

一个或多个监听器可以在单个 Envoy 实例中运行。在以上 9 到 36 行的代码提到了当前监听器的地址和端口。每个监听器也可以有一个或多个网络过滤器。这些过滤器可以启用路由、tls 终止、流量转移等活动。除了 envoy.http_connection_manager 使用的是内置过滤器之外,Envoy 还有其他几个过滤器。

路由

22 行到 34 行代码为过滤器配置了路由规范,同时它也指定了我们所接受请求的域以及路由匹配器。路由匹配器可以根据配置的规则匹配每个请求,并将请求转发到适当的集群。

集群

集群是 Envoy 将流量路由到的上游服务规范。41 行到 48 行代码定义了“Service A”,这是 Front Envoy 要通信的唯一上游。“connect_timeout”是在返回 503 之前建立与上游服务的连接的时间限制。


通常情况下,有多个“Serivce A”实例,并且 Envoy 支持多种负载均衡算法来路由流量。在本例中,我们使用了一个简单的循环算法。

端点

“host”指定我们要将流量路由到的 Service A 的实例。在本例中,我们只有 1 个实例。


第 47 行代码没有直接与 Service A 进行通信,而是与 Service A 的 Envoy 代理实例进行通信,该代理将路由到本地 Service A 实例。


我们还可以利用返回 Service A 的所有实例的服务名称(如 Kubernetes 中的 headless 服务),来执行客户端负载均衡。Envoy 缓存 Service A 的所有 host,并每 5 秒刷新一次 host 列表。


此外,Envoy 还支持主动和被动的健康检查。因此,如果我们要进行主动健康检查,我们需要在集群配置部分对其进行配置。

其他

第 2 行到第 7 行配置了管理服务器,它能够帮助查看配置、更改日志级别、查看统计信息等。


第 8 行的“static_resources”可以手动加载所有配置。我们将在下文讨论如何动态地执行此操作。


虽然这里描述了许多其他配置,但是我们的目标不是全面介绍所有配置,而是以最少的配置开始。

Service A

这是 Service A 的 Envoy 配置:


admin:  access_log_path: "/tmp/admin_access.log"  address:     socket_address:       address: "127.0.0.1"      port_value: 9901static_resources:  listeners:
- name: "service-a-svc-http-listener" address: socket_address: address: "0.0.0.0" port_value: 8786 filter_chains: - filters: - name: "envoy.http_connection_manager" config: stat_prefix: "ingress" codec_type: "AUTO" route_config: name: "service-a-svc-http-route" virtual_hosts: - name: "service-a-svc-http-route" domains: - "*" routes: - match: prefix: "/" route: cluster: "service_a" http_filters: - name: "envoy.router" - name: "service-b-svc-http-listener" address: socket_address: address: "0.0.0.0" port_value: 8788 filter_chains: - filters: - name: "envoy.http_connection_manager" config: stat_prefix: "egress" codec_type: "AUTO" route_config: name: "service-b-svc-http-route" virtual_hosts: - name: "service-b-svc-http-route" domains: - "*" routes: - match: prefix: "/" route: cluster: "service_b" http_filters: - name: "envoy.router"
- name: "service-c-svc-http-listener" address: socket_address: address: "0.0.0.0" port_value: 8791 filter_chains: - filters: - name: "envoy.http_connection_manager" config: stat_prefix: "egress" codec_type: "AUTO" route_config: name: "service-b-svc-http-route" virtual_hosts: - name: "service-b-svc-http-route" domains: - "*" routes: - match: prefix: "/" route: cluster: "service_c" http_filters: - name: "envoy.router" clusters: - name: "service_a" connect_timeout: "0.25s" type: "strict_dns" lb_policy: "ROUND_ROBIN" hosts: - socket_address: address: "service_a" port_value: 8081 - name: "service_b" connect_timeout: "0.25s" type: "strict_dns" lb_policy: "ROUND_ROBIN" hosts: - socket_address: address: "service_b_envoy" port_value: 8789
- name: "service_c" connect_timeout: "0.25s" type: "strict_dns" lb_policy: "ROUND_ROBIN" hosts: - socket_address: address: "service_c_envoy" port_value: 8790
复制代码


11 行到 39 行定义了一个监听器来路由流量到实际的 Service A 实例。在 103 行到 111 行中找到 service_a 实例的相应集群定义。


Service A 与 Service B 和 Service C 进行通信,它指向了两个以上的监听器以及集群。在本例中,我们为每个上游(localhost、Service B 和 Service C)分离了监听器。另一种方法是使用单个监听器,并根据 URL 或请求头路由到任意上游。

Service B 和 Service C

Service B 和 Service C 处于叶级,除了本地主机服务实例外,不与任何其他上游通信。因此其配置十分简单。


而让事情变得复杂的是上述配置中的单个监听器和单个集群。


配置完成后,我们将此设置部署到 Kubernetes 或使用 docker-compose 对其进行测试。你可以运行 docker-compose build 和 docker-compose up 并点击 localhost:8080,以查看请求是否成功通过所有服务和 Envoy 代理。我们可以使用日志对其进行验证。

Envoy xDS

我们为每个 sidecar 提供了配置,并且根据不同的服务,服务之间的配置也有所不同。虽然我们可以手动制作和管理 sidecar 配置,但最初至少要提供 2 或 3 个服务,并且随着服务数量的增加,配置会变得十分复杂。此外,每次 sidecar 配置更改时,你都必须重新启动 Envoy 实例,以使更改生效。


正如上文所讨论的,我们可以通过使用 API server 来避免手动配置并加载所有组件:集群(CDS)、端点(EDS)、监听器(LDS)以及路由(RDS)。所以每个 sidecar 将与 API server 通信并接收配置。当新配置更新到 API server 时,它将自动反映在 Envoy 实例中,从而避免了重新启动。


你可以在以下链接中了解关于动态配置的信息:


https://www.envoyproxy.io/docs/envoy/latest/configuration/overview/v2_overview#dynamic


这有一个简单的 xDS server:


https://github.com/tak2siva/Envoy-Pilot

如何在 Kubernetes 中实现

本部分将讨论如果我们要在 Kubernetes 中实现所讨论的设置该怎么办。以下是架构图:


因此,将需要更改:


  • Pod

  • 服务

部署 Pod

尽管 Pod 规范中仅定义了一个容器——按照定义,一个 Pod 可以容纳一个或多个容器。为了对每个服务实例运行 sidecar 代理,我们将 Envoy 容器添加到每个 Pod 中。为了与外界通信,服务容器将通过 localhost 与 Envoy 容器进行对话。


部署文件如下所示:


admin:  access_log_path: "/tmp/admin_access.log"  address:     socket_address:       address: "127.0.0.1"      port_value: 9901static_resources:  listeners:
- name: "service-b-svc-http-listener" address: socket_address: address: "0.0.0.0" port_value: 8789 filter_chains: - filters: - name: "envoy.http_connection_manager" config: stat_prefix: "ingress" codec_type: "AUTO" route_config: name: "service-b-svc-http-route" virtual_hosts: - name: "service-b-svc-http-route" domains: - "*" routes: - match: prefix: "/" route: cluster: "service_b" http_filters: - name: "envoy.router" clusters: - name: "service_b" connect_timeout: "0.25s" type: "strict_dns" lb_policy: "ROUND_ROBIN" hosts: - socket_address: address: "service_b" port_value: 8082
复制代码


在容器部分添加了 Envoy sidecar,并且在 33 到 39 行的 configmap 中我们挂载了我们的 Envoy 配置文件。

更改服务

Kubernetes 服务负责维护 Pod 端点列表,该列表可以路由流量。尽管 kube-proxy 通常处理 Pod 端点之间的负载均衡,但在本例中,我们将执行客户端负载均衡,并且我们不希望 kube-proxy 进行负载均衡。此外,我们想要提取 Pod 端点列表并对其进行负载均衡。为此,我们需要使用“headless 服务“来返回端点列表。


如下所示:


kind: Deploymentmetadata:  name: serviceaspec:  replicas: 2  template:    metadata:      labels:        app: servicea    spec:      containers:      - name: servicea        image: dnivra26/servicea:0.6        ports:        - containerPort: 8081          name: svc-port          protocol: TCP      - name: envoy        image: envoyproxy/envoy:latest        ports:          - containerPort: 9901            protocol: TCP            name: envoy-admin          - containerPort: 8786            protocol: TCP            name: envoy-web        volumeMounts:          - name: envoy-config-volume            mountPath: /etc/envoy-config/        command: ["/usr/local/bin/envoy"]        args: ["-c", "/etc/envoy-config/config.yaml", "--v2-config-only", "-l", "info","--service-cluster","servicea","--service-node","servicea", "--log-format", "[METADATA][%Y-%m-%d %T.%e][%t][%l][%n] %v"]      volumes:        - name: envoy-config-volume          configMap:            name: sidecar-config            items:              - key: envoy-config                path: config.yaml
复制代码


有两件事需要注意。一是第 6 行使服务变成 headless,二是我们不是将 Kubernetes 服务端口映射到应用程序的服务端口,而是映射到 Envoy 监听器端口。这意味着,流量首先通向 Envoy。即便如此,Kubernetes 也可以完美运行。


在本文中,我们看到了如何使用 Envoy 代理构建服务网格。其中,我们设置了所有通信都将通过网格。因此,现在网格不仅有大量有关流量的数据,而且还具有控制权。


以下链接中你可以获取我们所讨论的配置和代码:


https://github.com/dnivra26/envoy_servicemesh


原文链接:

https://www.thoughtworks.com/insights/blog/building-service-mesh-envoy-0


2020-05-18 18:07839

评论

发布
暂无评论
发现更多内容

2021Java常见笔试题,牛客网java编程题送信,字节Java面试题

Java 程序员 后端

2021Java开发面试解答,数据库mysql教程视频教程,90%的人看完都说好

Java 程序员 后端

2021Java高级面试题,极客时间vip年卡,看懂这些帮你轻松解决就业问题

Java 程序员 后端

上云,能打破低代码“内卷”吗?

海比研究院

低代码

2021Java者未来的出路在哪里,kafka从入门到精通

Java 程序员 后端

2021大厂Java社招最全面试题,2021年Java开发者常见面试题

Java 程序员 后端

2021一位Java中级程序员的跳槽面经,最全的BAT大厂面试题整理

Java 程序员 后端

2021大厂Java开发面试总结+解答,【一步教学,一步到位】

Java 程序员 后端

万物智联与烟火人间,一场跨越20年的双向奔赴

脑极体

做一名真正的软件工程师

百度开发者中心

程序员 最佳实践 分享 工程师

15个经典面试问题及回答思路,Java面试你必须要知道的那些知识

Java 程序员 后端

2021Java开发现状分析,看完这一篇你就懂了

Java 程序员 后端

Activity重启引起的重复发送消息Bug分析

轻口味

android 10月月更

2021Java高级面试题总结,kafka面试常见问题

Java 程序员 后端

2020-2021蚂蚁金服Java面试真题解析,2021最新Java面试真题解析

Java 程序员 后端

2021Java进阶者的新篇章,Java全栈知识体系

Java 程序员 后端

2021大厂Java面试真题集锦,京东健康Java面试

Java 程序员 后端

2021Java常见面试题,牛客网中级项目异步队列,Java高级面试题及答案整理

Java 程序员 后端

2021Java精选面试实战总结整理,架构师必备

Java 程序员 后端

2021Java面试心得,shiro框架视频尚硅谷,最新Java开发进阶

Java 程序员 后端

2021Java面试笔试总结,jdk使用教程,Java高级工程师必备知识

Java 程序员 后端

2021Java高级面试题汇总解答,Java开发新手入门教程

Java 程序员 后端

2021大厂Java开发面试总结+解答,Java基础笔试题大全带答案

Java 程序员 后端

2021Java开发学习路线,两年Java开发经验

Java 程序员 后端

2021Java网络编程总结篇,百度技术三面四面,最全Java知识总结

Java 程序员 后端

实时即未来!Flink Forward Asia 2021 议程正式上线!

Apache Flink

大数据 flink

2021Java高级进阶学习资料,字节跳动Java高级工程师

Java 程序员 后端

13分钟彻底搞懂分布式系统服务注册与发现原理,写给互联网大厂员工的真心话

Java 程序员 后端

2020-2021京东Java面试真题解析,在线面试指南

Java 程序员 后端

2021Java精选面试实战总结整理,讲的太透彻了

Java 程序员 后端

月经逆行、体能差、雌激素影响心态……女性进入太空,要经历哪些科技伪命题?

脑极体

服务网格数据平面的关键:层层剖析Envoy配置_文化 & 方法_Rancher_InfoQ精选文章