Please enable Javascript to view the contents

使用 tinygo 开发 Istio WasmPlugin

 ·  ☕ 2 分钟

wasme 只支持到 istio 1.9,而我使用的是 Istio 1.14,因此本篇直接使用 tinygo 进行验证和学习。

1. 安装 tinygo

  • 要求

Go v1.18+

  • 安装 tinygo
1
2
brew tap tinygo-org/tools
brew install tinygo
  • 查看版本
1
2
3
tinygo version

tinygo version 0.27.0 darwin/amd64 (using go version go1.19.3 and LLVM version 15.0.0)

2. 创建 wasm-istio 项目

  • 初始化项目
1
2
3
mkdir wasm-istio
cd wasm-istio
go mod init wasm-istio
  • 编辑 main.go

https://github.com/shaowenchen/demo/blob/master/wasm-istio/main.go 主要是下面这段

1
2
3
4
5
6
7
8
9
func (ctx *httpHeaders) OnHttpResponseHeaders(_ int, _ bool) types.Action {
	proxywasm.LogInfof("adding header: %s=%s", ctx.headerName, ctx.headerValue)

	// Add a hardcoded header
	if err := proxywasm.AddHttpResponseHeader("hello", "world"); err != nil {
		proxywasm.LogCriticalf("failed to set response constant header: %v", err)
	}
...
}
  • 编译生成 wasm
1
tinygo build -o plugin.wasm -scheduler=none -target=wasi -no-debug

3. 打包发布到镜像仓库

  • Dockerfile
1
2
FROM scratch
COPY plugin.wasm ./
  • 编译生成镜像
1
docker build -t shaowenchen/wasm-istio:v1 .
  • 推送镜像
1
docker push shaowenchen/wasm-istio:v1

4. 发布到 Istio WasmPlugin

  • 部署一个 blog 应用
1
2
3
kubectl label namespace default istio-injection=enabled --overwrite
kubectl create deploy blog --image=nginx
kubectl expose deploy blog  --port 80

网关配置见 https://github.com/shaowenchen/demo/blob/master/wasm-istio/blog.yaml

blog 应用具有以下标签

1
2
3
4
kubectl get pod --show-labels

NAME                    READY   STATUS    RESTARTS   AGE   LABELS
blog-64db778565-swdxg   2/2     Running   0          62s   app=blog,pod-template-hash=64db778565,security.istio.io/tlsMode=istio,service.istio.io/canonical-name=blog,service.istio.io/canonical-revision=latest
  • 创建以下 WasmPlugin 对象
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
  name: add-header-hello-world
  namespace: default
spec:
  selector:
    matchLabels:
      app: blog
  url: oci://docker.io/shaowenchen/wasm-istio:v1
  phase: UNSPECIFIED_PHASE

matchLabels 指定插件应用的 Pod 范围,需要注意 WasmPlugin 是命名空间级别的对象。phase 指定插件应用的阶段。其他参数可以参考 https://istio.io/latest/docs/reference/config/proxy_extensions/wasm-plugin/

  • 查看 WasmPlugin 列表
1
2
3
4
kubectl get wasmplugins.extensions.istio.io

NAME                     AGE
add-header-hello-world   27s
  • 查看 Istiod 日志
1
2
3
4
5
6
2023-02-22T08:31:10.017446Z	info	ads	Push debounce stable[75] 1 for config WasmPlugin/default/add-header-hello-world: 100.09877ms since last change, 100.098558ms since last push, full=true
2023-02-22T08:31:10.017744Z	info	ads	XDS: Pushing:2023-02-22T08:31:10Z/49 Services:10 ConnectedEndpoints:3 Version:2023-02-22T08:31:10Z/49
2023-02-22T08:31:10.017990Z	info	ads	LDS: PUSH for node:istio-egressgateway-7fcb98978c-ppkdx.istio-system resources:0 size:0B
2023-02-22T08:31:10.018241Z	info	ads	LDS: PUSH for node:istio-ingressgateway-55b6cffcbc-w6lwv.istio-system resources:1 size:3.7kB
2023-02-22T08:31:10.020476Z	info	ads	LDS: PUSH for node:blog-7cc68f9d6b-m9rpd.default resources:20 size:96.8kB
2023-02-22T08:31:10.066004Z	info	ads	ECDS: PUSH request for node:blog-7cc68f9d6b-m9rpd.default resources:1 size:327B

如果有报错,可能是访问镜像仓库权限问题。虽然 WasmPlugin 也支持 S3、文件服务地址,但支持 OCI 的镜像仓库是更好的选择。

  • 验证结果

在本地配置 hosts 将 VirtualService 中的域名,指向网关所在主机的 IP。在终端访问,查看响应头部:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
curl http://istio.chenshaowen.com:31990/ -I

HTTP/1.1 200 OK
server: istio-envoy
date: Wed, 22 Feb 2023 08:36:52 GMT
content-type: text/html
content-length: 615
last-modified: Tue, 13 Dec 2022 15:53:53 GMT
etag: "6398a011-267"
accept-ranges: bytes
x-envoy-upstream-service-time: 2
hello: world

此时,响应头部会比之前多出来一对 key: value,即 hello: world。

5. 参考


微信公众号
作者
微信公众号