从Nginx迁移到Envoy代理

哈Ha! 我引起您注意该帖子的翻译: 从Nginx迁移到Envoy Proxy


Envoy是为单个服务和应用程序设计的高性能分布式代理服务器(用C ++编写),它还是通信总线和为大型微服务“服务网格”体系结构设计的“通用数据平面”。 在创建它时,考虑了在开发诸如NGINX,HAProxy,硬件负载平衡器和云负载平衡器之类的服务器期间出现的问题的解决方案。 Envoy与每个应用程序一起使用并抽象化网络,无论平台如何,都提供通用功能。 当基础结构中的所有办公室流量都通过Envoy网格时,可以通过一致的可观察性可视化问题区域,调整整体性能,并在特定位置添加基本功能,这很容易。


可能性


  • 进程外架构:envoy是一台独立的高性能服务器,消耗少量RAM。 它可以与任何应用程序语言或框架结合使用。
  • 支持http / 2和grpc:envoy对入站和出站连接提供了对http / 2和grpc的一流支持。 这是从http / 1.1到http / 2的透明代理。
  • 先进的负载平衡:envoy支持先进的负载平衡功能,包括自动重试,断路,全局速度限制,影子请求,局部区域负载平衡等。
  • 配置管理API:envoy提供了一个健壮的API,用于动态管理其配置。
  • 可观察性:深入的L7流量可观察性,对mongodb,dynamodb和许多其他应用程序的分布式跟踪和可观察性的内置支持。

第1步-示例NGINX配置


该脚本基于NGINX Wiki中的完整示例,使用了一个特别创建的nginx.conf文件。 您可以通过打开nginx.conf在编辑器中查看配置


源nginx配置


