Envoy

Envoy

配置Envoy代理让Monzo运行更快

hokingyang 发表了文章 • 0 个评论 • 390 次浏览 • 2019-04-22 11:11 • 来自相关话题

Monzo Bank Ltd是一家位于英国的数字移动银行,英国金融科技初创公司之一,成立于2015年2月。最初通过移动应用和预付借记卡运营,2017年4月其获得了银行执照,使他们能够提供长期账户。Monzo经常被誉为“英国挑战者银行”。 ...查看全部
Monzo Bank Ltd是一家位于英国的数字移动银行,英国金融科技初创公司之一,成立于2015年2月。最初通过移动应用和预付借记卡运营,2017年4月其获得了银行执照,使他们能够提供长期账户。Monzo经常被誉为“英国挑战者银行”。

我们的架构核心系统是RPC,微服务可以通过网络进行可靠以及容错的通讯。RPC系统包含几个重要指标:

- 高性能:通讯应该尽量快;RPC应该支持最小延迟并且减小试错次数
- 可扩展性:我们的用户规模要求支撑每秒上万次请求。
- 弹性:面对系统不稳定(服务宕机、bugs、网络故障),应该支持容错性恢复
- 可监控的:面对每天海量的数据,RPC系统应该支持服务数据度量和监控。

2016年,我们发布了一篇关于融合用Linkerd 1.0搭建银行业务后端的博客,当时Service Mesh生态系统还相对不成熟。从那以后,许多新项目整合进来,现在是重新评估这一组件的时候了。
# Service Mesh
我们的微服务业务通过HTTP服务每秒产生上万次RPC调用,为了实现分布式容错系统,需要服务发现、自动重试、错误预算、负载均衡和中断循环的手段。

同时我们还系统支持各种编程语言。因为尽管大部分微服务都是用Go完成,但是还有一些团队选择其他语言(例如,数据团队处理机器学习服务时会采用Python)。

用每种语言实现复杂功能对采用新功能时是一个巨大的障碍。另外改变RPC调用意味着重新部署所有服务。

我们做出的一个关键性决定就是尽量保持这种复杂逻辑,用Linkerd提供尽量对服务透明的功能。
envoy-blog-1.png

Linkerd作为Kubernetes的守护进程集,每个服务都会同本机上运行的Linkerd通讯。
# 迁移到Envoy
如果不给Linkerd更多处理能力就无法处理负载,迫使我们不得不扩展架构。因为业务发展,RPC架构的资源也不能持久支撑业务。即使在正常负载情况下,Linkerd也是99%以上延迟的主要贡献者。

我们开始考察其它替代产品,例如Linkerd 2.0, Istio和Envoy。最终选择了Envoy,这是因为Envoy提供高性能,相对成熟,被大项目广泛采用的特点。

Envoy是Lyft开源的高性能Service Mesh工具,用C++写成,因此不会有垃圾回收或者编译暂停等问题。Istio和Ambassador都采用Envoy做底层的代理系统。

Envoy不内置任何Kubernetes组件,我们自己开发小型控制面板,可以监控Kubernetes架构中的改变(例如由于新Pod造成服务端点的修改),以及通过CDS API将改变推送给Envoy,以便知道新服务。

我们用自己开发的测试工具在原来Linkerd系统和Envoy系统上做了对比测试。
envoy-blog-2.png

在所有测试中,Envoy都比Linkerd 1.0表现更佳,而且需要更少的处理能力和内存资源。

也有一些不足之处,例如负载均衡的延迟和基于服务的错误预算。最终这些因素并没有成为障碍因为我们决定未来将这些功能加入其中。

我们想做到对服务透明的切换,因此希望支持回滚的功能。

像Linkerd一样,我们设置了Envoy通过HTTP接收并路由请求,并纳入了Kubernetes守护进程集。通过几个月压力测试,一旦要切换到生产系统,可以切换到某个时间点然后修复最后出现的问题。
# 可监控
Linkerd有很棒的控制面板,但是跟Prometheus的监控系统整合的不好。我们将Envoy投产之前,非常注意跟Prometheus的整合。

我们将对Prometheus的支持回馈到Envoy社区,使得我们有了很多内容丰富的面板支持。
envoy-blog-3.png

通过数据分析,我们对切换工作充满了自信。

应用与后台沟通时,经过Edge层进入微服务区获得服务。切换到Envoy后,在Edge层看到了很大的延迟降低,跟测试结果很类似,也给使用Monzo提供了更快的体验。
envoy-blog-4.png

# 作为边车的Envoy
我们希望将Envoy作为微服务容器的边车,也就意味着不需要与Envoy主机通讯而只跟本地Envoy通讯即可。

通过边车模式,我们设置Envoy支持Ingress和Egress。进来的请求通过本地Envoy,确认压力是合法的。出去的请求(Egress)通过边车Envoy路由到跟以前一样正确的地方。
envoy-blog-5.png

采用边车的优点是可以定义网络隔绝规则。之前,因为压力从共享的Envoy来,因此不能锁定敏感微服务只对某些特定IP的Pod提供网络层服务。服务必须自己判断访问请求是否合法。

将Envoy移入同一个Pod命名空间后,可以在Pod里加入Calico网络策略规则,为每个微服务创建合适的防火墙策略。本例中,Ingress进入的微服务访问流量只能从特定的子网进入,为防止非法访问提供了额外的安全保护。

另外比较Linkerd,Envoy只需要很少的系统资源和内存,目前Envoy边车支撑我们日益扩大的访问压力。
# 收获
迁移到Envoy是一个很大的成功。我们不需要重建已有的服务而能获得更佳的体验,尤其是在减少资源消耗和减少延迟方面,毋庸置疑,Envoy可以支撑我们未来的业务发展。

我们也非常感谢Envoy社区的帮助和支持,我们也希望能够继续回馈社区。

原文链接:We deployed Envoy Proxy to make Monzo faster(翻译:杨峰)

用Envoy配置Service Mesh

alex_wang2 发表了文章 • 0 个评论 • 589 次浏览 • 2019-03-15 16:16 • 来自相关话题

【编者的话】在这篇文章中,我们会简明扼要的介绍一下什么是Service Mesh,以及如何使用Envoy构建一个Service Mesh。 #那什么是Service Mesh呢? Service Mesh在微服务架构体系中属于通信层。所 ...查看全部
【编者的话】在这篇文章中,我们会简明扼要的介绍一下什么是Service Mesh,以及如何使用Envoy构建一个Service Mesh。
#那什么是Service Mesh呢?
Service Mesh在微服务架构体系中属于通信层。所有从微服务发出和收到的请求都会经过Mesh。每个微服务都有一个自己的代理服务,所有的这些代理服务一起构成Service Mesh。所以,如果微服务之间想进行相互调用,他们不是直接和对方进行通信的,而是先将请求路由到本地的代理服务,然后代理服务将其路由到目标的微服务。实际上,微服务根本不了解外部世界,只和本地代理打交道。
1.png

当我们讨论Service Mesh的时候,一定听说过一个词叫“Sidecar", 它是一个在服务之间的代理程序,它负责为每一个服务实例服务。
2.jpeg

#Service Mesh能提供什么?

  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来构建Service Mesh,其他的代理程序比如Nginx、Traefix也可以,但是在文本中,我们使用Envoy。

现在,我们来构建一个3个节点的Service Mesh,下面是我们的部署图:
3.png

#Front Envoy
"Front Envoy"是一个环境中的边缘代理,通常在这里执行TLS termination,authentication生成请求headers等操作……
---
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

下面是Front Envoy的配置信息:

主要由4部分组成:1、Listener;2、Routes;3、Clusters;4、Endpoints。
##Listeners
我们可以为一个Envoy配置1个或者多个Listener,从配置文件的第9-36行,可以看到当前侦听器的地址和端口,并且每个Listener可以有一个或多个network filter。通过这些filter,可以实现大多数功能,如routing,tls termination,traffic shifting等。“envoy.http_connection_manager”是我们在这里使用的内置filter之一,除了这个Envoy还有其他几个filter
##Routes
第22-34行是route的相关配置,包括domain(应该接受request的域),以及与每个request匹配后发送到其适当集群中。
##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缓存了所有Service A的实例,并且每5秒刷新一次。

Envoy支持主动和被动两种方式的健康检查。如果想使用主动方式,那就在cluster的配置信息里设置。
##Others
第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

上面定义了一个listener,用于将流量路由到实际的"Service A"的实例,您可以在103–111上找到Service A实例的相应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,所以他们的配置信息比较简单,如下:
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 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的示例。
#Kubernetes
这个小结中我们可以看到,如何在Kubernetes集群中配置Service Mesh:
4.png

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

  1. Pod
  2. Service

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

在container配置段,我们可以看到关于sidecar的配置信息,我们在33到39行通过configmap mount了Envoy的配置。
##Service
Kubernetes的service负责代理Pod的路由转发信息。用kube-proxy作为负载均衡(译者注:现在早已经不是kube-proxy负载了) 。但是在我们的例子中,我们采用客户端负载均衡,所以我们不适用kuber-proxy,我们要得到所有运行sideproxy的Pod的list,然后用"headless service"去负载。
kind: Service
apiVersion: v1
metadata:
name: servicea
spec:
clusterIP: None
ports:
- name: envoy-web
port: 8786
targetPort: 8786
selector:
app: servicea

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

