Envoy基础知识

18-10-29 banq
                   

Envoy是与HAProxy和ngin一样,都是同一领域中的新型网络代理/网络服务器。

关于任何软件,你可能会有几种问题:

  • 怎么用?
  • 为什么有用?
  • 它在内部如何工作?

什么是Envoy

它是一个网络代理。你编译以后把它放在你的服务器上,告诉它使用哪个配置文件,然后就可以了!

下面可能是使用Envoy最简单的例子。配置文件见这里。此案例在端口7777上启动一个Web服务器,该服务器其实代理另外一个端口为8000的HTTP服务器。

如果您有Docker,可以立即尝试 - 只需下载配置,启动Envoy docker镜像,然后离开!

python -mSimpleHTTPServer & # Start a HTTP server on port 8000 wget https://gist.githubusercontent.com/jvns/340e4d20c83b16576c02efc08487ed54/raw/1ddc3038ed11c31ddc70be038fd23dddfa13f5d3/envoy_config.json docker run --rm --net host -v=$PWD:/config envoyproxy/envoy /usr/local/bin/envoy -c /config/envoy_config.json

以上命令将启动Envoy HTTP服务器,然后你就可以向Envoy发出请求!

curl localhost:7777

它会代理你的请求转发到localhost:8000。

Envoy基本概念:集群,监听器,路由和过滤器

我们刚刚运行的这个小小的 envoy_config.json包含了所有基本的Envoy概念!

首先,有一个监听器。这告诉Envoy绑定到一个端口,在本例中为7777:

