由Nginx迁移至Envoy
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.com
及www.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默认不会将日志打印到本地,而会输出到stdout
及stderr
中。Envoy的日志配置关键词为access_log
。access_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 许可协议的使用请联系作者获得授权。