前置条件
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