2021年1月12日,Envoy 1.17.0 正式 released!本次更新值得大家关注的性能:

  1. wasm filter
  2. xds 资源 ttl
  3. skywalking tracer

本文次要小试Wasm filter。

Wasm扩大概述

Envoy Wasm扩大是一种Filter,可通过Wasm ABI 将Envoy外部 C++ API ”翻译“ 到 Wasm 运行时。 目前Envoy 反对以下4种Wasm 运行时:

NameDescription
envoy.wasm.runtime.v8V8-based runtime
envoy.wasm.runtime.wasmtimeWasmtime runtime
envoy.wasm.runtime.wavmWAVM runtime
envoy.wasm.runtime.nullCompiled modules linked into Envoy

默认状况下,Envoy发行镜像中不蕴含Wasmtime和WAVM运行时。

ABI 定义了Wasm扩大两侧的函数约定:主机公开的函数和Wasm模块实现的函数。主机公开的函数被“import”到Wasm模块中。

当然咱们在真正编写一个Wasm Filter的时候,咱们并不是间接操作ABI。咱们个别应用的是SDK,SDK是ABI的一种特定于语言的实现,它使应用该语言编写Wasm Filter变得更加容易。

实践上,咱们能够应用各种反对Wasm的语言编写Filter。不过目前官网实现了C++和 Rust 两种语言的SDK。

Envoy 反对 Wasm Network Filter 和 HTTP Filter。

Wasm是沙箱技术。从平安的角度来看,这是十分现实的,但它对内存模型有影响。 Envoy和Wasm VM之间的任何交互都将从Envoy内存复制到Wasm内存,而后再返回。

扩大示例

在本示例中,咱们基于 proxy-wasm-rust-sdk 实现一个Wasm 扩大 ,该扩大次要实现性能:当申请的Header中path属性值为“/hello”的时候,Envoy代理间接返回“Hello, World”。

1:创立库并设置

Wasm过滤器是从Rust库我的项目编译而成的,因而首先咱们须要创立该我的项目:

cargo new --lib my-http-wasm-filter

生产的库是要被Envoy C++ 代码加载的,因而无需蕴含任何Rust特定的信息。故咱们编辑Cargo.toml文件,将库的类型设置为"cdylib"。

同时咱们须要援用proxy-wasm-rust SDK,故须要配置一下proxy-wasm-rust SDK依赖。

如下:

[package]name = "my-http-wasm-filter"version = "0.1.0"authors = ["iyacontrol <gaohj2015@yeah.net>"]edition = "2018"[lib] crate-type = ["cdylib"][dependencies]log = "0.4.8"proxy-wasm = "0.1.3" # The Rust SDK for proxy-wasm

2:编写代码

src/lib.rs 代码如下:

use log::trace;use proxy_wasm::traits::*;use proxy_wasm::types::*;#[no_mangle]pub fn _start() {    proxy_wasm::set_log_level(LogLevel::Trace);    proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> { Box::new(HttpHeadersRoot) });}struct HttpHeadersRoot;impl Context for HttpHeadersRoot {}impl RootContext for HttpHeadersRoot {    fn get_type(&self) -> Option<ContextType> {        Some(ContextType::HttpContext)    }    fn create_http_context(&self, context_id: u32) -> Option<Box<dyn HttpContext>> {        Some(Box::new(HttpHeaders { context_id }))    }}struct HttpHeaders {    context_id: u32,}impl Context for HttpHeaders {}impl HttpContext for HttpHeaders {    fn on_http_request_headers(&mut self, _: usize) -> Action {        for (name, value) in &self.get_http_request_headers() {            trace!("#{} -> {}: {}", self.context_id, name, value);        }        match self.get_http_request_header(":path") {            Some(path) if path == "/hello" => {                self.send_http_response(                    200,                    vec![("Hello", "World"), ("Powered-By", "proxy-wasm")],                    Some(b"Hello, World!n"),                );                Action::Pause            }            _ => Action::Continue,        }    }    fn on_http_response_headers(&mut self, _: usize) -> Action {        for (name, value) in &self.get_http_response_headers() {            trace!("#{} <- {}: {}", self.context_id, name, value);        }        Action::Continue    }    fn on_log(&mut self) {        trace!("#{} completed.", self.context_id);    }}

3:编译

执行如下语句:

cargo build --target wasm32-unknown-unknown --release

生成的后果如下:

次要是my_http_wasm_filter.wasm文件。后续咱们会应用到该文件。

4: 运行

配置envoy启动文件,如下:

static_resources:  listeners:  - address:      socket_address:        address: 0.0.0.0        port_value: 8000    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          codec_type: auto          stat_prefix: ingress_http          route_config:            name: local_route            virtual_hosts:            - name: local_service              domains:              - "*"              routes:              - match:                  prefix: "/"                route:                  cluster: web_service          http_filters:          - name: envoy.filters.http.wasm            typed_config:              "@type": type.googleapis.com/udpa.type.v1.TypedStruct              type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm              value:                config:                  name: "my_plugin"                  root_id: "my_root_id"                  configuration:                    "@type": "type.googleapis.com/google.protobuf.StringValue"                    value: |                      {}                  vm_config:                    runtime: "envoy.wasm.runtime.v8"                    vm_id: "my_vm_id"                    code:                      local:                        filename: "/lib/my_http_wasm_filter.wasm"                    configuration: {}          - name: envoy.filters.http.router            typed_config: {}  clusters:  - name: web_service    connect_timeout: 0.5s    type: LOGICAL_DNS    lb_policy: round_robin    dns_lookup_family: V4_ONLY    load_assignment:      cluster_name: httpbin      endpoints:      - lb_endpoints:        - endpoint:            address:              socket_address:                address: httpbin.org                port_value: 80                ipv4_compat: true

通过envoy.filters.http.wasm配置项,将咱们编写的my_http_wasm_filter.wasm退出到envoy filter中。

为了简略,咱们基于Envoy 1.17 官网镜像打一个新的镜像,Dockerfile如下:

FROM envoyproxy/envoy:v1.17.0ADD ./target/wasm32-unknown-unknown/release/my_http_wasm_filter.wasm /lib/my_http_wasm_filter.wasmADD ./envoy.yaml /etc/envoy.yamlENTRYPOINT /usr/local/bin/envoy -c /etc/envoy.yaml -l debug --service-cluster proxy 

应用以下命令构建咱们新的镜像:

docker build -t iyacontrol/envoy:1.17.0 .

运行构建好的镜像:

docker run iyacontrol/envoy:1.17.0

失常状况下,咱们的Envoy失常运行。

5:验证

exec 到Envoy容器中,装置curl来测试。如果响应内容如下,则咱们的Wasm扩大预期工作。

# curl http://127.0.0.1:8000/helloHello, World!# curl http://127.0.0.1:8000<!DOCTYPE html><html lang="en">...

总结

置信当前官网会反对越来越多的语言编写Envoy的Wasm扩大。咱们能够轻松抉择本人相熟的语言实现诸如度量,可察看性,转换,数据失落预防,合规性验证或其余性能。