Running Filters in Production

The wasme CLI provides an easy way to get started building and deploying Web Assembly filters to an Envoy service mesh.

This is intended to be used in development and testing, but does not provide a declarative, stateless means by which to configure production Kubernetes clusters.

The Wasme Operator makes it possible to manage the deployment of WebAssembly Filters to a supported service mesh using Kubernetes CRDs.

The Wasme Operator consists of two components:

All components run in the wasme namespace by default.

Installation

Installing Istio

Wasme depends on a supported service mesh being installed to the cluster.

Currently, the Wasme Operator only supports Istio. If Istio (specifically the envoyfilters.networking.istio.io CRD) is not installed to the cluster, the wasme container will exit with an error at boot time.

To install istio, follow the Istio installation Guide.

Installing Wasme

First, install the Wasme CRDs:

kubectl apply -f https://github.com/solo-io/wasme/releases/latest/download/wasme.io_v1_crds.yaml

Output:

customresourcedefinition.apiextensions.k8s.io/filterdeployments.wasme.io created

Next install the Operator components:

kubectl apply -f https://github.com/solo-io/wasme/releases/latest/download/wasme-default.yaml

Output:

namespace/wasme created
configmap/wasme-cache created
serviceaccount/wasme-cache created
serviceaccount/wasme-operator created
clusterrole.rbac.authorization.k8s.io/wasme-operator created
clusterrolebinding.rbac.authorization.k8s.io/wasme-operator created
daemonset.apps/wasme-cache created
deployment.apps/wasme-operator created

To install an older version of wasme, use the url kubectl apply -f https://github.com/solo-io/wasme/releases/download/<VERSION>/wasme-default.yaml

Finally, confirm that the wasme operator is has started successfully:

kubectl get pod -n wasme

Output:

NAME                              READY   STATUS    RESTARTS   AGE
wasme-cache-5twpj                 1/1     Running   0          4m40s
wasme-operator-754bb5f654-5wd6h   1/1     Running   0          4m40s

Great! We’re now ready to get started deploying WebAssembly filters to our Istio service mesh!

See the next section to learn how to get started with the Operator.

Using the Wasme Operator

Interacting with the Wasme Operator happens through the FilterDeployment Custom Resource.

The full spec for this CRD can be read at https://github.com/solo-io/wasme/blob/master/operator/pkg/api/wasme.io/v1/types.go#L14

Let’s try the following example to see it in action:

Example Usage

In this example, we’ll deploy a simple application with Istio sidecars injected to it. We’ll deploy a simple “Hello World” filter to our application’s sidecars and see that it modifies request headers accordingly.

Deploy the Example

For our example we’ll use the Istio Bookinfo example.

To deploy it, let’s run the following:

# create the bookinfo namespace
kubectl create ns bookinfo

# label it for istio injection
kubectl label namespace bookinfo istio-injection=enabled --overwrite

# install the bookinfo application
kubectl apply -n bookinfo -f https://github.com/solo-io/wasme/blob/master/test/e2e/operator/bookinfo.yaml

The bookinfo app installed here is identical to that shipped with Istio 1.5.0.

Deploy the Filter

Deploying our filter to the Bookinfo sidecars is as simple as creating a FilterDeployment custom resource.

Let’s take a brief look at an example FilterDeployment:

apiVersion: wasme.io/v1
kind: FilterDeployment
metadata:
  name: bookinfo-custom-filter
  namespace: bookinfo
spec:
  deployment:
    istio:
      kind: Deployment
  filter:
    config: '{"name":"hello","value":"world"}'
    image: webassemblyhub.io/ilackarms/istio-test:1.5.0-0

This resource tells wasme to:

Run the following to add the filter to the Bookinfo app:

cat <<EOF | kubectl apply -f -
apiVersion: wasme.io/v1
kind: FilterDeployment
metadata:
  name: bookinfo-custom-filter
  namespace: bookinfo
