服务网格数据平面的关键:层层剖析Envoy配置
Envoy是一种高性能C++分布式代理,专为单个服务和应用程序设计。作为Service Mesh中的重要组件,充分理解其配置就显得尤为重要。本文列出了使用Envoy而不用其他代理的原因。并给出了Envoy及其服务的配置,然后对其进行详细解读,帮助读者理解其配置,从而掌握Envoy。
服务网格是微服务设置中的通信层,也就是说往返于每个服务的所有请求都通过网格。服务网格在微服务设置中也成为基础架构层,它能够让服务之间的通信变得安全可靠。关于Service Mesh的基础内容,我们已经在这篇文章中详细介绍过。
每一个服务都有自己的代理服务(sidecars),然后所有代理服务一起形成服务网格。Sidecars处理服务之间的通信,也就是说所有的流量都会通过网格并且该透明层可以控制服务之间如何交互。
服务网格通过由API控制的组件提供可观察性、服务发现以及负载均衡等。
实际上,如果一个服务要调用另一个服务,它不会直接调用目标服务。而是先将请求路由到本地代理,然后代理再将该请求路由到目标服务。这一过程意味着服务实例不会和其他服务直接接触,仅与本地代理进行通信。
根据ThoughtWorks Technology Radar(这是一份半年度的文档,用于评估现有技术和新生技术的风险和收益)指出,“服务网格提供一致的发现、安全性、跟踪(tracing)、监控以及故障处理,而无需共享资源(如API网关或ESB)。一个十分典型的用例是轻量的反向代理进程会与每个服务进程或单独的容器一起部署。”
当谈到服务网格时,不可避免谈到的是“sidecar”——可用于每个服务实例的代理。每个sidecar负责管理一个服务的一个实例。我们将在本文中进一步详细讨论sidecar。
服务网格可以交付什么?
当前,越来越多的企业和组织开始转向微服务架构。这样的企业需要服务网格所提供的上述功能。解耦库的使用或自定义代码的方法无疑是赢家。
为什么使用Envoy?
Envoy不是构建一个服务网格的唯一选择,市面上还有其他的代理如Nginx、Traefik等。我之所以选择Envoy,这个用C++编写的高性能代理,是因为我更喜欢Envoy的轻量、强大的路由,及其提供的可观察性和可扩展性。
让我们首先构建1个包含3个服务的服务网格设置,这是我们正在尝试构建的架构:
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: 9901 static_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: 9901 static_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: 9901 static_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服务“来返回端点列表。
如下所示:
apiVersion: apps/v1beta1 kind: Deployment metadata: name: servicea spec: 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
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
支持100+业务线、累计发布17万次|宜信容器云的A点与B点(分享实录)
宜信公司从2018年初开始建设容器云,至今,容器云的常用基本功能已经趋于完善,主要包括服务管理、应用商店、Nginx配置、存储管理、CI/CD、权限管理等,支持100+业务线、3500+的容器运行。伴随公司去VMware以及DevOps、微服务不断推进的背景,后续还会有更多的业务迁移到容器云上,容器云在宜信发挥着越来越重要的作用。本次分享主要介绍宜信容器云平台的背景、主要功能、落地实践及未来规划。 一、宜信容器云平台背景 宜信容器云平台的建设背景主要包括: 提高资源利用率。容器云建设之前,每台物理机上平均运行的虚拟机大概是20个,使用了容器云之后,每台物理机上平均运行的容器数达到50个;之前的CPU利用率大概在10%左右,迁移到容器云后,CPU利用率提高到20%以上,整个资源利用率得到了极大的提升。 提升服务可靠性。传统的虚拟机运维方式下,当机器宕机或系统故障时,需要运维手动重启虚拟机和服务,整个过程最快需要几十分钟到几个小时才能解决;使用容器云后,通过健康检查的方式,一旦发现有问题就自动重启恢复服务,可以达到分钟级甚至秒级的恢复。 节约成本。通过容器云提高了资源利用率,同时也节约了成...
- 下一篇
《程序人生》2020无畏年少青春,迎风潇洒前行,杭漂程序员2019的心路历程,披荆斩棘终雨过天晴
无畏年少青春,迎风潇洒前行 点赞再看,养成习惯 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试点思维导图,也整理了很多我的文档,欢迎Star和完善,大家面试可以参照考点复习,希望我们一起有点东西。 前言 人生是一个漫长的过程,我们怀有太多的期望,就难免会遭遇失望与挫折。 把理想束之高阁,回过头来却发现我们像是一条鱼,一直以为自己有翅膀便是飞鸟,却终于知道自己飞不了。 生活如水,时而浑浊,时而清澈,我们在社会这个大缸中挣扎——“我常常觉得生活亏待了我,别人为什么总比自己幸福和快乐呢?”。 面对挫折,我们抱怨生活欺骗了我们,我们以为自己的人生已经没有希望。 我们经常把自己比喻为迷失的天鹅,却忘记了自己要怎样去飞翔。 这期是我自己2019的小总结,2019感恩遇见,2019感谢遇见。 写这篇文章的时候本来是没什么的思路的,但是我划着2019年自己的朋友圈,突然就知道了怎么写了,我把自己的盆友圈,按照时间线写出来那不就是我过去一年发生的大事了不是嘛? 昂创作鬼才,就是我,我就是你们的丙丙。 Tip:文章中的不好情绪希望不要影响到您,这个文...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- SpringBoot2整合Redis,开启缓存,提高访问速度
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Hadoop3单机部署,实现最简伪集群
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16