We recently dove into a post that took readers into creating serverless Rust functions using WebAssembly. We wanted to follow up on that post by introducing you all to a new platform being developed by a startup called Suborbital that is allowing developers to create powerful WASM services in a declarative manner.
In this blog post, we’re going to take a deep dive into what Suborbital brings to the table as far as WebAssembly and how you can leverage that in your environment today.
What is Suborbital?
Suborbital is a cloud-native startup that seeks to leverage the power of WebAssembly to provide a compute platform for serverless developers that is faster and more secure than current compute offerings.
By leveraging the power of Wasm, Suborbital allows teams to build powerful API’s while leveraging third party code in a safe and secure manner. By leveraging a brandable IDE that can be embedded in just about any cloud-provider, engineering teams are able to build flexible and secure Wasm based API’s.
What is Atmo?
Under the hood, Suborbital runs on top of Atmo, their server application environment that leverages WebAssembly to allow developers to build and scale powerful web applications. Atmo used a declarative framework called the Directive format that makes it incredibly easy to create a scalable application without all the boilerplate code.
Now that we’ve talked a bit about what Atmo is, let’s dive into some of the underlying concepts that define its use.
When developers create an application with Atmo, they have the ability to segment the logic of that application into individual functions known as Runnables. By leveraging WebAssembly, Runnables have the ability to be written in any of the supported languages.
At startup, Atmo loads a Bundle of your applications Runnables and uses your application Directive (discussed next) to set up and execute your application.
Your applications Directive is a declarative file that allows you to describe your application's business logic. By describing your application declaratively, you can avoid all of the boilerplate code that normally comes with building a web service such as binding to ports, setting up TLS, constructing a router, etc.
Here's an example Directive:
This directive encapsulates all of the logic for your application. It describes three endpoints and the logic needed to handle them. Each handler describes a set of steps that composes a series of Runnables to handle the request.
The Runnable API
The Runnables that you developer for your Atmo application get compiled to WebAssembly, and are run in a controlled sandbox. The set of capabilities that Atmo grants to the sandbox is called the Runnable API and they are used to build your application's logic.
The Runnable API is provided via a library for each of the supported languages, and simply needs to be imported to turn your module into a Runnable. subo will configure all of this on your behalf.
The foremost basic part of the Runnable API is the Runnable interface (also known as a Rust trait or Swift protocol). Every Runnable you write will provide an instance of an object that conforms to this interface. It is very simple, and only requires one method. for example, in Rust you can run:
You can find more info about the Runnable API here.
Getting Started with Atmo
Installing the Subo CLI tool
We’re now ready to get started with our first Atmo project, but first we need to install the subo CLI tool. Subo is the command-line helper for working with the Suborbital Development Platform. It is used to build Wasm Runnables, generate new projects and config files, and more over time.
If you're on Mac (M1 or Intel), the easiest way to install is via brew:
Install via pre-built binary
If you are a Linux user and prefer to install via one of the pre-built binaries, you can download one of the latest tarballs found on the releases page.
Subo does not have official support for Windows.
Install from source (requires go)
If you use Linux or otherwise prefer to build from source, simply clone this repository or download a source code release archive and run:
This will install subo into your GOPATH ($HOME/go/bin/subo by default) which you may need to add to your shell's $PATH variable.
Verify subo was installed
To verify your installation, let’s run:
Creating a Atmo Project
Now that we have subo installed, we’re ready to create our first Atmo project. To do so, let’s run:
This project will create a Directive.yaml file which we talked a bit about earlier. It will also create an example Runnable called helloworld written in Rust. Again, The Directive file defines route handlers and connects Runnables to them.
In the Directive file, you'll see a handler set up for you that serves the POST /hello route using the helloworld Runnable:
Building a Bundle
To build our bundle, we’re going to want to cd into the important-api directory and run:
This will automatically compile each of your Runnables in a Docker container and bundle them together in runnables.wasm.zip to be used in Atmo. On completion, your output should look about like this:
Deploying Atmo with Zeet
Atmo is distributed as a Docker image titled as suborbital/atmo. This will allow us to easily deploy our project by leveraging Zeet’s powerful abstraction features. When you run the subo create command, Subo is going to create a Dockerfile that will COPY the ./runnables.wasm.zip and add Atmo as an ENTRYPOINT. It should look a lot like this:
Deploying Atmo to Zeet
Now that we’ve created a Dockerfile, it’s time to hop over to Zeet and deploy our project. First, we’ll want to log into Zeet and select Github as our project source:
Then we can move onto actually selecting the repository we’re going to use that contains the Dockerfile:
Then, after selecting our project settings, we’re ready to deploy our service into production!