18

Istio扩展性

 3 years ago
source link: https://zhuanlan.zhihu.com/p/269777095
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Istio的扩展性,主要体现在数据平面代理的扩展性。

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

WebAssembly 沙箱具备以下特点:

高效
功能
隔离
配置
开发友好

架构

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.
Qbayaqe.jpg!mobile

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

目前官方提供了 RustC++ 两种语言的sdk,此外社区另外提供了 TinyGoAssemblyScript 的实现,我们可以基于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 <[email protected]>"]
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

生成结果如下:

6ZzMVfR.jpg!mobile

主要是 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工具,大大简化了扩展的过程。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK