从 Nginx 迁移到 Envoy 代理

你好,哈布尔! 我提请您注意该帖子的翻译: 从 Nginx 迁移到 Envoy 代理.

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.conf,基于完整示例 NGINX 维基。 您可以通过打开来查看编辑器中的配置 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 以接受对主机的请求 one.example.com 在端口 8080 上。
  3. 设置目标位置,如何处理 URL 不同部分的流量。

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

  • 听众: 它们确定 Envoy 代理如何接受传入请求。 Envoy Proxy 目前仅支持基于 TCP 的侦听器。 一旦建立连接,它就会被传递到一组过滤器进行处理。
  • 过滤器: 它们是可以处理传入和传出数据的管道架构的一部分。 此功能包括 Gzip 等过滤器,它在将数据发送到客户端之前对其进行压缩。
  • 路由器: 它们将流量转发到所需的目的地(定义为集群)。
  • 集群: 它们定义流量和配置参数的端点。

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

第 2 步 - NGINX 配置

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

工人连接

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

worker_processes  2;

events {
  worker_connections   2000;
}

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

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

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

所有进一步的连接处理完全在工作线程中处理,包括任何转发行为。

对于 Envoy 中的每个工作线程,都有一个连接池。 因此,HTTP/2 连接池每次仅为每个外部主机建立一个连接,如果有四个工作线程,则每个外部主机将有四个处于稳定状态的 HTTP/2 连接。 通过将所有内容保留在一个工作线程中,几乎所有代码都可以在不阻塞的情况下编写,就像单线程一样。 如果分配的工作线程多于必要的数量,则可能会导致内存浪费,创建大量空闲连接,并减少连接返回池的次数。

欲了解更多信息,请访问 特使代理博客.

HTTP 配置

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

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

您可以使用 Envoy Proxy 中的过滤器自定义这些方面,我们将在稍后讨论。

第 3 步 - 服务器配置

在 HTTP 配置块中,NGINX 配置指定侦听端口 8080 并响应域的传入请求 one.example.com и www.one.example.com.

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

在 Envoy 内部,它由 Listeners 控制。

特使听众

开始使用 Envoy Proxy 的最重要的方面是定义您的侦听器。 您需要创建一个配置文件来描述您希望如何运行 Envoy 实例。

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

Envoy Proxy 使用 YAML 表示法进行配置。 有关此表示法的介绍,请参见此处 链接.

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

无需定义 服务器名称,因为 Envoy 代理过滤器将处理这个问题。

第 4 步 - 位置配置

当请求进入 NGINX 时,位置块决定如何处理流量以及将流量路由到何处。 在下面的片段中,该站点的所有流量都会传输到一个名为的上游(译者注:上游通常是应用服务器)集群 目标簇。 上游集群定义应处理请求的节点。 我们将在下一步讨论这个问题。

location / {
    proxy_pass         http://targetCluster/;
    proxy_redirect     off;

    proxy_set_header   Host             $host;
    proxy_set_header   X-Real-IP        $remote_addr;
}

在 Envoy,过滤器就是这样做的。

特使过滤器

对于静态配置,过滤器确定如何处理传入请求。 在这种情况下,我们设置匹配的过滤器 服务器名称 在上一步中。 当与某些域和路由匹配的传入请求到达时,流量将路由到集群。 这相当于 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 Proxy 中的内置过滤器。 其他过滤器包括 Redis的, 蒙戈, TCP。 您可以在以下位置找到完整列表: 文件资料.

有关其他负载均衡策略的更多信息,请访问 特使文档.

第 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 没有将错误日志推送到磁盘,而是采用基于云的方法。 所有应用程序日志都输出到 标准输出 и 斯特德.

当用户提出请求时,访问日志是可选的,并且默认情况下处于禁用状态。 要启用 HTTP 请求的访问日志,请启用配置 访问日志 用于 HTTP 连接管理器。 该路径可以是诸如 标准输出,或磁盘上的文件,具体取决于您的要求。

以下配置将所有访问日志重定向到 标准输出 (译者注 - 在 docker 内使用 envoy 需要 stdout。如果不使用 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格式输出 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 代理的唯一方法。 它内置了先进的跟踪和指标功能。 您可以在以下位置了解更多信息 追踪文档 或者通过 交互式跟踪脚本.

第 7 步 - 启动

您现在已将配置从 NGINX 迁移到 Envoy 代理。 最后一步是启动 Envoy Proxy 实例来测试它。

以用户身份运行

NGINX 配置行的顶部 用户 www www; 指定以低权限用户运行 NGINX 以提高安全性。

Envoy Proxy 采用基于云的方法来管理流程的所有者。 当我们通过容器运行 Envoy Proxy 时,我们可以指定一个低特权用户。

启动 Envoy 代理

下面的命令将通过主机上的 Docker 容器运行 Envoy Proxy。 此命令使 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 Proxy 没有可用的请求目的地。 以下命令将启动一系列与 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 }

译者提供的附加信息

安装 Envoy Proxy 的说明可以在网站上找到 https://www.getenvoy.io/

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

添加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 配置放在那里。

有一个使用 envoy 代理的电报聊天: https://t.me/envoyproxy_ru

Envoy 代理不支持提供静态内容。 因此,谁可以投票支持该功能: https://github.com/envoyproxy/envoy/issues/378

只有注册用户才能参与调查。 登录拜托

这篇文章是否鼓励您安装和测试 Envoy 代理?

  • 是的

  • 没有

75 位用户投票。 18 名用户弃权。

来源: habr.com

添加评论