Extending Istio with Wasm Plugin

Extending Istio with Wasm Plugin

Wasm plugin in Istio to improve API observability in Kubernetes

Introduction

In the last blog, we built a Wasm plugin for the Envoy proxy to observe API calls passively. This time, we’ll extend the Istio sidecar-based service mesh using that Wasm plugin. So, let’s get started.

As usual, this is also a hands-on tutorial.

Prerequisites

  • Basic understanding of Istio Service Mesh and Kubernetes.

  • Last blog where we built a Wasm Plugin.

  • A Working Kubernetes cluster.

  • A willingness to explore new concepts and technologies.

Overview

Before diving into implementation let’s understand what we’re going to do.

Use case

Our use case is to get observability into API calls made to/from service(s) running in the Kubernetes environment.

I know you’re thinking why can’t we use Istio’s built-in observability?

So let me answer it: We want deep observability of API calls made to/from both East-West and North-South gates and as minimal as possible overhead in the user’s environment. That’s why we opt for a Wasm-based extension.

Implementation

In 2020, Istio announced its support for Wasm-based extensions. So now we can extend it to fulfil our business requirement.

We’ll make use of the following Istio’s Custom Resources:

  • Istio Wasm Plugin - WasmPlugin provides a mechanism to extend the functionality provided by the Istio proxy through WebAssembly filters.

  • Istio EnvoyFilter - EnvoyFilter provides a mechanism to customize the Envoy configuration generated by istiod daemonset.

You can read more about these Custom Resources in Istio’s official docs.

Deploy Istio and Ingestion Service

Istio

First, let’s set up the Istio sidecar mode service mesh.

  • Download the istioctl binary from here.

  • Deploy Istio sidecar-mode service mesh:

istioctl install --set=profile=default -y
  • Enable the envoy proxy sidecar injection by labelling the namespace in which you'll deploy your workload:
kubectl label ns <namespace_name> istio-injection=enabled

Ingestion Service

Now let’s deploy the ingestion service that we built previously.

  • Create a Dockerfile to build its container image:
FROM golang:1.23 AS build

WORKDIR /go/src/app
COPY . .
RUN CGO_ENABLED=0 go build -o /go/bin/app

FROM scratch

EXPOSE 8888
COPY --from=build /go/bin/app /
ENTRYPOINT ["/app", "8888"]
  • Now build and push it:
docker build -t anuragrajawat/ingestion-service:v0.1
docker push anuragrajawat/ingestion-service:v0.1

You can use your container image registry.

  • Finally, create a K8s manifest file to deploy it:
apiVersion: v1
kind: Namespace
metadata:
  name: demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingestion-service
  namespace: demo
spec:
  selector:
    matchLabels:
      app: ingestion-service
  template:
    metadata:
      labels:
        app: ingestion-service
    spec:
      containers:
        - name: ingestion-service
          image: anuragrajawat/ingestion-service:v0.1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8888
---
apiVersion: v1
kind: Service
metadata:
  name: ingestion-service
  namespace: demo
spec:
  selector:
    app: ingestion-service
  ports:
    - port: 8888
      targetPort: 8888
  • Let’s deploy it
kubectl apply -f ingestion-service.yaml
  • Check the status
$ kubectl -n demo get po
NAME                                     READY   STATUS    RESTARTS   AGE
pod/ingestion-service-5546968ddc-zpl5w   1/1     Running   0          24m

As you can see, the ingestion service is running.

Deploy demo application

Let’s deploy a sample application, I’m using the BookInfo application from Istio for demonstration purposes.

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/bookinfo/platform/kube/bookinfo.yaml

Check its status

$ kubectl get po
NAME                                 READY   STATUS    RESTARTS   AGE
pod/details-v1-79dfbd6fff-pgkph      2/2     Running   0          86s
pod/productpage-v1-dffc47f64-v9rpn   2/2     Running   0          86s
pod/ratings-v1-65f797b499-r8ccz      2/2     Running   0          86s
pod/reviews-v1-5c4d6d447c-r7qvd      2/2     Running   0          86s
pod/reviews-v2-65cb66b45c-2fz69      2/2     Running   0          86s
pod/reviews-v3-f68f94645-z6l76       2/2     Running   0          86s

Wasm Plugin Deployment

