This page looks best with JavaScript enabled

Developing an Istio WasmPlugin with TinyGo

 ·  ☕ 3 min read

wasme only supports up to Istio 1.9, while I am using Istio 1.14, so this post goes straight to tinygo for verification and learning.

1. Installing tinygo

  • Requirements

Go v1.18+

  • Install tinygo
1
2
brew tap tinygo-org/tools
brew install tinygo
  • Check the version
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. Creating the wasm-istio project

  • Initialize the project
1
2
3
mkdir wasm-istio
cd wasm-istio
go mod init wasm-istio
  • Edit main.go

See https://github.com/shaowenchen/demo/blob/master/wasm-istio/main.go — the key part is the snippet below

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)
	}
...
}
  • Compile to generate the wasm
1
tinygo build -o plugin.wasm -scheduler=none -target=wasi -no-debug

3. Packaging and publishing to an image registry

  • Dockerfile
1
2
FROM scratch
COPY plugin.wasm ./
  • Build the image
1
docker build -t shaowenchen/wasm-istio:v1 .
  • Push the image
1
docker push shaowenchen/wasm-istio:v1

4. Publishing to Istio WasmPlugin

  • Deploy a blog application
1
2
3
kubectl label namespace default istio-injection=enabled --overwrite
kubectl create deploy blog --image=nginx
kubectl expose deploy blog  --port 80

See https://github.com/shaowenchen/demo/blob/master/wasm-istio/blog.yaml for the gateway configuration

The blog application has the following labels

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
  • Create the following WasmPlugin object
 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 specifies the range of Pods the plugin applies to; note that WasmPlugin is a namespace-scoped object. phase specifies the stage at which the plugin applies. For other parameters, see https://istio.io/latest/docs/reference/config/proxy_extensions/wasm-plugin/ .

  • List WasmPlugins
1
2
3
4
kubectl get wasmplugins.extensions.istio.io

NAME                     AGE
add-header-hello-world   27s
  • Check the Istiod logs
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

If there are errors, it may be a permission problem accessing the image registry. Although WasmPlugin also supports S3 and file service addresses, an OCI-capable image registry is the better choice.

  • Verify the result

Configure the local hosts file to point the domain in the VirtualService to the IP of the host where the gateway runs. Then access it from the terminal and check the response headers:

 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

At this point the response headers carry one extra key: value pair compared to before, namely hello: world.

5. References


微信公众号
WRITTEN BY
微信公众号