前言

Envoy 是一个开源的高性能、可扩展的代理服务,最初由 Lyft 公司开发。它设计用于处理现代的微服务架构中的网络通信,并提供了许多功能,包括负载均衡、服务发现、路由、认证、授权等。Envoy 被广泛用于构建和部署云原生应用程序以及微服务体系结构。
本文将通过将envoy作为前端代理来演示envoy的安装、配置和简单使用。

本文使用环境

  • Ubuntu 22.04.3 LTS Desktop 64-bit

1 安装

envoy 编译比较复杂,可以使用Envoy 社区提供的docker镜像和getenvoy项目,不过getenvoy所使用的版本比较老。在Linux下最简单的方式还是直接使用官方的envoy预编译二进制文件。

1.1 下载

  • 从Envoy 的 GitHub 发行版页面下载 Ubuntu 的最新版的envoy预编译二进制文件,这里选择“envoy-1.28.0-linux-x86_64”
    1
    https://github.com/envoyproxy/envoy/releases

1.2 安装envoy

新建项目目录,将文件复制到该目录下(本文使用/home/zhg/Mine/Workplace/getenvoy/)

  • 下载完成后如果是.tar.gz则需要解压
  • 如果是(application/x-executable)可执行文件,则需要添加添加可执行权限
    1
    2
    3
    4
    5
    # 重命名为"envoy"方便输入命令
    sudo mv envoy-1.28.0-linux-x86_64 envoy

    # 添加可执行权限
    chmod +x envoy
    通过以下命令可以查看envoy版本,以验证envoy是否正确安装
    1
    ./envoy --version

2 配置

配置参考官网

https://www.envoyproxy.io/docs/envoy/v1.28.0/configuration/best_practices/edge

envoy 可以通过静态配置和动态配置两种方式实现,静态文件通常yaml格式的文件进行配置,主要字段有:

  • listeners(监听器)

listeners 字段用于定义Envoy监听的网络地址和协议。它描述了Envoy如何接收和处理传入的连接请求。

1
2
3
4
listeners:
- name: 给监听器命名,方便引用。
- address: 指定监听的 IP 地址和端口。
- filters:指定用于处理传入连接的过滤器链,包括协议转码、路由、TLS 等。
  • filter(过滤器)

filters字段通常用于通过配置文件引入和加载Envoy的各种过滤器。过滤器是Envoy的功能组件,用于在请求或响应的处理过程中执行特定的操作。过滤器可以添加、修改或删除请求或响应的头信息,执行转换,执行日志记录等操作。

envoy.http_connection_manager 是Envoy的HTTP连接管理器,它用于处理HTTP请求和响应。它是Envoy配置的核心组件之一,负责管理HTTP连接的生命周期、处理HTTP协议、执行各种过滤器等。该连接管理器允许您配置各种HTTP功能,包括路由、重试、负载均衡、超时等

1
2
3
4
5
6
7
8
9
filters:                           # 过滤器列表
- name: envoy.http_connection_manager # 使用 Envoy 的 HTTP 连接管理器过滤器
typed_config: # 配置该过滤器的类型和参数
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: HTTP2 # 使用 HTTP/2 编解码器
stat_prefix: ingress_http # 用于生成统计信息的前缀
route_config: # 路由配置
name: local_route # 路由的名称
virtual_hosts: # 虚拟主机列表
  • clusters(集群)

clusters 字段用于定义集群(clusters)。集群是Envoy用于负载均衡和路由请求的基本单元,定义后端服务的地址、端口、协议等信息

1
2
3
4
5
6
7
clusters:
- name: 定义集群的名称。
- type: 指定集群类型,如 static, strict_dns, sds 等。
- connect_timeout: 连接超时时间。
- lb_policy: 负载均衡策略,如 round_robin, least_request 等。
- hosts: 指定集群的后端主机。
- tls_context: 配置 TLS。
  • routes(路由)

routes 字段用于定义路由规则。路由规则确定了Envoy在接收到请求时应该将其转发到哪个后端服务

1
2
3
4
5
routes:
- prefix: URL 前缀匹配。
- cluster: 指定请求应该转发到的集群。
- timeout: 设置请求超时时间。
- retry_policy: 配置请求重试策略。
  • admin(管理控制)

admin是用于提供管理和监控功能的配置选项。通过 Envoy 的 admin`接口,用户可以查看运行时统计信息、配置信息,执行一些诊断命令等

1
2
3
admin:
- access_log_path: 指定访问日志文件的路径。
- address:指定 Envoy 管理界面的监听地址和端口。

以下是一份配置实例,在项目目录打开终端,输入以下命令创建配置文件,并将配置内容复制到文件中。

1
touch envoy_conf.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# Envoy 管理配置
admin:
# 访问日志路径
access_log_path: "/home/zhg/Mine/Workplace/getenvoy/envoy.log"
# 管理界面监听地址和端口
address:
socket_address:
address: 0.0.0.0
port_value: 10001

# 静态资源配置
static_resources:
listeners:
# 定义一个监听器,监听在 0.0.0.0:10000
- address:
socket_address: { protocol: TCP, address: 0.0.0.0, port_value: 10000 }
filter_chains:
- filters:
# 使用 HTTP 连接管理器过滤器
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: auto
stat_prefix: http
access_log:
# 记录 HTTP 请求到文件
- name: envoy.access_loggers.file
typed_config:
"@type": type.googleapis.com/envoy.extensions.access_loggers.file.v3.FileAccessLog
path: "/home/zhg/Mine/Workplace/getenvoy/envoy_http.log"
log_format:
text_format: |
>>>>
start_time: "%START_TIME%"
method: "%REQ(:METHOD)%", original_path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%", protocol: "%PROTOCOL%", response_code: "%RESPONSE_CODE%", response_flags: "%RESPONSE_FLAGS%"
user_agent: "%REQ(USER-AGENT)%"
authority: "%REQ(:AUTHORITY)%"
upstream_host: "%UPSTREAM_HOST%"
request_id: "%REQ(X-REQUEST-ID)%"
custom_header: "%REQ(custom_header)%"
static_header: "%REQ(static_header)%"
route_config:
name: search_route
virtual_hosts:
- name: backend
domains:
- "*"
routes:
- match:
prefix: "/"
route:
# 将请求发送到 baidu 集群
cluster: baidu
http_filters:
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: baidu
connect_timeout: 1s
# 使用 STRICT_DNS 模式进行 DNS 解析
type: STRICT_DNS
dns_lookup_family: V4_ONLY
lb_policy: round_robin
load_assignment:
cluster_name: baidu
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
# 目标服务器地址
address: www.baidu.com
port_value: 80

3 运行envoy

写好配置文件后,就可以在项目目录打开终端,输入以下命令启动envoy

1
2
3
4
5
6
7

# 通过静态配置文件直接启动 Envoy
# -l debug :设置日志级别为debug,可省略
./envoy -c envoy_conf.yaml -l debug

//查看帮助
envoy --help

4.测试

4.1 查看envoy admin

打开浏览器,输入localhost:10001,可以看到envoy已经启动起来,可以正常访问admin页面

4.2 代理配置验证

普通 curl 请求

  • curl -vvv baidu.com
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    zhg@zhg-pc:~/Mine/Workplace/envoytest$ curl -vvv baidu.com
    * Trying 39.156.66.10:80...
    * Connected to baidu.com (39.156.66.10) port 80 (#0)
    > GET / HTTP/1.1
    > Host: baidu.com
    > User-Agent: curl/7.81.0
    > Accept: */*
    >
    * Mark bundle as not supporting multiuse
    < HTTP/1.1 200 OK
    < Date: Thu, 16 Nov 2023 03:42:54 GMT
    < Server: Apache
    < Last-Modified: Tue, 12 Jan 2010 13:48:00 GMT
    < ETag: "51-47cf7e6ee8400"
    < Accept-Ranges: bytes
    < Content-Length: 81
    < Cache-Control: max-age=86400
    < Expires: Fri, 17 Nov 2023 03:42:54 GMT
    < Connection: Keep-Alive
    < Content-Type: text/html
    <
    <html>
    <meta http-equiv="refresh" content="0;url=http://www.baidu.com/">
    </html>
    * Connection #0 to host baidu.com left intact


使用 curl 访问 Envoy,并添加 Header 字段 host: baidu.com

  • curl -v -H ‘Host: baidu.com’ 127.0.0.1:10000
  • 可以看到请求被转发到了 baidu.com,在响应头中,server: envoy 表示服务器使用的是 Envoy 代理。这是 Envoy 代理的标识,表示请求经过了 Envoy
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    zhg@zhg-pc:~/Mine/Workplace/envoytest$ curl -vvv -H 'Host: baidu.com' 127.0.0.1:15001
    * Trying 127.0.0.1:15001...
    * Connected to 127.0.0.1 (127.0.0.1) port 15001 (#0)
    > GET / HTTP/1.1
    > Host: baidu.com
    > User-Agent: curl/7.81.0
    > Accept: */*
    >
    * Mark bundle as not supporting multiuse
    < HTTP/1.1 200 OK
    < accept-ranges: bytes
    < cache-control: private, no-cache, no-store, proxy-revalidate, no-transform
    < content-length: 2381
    < content-type: text/html
    < date: Thu, 16 Nov 2023 03:45:17 GMT
    < etag: "588604dc-94d"
    < last-modified: Mon, 23 Jan 2017 13:27:56 GMT
    < pragma: no-cache
    < server: envoy
    < set-cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
    < x-envoy-upstream-service-time: 18
    <
    <!DOCTYPE html>
    ...省略...
    </html>
    * Connection #0 to host 127.0.0.1 left intact

4.3 代理到本机web服务

4.3.1 修改配置

在clusters字段下增加一个名为”localserver”的集群,配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
clusters:
- name: baidu
connect_timeout: 1s
# 使用 STRICT_DNS 模式进行 DNS 解析
type: STRICT_DNS
dns_lookup_family: V4_ONLY
lb_policy: round_robin
load_assignment:
cluster_name: baidu
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
# 目标服务器地址
address: www.baidu.com
port_value: 80
- name: localserver
connect_timeout: 1s
# 使用 STATIC 模式,直接指定目标地址
type: STATIC
dns_lookup_family: V4_ONLY
lb_policy: round_robin
load_assignment:
cluster_name: localserver
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
# 本地服务器地址
address: 127.0.0.1
port_value: 9001

并将routes的cluster 修改为改localserver

1
2
3
4
5
6
routes:
- match:
prefix: "/"
route:
# 将请求发送到 baidu 集群
cluster: localserver

4.3.2 使用Python搭建简易HTTP 服务器

适用:小型 web 项目在局域网内的预览

编写网页

新建项目目录和文件:web/index.html,并输入以下内容,创建一个简易的网页以进行验证。

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
WebServer for hello Envoy!
</body>
</html>

4.3.3 启动http服务器

在项目目录运行以下命令启动http服务器

1
2
3
4
5
6
# 服务器默认监听端口是 8000,支持自定义端口号
python3 -m http.server 9001

# 服务器默认工作目录为当前目录,可通过 -d/--directory 参数指定工作目录
# python -m http.server --directory /tmp/

4.3.4 验证地址

    1. 输入以下命令获取ubuntu的本机IP地址,假设ip是192.168.2.30
      1
      2
      # ubuntu 查看本机ip地址
      $ ip a
  • 2.访问网页
    例如ubuntu虚拟机所在的主机,使用浏览器连接ubuntu的ip地址,端口是envoy的监听端口9000,即

    http://192.168.2.30:10000/

  • 这时候应该能看到Ubuntu本地服务器web/index.html网页的内容,注意这里用的是10000端口,这是envoy程序的监听端口,如果是9001则是http服务器的端口,

参考链接

[1] envoy Official documentation
[2] 安装 – Envoy 中文指南, by cloudnative
[3] Envoy 文档, by icloudnative