"listeners": [{
  "address": { 
     "socket_address": { "address": "127.0.0.1", "port_value": 7777 } 

接下来,监听器有一个过滤器。过滤器告诉监听器如何处理它收到的请求,并为Envoy提供一系列过滤器。如果您需要做一些复杂的事情,那么要对每个请求使用几个过滤器。

有几种不同类型的过滤器(请参阅TCP过滤器列表),但最重要的过滤器可能是envoy.http_connection_manager过滤器,它用于代理HTTP请求。HTTP连接管理器还有一个适用的HTTP过滤器列表请参阅HTTP过滤器列表)。其中最重要的是将envoy.router的请求路由到后端的过滤器。

在我们的示例中,有一个TCP过滤器(envoy.http_connection_manager)和1个HTTP过滤器(envoy.router):

"filters": [
 {
   "name": "envoy.http_connection_manager",
   "config": {
     "stat_prefix": "ingress_http",
     "http_filters": [{ "name": "envoy.router", "config": {} }],

接下来,我们来谈谈路由。您可能会注意到,到目前为止,我们还没有告诉envoy.router过滤器如何处理它收到的请求,应该在哪里代理这些请求?它应该匹配哪些路径?在我们的例子中,答案将是“代理对localhost:8000的所有请求”。

envoy.router过滤器被配置为路由的阵列。在我们的例子中,只有一条路由规则。

"route_config": {
  "virtual_hosts": [
    {
      "name": "blah",
      "domains": "*",
      "routes": [
        {
          "match": { "prefix": "/" },
          "route": { "cluster": "banana" }

这里定义了要匹配的域列表(这些域与请求主机头匹配)。如果我们更换"domains": "*"到"domains": "my.cool.service",那么我们就需要传递头部信息“Host: my.cool.service”才行。

你会注意到我们案例中被代理的端口 8000未在任何地方定义过。只是有"cluster": "banana"。什么是集群?

好吧,集群是一个服务后端的地址(IP地址/端口)集合。例如,如果您有8台机器运行同一种HTTP服务,那么这个群集中可以有8台host主机集合。每个服务都需要自己的集群。这里示例集群非常简单:它只是一个在localhost上运行的IP /端口。

"clusters":[
    {
      "name": "banana",
      "type": "STRICT_DNS",
      "connect_timeout": "1s",
      "hosts": [
        { "socket_address": { "address": "127.0.0.1", "port_value": 8000 } }
      ]
    }
  ]

手动编写Envoy配置的提示

从头开始编写Envoy配置非常耗时 - 在Envoy存储库(https://github.com/envoyproxy/envoy)中有一些例子,但即使使用Envoy一年后,这个基本配置实际上还是花了我近45分钟,以下是一些提示:

  • Envoy有两种不同的API:v1和v2 API。许多较新的功能仅在v2 API中可用,我发现它的文档更容易导航,因为它是从protocol buffers自动生成的。(例如,集群文档是从cds.proto生成的)
  • Envoy API文档中的一些好的起点:监听器集群过滤器虚拟主机。要获得所需的所有信息,您需要点击很多资料(例如,查看如何为需要从“虚拟主机”启动的路由配置群集,然后单击route_config - > virtual_hosts - > routes - > route - > cluster ),但按照它这样做还是奏效的。
  • 这个体系结构概述文档是有用的,并给出一些Envoy是如何配置的全面解释。
  • 可以使用json或yaml配置Envoy。上面我使用了JSON。

使用服务器配置Envoy

尽管我们从磁盘上的配置文件开始,但使用Envoy与HAProxy或nginx完全不同的一点是,Envoy通常不是通过配置文件配置的。相反,可以使用一个或多个动态的配置服务器去更改配置Envoy 。

假设您正在使用Envoy将请求加载到50个后端服务器,这些服务器是您定期轮换出来的EC2实例。因此 http://your-website.com请求转到Envoy,并被路由到Envoy 群集,该群集需要是这些服务器的50个IP地址和端口的列表。

但是,如果随着时间的推移, 也许你正在推出新的服务器或者它们中一些会被终止。您可以通过定期更改Envoy配置文件并重新启动Envoy来处理此问题。要么!!可以设置“群集发现服务”(或“CDS”),例如,可以查询AWS API并将后端服务器的所有IP返回给Envoy。

我不打算详细介绍如何配置发现服务,但基本上它看起来像这样(来自这个模板)。您可以告诉它刷新的频率以及服务器的地址。

dynamic_resources:
  cds_config:
    api_config_source:
      cluster_names:
      - cds_cluster
      refresh_delay: 30s
...
  - name: cds_cluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    hosts:
    - socket_address:
        protocol: TCP
        address: cds.yourcompany.net
        port_value: 80

4种Envoy发现服务

有四种资源可以为Envoy设置发现服务 - 路由(“集群应该请求这个HTTP头转到什么地方”),集群(“这个服务有哪些后端?”),监听器(过滤器用于端口)和端点。这些分别称为RDS,CDS,LDS和EDS。XDS是整体协议。

从头开始编写发现服务的最简单方法可能是在Go中使用 go-control-plane库。

从头开始编写Envoy配置服务绝对是可能的,但还有一些其他开源项目可以实现Envoy发现服务。以下是我所知道的,但我确信还有更多:

  • 有一个叫做rotor开源Envoy发现服务看起来很有趣。建造它的公司几周前就关闭了
  • Istio(据我所知)基本上是一个Envoy发现服务,它使用来自Kubernetes API的信息(例如集群中的服务)来配置Envoy集群/路由。它有自己的配置语言。
  • consul可能会增加对Envoy的支持(请参阅此博客文章),但我并不完全了解那里的状态

什么是服务网格?

我听到的另一个术语是“服务网格”。基本上,“服务网格”是先安装Envoy,并通过Envoy代理所有网络请求。它可以让您更轻松地控制一堆不同的应用程序(可能用不同的编程语言编写)如何相互通信。

如果您的所有网络流量都是通过Envoy代理的,并且可从中央服务器控制所有Envoy配置,那么您可以:

  • 使用断路器
  • 将请求路由到仅关闭实例
  • 端到端加密网络流量
  • 运行受控代码部署(想要只将20%的流量发送到你刚上线的新服务器上吗?好的!)

无需在任何地方更改任何应用程序代码。基本上它是一个非常强大/灵活的分散式负载均衡器。

显然,设置一堆发现服务并运行它们和使用它们,这种以复杂的方式配置内部网络基础架构比单独“编写一个nginx配置文件”要复杂得多,对大多数人来说。我不打算告诉你谁应该或不应该使用Envoy,但我的经验是,像Kubernetes一样,它既非常强大又非常复杂。

超时标题和指标衡量

我真正喜欢Envoy的一个原因是你可以传递一个HTTP标头来告诉它如何重试/超时你的请求!这是惊人的,因为每种编程语言正确实现超时/重试逻辑的工作方式不同,人们总是弄错。因此能够传递如何测量指标就非常棒。

超时和重试头都记录在这里,这里是我的最爱:

  • x-envoy-max-retries:重试次数
  • x-envoy-retry-on:哪些失败重试(例如5xx或connect-failure)
  • x-envoy-upstream-rq-timeout-ms:总超时
  • x-envoy-upstream-rq-per-try-timeout-ms:每次重试超时