WASM

To add your new Wasm filter to the mesh, all you need is a WasmDeploymentPolicy Kubernetes custom resource. Paired with a valid Workspace and WorkspaceSettings to allow fine-tuned control over your namespace boundaries, all you need to do is specify which Workloads should be configured and with which Wasm filters, then let Gloo Mesh handle the rest. Gloo Mesh will watch for WasmDeployments and manage the lifecycle of all your Wasm deployments accordingly.

In this guide we will enable a Wasm filter for use by an Envoy proxy. The filter will add a custom header to the response from the reviews service in the bookinfo application. To do this, we will walk through the following steps:

  1. Prepare the Envoy sidecar to fetch Wasm filters
  2. Deploy the Wasm filter and validate

Before you begin

  1. Complete the example setup to install Gloo Mesh, Istio, and Bookinfo in your cluster.

  2. Create the Gloo Mesh resources for this policy in the management and workload clusters.

    The following files are examples only for testing purposes. Your actual setup might vary. You can use the files as a reference for creating your own tests.

    1. Download the following Gloo Mesh resources:
    2. Apply the files to your management cluster.
      kubectl apply -f kubernetes-cluster_gloo-mesh_cluster-1.yaml --context ${MGMT_CONTEXT}
      kubectl apply -f kubernetes-cluster_gloo-mesh_cluster-2.yaml --context ${MGMT_CONTEXT}
      kubectl apply -f workspace_gloo-mesh_anything.yaml --context ${MGMT_CONTEXT}
      
    1. Download the following Gloo Mesh resources:
    2. Apply the files to your workload cluster.
      kubectl apply -f workspace-settings_bookinfo_anything.yaml --context ${REMOTE_CONTEXT1}
      

Prepare the Envoy sidecar to fetch Wasm filters

Our Envoy instances will fetch their wasm filters from an envoy cluster that must be defined in the static bootstrap config. We must therefore perform a one-time operation to add the gloo-mesh-agent as a cluster in the Envoy bootstrap.

To do so, let's create a ConfigMap containing the custom additions to the Envoy bootstrap:

cat <<EOF | kubectl apply --context ${REMOTE_CONTEXT1} -n bookinfo -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: gloo-mesh-custom-envoy-bootstrap
  namespace: bookinfo
data:
  custom_bootstrap.json: |
    {
      "static_resources": {
        "clusters": [{
          "name": "gloo_mesh_agent_cluster",
          "type" : "STRICT_DNS",
          "connect_timeout": "1s",
          "lb_policy": "ROUND_ROBIN",
          "load_assignment": {
            "cluster_name": "gloo_mesh_agent_cluster",
            "endpoints": [{
              "lb_endpoints": [{
                "endpoint": {
                  "address":{
                    "socket_address": {
                      "address": "gloo-mesh-agent.gloo-mesh.svc.cluster.local",
                      "port_value": 9977
                    }
                  }
                }
              }]
            }]
          },
          "circuit_breakers": {
            "thresholds": [
              {
                "priority": "DEFAULT",
                "max_connections": 100000,
                "max_pending_requests": 100000,
                "max_requests": 100000
              },
              {
                "priority": "HIGH",
                "max_connections": 100000,
                "max_pending_requests": 100000,
                "max_requests": 100000
              }
            ]
          },
          "upstream_connection_options": {
            "tcp_keepalive": {
              "keepalive_time": 300
            }
          },
          "max_requests_per_connection": 1,
          "http2_protocol_options": { }
        }]
      }
    }
EOF

Next we'll patch the ratings-v1 deployment to include this custom boostrap in the sidecar:

kubectl patch deployment -n bookinfo ratings-v1 --context ${REMOTE_CONTEXT1} \
  --patch='{"spec":{"template": {"metadata": {"annotations": {"sidecar.istio.io/bootstrapOverride": "gloo-mesh-custom-envoy-bootstrap"}}}}}' \
  --type=merge

Now our deployment is wasm-ready.

The next step is to deploy the WasmDeploymentPolicy and start modifying traffic!

Deploy the Wasm filter and validate

We've got everything in place to use the Wasm filter, but first let's see what things look like without the filter added.

Test without Wasm Filter

As a sanity check, let's run a curl without any wasm filter deployed. First we'll create a temporary container to run curl from in the same namespace as the review service.

kubectl run -it -n bookinfo --context $REMOTE_CONTEXT1 curl \
  --image=curlimages/curl:7.73.0 --rm  -- sh

From the new terminal run the following:

curl http://ratings:9080/ratings/1 -v

You should see the following response:

*   Trying 10.96.31.140:9080...
* Connected to ratings (10.96.31.140) port 9080 (#0)
> GET /ratings/1 HTTP/1.1
> Host: ratings:9080
> User-Agent: curl/7.73.0-DEV
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< content-type: application/json
< date: Wed, 11 May 2022 17:00:40 GMT
< x-envoy-upstream-service-time: 104
< server: envoy
< transfer-encoding: chunked
<
* Connection #0 to host ratings left intact
{"id":1,"ratings":{"Reviewer1":5,"Reviewer2":4}}

Go ahead and exit the pod and it will delete itself. Next we'll try the same after we deploy the Wasm filter.

Deploy the Filter

Now let's deploy a Wasm filter with a WasmDeployment:

cat <<EOF | kubectl apply --context ${REMOTE_CONTEXT1} -f-
apiVersion: extensions.policy.gloo.solo.io/v2
kind: WasmDeploymentPolicy
metadata:
  name: wasm-deployment-policy
  namespace: bookinfo
spec:
  applyToWorkloads:
  - selector:
      cluster: cluster-1
      labels:
        app: ratings
      namespace: bookinfo
  config:
    filters:
    - filterContext: SIDECAR_INBOUND
      wasmImageSource:
        wasmImageTag: webassemblyhub.io/ilackarms/assemblyscript-test:istio-1.8
EOF

You can verify the filter has been deployed successfully by checking on the new WasmDeployment:

kubectl get --context ${REMOTE_CONTEXT1} wasmdeploymentpolicy -n bookinfo wasm-deployment-policy -o yaml

Let's try our curl again:

kubectl run -it -n bookinfo --context $REMOTE_CONTEXT1 curl \
  --image=curlimages/curl:7.73.0 --rm  -- sh

From the new terminal run the following:

curl http://ratings:9080/ratings/1 -v

Expected response:

*   Trying 10.96.31.140:9080...
* Connected to ratings (10.96.31.140) port 9080 (#0)
> GET /ratings/1 HTTP/1.1
> Host: ratings:9080
> User-Agent: curl/7.73.0-DEV
> Accept: */*
>
* Mark bundle as not supporting multiuse
  < HTTP/1.1 200 OK
  < content-type: application/json
  < date: Wed, 11 May 2022 17:09:10 GMT
  < x-envoy-upstream-service-time: 18
  < hello: world!
  < server: envoy
  < transfer-encoding: chunked
  <
* Connection #0 to host ratings left intact
  {"id":1,"ratings":{"Reviewer1":5,"Reviewer2":4}}

We should see the < hello: world! header in our response if the filter was deployed successfully.

Summary and Next Steps

In this guide you used Gloo Mesh Enterprise and the Wasm extension to push a Wasm filter to a service managed by Gloo Mesh.

This is a simple example of a Wasm filter to illustrate the concept. The flexibility of Wasm filters coupled with Envoy provides a platform for incredible innovation. Check out our docs on Web Assembly Hub for more information.