综合技术

用Envoy配置Service Mesh

微信扫一扫,分享到朋友圈

用Envoy配置Service Mesh
0

【编者的话】

在这篇文章中,我们会简明扼要的介绍一下什么是"Service Mesh",以及如何使用"Envoy"构建一个"Service Mesh"。

那什么是Service Mesh呢?

Service Mesh在微服务架构体系中属于通信层。所有从微服务发出和收到的请求都会经过mesh。每个微服务都有一个自己的代理服务,所有的这些代理服务一起构成"Service mesh"

所以,如果微服务直间想进行相互调用,他们不是直接发生通信的,而是先将请求路由到本地的代理服务,然后代理服务将其路由到目标的微服务。实际上,微服务根本不了解外部世界,只和本地代理打交道。

当我们讨论ServiceMesh的时候,一定听说过一个词叫"sidecar", 它是一个在服务之间的代理程序,它负责为每一个服务实例服务

What does a Service Mesh provide?

1、ServiceService Discovery

2、Observability (metrics)

3、Rate Limiting

4、Circuit Breaking

5、Traffic Shifting

6、Load Balancing

7、Authentication and Authorisation

8、Distributed Tracing

Envoy

Envoy是一个用c++语言编写的高性能代理程序。不是一定要使用Envoy来构建ServiceMesh,其他的代理程序比如nginx、traefix也可以,但是在文本中,我们使用Envoy。

现在,我们来构建一个3个节点的service mesh,下面是我们的部署图:

Front Envoy

"Front Envoy"是一个环境中的边缘代理,通常在这里执行TLS termination, authentication生成请求headers等操作…

下面是Front Envoy的配置信息:

主要由4部分组成:1、Listener 2、Routes 3、Clusters 4、Endpoints

1、Listeners

我们可以为一个Envoy配置1个或者多个listener,从配置文件的第9-36行,可以看到当前侦听器的地址和端口,并且每个listener可以有一个或多个network filter。通过这些过 filter,可以实现大多数功能,如routing, tls termination, traffic shifting等。"envoy.http_connection_manager"是我们在这里使用的内置filter之一,除了这个envoy还有其他几个filter。

2、Routes

第22-34行是route的相关配置,包括domain(应该接受request的域),以及与每个request匹配后发送到其适当集群中。

3、Clusters

Clusters段说明了Envoy将流量转发到哪个upstream Services

第41-50行定义了"service_a",这是"front envoy"将要与之通信的唯一的upstream service。

"connect_timeout"是指如果连接upstream服务器的时间超过了connect_timeout的制定,就会返回503错误。

通常会有多个"front envoy"实例,envoy支持多个负载平衡算法来路由请求。这里我们使用的是round robin。

Endpoints

"hosts"指定了我们会将流量转发到哪里,在本例中,我们只有一个Service_A。

在第48行,你可以发现,我们并不是把请求直接发送到service_A,而是发给了Service_A的Envoy代理service_a_envoy,然后将其路由到本地Service_a实例。

还可以注意到一个service的名字代表了所有的对应的实例,就类似Kubernetes里的面的headless service

我们在这里做一个客户端的负载均衡。Envoy缓存了所有ServiceA的实例,并且每5秒刷新一次。

Envoy支持主动和被动两种方式的健康检查。如果想使用主动方式,那就在cluster的配置信息里设置。

Others

第2-7行是关于管理方面的,比如日志级别,状态查看等。

第8行是"static_resources",意思是手动加载所有的配置选项,稍后的内容中我们会做详细介绍。

其实配置的选项还有很多,我们的目的不是介绍所有的选项及其含义,我们主要是想用一个最小的配置范例做一个入门介绍。

Service A

下面是一个Service A在Envoy的配置

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"

codec_type: "AUTO"

generate_request_id: true

route_config:

name: "local_route"

virtual_hosts:

name: "http-route"

domains:

– "*"

routes:

match:

prefix: "/"

route:

cluster: "service_a"

http_filters:

name: "envoy.router"

上面定义了一个listener,用于将流量路由到实际的"Service A"的实例,您可以在103–111上找到ServiceA实例的相应cluster定义。