spec:
  deployment:
    istio:
      kind: Deployment
  filter:
    config: '{"name":"hello","value":"world"}'
    image: webassemblyhub.io/ilackarms/istio-test:1.5.0-0
EOF
filterdeployment.wasme.io/bookinfo-custom-filter created

The Wasme Operator will immediately begin processing the FilterDeployment. We should see its status is updated within a few seconds:

kubectl get filterdeployments.wasme.io -n bookinfo -o yaml bookinfo-custom-filter 

Note the status of the FilterDeployment

apiVersion: wasme.io/v1
kind: FilterDeployment
metadata:
  creationTimestamp: "2020-01-20T19:16:07Z"
  generation: 1
  name: bookinfo-custom-filter
  namespace: bookinfo
  resourceVersion: "16085964"
  selfLink: /apis/wasme.io/v1/namespaces/bookinfo/filterdeployments/bookinfo-custom-filter
  uid: 4f3811aa-3bb9-11ea-b3ed-42010af0016c
spec:
  deployment:
    istio:
      kind: Deployment
  filter:
    config: '{"name":"hello","value":"world"}'
    image: webassemblyhub.io/ilackarms/istio-test:1.5.0-0
status:
  observedGeneration: "1"
  workloads:
    details-v1:
      state: Succeeded
    productpage-v1:
      state: Succeeded
    ratings-v1:
      state: Succeeded
    reviews-v1:
      state: Succeeded
    reviews-v2:
      state: Succeeded
    reviews-v3:
      state: Succeeded

The status contains the status of the deployment for each selected workload. This means the filter has been deployed to each.

Let’s test the filter with a curl:

kubectl exec -ti -n bookinfo deploy/productpage-v1 -c istio-proxy -- curl -v http://details.bookinfo:9080/details/123

The output should have a 200 OK response and contain the response header hello: world:

*   Trying 10.55.247.3...
* TCP_NODELAY set
* Connected to details.bookinfo (10.55.247.3) port 9080 (#0)
> GET /details/123 HTTP/1.1
> Host: details.bookinfo:9080
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: application/json
< server: istio-envoy
< date: Mon, 06 Jan 2020 18:13:12 GMT
< content-length: 180
< x-envoy-upstream-service-time: 1
< hello: world
< x-envoy-decorator-operation: details.bookinfo.svc.cluster.local:9080/*
<
* Connection #0 to host details.bookinfo left intact
{"id":123,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"}

We can easily modify the hello: world custom header by updating the FilterDeployment spec.filter.config:

cat <<EOF | kubectl apply -f -
apiVersion: wasme.io/v1
kind: FilterDeployment
metadata:
  name: bookinfo-custom-filter
  namespace: bookinfo
spec:
  deployment:
    istio:
      kind: Deployment
  filter:
    config: '{"name":"hello","value":"goodbye"}'
    image: webassemblyhub.io/ilackarms/istio-test:1.5.0-0
EOF

Try the request again:

kubectl exec -ti -n bookinfo deploy/productpage-v1 -c istio-proxy -- curl -v http://details.bookinfo:9080/details/123

The output should now contain the response header hello: goodbye:

*   Trying 10.55.247.3...
* TCP_NODELAY set
* Connected to details.bookinfo (10.55.247.3) port 9080 (#0)
> GET /details/123 HTTP/1.1
> Host: details.bookinfo:9080
> User-Agent: curl/7.58.0
> Accept: */*
>
< HTTP/1.1 200 OK
< content-type: application/json
< server: istio-envoy
< date: Mon, 20 Jan 2020 19:39:33 GMT
< content-length: 180
< x-envoy-upstream-service-time: 1
< hello: goodbye
< x-envoy-decorator-operation: details.bookinfo.svc.cluster.local:9080/*
<
* Connection #0 to host details.bookinfo left intact
{"id":123,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"}

Great! We’ve just seen how easy it is to deploy Wasm filters to Istio using Wasme!

To remove the filter, run:

kubectl delete filterdeployment -n bookinfo bookinfo-custom-filter

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