For those of you who don't know me too well, I've spent a lot of time around Kubernetes clusters. Managing Kubernetes clusters, writing applications for Kubernetes clusters, architecting solutions that centre around Kubernetes, planning my escape to a sun-bathed island with my own Kubernetes cluster in-hand...a fair bit of time.
A microservice architecture is typical for systems targeting a Kubernetes deployment - a number of loosely-coupled services which communicate frequently over the network, often via a message or event queue. The big reason for this is that Kubernetes can scale individual components of a system in response to a peak or trough of usage. Why scale an entire application when only parts of it are under stress, right?
Not so long ago, an article made it's way into my RSS reader about a CNCF sandbox project called wasmCloud. On the surface, wasmCloud looks like an opinionated but robust way to design and deliver a microservice application architecture.
It's a Kubernetes-like orchestrator for applications that have been compiled to WASM binaries instead of Containers.
Without regurgitating the documentation, there's components for your business logic, capabilities for pluggable functionality (such as messaging via Kafka) and interfaces for defining communication boundaries. As a bonus, you can link WASM runtimes via a "lattice", which is a mesh built upon NATS.
wasmCloud looks like it may be a Kubernetes replacement, running WASM applications instead of Containers. Whilst very similar, in that it provides a level of application orchestration, it can harness a Kubernetes cluster to run WASM applications as well as Containers. You get the benefits of Kubernetes' hardware management and the features of wasmCloud.
wasmCloud doesn't need a Kubernetes cluster to run though. It simply requires a WASM runtime to be installed on a host machine. This WASM runtime can be thought of as a JVM for Java applications, or a .NET runtime for dotnet applications. Thanks to this, the small binary size of WASM applications, and the NATS-based lattice, wasmCloud could be useful in edge computing scenarios - somewhere a Kubernetes deployment doesn't particularly shine.
Containers vs WASM
Why would you use WASM instead of Containers? - Well, let's look at the similarities first:
- Both are good options for polyglot dev teams, though WASM is a little more restrictive in programming language options.
- Both can be stored in an OCI compatible registry for distribution.
- Both enable applications to be run repeatably across multiple hosts.
- Containers aren't portable across CPU architectures though.
Now, some differences:
- Sandboxing
- Containers run a stripped down OS.
- WASM is purely application logic.
- Startup Times
- Containers take a few seconds to start running.
- WASM applications can be running in under a second.
- Multi-threading
- Containers support mutli-threaded applications.
- WASM applications are single-threaded but support asynchronous applications.
- Attack Surface
- For Containers, this depends on the Container OS and the host OS configuration.
- WASM applications run in a sandbox, with protected memory.
The above are just some highlights which I find interesting, there's more to take a look at.
Digging In
After doing a some digging, I found an example of a Rust project for using wasmCloud. It looks a little convoluted.
There seems to be a swath of tooling required, that isn't so visible in the project's documentation right now. This can be remediated quickly through the bolstering of the project's technical documentation, and through providing some tutorials that go below skin deep.
I think there's an opportunity for refinement to improve the developer experience here. Taking a look at some programming language tooling, like the Cargo ecosystem may prove useful. The wasmCloud CLI could include the features of the WebAssembly Compositions CLI and the WASI Virt CLI, perhaps via a Cargo-like plugin system.
Looking a little further into the codebase, I notice that there's a lot of toml
, yaml
and wac
configuration files required for gluing everything together.
This takes me back to the days of writing Oracle SOA applications using SOAP, where you needed WSDL and XSD definitions for your components to work together - it wasn't an experience that I particularly enjoyed as a developer but I do understand that, whilst verbose, it's a way of defining and maintaining an explicit contract of communication.
For the various configuration files that are required, is there a generator available? One that may enable the generation of these files at compile time? My thinking for this would be around providing small language-specific libraries where a developer could implement an interface, or trait. Then the composition part could live in whatever the language's equivalent of Cargo.toml
is.
Maybe a stupid question/idea but there must be a way of consolidating them to reduce the number of steps required to get components communicating with each other.
Looking Forwards
Whilst I feel there is room for improvement when it comes to the developer experience with wasmCloud, I do think that WASM + WASI has to be considered seriously for server-side workloads.
If your application doesn't require multiple CPU threads, there's too many benefits to choosing WASM over a Container: Smaller OCI artifacts have a large impact on the sustainability of a solution, faster start-up times increase developer velocity and decrease scale-out times, application sandboxing reduces the surface of attack available to bad actors...
I don't think that WASM will replace Containers entirely. But I believe we'll certainly see a huge move towards WASM for a lot of use-cases server-side.
I'm certainly going to be keeping an eye on the wasmCloud, WASM and WASI projects.