Welcome to the last lecture. Consider it the bonus lecture. WebAssembly is a strong (not-quite-anymore) newcomer to the field of cloud native. It is the right time to know what it is and to play around with a few usecases.

Last Updated: 2024-03-17

Why

What if Kubernetes is too bloated for my tiny function and I just want this function to run anywhere. And securely in a sandbox. And irrespective of what language it's written in. And no matter what architecture.

What

We will cover the following topics:

What you'll build today

By the end of today's lecture, you should have

Homework (Flipped Classroom)

How should I prepare

PreRead

What you'll need

Now: what on earth is webassembly, and why does it not really have anything to do with web?

Short answer: it came from the web, and the need to put more computationally expensive operations into browsers , so something was needed to combine with javascript ...

In the beginning, there was the internet and browser wars and applets

If you want to read the history of webassembly, please go through the TUW library to https://learning.oreilly.com/library/view/webassembly-the-definitive/9781492089834/

For our purposes, WASM is a framework to combine software elements built from different toolchains, over a share-nothing interface (WIT) , running in an architecture independent runtime, with an extremely small footprint.

We can export and import, and compose software. By default there is "shared nothing linking" so you need to explicitly expose your interfaces and they are strongly typed.

One of the most salient features of Webassembly is the component model, which is based on common open standards for runtime, type-interface, binary-format and build approach.

Not only can you interact with ANY wasm artefact, no matter what architecture it was built on. Also, you can run it on any runtime. There is something akin to Docker-Compose, and we will meet various runtimes, that you can either have directly on your machine, or on top of kubernetes, or somewhere else serverside as a PaaS.

https://static.sched.com/hosted_files/colocatedeventsna2023/ba/Bailey-Kate-CloudNativeWasmDay-NA-2023.pptx.pdf

In this KubeCon2023 talk, the authors demo the component model, by stating that no user should ever be able to get to the business logic without first going through the Auth middleware.

Also, we see the cli-import which is dealing with interacting with the WebAssembly host to e.g. get secrets from the environment.

Now, the Auth Middleware component has access to these cli-provided secrets, but the BusinessLogic Component does not (there is no wasi:cli/environment Import)

Demo 1 : Component Model Demo (like in Chicago WASMDay 2023)

Constanze, will demo this live and you can do this as homework and get the code from:

<this assumes you have the whole setup of the later Hands-on labs working>
git clone git@github.com:AustrianDataLAB/spin.git
make componentmodeldemo

[2024-06-24T14:31:25Z WARN ] instance `wasi:cli/terminal-stderr@0.2.0-rc-2023-10-18` will be imported because a dependency named `wasi:cli/terminal-stderr@0.2.0-rc-2023-10-18` could not be found
composed component `service.wasm`
Finished building all Spin components
Logging component stdio to "example/.spin/logs/"

Serving http://127.0.0.1:3000
Available Routes:
  example: http://127.0.0.1:3000 (wildcard)
no access token found in incoming request
no access token found in incoming request
no access token found in incoming request
authenticated
authenticated

You can find more runtimes in the github repo and you should play with wasmtime or deploy it to fermyon cloud https://github.com/fermyon/http-auth-middleware

Important to remember is, that you can deploy the *wasm binaries on any of the clouds and some of the standards are already on all runtimes (such as the key-value interface) , others (how to pass environment vars) are in the moment being standardized.

Server side Webassembly

Can you run WASM on or in Kubernetes? Yes.

