Microservices with Rust and WASM using Fermyon

B Shyam Sundar
6 min readDec 31, 2022

--

A look at the future of microservices with WASM and Fermyon.

Introduction

WebAssembly is still a nascent technology that requires some more time to become mature and go mainstream. However, there are companies like Fermyon who are in the forefront with WASM. The have built tools for running WASM on the cloud. Today, we will look at, how we can create our own microservice which is built with Rust, compiled to WASM and executed on the Fermyon cloud.

Prerequisites

Tools

  1. Rust (2021 Edition)-Getting started — Rust Programming Language (rust-lang.org)
  2. Spin — Install Spin | Fermyon Developer
  3. A account in Fermyon Cloud — Fermyon Cloud

Knowledge

Before going further, I would recommend some pre-reads. These articles requires some basic knowledge about Rust and WASM.

WASM:

WASM + WASI + WAGI + Web Assembly Modules in Rust | by B Shyam Sundar | Medium

Wasm, WASI, Wagi: What are they? | Fermyon Technologies (@FermyonTech)

Rust:

Learn Rust — Rust Programming Language (rust-lang.org)

Getting Started

Make sure you have Rust and Spin installed.

Then you need to add WASM target to the Rust toolchain. Run the following command to install the target toolchain

rustup target add wasm32-wasi

Spin provides a template list, which we can install using the following command.

spin templates install --git https://github.com/fermyon/spin

If all went well, then you should be seeing

Spin template install

Let us create a new rust project using Spin template. Run

spin new

Select http-rust and set the defaults

New Spin template

This will create a Rust project. Now let us run it.

Running the project

Build and run the project using

spin build --up

You should see

spin build — up

When you curl, you will see

curl -i 127.0.0.1:3000
curl result

We successfully got the response Hello, Fermyon.

Understanding how it works

The dependencies (Cargo.toml)

Cargo.toml

The lib section contains, crate-type = [“cdylib”]. This indicates that this crate has to be built to be a dynamic library. This is required because our library is going to be loaded from another language and at runtime (Browser, Server etc.,). An excellent explanation of by this has to be a dynamic library can be found here: Why must a WASM library in Rust set the crate-type to cdylib? — Stack Overflow

Dependencies:

anyhow —This crate helps in error handling.

bytes — This crate helps in working with bytes easy. This is a mandatory crate as the #[http_component] decorator is dependent on this crate. More on the decorator when we explore the code.

http — Is very helpful when working with common HTTP types, such as requests, response, status code etc.,

spin-sdk — This is the crate that provides the interface which will enable our crate to build http components and execute them in the Fermyon cloud’s runtime.

wit-bindgen-rust — This crate is essential for generating the required Rust WASM bindings for the WASI. This is a key crate that makes our wasm module to run. Two key concepts that help us understand WebAssembly is the concept of Hosts and Guests.

Hosts:

From the repo,

A host exists outside the WebAssembly runtime and can instantiate modules, satisfying their imports and using their exports.

In our case the Host would the Fermyon cloud.

The WebAssembly that runs inside the runtime is called the guest.

Our crate’s module would be the one that runs in the WebAssembly runtime.

Both hosts and guests can both have imports and exports. For example, a guest can import a WASI interface that the host exports to it.

This is key, because, this is how the Fermyon runtime exports the system interface to our module for us to use.

The configuration (spin.toml)

spin.toml

This file contains the configuration required for our spin application. Within this file at least one component section is mandatory.

trigger — Spin supports http and redis. Our application would be triggered by http and the trigger path would be the base path of “/”. Whatever value you give to the “base” attribute will be prepended to all routes of all components.

component — This section contains the configuration of every component in our crate. The “id” parameter has to be unique within the crate. The “source” parameter contains the source of this web assembly module. In our case we have pointed the source to our local built file. However, there are scenarios where we may point it to remote web assembly modules.

component.trigger — Trigger components are the ones that generate event which causes the execution of components. The “route” attribute is point to the root “/” and a wildcard “…” which would mean no matter what which path is passed, this component would be the one invoked. There is another attribute which is not mentioned in the “component.trigger”, that is the “executor”. The default value is “spin” which is what we need now. But, we can also specify WAGI. To know more about WAGI, refer this link.

component.build — This section contains the command that has to executed by the spin cli to build our module.

The code (src/lib.rs)

code

The function in itself is quite simple, we print the request headers and then we add a custom header in the response with the body “Hello, Fermyon”. But the #[http_component] macro is doing a few things behind the scenes. The important thing for us to understand is that the http_component macro generates the code required for WASI binding and the http trigger.

Deploying to the Cloud

After logging into Fermyon cloud, run the following command:

spin login

If all went well, you should see

Fermyon login

Now, to deploy our code to Fermyon Cloud run

spin deploy

If all went well, you should see

spin deploy

Now, curl the URL and you should see

Fermyon output

Now login to the web portal using Fermyon Cloud.

You should see your application along with the logs

Fermyon cloud

Though this example is simple, this actually enables us to write very powerful microservices.

References

Fermyon Developer Portal | Fermyon Developer

Wasm, WASI, Wagi: What are they? | Fermyon Technologies (@FermyonTech)

--

--