1. 前言
早就想写一个 envoy filter 开发的文章了,本来在我的 issue 中列了一篇 Venil Noronha 写的文章,想翻译来的,但是感觉那篇文章太简单了,而且没有实际操作过程,让我这种更愿意动手的人来说是一种折磨。
所以想还是自己写一个系列开始,打算是写 4~5 篇文章,具体的大纲如下:
-
官网 echo 示例编译测试
-
官网 http filter 示例编译测试
-
envoy filte 源码剖析(基于 echo 和 http filter)
-
自定义协议的 filter 开发
-
(待定)
这是第一篇文章,主要介绍官网 github 上的例子中 echo 这个例子的编译测试过程。这篇文章主要介绍操作过程,具体原理想下次文章再介绍。
2. 编译环境介绍
采用的是官网推荐的 Ubuntu 18.04,也曾想在自己的 mac 上编译,但是在开发机上编译之后放弃了,因为编译后的零时文件 10 多个 G。采用 8 核 16 G 内存的机器,磁盘空间 300G,磁盘空间还是要大一点,负责多编译几个版本之后空间就很吃紧了。
3. 安装 bazel
这部分按照官网的指引安装就可以了。https://github.com/envoyproxy/envoy/blob/master/bazel/README.md.
sudo wget -O /usr/local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-amd64 sudo chmod +x /usr/local/bin/bazel
4. 安装编译环境(这里我选择了gcc编译)
sudo apt-get install \ libtool \ cmake \ automake \ autoconf \ make \ ninja-build \ curl \ unzip \ virtualenv
gcc 要求是 7 以上的版本,所以安装后要检查一下。
ubuntu@ubuntu:/data/mesh/envoy-filter-example$ gcc --version gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ubuntu@ubuntu:/data/mesh/envoy-filter-example$
5. clone 代码编译测试例子
编译这里有点小技巧,反正我直接 clone 官方的例子之后没有编译通过,而是把 envoy 的版本设置到 1.14 和 1.15 才编译过的。
所以这里可以看一下,在 clone 了之后,要 checkout 到一个稳定版本,我是 checkout 到 1.14 和 1.15 都编译过的。
编译过程非常简单,按照 readme 中的编译命令就可以直接编译过: bazel build //:envoy
。不过编译非常耗时,8 核 cpu 编译了 20 多分钟才编译完成。
ubuntu@ubuntu:/data/mesh$ git clone https://github.com/envoyproxy/envoy-filter-example ubuntu@ubuntu:/data/mesh$ cd envoy-filter-example ubuntu@ubuntu:/data/mesh/envoy-filter-example$ git submodule update --init ubuntu@ubuntu:/data/mesh/envoy-filter-example/envoy$ git checkout 50ef0945fa2c5da4bff7627c3abf41fdd3b7cffd HEAD is now at 50ef0945f release: cutting 1.15 (#11898) ubuntu@ubuntu:/data/mesh/envoy-filter-example/envoy$ cd ../ ubuntu@ubuntu:/data/mesh/envoy-filter-example$ bazel build //:envoy
6. 测试编译后的例子
6.1 测试流程
先说一下基本的测试流程, echo
这个例子非常好测试,因为它是一个拦截 filter,就是说请求到这个 filter 这里就终止了,不会继续向下游传。而且是针对 tcp 协议的一个 filter,没有使用私有协议,所以测试工具也不用找了,直接使用 telnet 进行测试就好了。如下图所示:
所以测试流程也就非常简单了,罗列如下:
-
准备启动配置文件 test.yaml。
-
使用配置文件启动 envoy。
-
使用 telnet 工具进行测试。
-
验证测试结果
6.2 启动 envoy 命令
编译好的二进制就在当前目录的 bazel-bin
目录下,可以直接运行。不过还要修改一下启动配置文件,默认的配置文件端口配置都是 8080
,也就是是说启动的时候会随机启动端口,不好测试。所以我调整了一下 yaml 文件中监听的端口,比如下面的 test.yaml
文件中我修改为了 8080
。另外为了完整看到调用过程,并且配合 echo
这个插件中的 trace
日志,我把启动后的日志级别设置为了 trace
。下面是完整的启动命令。
ubuntu@ubuntu:/data/mesh/envoy-filter-example$ ./bazel-bin/envoy --config-path ./test.yaml -l trace
6.3 trace 日志和插件代码解读
envoy 的日志级别有
在 echo
这个插件的代码中是有一行 trace 日志的,如下面的代码。这段代码是 envoy
在收到信息后转给这个插件,在收到数据后,直接回写数据给客户端。并且终止把数据继续发往下游。这里返回了 StopIteration
。
// echo2.cc Network::FilterStatus Echo2::onData(Buffer::Instance& data, bool) { ENVOY_CONN_LOG(trace, "echo: got {} bytes", read_callbacks_->connection(), data.length()); read_callbacks_->connection().write(data, false); return Network::FilterStatus::StopIteration; }
6.4 配置文件
这里是完整的 test.yaml
文件内容。因为 echo
这个例子的特殊性,就不需要启动后端服务,所以这里的 endpoints
可以不用管。
admin: access_log_path: /dev/null address: socket_address: address: 127.0.0.1 port_value: 0 static_resources: clusters: name: cluster_0 connect_timeout: 0.25s load_assignment: cluster_name: cluster_0 endpoints: - lb_endpoints: - endpoint: address: socket_address: address: 127.0.0.1 port_value: 0 listeners: - name: listener_0 address: socket_address: address: 127.0.0.1 port_value: 8080 filter_chains: - filters: - name: echo2 config:
6.5 测试客户端
因为 echo
这个例子是一个 tcp
插件,所以这里可以直接使用 telnet
来测试。连接之后直接发送信息过去就可以看到回响信息了。
ubuntu@ubuntu:/data/mesh/envoy-filter-example/test/client$ telnet 127.0.0.1 8080 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. 112312 112312 12312312 12312312 ^] telnet> quit Connection closed. ubuntu@ubuntu:/data/mesh/envoy-filter-example/test/client$
6.6 测试日志
[2020-09-27 20:38:33.905][21762][debug][main] [external/envoy/source/server/server.cc:189] flushing stats [2020-09-27 20:38:36.371][21771][debug][conn_handler] [external/envoy/source/server/connection_handler_impl.cc:422] [C0] new connection [2020-09-27 20:38:36.371][21771][trace][connection] [external/envoy/source/common/network/connection_impl.cc:506] [C0] socket event: 2 [2020-09-27 20:38:36.371][21771][trace][connection] [external/envoy/source/common/network/connection_impl.cc:607] [C0] write ready [2020-09-27 20:38:38.908][21762][debug][main] [external/envoy/source/server/server.cc:189] flushing stats [2020-09-27 20:38:39.917][21771][trace][connection] [external/envoy/source/common/network/connection_impl.cc:506] [C0] socket event: 3 [2020-09-27 20:38:39.917][21771][trace][connection] [external/envoy/source/common/network/connection_impl.cc:607] [C0] write ready [2020-09-27 20:38:39.917][21771][trace][connection] [external/envoy/source/common/network/connection_impl.cc:544] [C0] read ready. dispatch_buffered_data=false [2020-09-27 20:38:39.917][21771][trace][connection] [external/envoy/source/common/network/raw_buffer_socket.cc:25] [C0] read returns: 8 [2020-09-27 20:38:39.917][21771][trace][connection] [external/envoy/source/common/network/raw_buffer_socket.cc:39] [C0] read error: Resource temporarily unavailable [2020-09-27 20:38:39.917][21771][trace][filter] [echo2.cc:12] [C0] echo: got 8 bytes [2020-09-27 20:38:39.917][21771][trace][connection] [external/envoy/source/common/network/connection_impl.cc:427] [C0] writing 8 bytes, end_stream false
7. 总结
我直接 clone 官网的代码下来编译是没有编译过的,主要是 envoy 中有报错,最后吧 envoy checkout 到 1.14 和 1.15 才编译过,所以感觉 envoy 的master 分支还是有些随意,没有编译通过的版本都能合并。目前我主要使用 1.15 来编译,看 1.16 有不少很实用的特性,但是目前看才完成了 24%,还有 41 个计划需求还没有完成,按我估计要到年底了才能发布 1.16。不过 1.16还是比较期待的,主要是 wasm。
整个测试流程我感觉还是比较清晰的,echo 是一个 tcp 的 filter,我们不用写单独的客户端,而且这个 filter 是接受到请求就直接返回了,相当于是一个返回改写的 filter,所以不需要下游服务支持,所以这个测试也非常简单,只要有配置文件就可以了。
看完本文有收获?请分享给更多人
关注「黑光技术」,关注大数据+微服务
CoLaBug.com遵循[CC BY-SA 4.0]分享并保持客观立场,本站不承担此类作品侵权行为的直接责任及连带责任。您有版权、意见、投诉等问题,请通过[eMail]联系我们处理,如需商业授权请联系原作者/原网站。