"Service A"与"Service B"和"Service C"通信,因此分别创建两个listener和cluster。在这里,我们为每个upstream(localhost、service b和service c)都有单独的listener,另一种方法是创建一个listener,然后根据url或headers路由到upstream。

Service B & Service C

service B和service C是最下层的服务,除了和本地服务实例通信外,没有其他的upsteam,所以他们的配置信息比较简单,如下:

Service B

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

Service C

admin:

access_log_path: "/tmp/admin_access.log"

address:

socket_address:

address: "127.0.0.1"

port_value: 9901

static_resources:

listeners:

name: "service-c-svc-http-listener"

address:

socket_address:

address: "0.0.0.0"

port_value: 8790

filter_chains:

filters:

name: "envoy.http_connection_manager"

config:

stat_prefix: "ingress"

codec_type: "AUTO"

route_config:

name: "service-c-svc-http-route"

virtual_hosts:

name: "service-c-svc-http-route"

domains:

– "*"

routes:

match:

prefix: "/"

route:

cluster: "service_c"

http_filters:

name: "envoy.router"

clusters:

name: "service_c"

connect_timeout: "0.25s"

type: "strict_dns"

lb_policy: "ROUND_ROBIN"

hosts:

socket_address:

address: "service_c"

port_value: 8083

可以看出Service B和Service C的配置没什么特别的,仅仅一个listener和一个cluster

至此,我们完成了所有的配置文件,现在可以把他们部署到kubernetes集群或者docker-compose里面了。运行"docker-compose build and docker-compose up" 并且访问"localhost:8080"端口。如果一切都没问题,那么http的访问请求会穿过所有的service和Envoy的proxy,并且在logs里可以看到这些记录。

Envoy xDS

我们完成了对sidecar的配置,设置了不同的service。如果我们仅仅有2到3个Sidecar和service的时候,手工配置还算ok,但是当服务的数量变得越来越多,手动配置几乎就是不太可能的了。并且一旦sidecar的配置改动后,还需要手动进行重启那就更麻烦了。

在刚开始我们提到过为了避免手工修改配置和加载组件,Clusters(CDS), Endpoints(EDS), Listeners(LDS) & Routes(RDS) 使用了api server。所以sidecar会从api server读取配置信息,并且会动态更新到sidecar里,而不是重启sidecar程序。

更多的关于动态配置可以点击这里查看,点击这里可以看到关于xDS的。

https://www.envoyproxy.io/docs … namic

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

Kubernetes

这个小结中我们可以看到,如何在kubernetes集群中配置service mesh:

所以我们需要做如下工作:

1、Pod

2、Service

Pod

通常情况下,一个pod里面之运行一个container,但其实在一个pod里可以运行多个container,因为我们想为每个service都运行一个sidecar的proxy,所以我们在每个Pod里都运行一个Envoy的container。所以为了和外界进行通信,service的container会通过本地网络(pod内部的local host)和Envoy Container进行通信。

在container配置段,我们可以看到关于sidecar的配置信息,我们在33到39行通过configmap mount了Envoy的配置。

(缺图)

Service

Kubernetes的service负责代理pod的路由转发信息。用kube-proxy作为负载均衡(译者注:现在早已经不是kube-proxy负载了) 。但是在我们的例子中,我们采用客户端负载均衡,所以我们不适用kuber-proxy,我们要得到所有运行sideproxy的pod的list,然后用"headless service"去负载。

(缺图)

第六行标注了service headless,你可以发现我们并没有mapping kubernetes的service 端口到应用的服务端口,而是mapping了Envoy的监听端口,所以流量会转发到Envoy。

通过以上的配置,service mesh应该可以运行在kubernetes里面了

阅读原文...


微信扫一扫,分享到朋友圈

用Envoy配置Service Mesh
0

DockOne

人工智能+建筑,会有什么化学反应?

上一篇

曙光历军年会演讲:继往开来,开启曙光新征程

下一篇

评论已经被关闭。

插入图片

热门分类

往期推荐

用Envoy配置Service Mesh

长按储存图像,分享给朋友