Let’s create an EnvoyFilter Custom Resource to tell Istio to use our Wasm Plugin.

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: http-filter
spec:
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_OUTBOUND
        listener:
          filterChain:
            filter:
              name: envoy.filters.network.http_connection_manager
              subFilter:
                name: envoy.filters.http.router
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.wasm
          typedConfig:
            "@type": type.googleapis.com/udpa.type.v1.TypedStruct
            typeUrl: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
            value:
              config:
                name: http-filter
                rootId: http-filter
                configuration: # Wasm Plugin configuration so that it can send data to our ingestion service.
                  "@type": "type.googleapis.com/google.protobuf.StringValue"
                  value: |
                    {
                        "upstream_name": "ingestion-service",
                        "authority": "ingestion-service",
                        "path": "/api/v1/events"
                    }
                vmConfig:
                  code:
                    local:
                      filename: /var/local/lib/wasm-filters/httpfilter.wasm # Path to Wasm Plugin
                  runtime: envoy.wasm.runtime.v8
                  vmId: ingestion-service
    - applyTo: CLUSTER
      match:
        context: SIDECAR_OUTBOUND
      patch:
        operation: ADD
        value:
          name: ingestion-service
          type: LOGICAL_DNS
          connect_timeout: 0.5s
          lb_policy: ROUND_ROBIN
          load_assignment:
            cluster_name: ingestion-service
            endpoints:
              - lb_endpoints:
                  - endpoint:
                      address:
                        socket_address:
                          protocol: TCP
                          address: "ingestion-service.demo" # Ingestion service address running in K8s. <service-name.service-namespace>
                          port_value: 8888

Here we’re applying this EnvoyFilter to observe all outbound calls, as you can see the context: SIDECAR_OUTBOUND. Here is the official doc that specifies where you can apply it.

kubectl apply -f envoy-filter.yaml
  • Create a configmap containing the Wasm Plugin binary in the same namespace as your workload:
kubectl create cm wasm-filter --from-file=envoy-wasm-filter/target/wasm32-unknown-unknown/release/httpfilter.wasm
  • Patch the workload to make use of the Wasm Plugin that we want to observe the calls of:
kubectl patch deploy ratings-v1 -p '{"spec":{"template":{"metadata":{"annotations":{"sidecar.istio.io/userVolume":"[{\"name\":\"wasmfilters-dir\", \"configMap\": {\"name\": \"wasm-filter\"}}]",
     "sidecar.istio.io/userVolumeMount": "[{\"mountPath\":\"/var/local/lib/wasm-filters\",\"name\":\"wasmfilters-dir\"}]"}}}}}'

By patching, your workload gets restarted:

  • Now let’s make a call to verify whether the plugin works as intended.
$ kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>
  • Verify whether our plugin is working by checking the logs of the ingestion service running in the demo namespace:
$ kubectl -n demo logs deploy/ingestion-service
2025/01/14 10:31:19 starting ingestion service
2025/01/14 10:31:19 ingestion service is listening on port: 8888
2025/01/14 10:35:08 API Event received
{"metadata":{"context_id":2,"timestamp":1736850908,"traffic_source_name":"Envoy","traffic_source_version":"","node_name":"kind-control-plane"},"request":{"headers":{":path":"/productpage",":method":"GET",":scheme":"http","user-agent":"curl/7.88.1","x-forwarded-proto":"http",":authority":"productpage:9080","accept":"*/*","x-request-id":"3a75d016-110f-4b67-87f4-d9c7fa0a61f2"},"body":""},"response":{"headers":{"content-type":"text/html; charset=utf-8","server":"istio-envoy","vary":"Cookie",":status":"200","content-length":"15066","date":"Tue, 14 Jan 2025 10:35:08 GMT"},"body":"\n<meta charset=\"utf-8\">\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\n\n<title>Simple Bookstore App</title>\n\n<script src=\"static/tailwind/tailwind.css\"></script>\n<script type=\"text/javascript\">\n  window.addEventListener(\"DOMContentLoaded\", (event) => {\n    const dialog = document.querySelector(\"dialog\");\n    const showButton = document.querySelector(\"#sign-in-button\");\n    const closeButton = document.querySelector(\"#close-dialog\");\n\n    if (showButton) {\n      showButton.addEventListener(\"click\", () => {\n        dialog.showModal();\n      });\n    }\n\n    if (closeButton) {\n      closeButton.addEventListener(\"click\", () => {\n        dialog.close();\n      });\n    }\n  })\n</script>\n\n\n\n<nav class=\"bg-gray-800\">\n  <div class=\"container mx-auto px-4 sm:px-6 lg:px-8\">\n    <div class=\"relative flex h-16 items-center justify-between\">\n      <a href=\"#\" class=\"text-white px-3 py-2 text-lg font-medium\" aria-current=\"page\">BookInfo Sample</a>\n      <div class=\"absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0\">\n        \n          <button type=\"button\" id=\"sign-in-button\" class=\"rounded-md bg-blue-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600\">\n            Sign in\n          </button>\n        \n      </div>\n    </div>\n  </div>\n</nav>\n\n<!-- Sign in dialog -->\n<dialog id=\"dialog\" class=\"w-full sm:w-2/3 lg:w-1/3 border rounded-md shadow-xl\">\n  <div class=\"flex min-h-full flex-col justify-center px-6 py-12 lg:px-8\">\n    <div class=\"absolute right-0 top-0 hidden pr-4 pt-4 sm:block\">\n      <button id=\"close-dialog\" type=\"button\" class=\"rounded-md bg-white text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2\">\n        <span class=\"sr-only\">Close</span>\n        <svg class=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" aria-hidden=\"true\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n        </svg>\n      </button>\n    </div>\n    <div class=\"sm:mx-auto sm:w-full sm:max-w-sm\">\n        <svg  class=\"mx-auto h-24 w-auto\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 320 320\"><g id=\"logo\" fill=\"#466BB0\"><polygon id=\"hull\" points=\"80 250 240 250 140 280 80 250\"/><polygon id=\"mainsail\" points=\"80 240 140 230 140 120 80 240\"/><polygon id=\"headsail\" points=\"150 230 240 240 150 40 150 230\"/></g></svg>\n        <h2 class=\"mt-5 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900\">Sign in to BookInfo</h2>\n    </div>\n    <div class=\"mt-10 sm:mx-auto sm:w-full sm:max-w-sm\">\n      <form class=\"space-y-6\" method=\"post\" action='login' name=\"login_form\">\n        <div>\n          <label for=\"email\" class=\"block text-sm font-medium leading-6 text-gray-900\">Username</label>\n          <div class=\"mt-2\">\n            <input id=\"username\" name=\"username\" required class=\"block w-full px-3 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6\">\n          </div>\n        </div>\n        <div>\n          <div class=\"flex items-center justify-between\">\n            <label for=\"password\" class=\"block text-sm font-medium leading-6 text-gray-900\">Password</label>\n          </div>\n          <div class=\"mt-2\">\n            <input id=\"password\" name=\"passwd\" type=\"password\" required class=\"block w-full px-3 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6\">\n          </div>\n        </div>\n        <div>\n          <button type=\"submit\" class=\"flex w-full justify-center rounded-md bg-blue-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600\">Sign in</button>\n        </div>\n      </form>\n      <p class=\"mt-10 text-center text-sm text-gray-500\">\n        Not using Istio yet?\n        <a href=\"https://istio.io\" target=\"_blank\" class=\"font-semibold leading-6 text-blue-600 hover:text-blue-500\">Start here</a>\n      </p>\n    </div>\n  </div>\n</dialog>\n\n<!-- Book description section -->\n<div class=\"container mt-8 mx-auto px-4 sm:px-6 lg:px-8\">\n  <h1 class=\"text-5xl font-bold tracking-tight text-blue-900\">The Comedy of Errors</h1>\n  <div class=\"mt-6 max-w-4xl\">\n    \n    <p class=\"mt-6 text-xl leading-8 text-gray-600\"><a href=\"https://en.wikipedia.org/wiki/The_Comedy_of_Errors\">Wikipedia Summary</a>: The Comedy of Errors is one of <b>William Shakespeare's</b> early plays. It is his shortest and one of his most farcical comedies, with a major part of the humour coming from slapstick and mistaken identity, in addition to puns and word play.</p>\n    \n    <div class=\"mt-6\">\n      <a href=\"https://istio.io\" target=\"_blank\" class=\"text-sm font-semibold leading-6 text-blue-600 hover:text-blue-700\">Learn more about Istio <span aria-hidden=\"true\">→</span></a>\n    </div>\n\n  </div>\n</div>\n\n<!-- Book details table -->\n<div class=\"container mt-8 mx-auto px-4 sm:px-6 lg:px-8\">\n  <div class=\"mt-4 py-10\">\n      <div class=\"max-w-2xl\">\n        <div class=\"flow-root\">\n          \n          <h4 class=\"text-3xl font-semibold\">Book Details</h4>\n          <div class=\"-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8\">\n            <div class=\"inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8\">\n              <table class=\"min-w-full divide-y divide-gray-300\">\n                <thead>\n                  <tr>\n                    <th scope=\"col\" class=\"whitespace-nowrap py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-0\">ISBN-10</th>\n                    <th scope=\"col\" class=\"whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-gray-900\">Publisher</th>\n                    <th scope=\"col\" class=\"whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-gray-900\">Pages</th>\n                    <th scope=\"col\" class=\"whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-gray-900\">Type</th>\n                    <th scope=\"col\" class=\"whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-gray-900\">Language</th>\n                  </tr>\n                </thead>\n                <tbody class=\"divide-y divide-gray-200 bg-white\">\n                  <tr>\n                    <td class=\"whitespace-nowrap py-2 pl-4 pr-3 text-sm text-gray-500 sm:pl-0\">1234567890</td>\n                    <td class=\"whitespace-nowrap px-2 py-2 text-sm font-medium text-gray-900\">PublisherA</td>\n                    <td class=\"whitespace-nowrap px-2 py-2 text-sm text-gray-900\">200</td>\n                    <td class=\"whitespace-nowrap px-2 py-2 text-sm text-gray-500\">paperback</td>\n                    <td class=\"whitespace-nowrap px-2 py-2 text-sm text-gray-500\">English</td>\n                  </tr>\n                </tbody>\n              </table>\n            </div>\n          </div>\n          \n        </div>\n      </div>\n  </div>\n</div>\n\n<!-- Book reviews section -->\n<div class=\"bg-blue-600/5 py-12 mx-auto\" >\n  <div class=\"container mx-auto px-4 sm:px-6 lg:px-8>\n    <div class=\"max-w-2xl\">\n      \n      <h4 class=\"text-3xl font-semibold\">Book Reviews</h4>\n      <div class=\"flex flex-col md:flex-row\">\n        \n        <section class=\"px-6 py-12 sm:py-8 lg:px-8\">\n          <div class=\"mx-auto max-w-2xl\">\n            \n            \n            <div class=\"flex gap-x-1 text-red-500\">\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              \n            </div>\n            \n            \n            <blockquote class=\"mt-10 text-xl font-semibold leading-8 tracking-tight text-gray-900 sm:text-2xl sm:leading-9\">\n              <p>\"An extremely entertaining play by Shakespeare. The slapstick humour is refreshing!\"</p>\n            </blockquote>\n            <div class=\"mt-4 flex items-center gap-x-6\">\n              <img class=\"h-16 w-16 rounded-full bg-gray-50\" src=\"/static/img/izzy.png\" alt=\"Izzy\">\n  \n              <div class=\"text-sm leading-6\">\n                <div class=\"font-semibold text-gray-900\">Reviewer1</div>\n                <div class=\"mt-0.5 text-gray-600 font-mono\">Reviews served by: \n                  reviews-v3-f68f94645-z6l76\n                  \n                </div>\n              </div>\n            </div>\n        </section>\n        \n        <section class=\"px-6 py-12 sm:py-8 lg:px-8\">\n          <div class=\"mx-auto max-w-2xl\">\n            \n            \n            <div class=\"flex gap-x-1 text-red-500\">\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              \n              <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"h-5 w-5 flex-none\">\n                <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z\" />\n              </svg>\n              \n            </div>\n            \n            \n            <blockquote class=\"mt-10 text-xl font-semibold leading-8 tracking-tight text-gray-900 sm:text-2xl sm:leading-9\">\n              <p>\"Absolutely fun and entertaining. The play lacks thematic depth when compared to other plays by Shakespeare.\"</p>\n            </blockquote>\n            <div class=\"mt-4 flex items-center gap-x-6\">\n              <img class=\"h-16 w-16 rounded-full bg-gray-50\" src=\"/static/img/izzy.png\" alt=\"Izzy\">\n  \n              <div class=\"text-sm leading-6\">\n                <div class=\"font-semibold text-gray-900\">Reviewer2</div>\n                <div class=\"mt-0.5 text-gray-600 font-mono\">Reviews served by: \n                  reviews-v3-f68f94645-z6l76\n                  \n                </div>\n              </div>\n            </div>\n        </section>\n        \n      </div>\n      \n    </div>\n    </div>\n  </div>\n</div>\n"},"source":{"name":"ratings-v1-7f5889c69d-fwzsc","namespace":"default","ip":"10.244.0.14","port":57292},"destination":{"name":"","namespace":"","ip":"10.96.6.109","port":9080},"protocol":"HTTP/1.1"}

As you can see, we’re getting logs for this API call.

Improvements

I know you’ve so many questions:

  • Why in this world do I need to restart my workload? I don’t want downtime.

  • Do I need to create configmaps and patch all the workloads I want observability for?

  • These are so many steps isn't there a simpler way to achieve the same?

I hear you and now we’ll address all these pain points.

Currently, we’re manually creating the configmap containing the Wasm plugin binary in each namespace that we want to observe workloads. And after that, we’re restarting the workloads. We’ll streamline this so we don’t have to repeat this painful process.

Wasm Plugin Image

Let’s create a container image for our Wasm plugin so that we can use it directly just like we do with other services.

Create a Dockerfile in the Wasm Plugin directory as follows:

FROM rust:1.81.0 AS builder

WORKDIR /envoy-plugin

COPY . .

RUN make toolchain build

FROM scratch

COPY --from=builder /envoy-plugin/target/wasm32-unknown-unknown/release/httpfilters.wasm ./plugin.wasm

Build and push the image:

Deployment

Now we’ll make use of both EnvoyFilter and WasmPlugin Istio custom resources.

Let’s update the EnvoyFilter as follows:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: http-filter
  # Deploy the filter to whatever istio considers its "root" namespace so that we
  # don't have to create the ConfigMap(s) containing the WASM filter binary,
  # and the associated annotations/configuration for the Istio sidecar(s).
  # https://istio.io/latest/docs/reference/config/istio.mesh.v1alpha1/#MeshConfig:~:text=No-,rootNamespace,-string
  namespace: istio-system
