由Nginx迁移至Envoy

2021-01-09
4分钟阅读时长

Nginx是一个较为常见的负载均衡、反向代理和网站服务器。而随着Envoy的不断发展,Envoy正在成为越来越多技术选型中的关键一环。本文将简单地描述如何将Nginx中的基本配置迁移到Envoy中。

Nginx基本配置

我们将迁移如下的Nginx基本配置:

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"';

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

  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中一般会有三种关键配置:

  • 配置Nginx服务器的基本信息,日志格式及Gzip设置等。
  • 配置Nginx服务器监听特定位置。
  • 配置Nginx服务器进行流量转发。

Envoy能实现与Nginx类似的功能,但在配置结构上有所不同。

Envoy基本配置

与Nginx的关键配置相对应地,Envoy也可以实现类似的功能,这些功能通过以下四种配置关键词实现:

  • Listener:定义Envoy如何接受传入的请求。目前Envoy只接受TCP请求。接受传入的请求后,会由过滤器进行处理。
  • Filters:加工处理流入流出的数据,以filter_chains的形式在配置文件中定义。
  • Routers:将流量转发需要的位置。
  • Clusters:定义目标端点及相关配置。

Envoy拥有多种配置方式,包含静态文件配置及动态配置等。在本文中,我们将使用静态文件进行配置。所以我们需指定类型为static_resources

由于Nginx与Envoy的配置结构不同,Nginx中的http基本配置将在Filters中被配置。我们将按照Envoy的配置顺序进行迁移。

Envoy Listeners

与Envoy Listeners对应的Nginx配置为:

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

该部分为监听由以上两个域名的80端口发来的请求。在Envoy中的配置如下所示:

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

可以看到,我们在其中定义一个listener并设置了其监听地址。Envoy不在listener中处理域名,我们将在filter中进行定义。

Envoy Filters及Envoy Route

我们将在Envoy Filters中定义Nginx中的域名信息及以下内容:

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

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

对应的Envoy的配置为:

filter_chains:
- filters:
  - name: envoy.filters.network.http_connection_manager
    typed_config:
      "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
      stat_prefix: ingress_http
      codec_type: AUTO
      route_config:
        name: local_route
        virtual_hosts:
        - name: local_service
          domains:
          - "one.example.com"
          - "www.one.example.com"
          routes:
          - match: { prefix: "/" }
            route:
              cluster: targetCluster
      http_filters:
      - name: envoy.filters.http.router

可以看到在其中我们将来自one.example.comwww.one.example.com的流量转发至targetCluster中。我们将在cluter中定义。

Envoy Clusters

最后我们需要定义的就是clusters配置。Nginx中的对应配置如下所示:

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

相应的Envoy配置为:

clusters:
- name: targetCluster
  connect_timeout: 0.25s
  type: STRICT_DNS
  lb_policy: ROUND_ROBIN
  load_assignment:
    cluster_name: n8n
    endpoints:
    - lb_endpoints:
      - endpoint:
          address:
            socket_address:
              address: 172.18.0.3
              port_value: 8080
      - endpoint:
          address:
            socket_address:
              address: 172.18.0.4
              port_value: 8080

Envoy Logging

Envoy默认不会将日志打印到本地,而会输出到stdoutstderr中。Envoy的日志配置关键词为access_logaccess_log关键词是可选的,以下配置将会输出日志到stdout中。

access_log:
- name: envoy.file_access_log
  config:
    path: "/dev/stdout"

Envoy默认的日志格式如下所示:

[%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格式,例如:

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

总结

至此我们已完成了配置的迁移,完整的Envoy配置如下所示:

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 8080 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          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"
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains:
              - "one.example.com"
              - "www.one.example.com"
              routes:
              - match: { prefix: "/" }
                route:
                  cluster: targetCluster
          http_filters:
          - name: envoy.filters.http.router

  clusters:
  - name: targetCluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: n8n
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 172.18.0.3
                port_value: 8080
        - endpoint:
            address:
              socket_address:
                address: 172.18.0.4
                port_value: 8080

本文首发于我的个人博客wangchucheng.com
原文链接:https://wangchucheng.com/zh/posts/migration-from-nginx-to-envoy/
本博客文章除特别声明外均为原创,采用CC BY-NC-SA 4.0 许可协议进行许可。超出CC BY-NC-SA 4.0 许可协议的使用请联系作者获得授权。

Avatar

WANG Chucheng

说学逗唱样样不精的地道天津人。