构建运行 WebAssembly 的 unikernel – 第 1 部分
Building a unikernel that runs WebAssembly – part 1

原始链接: https://flavio.castelli.me/2023/02/07/building-a-unikernel-that-runs-webassembly---part-1/

在 Hackweek 22 期间,Flavio Castelli 致力于通过他的个人项目构建一个运行 WebAssembly 的 unikernel,以探索混合 unikernels 和 WebAssembly 的可能性。 Unikernels 通常需要付出巨大的努力来适应各种系统原语,而 WebAssembly 提供了一组清晰的功能,这些功能仍然隐藏在表面之下,使开发变得更加容易,特别是在 Spiderlightning 等场景中。 为了创建 unikernel 应用程序,他使用了 RustyHermit 框架,与基于 BPF 构建的传统 unikernel 相比,该框架由于其简单性而已成为标准选择。 尽管最初遇到了涉及 Web 组装组件模型(Hyperledger Lumberjack 团队提出的 WebAssembly 组件模型提案)的兼容性问题的障碍,但他设法使用 wit-bindgen 克服了这些障碍,并将其扩展为处理 Rust 的异步功能。 他演示了使用 Rust 和 Redis 成功执行 Spiderlightning HTTP 服务器演示。 总的来说,unikernels 和 WebAssembly 的结合在效率、安全性和易于采用方面提供了令人兴奋的可能性,特别是在云平台或容器化应用程序中创建隔离环境时。 简而言之,此过程为开发人员提供了更大的控制权,同时减少资源消耗并提高性能,而不会影响稳健性或敏捷性。 尽管这种方法需要更密集的前期投资和严格的工程原理,但它在节省成本、更快的部署时间和简化的维护流程方面带来了巨大的好处。 随着技术的不断进步,与单独使用任一选项相比,提供更高效率水平和更高灵活性的混合解决方案变得越来越普遍。 With the convergence of disparate technologies driving new synergies between software architectures and hardware infrastructure, the future holds numerous opportunities for innovation, optimization, and experimentation through the intersection of both worlds. 总之,Flavio 对 unikernels 与 Web-Assembly 集成的持续探索是释放现代分布式系统真正潜力的重要一步,为跨不同计算环境的各个组件和服务提供有效的隔离机制。 通过他的实践经验,读者可以深入了解开发满足现代数据中心需求的高性能、安全且多功能的架构的好处和挑战。 作者利用 Rust、Redis 和 WebAssembly 在最小的开销时间内成功地展示了关键概念,取得了显着的成果。 通过分享实用技巧和宝贵的经验教训

这是令人着迷的,互补的。
相关文章

原文

Hackweek 22 took place last week. During this week all the SUSE employees are free to hack on whatever they want. This one of the perks of working at SUSE 😎.

This time my personal project has been about building a unikernel that runs WebAssembly.

I wanted this blog post to contain all the details about this journey. However I realized this would have been too much for a single post. I hence decided to split everything into smaller chunks. I’ll update this section to keep track of all the posts.

In the meantime, you can find the code of the POC here.

Why

There are multiple reasons why I did that, but I don’t want to repeat what I wrote inside of the project description. Learning and fun goals aside, I think there’s actually a good reason to mix unikernels and WebAssembly.

From the application developer POV, porting/writing an application to the unikernel is not an easy task. The application and all its dependencies have to support the target unikernel. Some patching might be required inside of the whole application stack to make it work.

From the unikernel maintainers POV, they have to invest quite some energies to ensure any kind of application can run in a seamless way on top of their platform. They don’t know which kind of system primitives the user applications will leverage, this makes everything harder.

On the other hand, when targeting a WebAssembly platform (think of Spin or Spiderlightning), the application has a clear set of capabilities that have to be provided by the WebAssembly runtime.

If you look at the Spiderlightning scenario, an application might be requiring Key/Value store capabilities at runtime. However, how these capabilities are implemented on the host side is not relevant to the application. That means the same .wasm module can be run by a runtime that implements the K/V store using Redis or using Azure Cosmos DB. That would be totally transparent to the end user application.

