Istio的扩展性,次要体现在数据立体代理的扩展性。

WebAssembly是一种沙箱技术,可用于扩大Istio代理(Envoy)。 Proxy-Wasm 沙箱API取代了Mixer,成为Istio中的次要扩大机制。 Istio 1.6将为Proxy-Wasm插件提供对立的配置API。

WebAssembly 沙箱具备以下特点:

  • 高效-扩大插件在实现性能的前提下,只带来很低的提早和大量的CPU和内存开销。
  • 性能-扩大插件能够执行策略,收集遥测和批改载荷。
  • 隔离-一个插件产生编程谬误或解体不会影响其余插件。
  • 配置-应用与其余Istio API统一的API配置插件。扩展名能够动静配置。
  • 开发敌对-该插件能够用几种编程语言编写,即反对wasm的语言简直都可能用来编写插件。

架构

Istio扩大(Proxy-Wasm插件)具备几个方面:

  • Filter Service Provider Interface (SPI) for building Proxy-Wasm plugins for filters.
  • Sandbox V8 Wasm Runtime embedded in Envoy.
  • Host APIs for headers, trailers and metadata.
  • Call out APIs for gRPC and HTTP calls.
  • Stats and Logging APIs for metrics and monitoring.

为了使Envoy可能加载WebAssembly插件并可能对其进行调用并被该插件调用,咱们须要一个稳固的接口。这是proxy-wasm的意义。它定义了一个应用程序二进制接口-从WebAssembly模块导出并在运行时可调用的一组函数。从实质上讲,这与动态链接库没有什么不同。

目前官网提供了Rust 和 C++两种语言的sdk,此外社区另外提供了TinyGo和 AssemblyScript 的实现,咱们能够基于sdk更加不便地扩大Envoy。

Demo

咱们的演示应用rust语言实现。大抵包含以下三步:

  • 构建一段Rust代码,该代码实现并应用ABI
  • 将代码编译为WebAssembly
  • 将此部署到Envoy代理中并进行测试。

工具筹备

确保你曾经装置了最新版的rust。能够通过以下命令查看并查看具体版本:

$ rustc -Vrustc 1.46.0 (04488afe3 2020-08-24)

而后查看是否装置了wasm32-unknown-unknown编译指标:

$ rustup target list | grep wasm32wasm32-unknown-emscriptenwasm32-unknown-unknown (installed)wasm32-wasi (installed) 

如果大家没有装置,那么能够执行以下命令进行装置:

$ rustup update$ rustup target add wasm32-unknown-unknown

创立库并设置

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

cargo new --lib my-wasm-filter

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

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

如下:

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

编写代码

src/lib.rs 代码如下:

use chrono::{DateTime, Utc};use log::info;use proxy_wasm::traits::*;use proxy_wasm::types::*;use std::time::Duration;#[no_mangle]pub fn _start() {    proxy_wasm::set_log_level(LogLevel::Trace);    proxy_wasm::set_root_context(|_| -> Box<dyn RootContext> { Box::new(HelloWorld) });}struct HelloWorld;impl Context for HelloWorld {}impl RootContext for HelloWorld {    fn on_vm_start(&mut self, _: usize) -> bool {        info!("Hello, World!");        self.set_tick_period(Duration::from_secs(5));        true    }    fn on_tick(&mut self) {        let datetime: DateTime<Utc> = self.get_current_time().into();        info!("It's {}", datetime);    }}

首先,咱们定义了一个名为_start的非凡函数,该函数是ABI的一部分(咱们应用no_mangle宏保留名称),而后让咱们初始化事件。在其中,咱们设置日志级别以跟踪和注册稍后定义的HttpContext。 HTTP上下文是可用的三种上下文类型之一,用于构建HTTP Filter以及RootContext和StreamContext,可别离用于配置和应用计时器以及TCP Filter。您能够浏览可用的API,它们非常简单。

其余代码定义了咱们的HelloWorld扩大,实现了必须的Context个性和HttpContext个性。

编译

执行如下语句:

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

生成后果如下:

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

运行

配置envoy启动文件,如下:

# envoy-bootstrap.ymladmin:    access_log_path: /dev/null    address:      socket_address:        address: 0.0.0.0        port_value: 19000static_resources:    listeners:      - name: listener_0        address:          socket_address: { address: 0.0.0.0, port_value: 8080 }        filter_chains:          - filters:              - name: envoy.http_connection_manager                config:                  codec_type: AUTO                  stat_prefix: ingress_http                  route_config:                    name: test                    virtual_hosts:                      - name: httpbin.com                        domains: ["*"]                        routes:                          - match: { prefix: "/" }                            route:                              cluster: static-cluster                              auto_host_rewrite: true                  http_filters:                  - name: envoy.filters.http.wasm                    config:                      config:                        name: "my_wasm_filter"                        root_id: "my_wasm_filter"                        vm_config:                          runtime: "envoy.wasm.runtime.v8"                          code:                            local:                              filename: "/etc/my_wasm_filter.wasm"                          allow_precompiled: true                  - name: envoy.router    clusters:      - name: static-cluster        connect_timeout: 0.25s        type: LOGICAL_DNS        lb_policy: ROUND_ROBIN        dns_lookup_family: V4_ONLY        hosts:          - socket_address:              address: httpbin.org              port_value: 80              ipv4_compat: true 

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

为了简略,咱们间接基于istio官网proxy镜像打一个新的镜像。Dockerfile如下:

FROM istio/proxyv2:1.7.3ADD ./target/wasm32-unknown-unknown/release/my_wasm_filter.wasm /etc/my_wasm_filter.wasm ADD ./envoy.yaml /etc/envoy.yamlENTRYPOINT /usr/local/bin/envoy -c /etc/envoy.yaml -l debug --service-cluster proxy 

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

docker build -t iyacontrol/proxyv2:1.7.3 .

运行构建好的镜像:

$ docker run iyacontrol/proxyv2:1.7.3...[2020-10-30 02:04:14.174][6][debug][upstream] [external/envoy/source/common/upstream/logical_dns_cluster.cc:153] DNS refresh rate reset for httpbin.org, refresh rate 5000 ms[2020-10-30 02:04:14.283][15][info][wasm] [external/envoy/source/extensions/common/wasm/context.cc:1009] wasm log my_wasm_filter : It's 2020-10-30 02:04:14.283022 UTC[2020-10-30 02:04:14.294][18][info][wasm] [external/envoy/source/extensions/common/wasm/context.cc:1009] wasm log my_wasm_filter : It's 2020-10-30 02:04:14.294866 UTC[2020-10-30 02:04:14.311][16][info][wasm] [external/envoy/source/extensions/common/wasm/context.cc:1009] wasm log my_wasm_filter : It's 2020-10-30 02:04:14.311076 UTC[2020-10-30 02:04:14.318][17][info][wasm] [external/envoy/source/extensions/common/wasm/context.cc:1009] wasm log my_wasm_filter : It's 2020-10-30 02:04:14.317969 UTC....

通过打印的日志能够看出,咱们的插件曾经完满运行。

论断

尽管目前次要用来编写遥测组件,然而后续的倒退过程中,咱们能够应用咱们相熟的语言,通过wasm实现一些性能插件,从而实现无需批改envoy主体代码,即可扩大咱们所需的性能的目标。

Solo.io 推出了一个名为WebAssembly Hub的wasm插件存储服务(应用OCI镜像),让咱们能够用来存储和散发wasm 插件。

同时也推出一个名为wasme的cli工具,大大简化了扩大的过程。