极简istio wasmplugin RUST语言开发示例

337 阅读3分钟

前置条件

k8s集群,版本1.23.8

安装方法略

istio安装完成demo,版本1.17.2

curl -L https://git.io/getLatestIstio | ISTIO_VERSION=1.17.2 sh
cd istio-1.17.2/
./bin/istioctl install --set profile=demo -y
kubectl label namespace default istio-injection=enabled --overwrite

安装httpbin,sleep 示例

httpbin主要为了提供http响应,也可以用已有的能够提供http服务的任意服务。

sleep 为了在pod里使用curl命令,有别的pod中能执行curl命令也可以。

kubectl apply -f samples/httpbin/httpbin.yaml
kubectl apply -f samples/sleep/sleep.yaml

本地docker环境,版本 20.10.21

docker安装略

RUST语言环境,版本 rustc 1.70.0

安装rust开发环境,一条命令即可

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

检查是否安装好

cargo --version

# cargo 1.70.0 (ec8a8a0ca 2023-04-25)

阿里云或其他镜像仓库

类似部署一个普通应用,wasm插件来源于某个镜像仓库。

为了方便使用了阿里云的免费镜像仓库,也可以本地搭建或使用别的仓库。

注意需要将阿里云的仓库设置为公开!

示例功能

  • 在请求头增加自定义的返回信息

直接看效果

使用我编译好的镜像直接部署,保存以下内容为 rustwasm.yaml

apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
  name: my-rust-wasm-plugin
  namespace: default
spec:
  selector:
    matchLabels:
      app: httpbin
  ## 编译好的镜像    
  url: oci://registry.cn-hangzhou.aliyuncs.com/hallywang/rustwasm:3.0
 

部署到k8s中

kubectl apply -f rustwasm.yaml

示例验证方法

  • 执行以下命令,从sleep pod中发送http 请求到 httpbin ,打印出返回的header
SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}

kubectl exec ${SLEEP_POD} -c sleep -- sh -c 'curl --head -s httpbin:8000/headers'

在返回的header中,将看到如下内容(如果之前安装了笔者go版本的plugin,在403情况下不会有这个头信息,因为go版本的代码在403的情况下不会继续走下一个filter) go版本玩法请跳转

x-rust-wasme-hello: proxy-wasm-rust

从代码开始

创建rust工程

cargo new rust-wasm-plugin --lib

修改 Cargo.toml 为以下内容

[package]
name = "rust-wasm-plugin"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
wasm-bindgen = "0.2.63"
log = "0.4.8"
proxy-wasm = "0.2.1"
# The Rust SDK for proxy-wasm   https://crates.io/search?q=proxy-wasm

[lib]
path = "src/lib.rs"
crate-type = ["cdylib","rlib"]

修改src/lib.rs

use log::info;
use proxy_wasm::traits::*;
use proxy_wasm::types::*;


proxy_wasm::main! {{
    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_response_headers(&mut self, _: usize, _: bool) -> Action {
       // 新增一个自定义头
        self.set_http_response_header("x-rust-wasme-hello", Some("proxy-wasm-rust"));
        Action::Continue
    }
}

新增文件 Dockerfile

# Dockerfile for building "compat" variant of Wasm Image Specification.
# https://github.com/solo-io/wasm/blob/master/spec/spec-compat.md

FROM scratch

COPY pkg/rust_wasm_plugin_bg.wasm  ./plugin.wasm

安装 wasm-pack

cargo install wasm-pack

编译rust为wasm

wasm-pack build

编译成功后,工程目录pkg子目录下将出现文件: rust_wasm_plugin_bg.wasm (其他js文件本文用不到)

build一个Docker镜像,推送到镜像仓库

docker build . -t registy.cn-hangzhou.aliyuncs.com/USER_NAME/rustwasm:0.1
docker push registy.cn-hangzhou.aliyuncs.com/USER_NAME/rustwasm:0.1

新增部署yaml

rustwasm.yaml

apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
  name: my-rust-wasm-plugin
  namespace: default
spec:
  selector:
    matchLabels:
      app: httpbin
  url: oci://registry.cn-hangzhou.aliyuncs.com/USER_NAME/rustwasm:0.1

部署到k8s,执行测试脚本

kubectl apply -f rustwasm.yaml

SLEEP_POD=$(kubectl get pod -l app=sleep -o jsonpath={.items..metadata.name}

kubectl exec ${SLEEP_POD} -c sleep -- sh -c 'curl --head -s httpbin:8000/headers;'

## 观察返回内容

删除插件

kubectl delete wasmplugins my-rust-wasm-plugin

本文代码

github.com/hallywang/r…

go版本玩法

juejin.cn/post/723954…

github.com/hallywang/g…

参考资料

rustwasm.github.io/wasm-pack/i…

github.com/proxy-wasm/…

crates.io/crates/prox…