spec:
  configPatches:
    - applyTo: CLUSTER
      match:
        context: SIDECAR_OUTBOUND
      patch:
        operation: ADD
        value:
          name: ingestion-service
          type: LOGICAL_DNS
          connect_timeout: 1s
          lb_policy: ROUND_ROBIN
          load_assignment:
            cluster_name: ingestion-service
            endpoints:
              - lb_endpoints:
                  - endpoint:
                      address:
                        socket_address:
                          protocol: TCP
                          address: ingestion-service.demo # Ingestion service address running in K8s. <service-name.service-namespace>
                          port_value: 8888

Create a WasmPlugin CR manifest file as follows:

apiVersion: extensions.istio.io/v1alpha1
kind: WasmPlugin
metadata:
  name: http-filter
  namespace: istio-system
spec:
  # Do not cause all requests to fail with 5xx.
  # Bypass the plugin execution on plugin issues.
  # https://istio.io/latest/docs/reference/config/proxy_extensions/wasm-plugin/#FailStrategy
  failStrategy: FAIL_OPEN
  match:
    - mode: CLIENT
  pluginConfig:
    upstream_name: ingestion-service
    authority: ingestion-service
    path: /api/v1/events
  pluginName: http-filter
  type: HTTP
  url: anuragrajawat/httpfilter:final # Change this to your image while trying locally

We’re creating both the EnvoyFilter and WasmPlugin in istio-system so we don’t have to create a Wasm plugin configmap for all the individual namespaces.

Delete the previously applied EnvoyFilter, configmap and annotations:

kubectl delete -f envoy-filter.yaml
kubectl delete cm wasm-filter
kubectl patch deploy ratings-v1 -p '{"spec":{"template":{"metadata":{"annotations":{"sidecar.istio.io/userVolume": null, "sidecar.istio.io/userVolumeMount": null}}}}}'

Let’s apply the new manifest files:

kubectl apply -f envoy-filter-simplified.yaml -f wasm-plugin.yaml

Again generate some traffic and check the captured logs for API calls in the ingestion service:

$ kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>
$ kubectl -n demo logs deploy/ingestion-service
# Existing logs
2025/01/14 10:42:43 API Event received
{"metadata":{"context_id":2,"timestamp":1736851363,"traffic_source_name":"Envoy","traffic_source_version":"","node_name":"kind-control-plane"},"request":{"headers":{"user-agent":"curl/7.88.1","accept":"*/*",":path":"/productpage",":scheme":"http","x-request-id":"4f0c9c96-8241-49b6-87f9-0af573d69f42",":authority":"productpage:9080",":method":"GET","x-forwarded-proto":"http"},"body":""},"response":{"headers":{"date":"Tue, 14 Jan 2025 10:42:43 GMT","vary":"Cookie","server":"istio-envoy",":status":"200","content-length":"15072","content-type":"text/html; charset=utf-8"},"body":"\n<meta charset=\"utf-8\">\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\n\n<title>Simple Bookstore App</title>\n\n<script src=\"static/tailwind/tailwind.css\"></script>\n<script type=\"text/javascript\">\n  window.addEventListener(\"DOMContentLoaded\", (event) => {\n    const dialog = document.querySelector(\"dialog\");\n    const showButton = document.querySelector(\"#sign-in-button\");\n    const closeButton = document.querySelector(\"#close-dialog\");\n\n    if (showButton) {\n      showButton.addEventListener(\"click\", () => {\n        dialog.showModal();\n      });\n    }\n\n    if (closeButton) {\n      closeButton.addEventListener(\"click\", () => {\n        dialog.close();\n      });\n    }\n  })\n</script>\n\n\n\n<nav class=\"bg-gray-800\">\n  <div class=\"container mx-auto px-4 sm:px-6 lg:px-8\">\n    <div class=\"relative flex h-16 items-center justify-between\">\n      <a href=\"#\" class=\"text-white px-3 py-2 text-lg font-medium\" aria-current=\"page\">BookInfo Sample</a>\n      <div class=\"absolute inset-y-0 right-0 flex items-center pr-2 sm:static sm:inset-auto sm:ml-6 sm:pr-0\">\n        \n          <button type=\"button\" id=\"sign-in-button\" class=\"rounded-md bg-blue-600 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600\">\n            Sign in\n          </button>\n        \n      </div>\n    </div>\n  </div>\n</nav>\n\n<!-- Sign in dialog -->\n<dialog id=\"dialog\" class=\"w-full sm:w-2/3 lg:w-1/3 border rounded-md shadow-xl\">\n  <div class=\"flex min-h-full flex-col justify-center px-6 py-12 lg:px-8\">\n    <div class=\"absolute right-0 top-0 hidden pr-4 pt-4 sm:block\">\n      <button id=\"close-dialog\" type=\"button\" class=\"rounded-md bg-white text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2\">\n        <span class=\"sr-only\">Close</span>\n        <svg class=\"h-6 w-6\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" aria-hidden=\"true\">\n          <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n        </svg>\n      </button>\n    </div>\n    <div class=\"sm:mx-auto sm:w-full sm:max-w-sm\">\n        <svg  class=\"mx-auto h-24 w-auto\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 320 320\"><g id=\"logo\" fill=\"#466BB0\"><polygon id=\"hull\" points=\"80 250 240 250 140 280 80 250\"/><polygon id=\"mainsail\" points=\"80 240 140 230 140 120 80 240\"/><polygon id=\"headsail\" points=\"150 230 240 240 150 40 150 230\"/></g></svg>\n        <h2 class=\"mt-5 text-center text-2xl font-bold leading-9 tracking-tight text-gray-900\">Sign in to BookInfo</h2>\n    </div>\n    <div class=\"mt-10 sm:mx-auto sm:w-full sm:max-w-sm\">\n      <form class=\"space-y-6\" method=\"post\" action='login' name=\"login_form\">\n        <div>\n          <label for=\"email\" class=\"block text-sm font-medium leading-6 text-gray-900\">Username</label>\n          <div class=\"mt-2\">\n            <input id=\"username\" name=\"username\" required class=\"block w-full px-3 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6\">\n          </div>\n        </div>\n        <div>\n          <div class=\"flex items-center justify-between\">\n            <label for=\"password\" class=\"block text-sm font-medium leading-6 text-gray-900\">Password</label>\n          </div>\n          <div class=\"mt-2\">\n            <input id=\"password\" name=\"passwd\" type=\"password\" required class=\"block w-full px-3 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-blue-600 sm:text-sm sm:leading-6\">\n          </div>\n        </div>\n        <div>\n          <button type=\"submit\" class=\"flex w-full justify-center rounded-md bg-blue-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600\">Sign in</button>\n        </div>\n      </form>\n      <p class=\"mt-10 text-center text-sm text-gray-500\">\n        Not using Istio yet?\n        <a href=\"https://istio.io\" target=\"_blank\" class=\"font-semibold leading-6 text-blue-600 hover:text-blue-500\">Start here</a>\n      </p>\n    </div>\n  </div>\n</dialog>\n\n<!-- Book description section -->\n<div class=\"container mt-8 mx-auto px-4 sm:px-6 lg:px-8\">\n  <h1 class=\"text-5xl font-bold tracking-tight text-blue-900\">The Comedy of Errors</h1>\n  <div class=\"mt-6 max-w-4xl\">\n    \n    <p class=\"mt-6 text-xl leading-8 text-gray-600\"><a href=\"https://en.wikipedia.org/wiki/The_Comedy_of_Errors\">Wikipedia Summary</a>: The Comedy of Errors is one of <b>William Shakespeare's</b> early plays. It is his shortest and one of his most farcical comedies, with a major part of the humour coming from slapstick and mistaken identity, in addition to puns and word play.</p>\n    \n    <div class=\"mt-6\">\n      <a href=\"https://istio.io\" target=\"_blank\" class=\"text-sm font-semibold leading-6 text-blue-600 hover:text-blue-700\">Learn more about Istio <span aria-hidden=\"true\">→</span></a>\n    </div>\n\n  </div>\n</div>\n\n<!-- Book details table -->\n<div class=\"container mt-8 mx-auto px-4 sm:px-6 lg:px-8\">\n  <div class=\"mt-4 py-10\">\n      <div class=\"max-w-2xl\">\n        <div class=\"flow-root\">\n          \n          <h4 class=\"text-3xl font-semibold\">Book Details</h4>\n          <div class=\"-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8\">\n            <div class=\"inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8\">\n              <table class=\"min-w-full divide-y divide-gray-300\">\n                <thead>\n                  <tr>\n                    <th scope=\"col\" class=\"whitespace-nowrap py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-0\">ISBN-10</th>\n                    <th scope=\"col\" class=\"whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-gray-900\">Publisher</th>\n                    <th scope=\"col\" class=\"whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-gray-900\">Pages</th>\n                    <th scope=\"col\" class=\"whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-gray-900\">Type</th>\n                    <th scope=\"col\" class=\"whitespace-nowrap px-2 py-3.5 text-left text-sm font-semibold text-gray-900\">Language</th>\n                  </tr>\n                </thead>\n                <tbody class=\"divide-y divide-gray-200 bg-white\">\n                  <tr>\n                    <td class=\"whitespace-nowrap py-2 pl-4 pr-3 text-sm text-gray-500 sm:pl-0\">1234567890</td>\n                    <td class=\"whitespace-nowrap px-2 py-2 text-sm font-medium text-gray-900\">PublisherA</td>\n                    <td class=\"whitespace-nowrap px-2 py-2 text-sm text-gray-900\">200</td>\n                    <td class=\"whitespace-nowrap px-2 py-2 text-sm text-gray-500\">paperback</td>\n                    <td class=\"whitespace-nowrap px-2 py-2 text-sm text-gray-500\">English</td>\n                  </tr>\n                </tbody>\n              </table>\n            </div>\n          </div>\n          \n        </div>\n      </div>\n  </div>\n</div>\n\n<!-- Book reviews section -->\n<div class=\"bg-blue-600/5 py-12 mx-auto\" >\n  <div class=\"container mx-auto px-4 sm:px-6 lg:px-8>\n    <div class=\"max-w-2xl\">\n      \n      <h4 class=\"text-3xl font-semibold\">Book Reviews</h4>\n      <div class=\"flex flex-col md:flex-row\">\n        \n        <section class=\"px-6 py-12 sm:py-8 lg:px-8\">\n          <div class=\"mx-auto max-w-2xl\">\n            \n            \n            <div class=\"flex gap-x-1 text-black-500\">\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              \n            </div>\n            \n            \n            <blockquote class=\"mt-10 text-xl font-semibold leading-8 tracking-tight text-gray-900 sm:text-2xl sm:leading-9\">\n              <p>\"An extremely entertaining play by Shakespeare. The slapstick humour is refreshing!\"</p>\n            </blockquote>\n            <div class=\"mt-4 flex items-center gap-x-6\">\n              <img class=\"h-16 w-16 rounded-full bg-gray-50\" src=\"/static/img/izzy.png\" alt=\"Izzy\">\n  \n              <div class=\"text-sm leading-6\">\n                <div class=\"font-semibold text-gray-900\">Reviewer1</div>\n                <div class=\"mt-0.5 text-gray-600 font-mono\">Reviews served by: \n                  reviews-v2-65cb66b45c-2fz69\n                  \n                </div>\n              </div>\n            </div>\n        </section>\n        \n        <section class=\"px-6 py-12 sm:py-8 lg:px-8\">\n          <div class=\"mx-auto max-w-2xl\">\n            \n            \n            <div class=\"flex gap-x-1 text-black-500\">\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              <svg id=\"glyphicon glyphicon-star\" class=\"h-5 w-5 flex-none\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n                <path fill-rule=\"evenodd\" d=\"M10.868 2.884c-.321-.772-1.415-.772-1.736 0l-1.83 4.401-4.753.381c-.833.067-1.171 1.107-.536 1.651l3.62 3.102-1.106 4.637c-.194.813.691 1.456 1.405 1.02L10 15.591l4.069 2.485c.713.436 1.598-.207 1.404-1.02l-1.106-4.637 3.62-3.102c.635-.544.297-1.584-.536-1.65l-4.752-.382-1.831-4.401z\" clip-rule=\"evenodd\" />\n              </svg>\n              \n              \n              <svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke-width=\"1.5\" stroke=\"currentColor\" class=\"h-5 w-5 flex-none\">\n                <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M11.48 3.499a.562.562 0 0 1 1.04 0l2.125 5.111a.563.563 0 0 0 .475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 0 0-.182.557l1.285 5.385a.562.562 0 0 1-.84.61l-4.725-2.885a.562.562 0 0 0-.586 0L6.982 20.54a.562.562 0 0 1-.84-.61l1.285-5.386a.562.562 0 0 0-.182-.557l-4.204-3.602a.562.562 0 0 1 .321-.988l5.518-.442a.563.563 0 0 0 .475-.345L11.48 3.5Z\" />\n              </svg>\n              \n            </div>\n            \n            \n            <blockquote class=\"mt-10 text-xl font-semibold leading-8 tracking-tight text-gray-900 sm:text-2xl sm:leading-9\">\n              <p>\"Absolutely fun and entertaining. The play lacks thematic depth when compared to other plays by Shakespeare.\"</p>\n            </blockquote>\n            <div class=\"mt-4 flex items-center gap-x-6\">\n              <img class=\"h-16 w-16 rounded-full bg-gray-50\" src=\"/static/img/izzy.png\" alt=\"Izzy\">\n  \n              <div class=\"text-sm leading-6\">\n                <div class=\"font-semibold text-gray-900\">Reviewer2</div>\n                <div class=\"mt-0.5 text-gray-600 font-mono\">Reviews served by: \n                  reviews-v2-65cb66b45c-2fz69\n                  \n                </div>\n              </div>\n            </div>\n        </section>\n        \n      </div>\n      \n    </div>\n    </div>\n  </div>\n</div>\n"},"source":{"name":"ratings-v1-65f797b499-k5j28","namespace":"default","ip":"10.244.0.15","port":35596},"destination":{"name":"","namespace":"","ip":"10.96.6.109","port":9080},"protocol":"HTTP/1.1"}

As you can see, we're still getting logs for the outbound call. This time, we didn't do much; we just created an EnvoyFilter and a WasmPlugin.

That’s it for now. You can find the complete code here.

Please feel free to comment or criticize :)

Summary

In this hands-on tutorial, we explore extending the Istio sidecar-based service mesh using a WebAssembly (Wasm) plugin for advanced API call observability in a Kubernetes environment. The guide covers deploying Istio, setting up an ingestion service, and using Istio's Custom Resources to implement the Wasm plugin. We address common concerns about deploying Wasm plugins, streamline the process with Wasm plugin container images, and simplify the integration with Istio through updated EnvoyFilter and WasmPlugin resources. The article also emphasizes enhancing observability with minimal overhead and provides practical implementation steps.

References