通过以上的配置,Service Mesh应该可以运行在Kubernetes里面了,从这个连接可以找到文章中提到的所有demo。

原文连接:Service Mesh with Envoy 101(翻译:王晓轩)

云原生计算基金会宣布Envoy项目正式“毕业”

Andy_Lee 发表了文章 • 0 个评论 • 873 次浏览 • 2018-11-29 09:30 • 来自相关话题

【项目背景】Envoy项目旨在实现服务与边缘代理功能,通过管理微服务之间的交互以确保应用程序性能,从而协助简化云原生架构的过渡与运营流程。该项目提供的超时、速率限制、断路、负载均衡、重试、统计、日志记录以及分布式追踪等高级功能,可以帮助用户以高容错性以及高可靠 ...查看全部
【项目背景】Envoy项目旨在实现服务与边缘代理功能,通过管理微服务之间的交互以确保应用程序性能,从而协助简化云原生架构的过渡与运营流程。该项目提供的超时、速率限制、断路、负载均衡、重试、统计、日志记录以及分布式追踪等高级功能,可以帮助用户以高容错性以及高可靠性方式处理各类网络故障问题。

云原生计算基金会(简称CNCF)日前宣布,Envoy代理已经成为其继Kubernetes与Prometheus之后第三个正式毕业的项目。事实上,要从孵化项目逐步发展成熟并走向毕业,相关项目必须表现出蓬勃的采用势头、拥有完善记录的中立治理流程、众多组织对提交贡献的参与,以及背后社区做出的可持续且高度包容的坚定承诺。

云原生计算基金会COO Chris Aniszczyk表示,“自从加入云原生计算基金会以来,Envoy代理一直是我们发展速度最快的项目之一,且一直在根据我们在服务以及边缘代理领域中发现的变化趋势做出贡献。凭借着当今众多规模最大的组织用户以及不少水平极高的开发人员的关注,我们很高兴地宣布Envoy社区已经成为云原生计算基金会旗下新的毕业项目。”

作为最初由Lyft创建的项目,Envoy是一款开源、高性能边缘、中间与服务代理。Envoy项目旨在实现服务与边缘代理功能,通过管理微服务之间的交互以确保应用程序性能,从而协助简化云原生架构的过渡与运营流程。

Envoy的进程外架构适用于任何应用程序、任何语言或者运行时; 其支持的协议与功能包括HTTP/2、gRPC、MongoDB、Redis、Thrift、外部授权、全局速率限制以及一个富配置API等等。

Lift软件工程师与Envoy架构师Matt Klein解释称,“Envoy项目在过去两年当中实现了令人震惊的发展态势,这显然超出了我在项目刚刚启动时做出的所有预期。从最终用户到更高级别的产品创造者,再到主流云服务供应商,基于Envoy的解决方案的持续普及让我感到喜出望外。从云原生计算基金会毕业代表着一个重要的里程碑,这证明Envoy社区极为强大,且项目本身也已经做好了迎接广泛企业级采用的准备。”

得利益于其活跃的维护者团队以及近250位贡献者的支持,Envoy被InfoWorld网站评为2018年云计算最佳开源软件之一。该项目的用户社区目前仍在不断增长,其中包括Airbnb、Booking.com、eBay、F5、谷歌、IBM、Lyft、Medium、微软、Netflix、Pinterest、Salesforce、Square、Stripe、腾讯、Twilio、Verizon以及VSCO等等。截至目前,项目提交量已经超过3000份。

Actapio公司的Hirotaka Ichikawa指出,“我们很高兴地庆祝Envoy项目从云原生计算基金会的孵化器阶段顺利毕业。这证明Envoy对于像我们这样的企业确实能够提供成熟的用例。举例来说,雅虎日本下辖子公司Actapio就与Heptio合作以利用Envoy代理构建开源项目Heptio Gimbal,此项目用于处理私有云当中大量Kubernetes与OpenStack集群可能面对的成规模入站流量。在Envoy的帮助下,我们也已经显著加快了我们的软件开发与发布周期。”

Datawire公司CEO Richard Li也表示,“Envoy代理已经迅速成为业界领先的云原生L7代理。目前,数以千计的组织已经利用Ambassador API Gateway将Envoy部署在Kubernetes之上。我们对Envoy的功能集以及业界领先的架构表示高度赞赏,而我们也很高兴能够成为Envoy充满活力的技术社区中的一分子。”

谷歌云主管软件工程师兼Envoy高级维护者Harvey Tuch解释称,“Envoy不仅是Istio当中的重要组成部分,同时也在我们即将推出的Cloud Networking服务中占据着举足轻重的地位。Envoy与Istio被部署在全球范围内的各类生产环境当中。作为Envoy的强大贡献者与支持者,我们谷歌很高兴看到Envoy项目顺利毕业,并凭借着自身的技术成果、社区发展以及对各类用例的高度适用性而获得广泛认可。”

Lyft工程技术副总裁Peter Morelli指出,“Envoy提供应用程序网络抽象能力,从而为Lyft的实时微服务架构中的全部边缘与服务到服务流量提供支持。Envoy项目目前已经成为一大至关重要且极为可靠的组件,帮助Lyft可以顺利扩展至数百项服务、数千名工程师以及每秒数百万流量请求。我可以毫不怀疑地讲,如果没有Envoy,达成我们当前业务规模与目标的难度将大大增加。”

Pinterest工程经理Brian Pane介绍称,“在Pinterest,我们利用Envoy作为边缘代理,为每月超过2.5亿位不同用户提供服务。作为用户及代码的贡献者,我们很享受与Envoy项目的合作过程,也对该项目的顺利毕业感到由衷高兴。我们期待着利用Envoy解决更多未来的新型扩展问题,并继续为Envoy项目提供功能与优化贡献。”

Solo公司创始人兼CEO Idit Levine指出,“Envoy之所以能够成为如此成功且得到广泛应用的项目,其根本原因在于强大且可扩展的基础架构。Envoy用户能够以任何一种最适合自身原有技术特性的方式对Envoy进行扩展,这使得我们Solo公司能够轻松以Envoy项目为基础开发自己的技术,最终加快创新活动速度。当然,我们也为项目的上游开发工作做出了贡献。值此Envoy项目顺利毕业之际,我们要向项目中的各位合作好友表达诚挚的祝贺。”

腾讯公司中间件高级工程师单家骏表示,“Envoy是一个性能出色且可靠性极高的伟大项目。我们的团队在我们的腾讯服务框架(简称TSF)产品当中采用了Envoy。目前,我们正致力于对Envoy进行优化并开发插件,同时也期待着与项目社区开展合作。”

以Envoy与服务网格为业务核心的隐形初创企业Tetrate公司CEO Varun Talwar表示,“在Envoy项目出现之前,从来没有一款集中式软件能够将开放性、高性能、可扩展以及网络与安全行为可编程性等一流概念融于一身。”

为了从孵化状态顺利毕业,Envoy项目还遵循云原生计算基金会提出的行为准则

原文链接:Cloud Native Computing Foundation Announces Envoy Graduation

Lyft Envoy入门教程

colstuwjx 发表了文章 • 0 个评论 • 2657 次浏览 • 2018-09-08 10:57 • 来自相关话题

【编者的话】Envoy是一款由Lyft开源的7层代理和通信总线,本文作者就Envoy的背景、主打功能特性以及一些配置细节做了简单介绍。 使用微服务来解决现实世界中遇到的问题常常会比简单地编写代码更加深入。你需要测试你的服务。你需要弄清 ...查看全部
【编者的话】Envoy是一款由Lyft开源的7层代理和通信总线,本文作者就Envoy的背景、主打功能特性以及一些配置细节做了简单介绍。

使用微服务来解决现实世界中遇到的问题常常会比简单地编写代码更加深入。你需要测试你的服务。你需要弄清楚如何进行持续部署。你需要找出一个服务之间干净,优雅,弹性的交互方式。

Lyft公司出品的Envoy是一款非常有趣的工具,它可以帮助服务之间“互相交谈”。
## Lyft Envoy概览
Envoy Proxy是一款现代化的,高性能,小体积的边缘及服务代理。Enovy为用户的服务加入了弹性和监测能力,它是通过一种对服务透明的方式做到这一点的。你可能会觉得很奇怪,我们为什么要给一个自称为代理的家伙加油打气呢 —— 毕竟,在此之前业内已经出现了无数款代理软件,其中还包括一些重量级的明星产品,像NGINXHAProxy,是吧?然而,这也正是Enovy的有趣之处:

  • 它能够代理任何TCP协议
  • 它支持双向SSL
  • 它将HTTP/2视为一等公民,并且可以在HTTP/2和HTTP/1.1之间相互转换(双向)
  • 它在服务发现和负载均衡方面很灵活
  • 它被设计用于提高系统的可见性
- 尤其是,Enovy可以生成许多流量方面的统计数据,这是其它代理软件很难取代的地方 - 在某些情况下(如MongoDB和Amazon RDS),Enovy可以很确切地知道如何查看压缩协议(wire protocol)并进行透明监控
  • 相比于其它代理软件,Envoy更容易搭建
  • Envoy是一个sidecar进程,因此它对服务的实现语言完全无感知

Enovy可以通过一些相对高端——而复杂——的方式扩展,我们会在之后深入了解这块——可能要很久以后。现在我们先简单了解一下。(如果你感兴趣,想了解更多关于Envoy的细节,Matt Klein2017年微服务实践者峰会上有过一次很棒的演讲)。

Envoy支持任意TCP协议的代理,包括SSL,做到这一点是相当了不起的。想要代理Websockets?Postgres?Raw TCP?都没问题。另外,Envoy支持同时接收和发起SSL连接,这在某些时候很方便:你可以让Enovy做客户端证书验证,而与此同时仍然在Envoy和你的服务之间维持一个SSL连接。

当然,HAProxy也支持任意协议的TCP和SSL代理,但在HTTP/2方面,它只支持将整个流转发到一个支持HTTP/2的后端服务器。NGINX不支持任意协议的代理(公平地讲,Enovy也不支持像FastCGI这样的协议,因为Envoy不是一个Web服务器)。无论是开源的NGINX还是HAProxy都不能很好的处理服务发现(尽管NGINX Plus有提供一些参数),并且它们也无法提供和一个配置好的Envoy代理所给出的统计数据等同的功能。

总的来说,我们认为Envoy前景良好,它通过一款单一的软件满足了我们的众多需求,而不需要我们去搭配一些工具混合使用。
## Envoy架构
虽然我说过,相比一些曾经使用过的其他产品,Envoy的配置并不是那么繁琐。但是你可能会注意到,我并没有说过它一定很容易。Envoy的学习曲线刚开始是有些陡峭的,这是有原因的,而且也是值得的。
## Envoy和它的网络栈
假设你要编写一款HTTP网络代理。有两种显而易见的方式:在HTTP层工作,或者在TCP层工作。

在HTTP层的话,你将会从传输线路上读取整个HTTP请求的数据,对它做解析,查看HTTP头部和URL,并决定接下来要做什么。随后,你将从后端读取整个响应的数据,并将其发送给客户端。这即是一款OSI 7层(应用层)代理:代理完全明白用户想要做什么,并且可以利用这些认知做出非常聪明的决策。

这种做法的缺点就是非常复杂和缓慢 —— 试想在做出任何决定之前因为读取和解析整个请求而引入的延迟!更糟糕的是,有时候最高级别的协议根本没有决策所需的信息。一个很好的例子便是SSL:在添加SRI扩展之前,SSL客户端永远不会说明它在尝试连接哪台主机 —— 因此尽管HTTP服务器能够很好地处理虚拟主机(使用HTTP/1.1协议中定义的`Host`头部),一旦涉及到SSL,你就必须给你的服务器专门分配一个IP地址,因为一个7层代理根本没有正确代理SSL所需的信息。

因此,也许更好的选择是下沉到TCP层操作:只读取和写入字节,并使用IP地址,TCP端口号等来决定如何处理事务。这即是OSI3层(网络)或4层(传输)代理,具体取决于用户要交互的对象。我们将借用Envoy里的术语,将其称之为3/4层代理。

在这个模型中,代理处理事务的速度很快,某些事情变得更优雅和简单(参见上面的SSL示例)。另一方面,假设用户要根据不同的URL代理到不同的后端呢?对于经典的L3 / 4代理,这是不可能的:在这些层上无法访问更高层的应用程序信息。

Envoy支持同时在3,4层和7层操作,以此应对这两种方法各自都有其实际限制的现实。这很强大,并且也非常高效...但是用户通常付出的代价便是配置的复杂性。

我们面临的挑战是让简单的事务维持它的简便,同时允许复杂的事务成为可能,而Envoy在HTTP代理等方面做得相当不错。
## Envoy网格
关于Envoy,接下来这一点可能会让人感到多少有些惊讶,那便是大多数应用涉及到的是两层Envoy,而不是一层:

* 首先,会有一个“边缘Envoy”在某个地方单独运行。边缘Envoy的工作是给其他地方提供一个入口。来自外部的传入连接请求到这里,边缘Envoy将会决定他们在内部的转发路径。

* 其次,服务的每个实例都有自己的Envoy与它一起运行,这是一个运行在服务一侧的独立进程。这些“服务Envoy”会密切关注他们的服务,并且记住哪些是正在运行的,哪些不是。

* 所有的Envoy形成一个网格,然后在他们之间共享路由信息。

* 如果需要的话(通常都是这样),服务间调用也可以通过Envoy网格。我们稍后会讨论到这个问题。

注意,你当然也可以只使用边缘Envoy,然后去掉Envoy服务这一层。 但是,使用完整网格的话,服务Envoy可以对应用服务进行健康监控等,让网格知道尝试联系一个挂掉的服务是否是毫无意义的。此外,Envoy的统计数据收集最适合用在全网格上(尽管这块更多内容会放到一篇单独的文章里)。

网格中的所有Envoy使用同一份代码运行,但是它们的配置显然是不同的……这就来到了下一节,关于Envoy的配置文件。
## Envoy配置概览
Envoy的配置看起来很简单:它主要由监听器(listener)和集群(cluster)组成。

一个监听器告诉Envoy它应该监听的TCP端口,以及决定Envoy应该收听处理的一组过滤器(filter)。集群会告诉Envoy,它可以代理传入请求的一个或多个后端主机。到目前为止一切还挺顺利。但是,这里有两个方法可以让事情变得更简单:

* 过滤器可以——通常也是必须的——拥有他们自己的配置,而且通常他们会比监听器的配置更加复杂!

* 集群和负载平衡可以放在一起,并且可以用到像DNS之类的一些外部事物。

由于我们一直在谈论HTTP层的代理,我们不妨继续看一下`http_connection_manager`这个过滤器。该过滤器工作在3/4层,因此它可以访问来自IP和TCP的信息(如连接两端的主机和端口号),但是它也可以很好地理解HTTP协议,获取HTTP URL、标题等,这均适用于HTTP/1.1和HTTP/2。每当新连接抵达时,`http_connection_manager`都会利用上述的所有这些信息来决定哪个Envoy集群最适合处理该连接。然后,Envoy集群将会使用其负载平衡算法挑选出单个成员来处理该HTTP连接。

`http_connection_manager`的过滤器配置是一个包含很多选项的字典,但是目前最重要的一个参数是`virtual_hosts`数组,它定义了过滤器该如何做出路由决策。数组中的每个元素都是包含如下属性的字典:

* `name`:一个服务的可读名称
* `domains`:一组DNS风格的域名,每个必须和该虚拟主机的URL中的域名匹配才能匹配
* `routes`:一组路由字典

每个路由字典至少需要包含:

* `prefix`:此路由的URL路径前缀
* `cluster`:处理此请求的Envoy集群
* `timeout_ms`:如果出错放弃的超时时间

所有这一切即代表着一套最简单的HTTP代理 - 在HTTP的指定端口上侦听,然后根据URL路由到不同的主机 - 实际上在Envoy中配置起来也非常简单。

例如:将以`/service1`开头的URL代理到名为`service1`的集群,将以`/service2`开头的URL代理到名为`service2`的集群,你可以使用:
“virtual_hosts”: [
{
“name”: “service”,
“domains”: [“*”],
“routes”: [
{
“timeout_ms”: 0,
“prefix”: “/service1”,
“cluster”: “service1”
},
{
“timeout_ms”: 0,
“prefix”: “/service2”,
“cluster”: “service2”
}
]
}
]

就是这样。请注意,我们使用`domains [“*”]`表明我们不太关心请求哪个主机,并且值得一提的是我们可以按需添加多条路由。最后,边缘Envoy和服务Envoy之间的这个监听器配置基本相同:主要区别在于服务Envoy可能只有一个路由,它只会代理localhost上的服务而不是包含多个主机的一个集群。

当然,我们仍然需要定义上面`virtual_hosts`部分中引用的`service1`和`service2`集群。 我们可以在`cluster_manager`配置部分实现这一点,它也是一个字典,并且还有一个称为`clusters`的关键组件。它的值,又是一组词典:

* `name`:集群的一个可读名称
* `type`:此集群将如何知道哪些主机已启动?
* `lb_type`:这个集群将如何处理负载均衡?
* `hosts`:定义集群所属主机的一个URL数组(实际上通常是`tcp://` URLs)。

`type`的可选值有:

* `static`:在集群中列出所有可代理的主机
* `strict_dns`:Envoy将会监控DNS,而每个匹配的A记录都将被认为是有效的
* `logical_dns`:Envoy一般会使用DNS来添加主机,但是如果DNS不再返回它们时,也不会丢弃它们(想想有数百台主机的round-robin DNS - 我们将在后续文章中详细介绍)
* `sds`:Envoy将会去调用一个外部的REST服务以查找集群成员

而`lb_type`的可选值有:

* `round_robin`:按顺序循环遍历所有健康的主机
* `weighted_least_request`:选择两个随机健康的主机并选择请求最少的主机(这是O(1),其中扫描所有健康的主机将是O(n)。Lyft声称研究表明O(1)算法"差不多"和全扫描的效果“一样好”。
* `random`:随机挑选一台主机

关于负载均衡还有一个有趣的注意事项:集群还可以定义一个恐慌阈值(panic threshold),其中,如果集群中健康主机的数量低于恐慌阈值,集群将判定健康检查算法可能存在问题,并且假定所有主机在集群中是健康的。这可能会导致一些意外情况发生,因此这一点最好留意一下!

一个边缘Envoy的简单用例可能是这样的:
“clusters”: [
{
“name”: “service1”,
“type”: “strict_dns”,
“lb_type”: “round_robin”,
“hosts”: [
{
“url”: “tcp://service1:80”
}
]
},
{
“name”: “service2”,
“type”: “strict_dns”,
“lb_type”: “round_robin”,
“hosts”: [
{
“url”: “tcp://service2:80”
}
]
}
]

由于我们将这个集群标记为`strict_dns`类型,它将依赖于在DNS中查找`service1`和`service2`,我们假定任何新起的服务实例将会被添加到DNS中 ———— 这可能适用于像使用docker-compose配置的类似情况。针对服务Envoy(比如`service1`),我们可能会采取一个更直接的路由方式:
“clusters”: [
{
“name”: “service1”,
“type”: “static”,
“lb_type”: “round_robin”,
“hosts”: [
{
“url”: “tcp://127.0.0.1:5000”
}
]
}
]

想法类似,只是目标不太一样:我们总是在本地主机上转发到我们的服务,而不是重定向到其他主机。
## 接下来
这就是Envoy千里之行的一小步,我们还介绍了一些深入内容,关于Envoy的背景和配置。接下来,我们将使用Kubernetes,Postgres,Flask和Envoy实际部署一个简单的应用程序,并在这个过程中观察我们扩容和缩容时会发生什么。敬请关注。

原文链接:Part 1: Getting started with Lyft Envoy for microservices resilience(译者:吴佳兴)

配置Envoy代理让Monzo运行更快

hokingyang 发表了文章 • 0 个评论 • 390 次浏览 • 2019-04-22 11:11 • 来自相关话题

Monzo Bank Ltd是一家位于英国的数字移动银行,英国金融科技初创公司之一,成立于2015年2月。最初通过移动应用和预付借记卡运营,2017年4月其获得了银行执照,使他们能够提供长期账户。Monzo经常被誉为“英国挑战者银行”。 ...查看全部
Monzo Bank Ltd是一家位于英国的数字移动银行,英国金融科技初创公司之一,成立于2015年2月。最初通过移动应用和预付借记卡运营,2017年4月其获得了银行执照,使他们能够提供长期账户。Monzo经常被誉为“英国挑战者银行”。

我们的架构核心系统是RPC,微服务可以通过网络进行可靠以及容错的通讯。RPC系统包含几个重要指标:

- 高性能:通讯应该尽量快;RPC应该支持最小延迟并且减小试错次数
- 可扩展性:我们的用户规模要求支撑每秒上万次请求。
- 弹性:面对系统不稳定(服务宕机、bugs、网络故障),应该支持容错性恢复
- 可监控的:面对每天海量的数据,RPC系统应该支持服务数据度量和监控。

2016年,我们发布了一篇关于融合用Linkerd 1.0搭建银行业务后端的博客,当时Service Mesh生态系统还相对不成熟。从那以后,许多新项目整合进来,现在是重新评估这一组件的时候了。
# Service Mesh
我们的微服务业务通过HTTP服务每秒产生上万次RPC调用,为了实现分布式容错系统,需要服务发现、自动重试、错误预算、负载均衡和中断循环的手段。

同时我们还系统支持各种编程语言。因为尽管大部分微服务都是用Go完成,但是还有一些团队选择其他语言(例如,数据团队处理机器学习服务时会采用Python)。

用每种语言实现复杂功能对采用新功能时是一个巨大的障碍。另外改变RPC调用意味着重新部署所有服务。

我们做出的一个关键性决定就是尽量保持这种复杂逻辑,用Linkerd提供尽量对服务透明的功能。
envoy-blog-1.png

Linkerd作为Kubernetes的守护进程集,每个服务都会同本机上运行的Linkerd通讯。
# 迁移到Envoy
如果不给Linkerd更多处理能力就无法处理负载,迫使我们不得不扩展架构。因为业务发展,RPC架构的资源也不能持久支撑业务。即使在正常负载情况下,Linkerd也是99%以上延迟的主要贡献者。

我们开始考察其它替代产品,例如Linkerd 2.0, Istio和Envoy。最终选择了Envoy,这是因为Envoy提供高性能,相对成熟,被大项目广泛采用的特点。

Envoy是Lyft开源的高性能Service Mesh工具,用C++写成,因此不会有垃圾回收或者编译暂停等问题。Istio和Ambassador都采用Envoy做底层的代理系统。

Envoy不内置任何Kubernetes组件,我们自己开发小型控制面板,可以监控Kubernetes架构中的改变(例如由于新Pod造成服务端点的修改),以及通过CDS API将改变推送给Envoy,以便知道新服务。

我们用自己开发的测试工具在原来Linkerd系统和Envoy系统上做了对比测试。
envoy-blog-2.png

在所有测试中,Envoy都比Linkerd 1.0表现更佳,而且需要更少的处理能力和内存资源。

也有一些不足之处,例如负载均衡的延迟和基于服务的错误预算。最终这些因素并没有成为障碍因为我们决定未来将这些功能加入其中。

我们想做到对服务透明的切换,因此希望支持回滚的功能。

像Linkerd一样,我们设置了Envoy通过HTTP接收并路由请求,并纳入了Kubernetes守护进程集。通过几个月压力测试,一旦要切换到生产系统,可以切换到某个时间点然后修复最后出现的问题。
# 可监控
Linkerd有很棒的控制面板,但是跟Prometheus的监控系统整合的不好。我们将Envoy投产之前,非常注意跟Prometheus的整合。

我们将对Prometheus的支持回馈到Envoy社区,使得我们有了很多内容丰富的面板支持。
envoy-blog-3.png

通过数据分析,我们对切换工作充满了自信。

应用与后台沟通时,经过Edge层进入微服务区获得服务。切换到Envoy后,在Edge层看到了很大的延迟降低,跟测试结果很类似,也给使用Monzo提供了更快的体验。
envoy-blog-4.png

# 作为边车的Envoy
我们希望将Envoy作为微服务容器的边车,也就意味着不需要与Envoy主机通讯而只跟本地Envoy通讯即可。

通过边车模式,我们设置Envoy支持Ingress和Egress。进来的请求通过本地Envoy,确认压力是合法的。出去的请求(Egress)通过边车Envoy路由到跟以前一样正确的地方。
envoy-blog-5.png

采用边车的优点是可以定义网络隔绝规则。之前,因为压力从共享的Envoy来,因此不能锁定敏感微服务只对某些特定IP的Pod提供网络层服务。服务必须自己判断访问请求是否合法。

将Envoy移入同一个Pod命名空间后,可以在Pod里加入Calico网络策略规则,为每个微服务创建合适的防火墙策略。本例中,Ingress进入的微服务访问流量只能从特定的子网进入,为防止非法访问提供了额外的安全保护。

另外比较Linkerd,Envoy只需要很少的系统资源和内存,目前Envoy边车支撑我们日益扩大的访问压力。
# 收获
迁移到Envoy是一个很大的成功。我们不需要重建已有的服务而能获得更佳的体验,尤其是在减少资源消耗和减少延迟方面,毋庸置疑,Envoy可以支撑我们未来的业务发展。

我们也非常感谢Envoy社区的帮助和支持,我们也希望能够继续回馈社区。

原文链接:We deployed Envoy Proxy to make Monzo faster(翻译:杨峰)

用Envoy配置Service Mesh

alex_wang2 发表了文章 • 0 个评论 • 589 次浏览 • 2019-03-15 16:16 • 来自相关话题

【编者的话】在这篇文章中,我们会简明扼要的介绍一下什么是Service Mesh,以及如何使用Envoy构建一个Service Mesh。 #那什么是Service Mesh呢? Service Mesh在微服务架构体系中属于通信层。所 ...查看全部
【编者的话】在这篇文章中,我们会简明扼要的介绍一下什么是Service Mesh,以及如何使用Envoy构建一个Service Mesh。
#那什么是Service Mesh呢?
Service Mesh在微服务架构体系中属于通信层。所有从微服务发出和收到的请求都会经过Mesh。每个微服务都有一个自己的代理服务,所有的这些代理服务一起构成Service Mesh。所以,如果微服务之间想进行相互调用,他们不是直接和对方进行通信的,而是先将请求路由到本地的代理服务,然后代理服务将其路由到目标的微服务。实际上,微服务根本不了解外部世界,只和本地代理打交道。
1.png

当我们讨论Service Mesh的时候,一定听说过一个词叫“Sidecar", 它是一个在服务之间的代理程序,它负责为每一个服务实例服务。
2.jpeg

#Service Mesh能提供什么?

  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来构建Service Mesh,其他的代理程序比如Nginx、Traefix也可以,但是在文本中,我们使用Envoy。

现在,我们来构建一个3个节点的Service Mesh,下面是我们的部署图:
3.png

#Front Envoy
"Front Envoy"是一个环境中的边缘代理,通常在这里执行TLS termination,authentication生成请求headers等操作……
---
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

下面是Front Envoy的配置信息:

主要由4部分组成:1、Listener;2、Routes;3、Clusters;4、Endpoints。
##Listeners
我们可以为一个Envoy配置1个或者多个Listener,从配置文件的第9-36行,可以看到当前侦听器的地址和端口,并且每个Listener可以有一个或多个network filter。通过这些filter,可以实现大多数功能,如routing,tls termination,traffic shifting等。“envoy.http_connection_manager”是我们在这里使用的内置filter之一,除了这个Envoy还有其他几个filter
##Routes
第22-34行是route的相关配置,包括domain(应该接受request的域),以及与每个request匹配后发送到其适当集群中。
##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缓存了所有Service A的实例,并且每5秒刷新一次。

Envoy支持主动和被动两种方式的健康检查。如果想使用主动方式,那就在cluster的配置信息里设置。
##Others
第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

上面定义了一个listener,用于将流量路由到实际的"Service A"的实例,您可以在103–111上找到Service A实例的相应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,所以他们的配置信息比较简单,如下:
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 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的示例。
#Kubernetes
这个小结中我们可以看到,如何在Kubernetes集群中配置Service Mesh:
4.png

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

  1. Pod
  2. Service

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

在container配置段,我们可以看到关于sidecar的配置信息,我们在33到39行通过configmap mount了Envoy的配置。
##Service
Kubernetes的service负责代理Pod的路由转发信息。用kube-proxy作为负载均衡(译者注:现在早已经不是kube-proxy负载了) 。但是在我们的例子中,我们采用客户端负载均衡,所以我们不适用kuber-proxy,我们要得到所有运行sideproxy的Pod的list,然后用"headless service"去负载。
kind: Service
apiVersion: v1
metadata:
name: servicea
spec:
clusterIP: None
ports:
- name: envoy-web
port: 8786
targetPort: 8786
selector:
app: servicea

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

通过以上的配置,Service Mesh应该可以运行在Kubernetes里面了,从这个连接可以找到文章中提到的所有demo。

原文连接:Service Mesh with Envoy 101(翻译:王晓轩)

云原生计算基金会宣布Envoy项目正式“毕业”

Andy_Lee 发表了文章 • 0 个评论 • 873 次浏览 • 2018-11-29 09:30 • 来自相关话题

【项目背景】Envoy项目旨在实现服务与边缘代理功能,通过管理微服务之间的交互以确保应用程序性能,从而协助简化云原生架构的过渡与运营流程。该项目提供的超时、速率限制、断路、负载均衡、重试、统计、日志记录以及分布式追踪等高级功能,可以帮助用户以高容错性以及高可靠 ...查看全部
【项目背景】Envoy项目旨在实现服务与边缘代理功能,通过管理微服务之间的交互以确保应用程序性能,从而协助简化云原生架构的过渡与运营流程。该项目提供的超时、速率限制、断路、负载均衡、重试、统计、日志记录以及分布式追踪等高级功能,可以帮助用户以高容错性以及高可靠性方式处理各类网络故障问题。

云原生计算基金会(简称CNCF)日前宣布,Envoy代理已经成为其继Kubernetes与Prometheus之后第三个正式毕业的项目。事实上,要从孵化项目逐步发展成熟并走向毕业,相关项目必须表现出蓬勃的采用势头、拥有完善记录的中立治理流程、众多组织对提交贡献的参与,以及背后社区做出的可持续且高度包容的坚定承诺。

云原生计算基金会COO Chris Aniszczyk表示,“自从加入云原生计算基金会以来,Envoy代理一直是我们发展速度最快的项目之一,且一直在根据我们在服务以及边缘代理领域中发现的变化趋势做出贡献。凭借着当今众多规模最大的组织用户以及不少水平极高的开发人员的关注,我们很高兴地宣布Envoy社区已经成为云原生计算基金会旗下新的毕业项目。”

作为最初由Lyft创建的项目,Envoy是一款开源、高性能边缘、中间与服务代理。Envoy项目旨在实现服务与边缘代理功能,通过管理微服务之间的交互以确保应用程序性能,从而协助简化云原生架构的过渡与运营流程。

Envoy的进程外架构适用于任何应用程序、任何语言或者运行时; 其支持的协议与功能包括HTTP/2、gRPC、MongoDB、Redis、Thrift、外部授权、全局速率限制以及一个富配置API等等。

Lift软件工程师与Envoy架构师Matt Klein解释称,“Envoy项目在过去两年当中实现了令人震惊的发展态势,这显然超出了我在项目刚刚启动时做出的所有预期。从最终用户到更高级别的产品创造者,再到主流云服务供应商,基于Envoy的解决方案的持续普及让我感到喜出望外。从云原生计算基金会毕业代表着一个重要的里程碑,这证明Envoy社区极为强大,且项目本身也已经做好了迎接广泛企业级采用的准备。”

得利益于其活跃的维护者团队以及近250位贡献者的支持,Envoy被InfoWorld网站评为2018年云计算最佳开源软件之一。该项目的用户社区目前仍在不断增长,其中包括Airbnb、Booking.com、eBay、F5、谷歌、IBM、Lyft、Medium、微软、Netflix、Pinterest、Salesforce、Square、Stripe、腾讯、Twilio、Verizon以及VSCO等等。截至目前,项目提交量已经超过3000份。

Actapio公司的Hirotaka Ichikawa指出,“我们很高兴地庆祝Envoy项目从云原生计算基金会的孵化器阶段顺利毕业。这证明Envoy对于像我们这样的企业确实能够提供成熟的用例。举例来说,雅虎日本下辖子公司Actapio就与Heptio合作以利用Envoy代理构建开源项目Heptio Gimbal,此项目用于处理私有云当中大量Kubernetes与OpenStack集群可能面对的成规模入站流量。在Envoy的帮助下,我们也已经显著加快了我们的软件开发与发布周期。”

Datawire公司CEO Richard Li也表示,“Envoy代理已经迅速成为业界领先的云原生L7代理。目前,数以千计的组织已经利用Ambassador API Gateway将Envoy部署在Kubernetes之上。我们对Envoy的功能集以及业界领先的架构表示高度赞赏,而我们也很高兴能够成为Envoy充满活力的技术社区中的一分子。”

谷歌云主管软件工程师兼Envoy高级维护者Harvey Tuch解释称,“Envoy不仅是Istio当中的重要组成部分,同时也在我们即将推出的Cloud Networking服务中占据着举足轻重的地位。Envoy与Istio被部署在全球范围内的各类生产环境当中。作为Envoy的强大贡献者与支持者,我们谷歌很高兴看到Envoy项目顺利毕业,并凭借着自身的技术成果、社区发展以及对各类用例的高度适用性而获得广泛认可。”

Lyft工程技术副总裁Peter Morelli指出,“Envoy提供应用程序网络抽象能力,从而为Lyft的实时微服务架构中的全部边缘与服务到服务流量提供支持。Envoy项目目前已经成为一大至关重要且极为可靠的组件,帮助Lyft可以顺利扩展至数百项服务、数千名工程师以及每秒数百万流量请求。我可以毫不怀疑地讲,如果没有Envoy,达成我们当前业务规模与目标的难度将大大增加。”

Pinterest工程经理Brian Pane介绍称,“在Pinterest,我们利用Envoy作为边缘代理,为每月超过2.5亿位不同用户提供服务。作为用户及代码的贡献者,我们很享受与Envoy项目的合作过程,也对该项目的顺利毕业感到由衷高兴。我们期待着利用Envoy解决更多未来的新型扩展问题,并继续为Envoy项目提供功能与优化贡献。”

Solo公司创始人兼CEO Idit Levine指出,“Envoy之所以能够成为如此成功且得到广泛应用的项目,其根本原因在于强大且可扩展的基础架构。Envoy用户能够以任何一种最适合自身原有技术特性的方式对Envoy进行扩展,这使得我们Solo公司能够轻松以Envoy项目为基础开发自己的技术,最终加快创新活动速度。当然,我们也为项目的上游开发工作做出了贡献。值此Envoy项目顺利毕业之际,我们要向项目中的各位合作好友表达诚挚的祝贺。”

腾讯公司中间件高级工程师单家骏表示,“Envoy是一个性能出色且可靠性极高的伟大项目。我们的团队在我们的腾讯服务框架(简称TSF)产品当中采用了Envoy。目前,我们正致力于对Envoy进行优化并开发插件,同时也期待着与项目社区开展合作。”

以Envoy与服务网格为业务核心的隐形初创企业Tetrate公司CEO Varun Talwar表示,“在Envoy项目出现之前,从来没有一款集中式软件能够将开放性、高性能、可扩展以及网络与安全行为可编程性等一流概念融于一身。”

为了从孵化状态顺利毕业,Envoy项目还遵循云原生计算基金会提出的行为准则

原文链接:Cloud Native Computing Foundation Announces Envoy Graduation

配置Envoy代理让Monzo运行更快

hokingyang 发表了文章 • 0 个评论 • 390 次浏览 • 2019-04-22 11:11 • 来自相关话题

Monzo Bank Ltd是一家位于英国的数字移动银行,英国金融科技初创公司之一,成立于2015年2月。最初通过移动应用和预付借记卡运营,2017年4月其获得了银行执照,使他们能够提供长期账户。Monzo经常被誉为“英国挑战者银行”。 ...查看全部
Monzo Bank Ltd是一家位于英国的数字移动银行,英国金融科技初创公司之一,成立于2015年2月。最初通过移动应用和预付借记卡运营,2017年4月其获得了银行执照,使他们能够提供长期账户。Monzo经常被誉为“英国挑战者银行”。

我们的架构核心系统是RPC,微服务可以通过网络进行可靠以及容错的通讯。RPC系统包含几个重要指标:

- 高性能:通讯应该尽量快;RPC应该支持最小延迟并且减小试错次数
- 可扩展性:我们的用户规模要求支撑每秒上万次请求。
- 弹性:面对系统不稳定(服务宕机、bugs、网络故障),应该支持容错性恢复
- 可监控的:面对每天海量的数据,RPC系统应该支持服务数据度量和监控。

2016年,我们发布了一篇关于融合用Linkerd 1.0搭建银行业务后端的博客,当时Service Mesh生态系统还相对不成熟。从那以后,许多新项目整合进来,现在是重新评估这一组件的时候了。
# Service Mesh
我们的微服务业务通过HTTP服务每秒产生上万次RPC调用,为了实现分布式容错系统,需要服务发现、自动重试、错误预算、负载均衡和中断循环的手段。

同时我们还系统支持各种编程语言。因为尽管大部分微服务都是用Go完成,但是还有一些团队选择其他语言(例如,数据团队处理机器学习服务时会采用Python)。

用每种语言实现复杂功能对采用新功能时是一个巨大的障碍。另外改变RPC调用意味着重新部署所有服务。

我们做出的一个关键性决定就是尽量保持这种复杂逻辑,用Linkerd提供尽量对服务透明的功能。
envoy-blog-1.png

Linkerd作为Kubernetes的守护进程集,每个服务都会同本机上运行的Linkerd通讯。
# 迁移到Envoy
如果不给Linkerd更多处理能力就无法处理负载,迫使我们不得不扩展架构。因为业务发展,RPC架构的资源也不能持久支撑业务。即使在正常负载情况下,Linkerd也是99%以上延迟的主要贡献者。

我们开始考察其它替代产品,例如Linkerd 2.0, Istio和Envoy。最终选择了Envoy,这是因为Envoy提供高性能,相对成熟,被大项目广泛采用的特点。

Envoy是Lyft开源的高性能Service Mesh工具,用C++写成,因此不会有垃圾回收或者编译暂停等问题。Istio和Ambassador都采用Envoy做底层的代理系统。

Envoy不内置任何Kubernetes组件,我们自己开发小型控制面板,可以监控Kubernetes架构中的改变(例如由于新Pod造成服务端点的修改),以及通过CDS API将改变推送给Envoy,以便知道新服务。

我们用自己开发的测试工具在原来Linkerd系统和Envoy系统上做了对比测试。
envoy-blog-2.png

在所有测试中,Envoy都比Linkerd 1.0表现更佳,而且需要更少的处理能力和内存资源。

也有一些不足之处,例如负载均衡的延迟和基于服务的错误预算。最终这些因素并没有成为障碍因为我们决定未来将这些功能加入其中。

我们想做到对服务透明的切换,因此希望支持回滚的功能。

像Linkerd一样,我们设置了Envoy通过HTTP接收并路由请求,并纳入了Kubernetes守护进程集。通过几个月压力测试,一旦要切换到生产系统,可以切换到某个时间点然后修复最后出现的问题。
# 可监控
Linkerd有很棒的控制面板,但是跟Prometheus的监控系统整合的不好。我们将Envoy投产之前,非常注意跟Prometheus的整合。

我们将对Prometheus的支持回馈到Envoy社区,使得我们有了很多内容丰富的面板支持。
envoy-blog-3.png

通过数据分析,我们对切换工作充满了自信。

应用与后台沟通时,经过Edge层进入微服务区获得服务。切换到Envoy后,在Edge层看到了很大的延迟降低,跟测试结果很类似,也给使用Monzo提供了更快的体验。
envoy-blog-4.png

# 作为边车的Envoy
我们希望将Envoy作为微服务容器的边车,也就意味着不需要与Envoy主机通讯而只跟本地Envoy通讯即可。

通过边车模式,我们设置Envoy支持Ingress和Egress。进来的请求通过本地Envoy,确认压力是合法的。出去的请求(Egress)通过边车Envoy路由到跟以前一样正确的地方。
envoy-blog-5.png

采用边车的优点是可以定义网络隔绝规则。之前,因为压力从共享的Envoy来,因此不能锁定敏感微服务只对某些特定IP的Pod提供网络层服务。服务必须自己判断访问请求是否合法。

将Envoy移入同一个Pod命名空间后,可以在Pod里加入Calico网络策略规则,为每个微服务创建合适的防火墙策略。本例中,Ingress进入的微服务访问流量只能从特定的子网进入,为防止非法访问提供了额外的安全保护。

另外比较Linkerd,Envoy只需要很少的系统资源和内存,目前Envoy边车支撑我们日益扩大的访问压力。
# 收获
迁移到Envoy是一个很大的成功。我们不需要重建已有的服务而能获得更佳的体验,尤其是在减少资源消耗和减少延迟方面,毋庸置疑,Envoy可以支撑我们未来的业务发展。

我们也非常感谢Envoy社区的帮助和支持,我们也希望能够继续回馈社区。

原文链接:We deployed Envoy Proxy to make Monzo faster(翻译:杨峰)

用Envoy配置Service Mesh

alex_wang2 发表了文章 • 0 个评论 • 589 次浏览 • 2019-03-15 16:16 • 来自相关话题

【编者的话】在这篇文章中,我们会简明扼要的介绍一下什么是Service Mesh,以及如何使用Envoy构建一个Service Mesh。 #那什么是Service Mesh呢? Service Mesh在微服务架构体系中属于通信层。所 ...查看全部
【编者的话】在这篇文章中,我们会简明扼要的介绍一下什么是Service Mesh,以及如何使用Envoy构建一个Service Mesh。
#那什么是Service Mesh呢?
Service Mesh在微服务架构体系中属于通信层。所有从微服务发出和收到的请求都会经过Mesh。每个微服务都有一个自己的代理服务,所有的这些代理服务一起构成Service Mesh。所以,如果微服务之间想进行相互调用,他们不是直接和对方进行通信的,而是先将请求路由到本地的代理服务,然后代理服务将其路由到目标的微服务。实际上,微服务根本不了解外部世界,只和本地代理打交道。
1.png

当我们讨论Service Mesh的时候,一定听说过一个词叫“Sidecar", 它是一个在服务之间的代理程序,它负责为每一个服务实例服务。
2.jpeg

#Service Mesh能提供什么?

  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来构建Service Mesh,其他的代理程序比如Nginx、Traefix也可以,但是在文本中,我们使用Envoy。

现在,我们来构建一个3个节点的Service Mesh,下面是我们的部署图:
3.png

#Front Envoy
"Front Envoy"是一个环境中的边缘代理,通常在这里执行TLS termination,authentication生成请求headers等操作……
---
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

下面是Front Envoy的配置信息:

主要由4部分组成:1、Listener;2、Routes;3、Clusters;4、Endpoints。
##Listeners
我们可以为一个Envoy配置1个或者多个Listener,从配置文件的第9-36行,可以看到当前侦听器的地址和端口,并且每个Listener可以有一个或多个network filter。通过这些filter,可以实现大多数功能,如routing,tls termination,traffic shifting等。“envoy.http_connection_manager”是我们在这里使用的内置filter之一,除了这个Envoy还有其他几个filter
##Routes
第22-34行是route的相关配置,包括domain(应该接受request的域),以及与每个request匹配后发送到其适当集群中。
##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缓存了所有Service A的实例,并且每5秒刷新一次。

Envoy支持主动和被动两种方式的健康检查。如果想使用主动方式,那就在cluster的配置信息里设置。
##Others
第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

上面定义了一个listener,用于将流量路由到实际的"Service A"的实例,您可以在103–111上找到Service A实例的相应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,所以他们的配置信息比较简单,如下:
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 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的示例。
#Kubernetes
这个小结中我们可以看到,如何在Kubernetes集群中配置Service Mesh:
4.png

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

  1. Pod
  2. Service

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

在container配置段,我们可以看到关于sidecar的配置信息,我们在33到39行通过configmap mount了Envoy的配置。
##Service
Kubernetes的service负责代理Pod的路由转发信息。用kube-proxy作为负载均衡(译者注:现在早已经不是kube-proxy负载了) 。但是在我们的例子中,我们采用客户端负载均衡,所以我们不适用kuber-proxy,我们要得到所有运行sideproxy的Pod的list,然后用"headless service"去负载。
kind: Service
apiVersion: v1
metadata:
name: servicea
spec:
clusterIP: None
ports:
- name: envoy-web
port: 8786
targetPort: 8786
selector:
app: servicea

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

通过以上的配置,Service Mesh应该可以运行在Kubernetes里面了,从这个连接可以找到文章中提到的所有demo。

原文连接:Service Mesh with Envoy 101(翻译:王晓轩)

云原生计算基金会宣布Envoy项目正式“毕业”

Andy_Lee 发表了文章 • 0 个评论 • 873 次浏览 • 2018-11-29 09:30 • 来自相关话题

【项目背景】Envoy项目旨在实现服务与边缘代理功能,通过管理微服务之间的交互以确保应用程序性能,从而协助简化云原生架构的过渡与运营流程。该项目提供的超时、速率限制、断路、负载均衡、重试、统计、日志记录以及分布式追踪等高级功能,可以帮助用户以高容错性以及高可靠 ...查看全部
【项目背景】Envoy项目旨在实现服务与边缘代理功能,通过管理微服务之间的交互以确保应用程序性能,从而协助简化云原生架构的过渡与运营流程。该项目提供的超时、速率限制、断路、负载均衡、重试、统计、日志记录以及分布式追踪等高级功能,可以帮助用户以高容错性以及高可靠性方式处理各类网络故障问题。

云原生计算基金会(简称CNCF)日前宣布,Envoy代理已经成为其继Kubernetes与Prometheus之后第三个正式毕业的项目。事实上,要从孵化项目逐步发展成熟并走向毕业,相关项目必须表现出蓬勃的采用势头、拥有完善记录的中立治理流程、众多组织对提交贡献的参与,以及背后社区做出的可持续且高度包容的坚定承诺。

云原生计算基金会COO Chris Aniszczyk表示,“自从加入云原生计算基金会以来,Envoy代理一直是我们发展速度最快的项目之一,且一直在根据我们在服务以及边缘代理领域中发现的变化趋势做出贡献。凭借着当今众多规模最大的组织用户以及不少水平极高的开发人员的关注,我们很高兴地宣布Envoy社区已经成为云原生计算基金会旗下新的毕业项目。”

作为最初由Lyft创建的项目,Envoy是一款开源、高性能边缘、中间与服务代理。Envoy项目旨在实现服务与边缘代理功能,通过管理微服务之间的交互以确保应用程序性能,从而协助简化云原生架构的过渡与运营流程。

Envoy的进程外架构适用于任何应用程序、任何语言或者运行时; 其支持的协议与功能包括HTTP/2、gRPC、MongoDB、Redis、Thrift、外部授权、全局速率限制以及一个富配置API等等。

Lift软件工程师与Envoy架构师Matt Klein解释称,“Envoy项目在过去两年当中实现了令人震惊的发展态势,这显然超出了我在项目刚刚启动时做出的所有预期。从最终用户到更高级别的产品创造者,再到主流云服务供应商,基于Envoy的解决方案的持续普及让我感到喜出望外。从云原生计算基金会毕业代表着一个重要的里程碑,这证明Envoy社区极为强大,且项目本身也已经做好了迎接广泛企业级采用的准备。”

得利益于其活跃的维护者团队以及近250位贡献者的支持,Envoy被InfoWorld网站评为2018年云计算最佳开源软件之一。该项目的用户社区目前仍在不断增长,其中包括Airbnb、Booking.com、eBay、F5、谷歌、IBM、Lyft、Medium、微软、Netflix、Pinterest、Salesforce、Square、Stripe、腾讯、Twilio、Verizon以及VSCO等等。截至目前,项目提交量已经超过3000份。

Actapio公司的Hirotaka Ichikawa指出,“我们很高兴地庆祝Envoy项目从云原生计算基金会的孵化器阶段顺利毕业。这证明Envoy对于像我们这样的企业确实能够提供成熟的用例。举例来说,雅虎日本下辖子公司Actapio就与Heptio合作以利用Envoy代理构建开源项目Heptio Gimbal,此项目用于处理私有云当中大量Kubernetes与OpenStack集群可能面对的成规模入站流量。在Envoy的帮助下,我们也已经显著加快了我们的软件开发与发布周期。”

Datawire公司CEO Richard Li也表示,“Envoy代理已经迅速成为业界领先的云原生L7代理。目前,数以千计的组织已经利用Ambassador API Gateway将Envoy部署在Kubernetes之上。我们对Envoy的功能集以及业界领先的架构表示高度赞赏,而我们也很高兴能够成为Envoy充满活力的技术社区中的一分子。”

谷歌云主管软件工程师兼Envoy高级维护者Harvey Tuch解释称,“Envoy不仅是Istio当中的重要组成部分,同时也在我们即将推出的Cloud Networking服务中占据着举足轻重的地位。Envoy与Istio被部署在全球范围内的各类生产环境当中。作为Envoy的强大贡献者与支持者,我们谷歌很高兴看到Envoy项目顺利毕业,并凭借着自身的技术成果、社区发展以及对各类用例的高度适用性而获得广泛认可。”

Lyft工程技术副总裁Peter Morelli指出,“Envoy提供应用程序网络抽象能力,从而为Lyft的实时微服务架构中的全部边缘与服务到服务流量提供支持。Envoy项目目前已经成为一大至关重要且极为可靠的组件,帮助Lyft可以顺利扩展至数百项服务、数千名工程师以及每秒数百万流量请求。我可以毫不怀疑地讲,如果没有Envoy,达成我们当前业务规模与目标的难度将大大增加。”

Pinterest工程经理Brian Pane介绍称,“在Pinterest,我们利用Envoy作为边缘代理,为每月超过2.5亿位不同用户提供服务。作为用户及代码的贡献者,我们很享受与Envoy项目的合作过程,也对该项目的顺利毕业感到由衷高兴。我们期待着利用Envoy解决更多未来的新型扩展问题,并继续为Envoy项目提供功能与优化贡献。”

Solo公司创始人兼CEO Idit Levine指出,“Envoy之所以能够成为如此成功且得到广泛应用的项目,其根本原因在于强大且可扩展的基础架构。Envoy用户能够以任何一种最适合自身原有技术特性的方式对Envoy进行扩展,这使得我们Solo公司能够轻松以Envoy项目为基础开发自己的技术,最终加快创新活动速度。当然,我们也为项目的上游开发工作做出了贡献。值此Envoy项目顺利毕业之际,我们要向项目中的各位合作好友表达诚挚的祝贺。”

腾讯公司中间件高级工程师单家骏表示,“Envoy是一个性能出色且可靠性极高的伟大项目。我们的团队在我们的腾讯服务框架(简称TSF)产品当中采用了Envoy。目前,我们正致力于对Envoy进行优化并开发插件,同时也期待着与项目社区开展合作。”

以Envoy与服务网格为业务核心的隐形初创企业Tetrate公司CEO Varun Talwar表示,“在Envoy项目出现之前,从来没有一款集中式软件能够将开放性、高性能、可扩展以及网络与安全行为可编程性等一流概念融于一身。”

为了从孵化状态顺利毕业,Envoy项目还遵循云原生计算基金会提出的行为准则

原文链接:Cloud Native Computing Foundation Announces Envoy Graduation

Lyft Envoy入门教程

colstuwjx 发表了文章 • 0 个评论 • 2657 次浏览 • 2018-09-08 10:57 • 来自相关话题

【编者的话】Envoy是一款由Lyft开源的7层代理和通信总线,本文作者就Envoy的背景、主打功能特性以及一些配置细节做了简单介绍。 使用微服务来解决现实世界中遇到的问题常常会比简单地编写代码更加深入。你需要测试你的服务。你需要弄清 ...查看全部
【编者的话】Envoy是一款由Lyft开源的7层代理和通信总线,本文作者就Envoy的背景、主打功能特性以及一些配置细节做了简单介绍。

使用微服务来解决现实世界中遇到的问题常常会比简单地编写代码更加深入。你需要测试你的服务。你需要弄清楚如何进行持续部署。你需要找出一个服务之间干净,优雅,弹性的交互方式。

Lyft公司出品的Envoy是一款非常有趣的工具,它可以帮助服务之间“互相交谈”。
## Lyft Envoy概览
Envoy Proxy是一款现代化的,高性能,小体积的边缘及服务代理。Enovy为用户的服务加入了弹性和监测能力,它是通过一种对服务透明的方式做到这一点的。你可能会觉得很奇怪,我们为什么要给一个自称为代理的家伙加油打气呢 —— 毕竟,在此之前业内已经出现了无数款代理软件,其中还包括一些重量级的明星产品,像NGINXHAProxy,是吧?然而,这也正是Enovy的有趣之处:

  • 它能够代理任何TCP协议
  • 它支持双向SSL
  • 它将HTTP/2视为一等公民,并且可以在HTTP/2和HTTP/1.1之间相互转换(双向)
  • 它在服务发现和负载均衡方面很灵活
  • 它被设计用于提高系统的可见性
- 尤其是,Enovy可以生成许多流量方面的统计数据,这是其它代理软件很难取代的地方 - 在某些情况下(如MongoDB和Amazon RDS),Enovy可以很确切地知道如何查看压缩协议(wire protocol)并进行透明监控
  • 相比于其它代理软件,Envoy更容易搭建
  • Envoy是一个sidecar进程,因此它对服务的实现语言完全无感知

Enovy可以通过一些相对高端——而复杂——的方式扩展,我们会在之后深入了解这块——可能要很久以后。现在我们先简单了解一下。(如果你感兴趣,想了解更多关于Envoy的细节,Matt Klein2017年微服务实践者峰会上有过一次很棒的演讲)。

Envoy支持任意TCP协议的代理,包括SSL,做到这一点是相当了不起的。想要代理Websockets?Postgres?Raw TCP?都没问题。另外,Envoy支持同时接收和发起SSL连接,这在某些时候很方便:你可以让Enovy做客户端证书验证,而与此同时仍然在Envoy和你的服务之间维持一个SSL连接。

当然,HAProxy也支持任意协议的TCP和SSL代理,但在HTTP/2方面,它只支持将整个流转发到一个支持HTTP/2的后端服务器。NGINX不支持任意协议的代理(公平地讲,Enovy也不支持像FastCGI这样的协议,因为Envoy不是一个Web服务器)。无论是开源的NGINX还是HAProxy都不能很好的处理服务发现(尽管NGINX Plus有提供一些参数),并且它们也无法提供和一个配置好的Envoy代理所给出的统计数据等同的功能。

总的来说,我们认为Envoy前景良好,它通过一款单一的软件满足了我们的众多需求,而不需要我们去搭配一些工具混合使用。
## Envoy架构
虽然我说过,相比一些曾经使用过的其他产品,Envoy的配置并不是那么繁琐。但是你可能会注意到,我并没有说过它一定很容易。Envoy的学习曲线刚开始是有些陡峭的,这是有原因的,而且也是值得的。
## Envoy和它的网络栈
假设你要编写一款HTTP网络代理。有两种显而易见的方式:在HTTP层工作,或者在TCP层工作。

在HTTP层的话,你将会从传输线路上读取整个HTTP请求的数据,对它做解析,查看HTTP头部和URL,并决定接下来要做什么。随后,你将从后端读取整个响应的数据,并将其发送给客户端。这即是一款OSI 7层(应用层)代理:代理完全明白用户想要做什么,并且可以利用这些认知做出非常聪明的决策。

这种做法的缺点就是非常复杂和缓慢 —— 试想在做出任何决定之前因为读取和解析整个请求而引入的延迟!更糟糕的是,有时候最高级别的协议根本没有决策所需的信息。一个很好的例子便是SSL:在添加SRI扩展之前,SSL客户端永远不会说明它在尝试连接哪台主机 —— 因此尽管HTTP服务器能够很好地处理虚拟主机(使用HTTP/1.1协议中定义的`Host`头部),一旦涉及到SSL,你就必须给你的服务器专门分配一个IP地址,因为一个7层代理根本没有正确代理SSL所需的信息。

因此,也许更好的选择是下沉到TCP层操作:只读取和写入字节,并使用IP地址,TCP端口号等来决定如何处理事务。这即是OSI3层(网络)或4层(传输)代理,具体取决于用户要交互的对象。我们将借用Envoy里的术语,将其称之为3/4层代理。

在这个模型中,代理处理事务的速度很快,某些事情变得更优雅和简单(参见上面的SSL示例)。另一方面,假设用户要根据不同的URL代理到不同的后端呢?对于经典的L3 / 4代理,这是不可能的:在这些层上无法访问更高层的应用程序信息。

Envoy支持同时在3,4层和7层操作,以此应对这两种方法各自都有其实际限制的现实。这很强大,并且也非常高效...但是用户通常付出的代价便是配置的复杂性。

我们面临的挑战是让简单的事务维持它的简便,同时允许复杂的事务成为可能,而Envoy在HTTP代理等方面做得相当不错。
## Envoy网格
关于Envoy,接下来这一点可能会让人感到多少有些惊讶,那便是大多数应用涉及到的是两层Envoy,而不是一层:

* 首先,会有一个“边缘Envoy”在某个地方单独运行。边缘Envoy的工作是给其他地方提供一个入口。来自外部的传入连接请求到这里,边缘Envoy将会决定他们在内部的转发路径。

* 其次,服务的每个实例都有自己的Envoy与它一起运行,这是一个运行在服务一侧的独立进程。这些“服务Envoy”会密切关注他们的服务,并且记住哪些是正在运行的,哪些不是。

* 所有的Envoy形成一个网格,然后在他们之间共享路由信息。

* 如果需要的话(通常都是这样),服务间调用也可以通过Envoy网格。我们稍后会讨论到这个问题。

注意,你当然也可以只使用边缘Envoy,然后去掉Envoy服务这一层。 但是,使用完整网格的话,服务Envoy可以对应用服务进行健康监控等,让网格知道尝试联系一个挂掉的服务是否是毫无意义的。此外,Envoy的统计数据收集最适合用在全网格上(尽管这块更多内容会放到一篇单独的文章里)。

网格中的所有Envoy使用同一份代码运行,但是它们的配置显然是不同的……这就来到了下一节,关于Envoy的配置文件。
## Envoy配置概览
Envoy的配置看起来很简单:它主要由监听器(listener)和集群(cluster)组成。

一个监听器告诉Envoy它应该监听的TCP端口,以及决定Envoy应该收听处理的一组过滤器(filter)。集群会告诉Envoy,它可以代理传入请求的一个或多个后端主机。到目前为止一切还挺顺利。但是,这里有两个方法可以让事情变得更简单:

* 过滤器可以——通常也是必须的——拥有他们自己的配置,而且通常他们会比监听器的配置更加复杂!

* 集群和负载平衡可以放在一起,并且可以用到像DNS之类的一些外部事物。

由于我们一直在谈论HTTP层的代理,我们不妨继续看一下`http_connection_manager`这个过滤器。该过滤器工作在3/4层,因此它可以访问来自IP和TCP的信息(如连接两端的主机和端口号),但是它也可以很好地理解HTTP协议,获取HTTP URL、标题等,这均适用于HTTP/1.1和HTTP/2。每当新连接抵达时,`http_connection_manager`都会利用上述的所有这些信息来决定哪个Envoy集群最适合处理该连接。然后,Envoy集群将会使用其负载平衡算法挑选出单个成员来处理该HTTP连接。

`http_connection_manager`的过滤器配置是一个包含很多选项的字典,但是目前最重要的一个参数是`virtual_hosts`数组,它定义了过滤器该如何做出路由决策。数组中的每个元素都是包含如下属性的字典:

* `name`:一个服务的可读名称
* `domains`:一组DNS风格的域名,每个必须和该虚拟主机的URL中的域名匹配才能匹配
* `routes`:一组路由字典

每个路由字典至少需要包含:

* `prefix`:此路由的URL路径前缀
* `cluster`:处理此请求的Envoy集群
* `timeout_ms`:如果出错放弃的超时时间

所有这一切即代表着一套最简单的HTTP代理 - 在HTTP的指定端口上侦听,然后根据URL路由到不同的主机 - 实际上在Envoy中配置起来也非常简单。

例如:将以`/service1`开头的URL代理到名为`service1`的集群,将以`/service2`开头的URL代理到名为`service2`的集群,你可以使用:
“virtual_hosts”: [
{
“name”: “service”,
“domains”: [“*”],
“routes”: [
{
“timeout_ms”: 0,
“prefix”: “/service1”,
“cluster”: “service1”
},
{
“timeout_ms”: 0,
“prefix”: “/service2”,
“cluster”: “service2”
}
]
}
]

就是这样。请注意,我们使用`domains [“*”]`表明我们不太关心请求哪个主机,并且值得一提的是我们可以按需添加多条路由。最后,边缘Envoy和服务Envoy之间的这个监听器配置基本相同:主要区别在于服务Envoy可能只有一个路由,它只会代理localhost上的服务而不是包含多个主机的一个集群。

当然,我们仍然需要定义上面`virtual_hosts`部分中引用的`service1`和`service2`集群。 我们可以在`cluster_manager`配置部分实现这一点,它也是一个字典,并且还有一个称为`clusters`的关键组件。它的值,又是一组词典:

* `name`:集群的一个可读名称
* `type`:此集群将如何知道哪些主机已启动?
* `lb_type`:这个集群将如何处理负载均衡?
* `hosts`:定义集群所属主机的一个URL数组(实际上通常是`tcp://` URLs)。

`type`的可选值有:

* `static`:在集群中列出所有可代理的主机
* `strict_dns`:Envoy将会监控DNS,而每个匹配的A记录都将被认为是有效的
* `logical_dns`:Envoy一般会使用DNS来添加主机,但是如果DNS不再返回它们时,也不会丢弃它们(想想有数百台主机的round-robin DNS - 我们将在后续文章中详细介绍)
* `sds`:Envoy将会去调用一个外部的REST服务以查找集群成员

而`lb_type`的可选值有:

* `round_robin`:按顺序循环遍历所有健康的主机
* `weighted_least_request`:选择两个随机健康的主机并选择请求最少的主机(这是O(1),其中扫描所有健康的主机将是O(n)。Lyft声称研究表明O(1)算法"差不多"和全扫描的效果“一样好”。
* `random`:随机挑选一台主机

关于负载均衡还有一个有趣的注意事项:集群还可以定义一个恐慌阈值(panic threshold),其中,如果集群中健康主机的数量低于恐慌阈值,集群将判定健康检查算法可能存在问题,并且假定所有主机在集群中是健康的。这可能会导致一些意外情况发生,因此这一点最好留意一下!

一个边缘Envoy的简单用例可能是这样的:
“clusters”: [
{
“name”: “service1”,
“type”: “strict_dns”,
“lb_type”: “round_robin”,
“hosts”: [
{
“url”: “tcp://service1:80”
}
]
},
{
“name”: “service2”,
“type”: “strict_dns”,
“lb_type”: “round_robin”,
“hosts”: [
{
“url”: “tcp://service2:80”
}
]
}
]

由于我们将这个集群标记为`strict_dns`类型,它将依赖于在DNS中查找`service1`和`service2`,我们假定任何新起的服务实例将会被添加到DNS中 ———— 这可能适用于像使用docker-compose配置的类似情况。针对服务Envoy(比如`service1`),我们可能会采取一个更直接的路由方式:
“clusters”: [
{
“name”: “service1”,
“type”: “static”,
“lb_type”: “round_robin”,
“hosts”: [
{
“url”: “tcp://127.0.0.1:5000”
}
]
}
]

想法类似,只是目标不太一样:我们总是在本地主机上转发到我们的服务,而不是重定向到其他主机。
## 接下来
这就是Envoy千里之行的一小步,我们还介绍了一些深入内容,关于Envoy的背景和配置。接下来,我们将使用Kubernetes,Postgres,Flask和Envoy实际部署一个简单的应用程序,并在这个过程中观察我们扩容和缩容时会发生什么。敬请关注。

原文链接:Part 1: Getting started with Lyft Envoy for microservices resilience(译者:吴佳兴)