Can you convert a Docker Container to WASM ? Yes (but that's more of a hack)

Can you run WASM inside a Container? Yes

Can you run WASM inside WASM? Yes (but ... but .. but ...)

https://cosmonic.com/k8s

https://static.sched.com/hosted_files/colocatedeventseu2024/2f/WasmDay%20EU%20Keynote%202024.pdf

Lets look at some internals: if we compare it to (docker) containers, we see that it isnt a packaging format. Rather it is a compile target that runs on anything as long as whatever is on that computer is running the webassembly runtime (there are currently several). The WASM runtime then uses a system interface to talk to the OS of the underlying computer .

This immediately achieves a few things:

https://static.sched.com/hosted_files/kccnceu2024/5e/Cloud%20Native%20Wasm%20and%20How%20to%20Use%20It.pdf

Lets see what projects are out there and how they differ

WASM has its own tile

https://landscape.cncf.io

So : when should you use WASM?

Let's get all setup

Follow the onboarding on fermyon

In the following class, we ll need rust and several runtimes: you can natively install them OR put them into a container. . Or do as you please.

ALL of today's examples are in RUST, but you can switch them out for GO if you want to rewrite it all.

If you need rust:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add wasm32-wasi 

(you can choose to put all of this into a rust container , then you dont have to clutter up your laptop docker run --rm -it rust:1-slim-buster )

https://developer.fermyon.com/cloud/quickstart

At step3 , please choose Cloud Start as the sample application.

You may have to put `spin` into your PATH (container or native OS)

[OPTIONAL] docker run --rm -it rust:1-slim-buster
curl -fsSL https://developer.fermyon.com/downloads/install.sh | bash
rustup target add wasm32-wasi
./spin login
git clone https://github.com/fermyon/cloud-start && cd cloud-start
❯ ls
Cargo.lock Cargo.toml LICENSE    Makefile   README.md  spin.toml  src        target
❯ ../spin cloud deploy
Uploading cloud_start version 0.1.0 to Fermyon Cloud...
Deploying...
Waiting for application to become ready......... ready
View application:   https://cloud-start-XXXXXX.fermyon.app/
Manage application: https://cloud.fermyon.com/app/cloud_start

We ll talk about what just happened,

Now, onto something slightly more interesting :

Cool, now you have a minimal UI and you can use it as a reminder app \o/

Exercise 1 :

  1. Test your rust - situation by modifying the cloud start up a tiny bit and running `Make`

Once, you can deploy a new version of the cloud-start app, you should have a look at `lib.rs` and understand how the javascript is executed .

And WHERE

Running WASM on kubernetes

https://www.spinkube.dev/docs/overview/

1 Install on kind

https://www.spinkube.dev/docs/spin-operator/installation/installing-with-helm/

(unless you already have clone the AustrianOpenCloudCommunity/spin repo, clone it now.)

git clone git@github.com:AustrianDataLAB/spin.git
make kind
make spin-operator
make application

git clone https://github.com/spinkube/spin-operator.git

It is possible (via spin) to push spin-apps to OCI registries, like ghcr.io

https://developer.fermyon.com/spin/v2/registry-tutorial , there are still many wasm apps around that don't support OCI.

From here we follow the tutorial here (it s all in your makefile)

https://www.spinkube.dev/docs/spin-operator/tutorials/assigning-variables/

Exercise:

Write you own app following the tutorial here

https://www.spinkube.dev/docs/spin-operator/tutorials/package-and-deploy/

WASM runtime and WASI

https://static.sched.com/hosted_files/kccnceu2024/5e/Cloud%20Native%20Wasm%20and%20How%20to%20Use%20It.pdf

make wasmtime
curl localhost:8080
Hello, wasi:http/proxy world!

If it complains about workspace conflicts with the Cargo.toml on the higher level, add line 9 : and empty workspace directive to the Cargo.toml of the hello-wasi-http

Adding standard components such as logs and DB

Lets install more stuff, yaya

Install `wash` https://wasmcloud.com/docs/installation - Run through the quickstart https://wasmcloud.com/docs/tour/hello-world - Add persistent storage and logging https://wasmcloud.com/docs/tour/adding-capabilities - Scale and distribute

wash new component hello --template-name hello-world-rust
... downloading nats
... starting wadm
... downloading wasmcloud 
cd hello
wash build
wasmtime serve -Scommon build/http-hello_world_s.wasm

wasm-tools component wit  build/http-hello_world_s.wasm

Now , lets add some additional components

First, look at the wadm.yaml -> it should remind you strongly of something 🙂

wash app deploy wadm.yaml 
wash app list
wash get inventory
❯ curl localhost:8080
Hello from Rust!

Exercise 2:

You can alternatively use the rust lib.rs from Constanze s git repo, since she had to make some more edits to the code to get it to work.

#![allow(clippy::missing_safety_doc)]
wit_bindgen::generate!();

use exports::wasi::http::incoming_handler::Guest;
use wasi::http::types::*;


struct HttpServer;

impl Guest for HttpServer {
   fn handle(request: IncomingRequest, response_out: ResponseOutparam) {
       // Get the path & query to the incoming request
       let path_with_query = request
           .path_with_query()
           .expect("failed to get path with query");

       // At first, we can assume the object name will be the path with query
       // (ex. simple paths like '/some-key-here')
       let mut object_name = path_with_query.clone();

     
       let mut link_name = "default";

       
       if let Some((path, query)) = path_with_query.split_once('?') {
           object_name = path.to_string();

           let query_params = query
               .split('&')
               .filter_map(|v| v.split_once('='))
               .collect::<Vec<(&str, &str)>>();

      
           if let Some((_, configured_link_name)) = query_params
               .iter()
               .find(|(k, _v)| k.to_lowercase() == "link_name")
           {
               link_name = configured_link_name;
           }
       }
       wasi::logging::logging::log(
           wasi::logging::logging::Level::Info,
           "",
           &format!("Greeting {link_name}"),
       );
       

              let bucket = wasi::keyvalue::store::open("").expect("failed to open empty bucket");
       let count = wasi::keyvalue::atomics::increment(&bucket, &object_name, 1)
           .expect("failed to increment count");

       // Build & send HTTP response
       let response = OutgoingResponse::new(Fields::new());
       response.set_status_code(200).unwrap();
       let response_body = response.body().unwrap();
       response_body
           .write()
           .unwrap()
           .blocking_write_and_flush(format!("Counter {object_name}: {count}\n").as_bytes())
           .unwrap();
       OutgoingBody::finish(response_body, None).expect("failed to finish response body");
       ResponseOutparam::set(response_out, Ok(response));
   }
}

export!(HttpServer);
package wasmcloud:hello;

world hello {

  import wasi:keyvalue/atomics@0.2.0-draft; 
  import wasi:keyvalue/store@0.2.0-draft; 
  import wasi:logging/logging;
  export wasi:http/incoming-handler@0.2.0;
}

docker run -d --name redis -p 6379:6379 redis
wash build
wash app delete rust-hello-world wash app list
wash app deploy wadm.yaml
❯ curl localhost:8080/hiLVA
Counter /hiLVA: 1

You can check in your redis, that the keys really are being incremented:

docker exec -it redis redis-cli KEYS '*'
1) "World"
2) "/hiLVA"
3) "Bob"
docker exec -it redis redis-cli GET '/hiLVA'
"1"

WASM runtime and WASI

https://static.sched.com/hosted_files/kccnceu2024/5e/Cloud%20Native%20Wasm%20and%20How%20to%20Use%20It.pdf

https://llamaedge.com/

make llm
(by default it loads the gemma-2b-it-Q5 model)
(if you havnt predownloaded it, it ll take a while)

You can find more examples here https://github.com/second-state/WasmEdge-WASINN-examples/blob/master/README.md

Fear not, we got you covered

You're almost there :)

Cant wait to see the finished products

Dont forget that you can make your audience play "a certain part" and make sure that the audience knows what your team did (most people have no idea what the other teams really worked on, so put an overview graphic somewhere)

Congratulations, you've successfully completed this training on WebAssembly and some different WASM runtimes

What's next?

Further