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 -V
rustc 1.46.0 (04488afe3 2020-08-24)
而后查看是否装置了 wasm32-unknown-unknown
编译指标:
$ rustup target list | grep wasm32
wasm32-unknown-emscripten
wasm32-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.yml
admin:
access_log_path: /dev/null
address:
socket_address:
address: 0.0.0.0
port_value: 19000
static_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.3
ADD ./target/wasm32-unknown-unknown/release/my_wasm_filter.wasm /etc/my_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/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 工具,大大简化了扩大的过程。