user www www; pid /var/run/nginx.pid; worker_processes 2; events { worker_connections 2000; } http { gzip on; gzip_min_length 1100; gzip_buffers 4 8k; gzip_types text/plain; log_format main '$remote_addr - $remote_user [$time_local] ' '"$request" $status $bytes_sent ' '"$http_referer" "$http_user_agent" ' '"$gzip_ratio"'; log_format download '$remote_addr - $remote_user [$time_local] ' '"$request" $status $bytes_sent ' '"$http_referer" "$http_user_agent" ' '"$http_range" "$sent_http_content_range"'; upstream targetCluster { 172.18.0.3:80; 172.18.0.4:80; } server { listen 8080; server_name one.example.com www.one.example.com; access_log /var/log/nginx.access_log main; error_log /var/log/nginx.error_log info; location / { proxy_pass http://targetCluster/; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } } 

NGINX配置通常具有三个关键元素:


  1. 配置NGINX服务器,日志结构和Gzip功能。 这在所有情况下都是全局确定的。
  2. 将NGINX配置为在端口8080上接受对one.example.com主机的请求。
  3. 设置目标位置,以及如何处理URL不同部分的流量。

并非所有配置都将应用于Envoy代理,并且您不需要配置某些设置。 Envoy代理具有四种支持NGINX提供的基础结构的关键类型 。 核心是:


  • 侦听器:他们确定Envoy代理如何接受传入的请求。 Envoy代理当前仅支持基于TCP的侦听器。 建立连接后,会将其传输到一组过滤器进行处理。
  • 过滤器:它们是可以处理传入和传出数据的流水线体系结构的一部分。 此功能包括过滤器,例如Gzip,可在将数据发送到客户端之前先对其进行压缩。
  • 路由器:它们将流量重定向到所需的目的地(定义为群集)。
  • 群集:它们定义流量和配置设置的端点。

我们将使用这四个组件来创建Envoy代理配置,以匹配特定的NGINX配置。 Envoy的目标是使用API​​和动态配置。 在这种情况下,基本配置将使用NGINX的静态硬编码参数。


第2步-配置NGINX


nginx.conf的第一部分定义了一些需要配置的内部NGINX组件。


工人连接


下面的配置确定工作流程和连接的数量。 这表明NGINX将如何扩展以满足需求。


 worker_processes 2; events { worker_connections 2000; } 

Envoy代理以不同的方式管理工作流程和连接。


Envoy为系统中的每个硬件线程创建一个工作流。 每个工作线程运行一个非阻塞事件循环,该循环负责


  1. 倾听每个听众
  2. 接受新的连接
  3. 为连接创建过滤器集
  4. 在连接的整个生命周期内处理所有I / O操作。

所有进一步的连接处理都将在工作流中得到完全处理,包括任何转发行为。


对于Envoy中的每个工作流程,池中都有一个连接。 因此,HTTP / 2连接池一次仅为每个外部主机建立一个连接;如果有四个工作线程,则处于稳定状态的每个外部主机将有四个HTTP / 2连接。 通过将所有内容存储在一个工作流中,几乎所有代码都可以编写而无需锁定,就好像它们是单线程的一样。 如果分配了不必要的工作流,则可能导致内存的非合理使用,大量空闲连接的创建以及返回到池中的连接数量的减少。


有关更多信息,请访问Envoy代理博客


HTTP配置


以下NGINX配置块定义了HTTP设置,例如:


  • 支持哪些MIME类型
  • 默认超时
  • Gzip配置

您可以使用Envoy代理中的过滤器配置这些方面,我们将在后面讨论。


第3步-服务器配置


在HTTP配置块中,NGINX配置指示您侦听端口8080并响应对域one.example.comwww.one.example.com的传入请求。


  server { listen 8080; server_name one.example.com www.one.example.com; 

在Envoy内部,由监听器控制。


特使听众


使用Envoy代理最重要的方面是识别侦听器。 您需要创建一个配置文件,该文件描述您要如何运行Envoy实例。


下面的代码片段将创建一个新的侦听器并将其与端口8080关联。配置告诉Envoy代理它应将哪些端口绑定到传入请求。


Envoy代理对其配置使用YAML表示法。 要熟悉此符号,请参见此处的链接


 Copy to Editorstatic_resources: listeners: - name: listener_0 address: socket_address: { address: 0.0.0.0, port_value: 8080 } 

不需要定义server_name ,因为Envoy代理过滤器可以处理此问题。


第4步-位置配置


当请求到达NGINX时,位置块确定如何处理以及将流量定向到何处。 在以下片段中,到站点的所有流量都传输到名为targetCluster的上游群集(译者注:上游通常是应用程序服务器)。 上游群集定义应处理请求的节点。 我们将在下一步中对此进行讨论。


 location / { proxy_pass http://targetCluster/; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } 

在Envoy,过滤器会执行此操作。


使节过滤器


对于静态配置,过滤器确定如何处理传入的请求。 在这种情况下,我们在上一步中设置与server_names匹配的过滤器。 当到达的请求对应于特定的域和路由时,流量将路由到群集。 这等效于NGINX上游配置。


 Copy to Editor filter_chains: - filters: - name: envoy.http_connection_manager config: codec_type: auto stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: backend domains: - "one.example.com" - "www.one.example.com" routes: - match: prefix: "/" route: cluster: targetCluster http_filters: - name: envoy.router 

名称envoy.http_connection_manager是Envoy代理中的内置过滤器。 其他过滤器包括RedisMongoTCP 。 您可以在文档中找到完整列表。


有关其他负载平衡策略的更多信息,请访问Envoy文档


步骤5-代理和上游配置


在NGINX中,上游配置定义了将处理流量的目标服务器集。 在这种情况下,分配了两个群集。


  upstream targetCluster { 172.18.0.3:80; 172.18.0.4:80; } 

在Envoy中,它是集群管理的。


特使群


上游的等效项定义为群集。 在这种情况下,将确定将为流量提供服务的主机。 一种访问主机的方法(例如超时)被定义为群集配置。 这使您可以更准确地控制延迟和负载平衡等方面的粒度。


 Copy to Editor clusters: - name: targetCluster connect_timeout: 0.25s type: STRICT_DNS dns_lookup_family: V4_ONLY lb_policy: ROUND_ROBIN hosts: [ { socket_address: { address: 172.18.0.3, port_value: 80 }}, { socket_address: { address: 172.18.0.4, port_value: 80 }} ] 

使用STRICT_DNS服务发现时, Envoy将连续且异步地解析指定的DNS目标。 由于DNS而返回的每个IP地址都将被视为上游群集中的显式主机。 这意味着,如果请求返回两个IP地址,Envoy将假定群集中有两个主机,并且两个主机都必须进行负载平衡。 如果从结果中删除了主机,则Envoy会假定它不再存在,并将从任何现有的连接池中选择流量。


有关更多信息,请参阅Envoy代理文档


第6步-日志访问和错误


最终配置是注册。 Envoy Proxy不会将错误日志传输到磁盘,而是使用基于云的方法。 所有应用程序日志都显示在stdoutstderr中


用户发出请求时,访问日志是可选的,默认情况下处于禁用状态。 要为HTTP请求启用访问日志,请为HTTP连接管理器启用access_log配置。 该路径可以是设备(例如stdout) ,也可以是磁盘上的文件,具体取决于您的要求。


以下配置会将所有访问日志重定向到stdout (译者注-stdout是在docker内部使用envoy所必需的。如果在不使用docker的情况下使用,请用常规日志文件的路径替换/ dev / stdout)。 将代码段复制到连接管理器的配置部分:


 Copy to Clipboardaccess_log: - name: envoy.file_access_log config: path: "/dev/stdout" 

结果应如下所示:


  - name: envoy.http_connection_manager config: codec_type: auto stat_prefix: ingress_http access_log: - name: envoy.file_access_log config: path: "/dev/stdout" route_config: 

默认情况下,Envoy的格式字符串包含HTTP请求的详细信息:


 [%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-FORWARDED-FOR)%" "%REQ(USER-AGENT)%" "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"\n 

此格式字符串的结果:


 [2018-11-23T04:51:00.281Z] "GET / HTTP/1.1" 200 - 0 58 4 1 "-" "curl/7.47.0" "f21ebd42-6770-4aa5-88d4-e56118165a7d" "one.example.com" "172.18.0.4:80" 

可以通过设置格式字段来自定义输出内容。 例如:


 access_log: - name: envoy.file_access_log config: path: "/dev/stdout" format: "[%START_TIME%] "%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%" %RESPONSE_CODE% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% "%REQ(X-REQUEST-ID)%" "%REQ(:AUTHORITY)%" "%UPSTREAM_HOST%"\n" 

通过设置json_format字段,日志字符串也可以JSON格式输出。 例如:


 access_log: - name: envoy.file_access_log config: path: "/dev/stdout" json_format: {"protocol": "%PROTOCOL%", "duration": "%DURATION%", "request_method": "%REQ(:METHOD)%"} 

有关特使注册技术的更多信息,请访问


https://www.envoyproxy.io/docs/envoy/latest/configuration/access_log#config-access-log-format-dictionaries


记录并不是获得使用Envoy Proxy的唯一方法。 它具有用于跟踪和指标的内置高级功能。 您可以在跟踪文档中或通过“ 交互式跟踪脚本”找到更多信息。


第7步-启动


现在,您已将配置从NGINX转移到Envoy代理。 最后一步是运行Envoy代理实例进行测试。


从用户运行


在NGINX配置的顶部,线路用户www www ;。 表示已以低特权用户身份启动NGINX,以增强安全性。


Envoy Proxy采用基于云的方法来管理谁拥有流程。 通过容器运行Envoy代理时,可以指定特权级别低的用户。


启动特使代理


下面的命令将通过主机上的Docker容器启动Envoy代理。 此命令使Envoy能够通过端口80侦听传入的请求。但是,如侦听器配置中所示,Envoy代理通过端口8080侦听传入的通信。这使该进程可以低特权用户身份运行。


 docker run --name proxy1 -p 80:8080 --user 1000:1000 -v /root/envoy.yaml:/etc/envoy/envoy.yaml envoyproxy/envoy 

测试中


使用代理运行,现在可以进行测试并进行处理。 以下cURL命令使用代理配置中定义的主机头发出请求。


 curl -H "Host: one.example.com" localhost -i 

HTTP请求将导致错误503 。 这是由于以下事实:上游连接不起作用并且不可用。 因此,Envoy代理对该请求没有任何可用的目标目的地。 以下命令将启动一系列与为Envoy定义的配置相匹配的HTTP服务。


 docker run -d katacoda/docker-http-server; docker run -d katacoda/docker-http-server; 

有了可用的服务,Envoy可以成功地将流量代理到其目的地。


 curl -H "Host: one.example.com" localhost -i 

您应该看到一个响应,指示哪个Docker容器已经处理了请求。 在Envoy代理日志中,您还应该看到显示的访问字符串。


其他HTTP响应标头


您将在实际请求的响应标头中看到其他HTTP标头。 标头显示上游主机花费在处理请求上的时间。 以毫秒为单位。 如果客户端希望确定服务时间(相对于网络延迟),这将很有用。


 x-envoy-upstream-service-time: 0 server: envoy 

最终配置


 static_resources: listeners: - name: listener_0 address: socket_address: { address: 0.0.0.0, port_value: 8080 } filter_chains: - filters: - name: envoy.http_connection_manager config: codec_type: auto stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: backend domains: - "one.example.com" - "www.one.example.com" routes: - match: prefix: "/" route: cluster: targetCluster http_filters: - name: envoy.router clusters: - name: targetCluster connect_timeout: 0.25s type: STRICT_DNS dns_lookup_family: V4_ONLY lb_policy: ROUND_ROBIN hosts: [ { socket_address: { address: 172.18.0.3, port_value: 80 }}, { socket_address: { address: 172.18.0.4, port_value: 80 }} ] admin: access_log_path: /tmp/admin_access.log address: socket_address: { address: 0.0.0.0, port_value: 9090 } 

翻译人员提供的其他信息


可以在https://www.getenvoy.io/上找到Envoy代理安装说明。


默认情况下,rpm中没有systemd服务配置。


添加系统服务配置/etc/systemd/system/envoy.service:


 [Unit] Description=Envoy Proxy Documentation=https://www.envoyproxy.io/ After=network-online.target Requires=envoy-auth-server.service Wants=nginx.service [Service] User=root Restart=on-failure ExecStart=/usr/bin/envoy --config-path /etc/envoy/config.yaml [Install] WantedBy=multi-user.target 

您需要创建目录/ etc / envoy /,并将config.yaml配置放在此处。


通过特使代理进行电报聊天: https : //t.me/envoyproxy_ru


Envoy代理不支持静态内容分发。 那么谁可以投票支持功能: https : //github.com/envoyproxy/envoy/issues/378

Source: https://habr.com/ru/post/zh-CN469455/


All Articles