Deploying Filters to Gloo

In this tutorial we’ll deploy an existing WebAssembly (WASM) module from the WebAssembly Hub directly to Envoy via Gloo installed to our kubernetes cluster.

Prepare environment

To get started, let’s deploy a sample service that we can call through Envoy. We’ll deploy the sample petstore API:

kubectl apply -f \
https://raw.githubusercontent.com/solo-io/gloo/master/example/petstore/petstore.yaml

You should now have the petstore running:

kubectl get po 

NAME                        READY   STATUS    RESTARTS   AGE
petstore-5dcf5d6b66-n8tjt   1/1     Running   0          2m20s

Deploying Envoy

In this tutorial, we’ll use Gloo, an API Gateway based on Envoy that has built-in wasm support but these steps should also work for base Envoy.

First, install Gloo via the helm chart:

helm repo update
kubectl create ns gloo-system
helm install gloo-gateway gloo/gloo --namespace gloo-system \
  --set global.wasm.enabled=true

Gloo will be installed to the gloo-system namespace.

Verify set up

Lastly, we’ll set up our routing rules to be able to call our petstore service. Let’s add a route to the routing table:

Apply the virtual service manifest

cat <<EOF | kubectl apply -f -
apiVersion: gateway.solo.io/v1
kind: VirtualService
metadata:
  name: default
  namespace: gloo-system  
spec:
  virtualHost:
    domains:
    - '*'
    routes:
    - matchers:
      - prefix: /
      routeAction:
        single:
          upstream:
            name: default-petstore-8080
            namespace: gloo-system
EOF

To get Gloo’s external IP, run the following:

URL=$(kubectl get svc -n gloo-system gateway-proxy \
 -o jsonpath='{.status.loadBalancer.ingress[*].ip}')

Now let’s curl that URL:

curl -v $URL/api/pets

*   Trying 35.184.102.75...
* TCP_NODELAY set
* Connected to 35.184.102.75 (35.184.102.75) port 80 (#0)
> GET /api/pets HTTP/1.1
> Host: 35.184.102.75
> User-Agent: curl/7.54.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< content-type: application/xml
< date: Tue, 10 Dec 2019 16:02:00 GMT
< content-length: 86
< x-envoy-upstream-service-time: 2
< server: envoy
< 
[{"id":1,"name":"Dog","status":"available"},{"id":2,"name":"Cat","status":"pending"}]

If you’re able to get to this point, we have a working Envoy proxy and we’re able to call it externally.

Deploying a WASM module from the Hub

Refer to the installation guide for getting the WebAssembly Hub CLI wasme.

Let’s run wasme list to see what’s available on the hub:

wasme list
NAME                 SHA      UPDATED             SIZE   TAGS
...
ilackarms/hello:v0.1 3753eeaf 15 Sep 19 23:41 EST 1.0 MB v0.1
...

Let’s try deploying one of these to Gloo:

wasme deploy gloo webassemblyhub.io/ilackarms/gloo-hello:1.3.4 --id=myfilter --config '{"value":"something"}'

This filter adds the header newheader: something to responses.

The deployment should have added our filter to the Gloo Gateway. Let’s check this with kubectl:

kubectl get gateway -n gloo-system '-ojsonpath={.items[0].spec.httpGateway.options.wasm}'
map[image:webassemblyhub.io/ilackarms/hello:v0.1 name:myfilter rootId:add_header_root_id]

If we try our request again, we should see the hello: World header was added by our filter:

curl -v $URL/api/pets
*   Trying 34.73.225.160...
* TCP_NODELAY set
* Connected to 34.73.225.160 (34.73.225.160) port 80 (#0)
> GET /api/pets HTTP/1.1
> Host: 34.73.225.160
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: application/xml
< date: Fri, 20 Dec 2019 19:17:13 GMT
< content-length: 86
< x-envoy-upstream-service-time: 0
< newheader: something
< location: envoy-wasm
< server: envoy
<
[{"id":1,"name":"Dog","status":"available"},{"id":2,"name":"Cat","status":"pending"}]

Note that deploying filters is dynamic and does not require restarting the proxy.

Cleaning up

We can clean up our filter with the wasme undeploy command:

wasme undeploy gloo --id=myfilter

Then re-try the curl:

curl -v $URL/api/pets
*   Trying 34.73.225.160...
* TCP_NODELAY set
* Connected to 34.73.225.160 (34.73.225.160) port 80 (#0)
> GET /api/pets HTTP/1.1
> Host: 34.73.225.160
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: application/xml
< date: Fri, 20 Dec 2019 19:19:13 GMT
< content-length: 86
< x-envoy-upstream-service-time: 1
< server: envoy
<
[{"id":1,"name":"Dog","status":"available"},{"id":2,"name":"Cat","status":"pending"}]
* Connection #0 to host 34.73.225.160 left intact

Cool! We’ve just seen how easy it is to dynamically add and remove filters from Envoy using wasme.

For more information and support using wasme and the Web Assembly Hub, visit the Solo.io slack channel at https://slack.solo.io.