Deploy a Wasm FaaS on a Pi3 a+

Deploy a Wasm FaaS on a Pi3 a+

Use WASM plug-ins, this is the way!

Small reminder: What is Simplism?

Simplism is a highly lightweight application server that can serve WebAssembly plug-ins via HTTP as microservices speedily and straightforwardly. Simplism is cloud provider-agnostic, allowing you to deploy it anywhere, from a simple Raspberry Pi Zero to Kubernetes.

Then, it's effortless to run Simplism on a Pi, but you can do even more...

Simplism can spawn Simplism!

Simplism brings additional features: a Simplism process can serve as a service discovery, a wasm files registry, and a launcher for other Simplism processes (it's the "spawn mode"). Suppose you combine these three functionalities (along with the system for executing a plugin remotely). In that case, you get a small and simple (yet powerful) Function-as-a-service (FaaS) system that allows serving functions written in different languages. 🎉😲🤩

So, let's do that on a Pi!

This is a Pi3 A+

Pi3 A+ setup

I am not going to detail point by point how to install the OS and configure the Pi, but here are the main steps:

OS Install

Update the Pi hosts file

Edit /etc/hosts:

sudo pico /etc/hosts

Change the first line by adding the local domain of the Pi:

127.0.0.1       localhost starfleet.local

Remote installation of Simplism on the Pi

Now you can connect to the Pi with SSH:

ssh k33g@starfleet.local

Installation of Simplism

In a terminal from the host, run the following command:

ssh k33g@starfleet.local '
SIMPLISM_DISTRO="Linux_arm64"
VERSION="0.1.2"
wget https://github.com/bots-garden/simplism/releases/download/v${VERSION}/simplism_${SIMPLISM_DISTRO}.tar.gz -O simplism.tar.gz
sudo tar -xf simplism.tar.gz -C /usr/bin
rm simplism.tar.gz
simplism version

mkdir -p wasm-files
mkdir -p tmp
'

In the end, you should see this message: simplism v0.1.2 🌍 [earth]

Start Simplism as a FaaS

When you run Simplism as a FaaS, every Simplism process instance will download the Wasm plug-ins remotely. That means you have published the WASM files somewhere, for example, as an asset of a GitHub release, as an item of a GitLab generic package registry, etc...

So, we need to serve the WASM files; for that, we can use the "registry mode" of Simplism.

Start the Registry (always first)

Type the following command:

ssh k33g@starfleet.local -f '
simplism listen ? ? \
--http-port 9000 \
--log-level info \
--information "📦 registry service" \
--registry-mode true \
--registry-path ./wasm-files
'

You should get this message:

🐳 small wasm registry activated
🌍 http server is listening on: 9000

You can check the registry install with this request:

curl http://starfleet.local:9000
# you should get this message
🖖 Live long and prosper 🤗

Start the Spawner

We will start a Simplism instance in "spawn mode". That means we can send requests to this instance to spawn a new Simplism process.

Type the following command:

ssh k33g@starfleet.local -f '
simplism listen ? ? \
--http-port 7000 \
--log-level info \
--service-discovery true \
--information "🚀 spawner service" \
--spawn-mode true \
--http-port-auto true
'

You should get something like this:

😡 Error deleting the db file: remove scratch.wasm.processes.db: no such file or directory
🔎 discovery mode activated: /discovery  ( 7000 )
🚀 this service can spawn other services
🛟 recovery mode activated recovery.yaml
😡 reading the recovery file: open recovery.yaml: no such file or directory
🌍 http server is listening on: 7000

The error messages are "normal": Simplism has a recovery mode to relaunch the WASM services in case of crash or stop/restart. As it's the first launch, there is nothing to re-start.

You can check if the Simplism Spawner is running:

curl http://starfleet.local:7000
# you should get: 🖖 Live long and prosper 🤗

Create and build the WASM plug-ins to deploy

To create and build WASM plug-ins for Simplism, read this blog post: Getting started simple with Simplism.

Then, create some plugins, or you can download these ones:

wget https://github.com/simplism-registry/hello-world/releases/download/v0.0.1/hello-world.wasm
wget https://github.com/simplism-registry/small-cow/releases/download/v0.0.0/small-cow.wasm
wget https://github.com/simplism-registry/small-ant/releases/download/v0.0.0/small_ant.wasm

Download links:

Publish the wasm files to the Simplism registry

To upload hello-world.wasm to the registry, use the following command:

curl http://starfleet.local:9000/registry/push \
-F 'file=@hello-world.wasm'

You should get this output:

📝 uploaded file: ./wasm-files/hello-world.wasm
📐 file size: 194646
📙 MIME header: map[Content-Disposition:[form-data; name="file"; filename="hello-world.wasm"] Content-Type:[application/octet-stream]]
🎉 hello-world.wasm successfully uploaded!

Publish the two other files:

curl http://starfleet.local:9000/registry/push \
-F 'file=@small-cow.wasm'

curl http://starfleet.local:9000/registry/push \
-F 'file=@small_ant.wasm'

The Simplism registry exposes an API to get the list of the published WASM files:

curl http://starfleet.local:9000/registry/discover \
-H 'content-type:text/plain; charset=UTF-8'

If you prefer a JSON output, you need to change the content type header of the request:

curl http://starfleet.local:9000/registry/discover \
-H 'content-type:application/json; charset=UTF-8'

If you want to upload a WASM file with another name (it's helpful to publish several versions of the same plug-in), use this request:

curl http://starfleet.local:9000/registry/push \
-F 'file=@hello.wasm;filename=hello.0.0.1.wasm'

You can delete files and even protect the registry with a token (see the documentation 📝 Use the registry mode).

Now, it's time to deploy and serve the plug-ins.

Deploy WASM functions (plug-ins)

To deploy the hello-world.wasm plug-in and serve it as an HTTP function, use the following command:

curl -X POST \
http://starfleet.local:7000/spawn \
--data-binary @- << EOF
{
    "wasm-file":"./tmp/hello-world.wasm", 
    "wasm-function":"handle",
    "wasm-url": "http://starfleet.local:9000/registry/pull/hello-world.wasm",
    "discovery-endpoint":"http://starfleet.local:7000/discovery", 
    "service-name": "hello-world"
}
EOF

You should get the following output:

🚀 process spawned: hello-world                                                        🚀 hello-world spawned [ 125972 ]
🌍 downloading http://starfleet.local:9000/registry/pull/hello-world.wasm ...
2024/01/21 15:52:43 📝 wasm file written : 194646
👋 this service is discoverable
🌍 http server is listening on: 33989

The WASM file has been downloaded from the registry to the tmp directory, and then a Simplism server (serving the WASM file) has been started listening on 33989.

Now, deploy the two other wasm files:

curl -X POST \
http://starfleet.local:7000/spawn \
--data-binary @- << EOF
{
    "wasm-file":"./tmp/small-cow.wasm", 
    "wasm-function":"handle",
    "wasm-url": "http://starfleet.local:9000/registry/pull/small-cow.wasm",
    "discovery-endpoint":"http://starfleet.local:7000/discovery", 
    "service-name": "small-cow"
}
EOF

curl -X POST \
http://starfleet.local:7000/spawn \
--data-binary @- << EOF
{
    "wasm-file":"./tmp/small-ant.wasm", 
    "wasm-function":"handle",
    "wasm-url": "http://starfleet.local:9000/registry/pull/small_ant.wasm",
    "discovery-endpoint":"http://starfleet.local:7000/discovery", 
    "service-name": "small_ant"
}
EOF

It's possible to protect the spawner and discovery service with tokens, see the documentation 📝 Spawn mode and Discovery Mode (the spawner can act at the service discovery).

Discovering the services

To get the list of the running services, use the following request:

curl http://starfleet.local:7000/discovery \
-H 'content-type:text/plain; charset=UTF-8'

You should get the following output:

Change the value of the content type header if you want a JSON output:

curl http://starfleet.local:7000/discovery \
-H 'content-type:application/json; charset=UTF-8'

Call the services

Call the hello-world service with this request:

curl http://starfleet.local:7000/service/hello-world \
-H 'content-type: application/json; charset=utf-8' \
-d '{"firstName":"Bob","lastName":"Morane"}'

Call the small-cow service with the following request:

curl http://starfleet.local:7000/service/small-cow \
-d '👋 Hello World 🌍'

Call the small-ant service with the following request:

curl http://starfleet.local:7000/service/small_ant \
-d '✋ Hey people 🤗'

And, of course, you can delete (un-deploy) a service with this command:

curl -X DELETE http://starfleet.local:7000/spawn/name/hello-world

In production, you can protect this with an authentication token

That is all for today. Simplism brings a lot of other features. Right now, I'm working on improving the documentation, the structure of the samples and a set of scripts to ease the use of the spawn mode.

Have fun with your Raspberry PI.😊

The FaaS is running on bare metal here: