乐趣区

关于docker:通过-Wasm-扩展-Envoy-117

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 运行时:

Name Description
envoy.wasm.runtime.v8 V8-based runtime
envoy.wasm.runtime.wasmtime Wasmtime runtime
envoy.wasm.runtime.wavm WAVM runtime
envoy.wasm.runtime.null Compiled 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.0
ADD ./target/wasm32-unknown-unknown/release/my_http_wasm_filter.wasm /lib/my_http_wasm_filter.wasm
ADD ./envoy.yaml /etc/envoy.yaml
ENTRYPOINT /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/hello
Hello, World!


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

总结

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

退出移动版