You might see where I’m going with all that…

If we write a unikernel application that runs WebAssembly modules and supports a set of Spiderlightning APIs, then the same Spiderlightning application could be run both on top of the regular slight runtime and of this unikernel.

All of that without any additional work from the application developer. The Wasm module wouldn’t even realize that. The complexity would fall only on the unikernel developer who, whoever, would have a clear set of functionalities to implement (as opposed to “let’s try to make any kind of application work”).

How

Sometimes ago I stumbled over the RustyHermit project, this is a unikernel written in Rust. I decided to use it as the foundation to write my unikernel application.

Building a RustyHermit application is pretty straightforward. Their documentation, even though is a bit scattered, is good and their examples help a lot.

The cool thing is that RustyHermit is part of Rust nightly, which makes the whole developer experience great. It feels like writing a regular Rust application.

Obviously you cannot expect all kind of Rust crates to just work with RustyHermit. You will see how that influenced the development of the POC.

The next sections go over some of the major challenges I faced during the last week. I’ll share more details inside of the upcoming blog posts (see the disclaimer section at the top of the page).

The WebAssembly runtime

Unfortunately Wasmtime, my favorite WebAssembly runtime, does not build on top of RustyHermit. Many of its dependencies expect libc or other low level libraries to be around. The same applies to wasmer.

I thought about using something like WebAssembly Micro Runtime (WAMR), but I preferred to stick with something written in Rust and have the “full RustyHermit experience”.

After some searching I found wasmi a pure Rust WebAssembly runtime. This works fine on top of RustyHermit, plus its design is inspired by the one of Wasmtime, which allowed me to reuse a lot of my previous knowledge.

WebAssembly Component Model

Spiderlightning leverages the WebAssembly Component Model proposal to offer capabilities to the WebAssembly guests and to allow the host to consume capabilities offered by the WebAssembly guest.

The communication between the host and the guest happens using types defined with the Wasm Interface Type.

To give some concrete examples, the demo I’m going to run leverages the WebAssembly Component Model in these ways:

  • The guest asks the host to start a HTTP server. When doing that, the guest informs the host about the HTTP routes that have to be registered, plus the names of its internal handlers (the functions that have to be executed). This is done by using the http-server types. In this case it’s the guest that leverages capabilities offered by the host.
  • The host handles the incoming HTTP requests using the routing information provided by the guest. The http handlers mentioned before are functions exposes by the WebAssembly guest. The server is now consuming capabilities offered by the guest. The communication is done using the http-handler types.
  • Some of the http handlers defined by the guest are also interacting with a Key/Value store. Also in this case the guest is leveraging a set of capabilities offered by the host. These are defined using the keyvalue types.

As you can see there are many WIT types involved. For each one of them we need code both inside of the guest (a SDK basically) and on the host (the code that implements the guest SDK). This code can be scaffolded by a cli tool called wit-bindgen, which generates host/guest code starting from a .wit file.

In this case I only had to implement the host side of these interfaces inside of the unikernel.

The code generated by wit-bindgen is doing low level operations using the WebAssembly runtime. The code to be scaffolded depends on the programming language and on the WebAssembly runtime used on the host side.

Obviously the wasmi WebAssembly runtime was not supported by wit-bindgen, hence I had to extend wit-bindgen to handle it. The code can be found inside of this fork, under the wasmi branch.

With all of that in place, I scaffolded the host side of the Key/Value capability and I made a simple implementation of the host traits. The host code was just emitting some debug information. I was then able run the vanilla keyvalue-demo from the Spiderlightning project. 🥳

Summary

You made to the bottom of this long post, kudos! I think you deserve a prize for that, so here we go…

This is a recording of the unikernel application running the Spiderlightning http-server demo.

A screencast of the unikernel application running the Spiderlightning http-server demo

I hope you enjoyed the reading. Stay tuned for the next part of the journey. This will cover Rust async, Redis and some weird errors.

联系我们 contact @ memedata.com