Skip to content

Commit

Permalink
Merge pull request #357 from gunamata/expanded-wasm-tutorial
Browse files Browse the repository at this point in the history
Expanded Wasm tutorial to cover steps from code to Wasm to containers
  • Loading branch information
gunamata authored Apr 9, 2024
2 parents 8ce1494 + b1b2ce6 commit e771d5d
Show file tree
Hide file tree
Showing 3 changed files with 433 additions and 34 deletions.
157 changes: 145 additions & 12 deletions docs/tutorials/working-with-webassembly.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,35 +26,168 @@ For now additional shims can be installed by the user into the `containerd-shims

Any shim installed there will automatically be copied into the VM and configured for the container engine when Rancher Desktop is started (installing a newer version of the `spin` shim will override the bundled version).

## Running Wasm apps with the container engine
## Developing Wasm Applications with Rancher Desktop

Running WebAssembly applications directly is currently only supported with the `moby` container engine; there is a bug in `nerdctl` that prevents it from working with `containerd`.
Developing Wasm applications on your local machine on top of Rancher Desktop typically involves below steps:

The following command runs the `spin-rust-hello` sample `spin` application on the `moby` engine (note the final `/` on the last line; it is the command to run, and `docker run` will fail if it is omitted):
- Create an application in your programming language of choice. You can compile code written in many languages, such as C, C++, Rust, Go, and others, into Wasm modules
- Compile the code into a Wasm module
- Package the Wasm module as a OCI container image and push to a container registry
- Run the Wasm container and/or
- Deploy the Wasm container into Kubernetes

### Creating a Simple App and Compiling It Into a Wasm Module

You can use the Spin framework from Fermyon to quickly bootstrap a simple Wasm app. Install Spin on your machine following the instructions on the [Installing Spin](https://developer.fermyon.com/spin/v2/install) page.

Once you have successfully installed Spin, create a new app via the command `spin new`.

Select the language you would like to use for development.
```console
$spin new
Pick a template to start your application with:
http-js (HTTP request handler using Javascript)
> http-ts (HTTP request handler using Typescript)
```

Give a name to your app
```console
$spin new
Pick a template to start your application with: http-ts (HTTP request handler using Typescript)
Enter a name for your new application: rd-spin-hello-world
```

Provide an optional description and leave the API route path to default
```console
$spin new
Pick a template to start your application with: http-ts (HTTP request handler using Typescript)
Enter a name for your new application: rd-spin-hello-world
Description []: This is a simple typescript app that will be compiled into a Wasm module and run as a Wasm container
HTTP path: /...
```

Once the command ran successfully, you should see a directory created with the boilerplate code for the Spin app.

Update the `index.ts` file to return a different message than the default.

```console
import { HandleRequest, HttpRequest, HttpResponse } from "@fermyon/spin-sdk"

export const handleRequest: HandleRequest = async function (request: HttpRequest): Promise<HttpResponse> {
return {
status: 200,
headers: { "content-type": "text/plain" },
body: "Hello from Wasm container!"
}
}
```

Change to the app directory and run the `spin build` command to compile the app code into a Wasm module.

```console
$spin build
Building component rd-spin-hello-world with `npm run build`

$ [email protected] build
$ npx webpack --mode=production && mkdir -p target && spin js2wasm -o target/rd-spin-hello-world.wasm dist/spin.js

asset spin.js 4.57 KiB [compared for emit] (name: main)
runtime modules 670 bytes 3 modules
./src/index.ts 2.86 KiB [built] [code generated]
webpack 5.91.0 compiled successfully in 1355 ms

Starting to build Spin compatible module
Spin compatible module built successfully
Finished building all Spin components
```

Once the build command ran successfully, you should see the `rd-spin-hello-world.wasm` module created inside the `target` directory.

### Package the Wasm Module as an OCI Container Image and Push to a Container Registry

Create a `Dockerfile` with below code to package the `Wasm` module as a docker image.

```console
FROM scratch
COPY spin.toml /spin.toml
COPY /target/rd-spin-hello-world.wasm /target/rd-spin-hello-world.wasm
```

Run the command below to package the Wasm module as a container image.

<Tabs groupId="container-runtime">
<TabItem value="nerdctl" default>

```console
nerdctl build \
--namespace k8s.io \
--platform wasi/wasm \
-t ghcr.io/rancher-sandbox/rd-spin-hello-world:0.1.0 .
```

</TabItem>
<TabItem value="docker">

```console
docker buildx build \
--load \
--platform wasi/wasm \
--provenance=false \
-t ghcr.io/rancher-sandbox/rd-spin-hello-world:0.1.0 .
```

</TabItem>
</Tabs>

Push the image to the container registry

<Tabs groupId="container-runtime">
<TabItem value="nerdctl" default>

```console
nerdctl push ghcr.io/rancher-sandbox/rd-spin-hello-world:0.1.0
```

</TabItem>
<TabItem value="docker">

```console
docker push ghcr.io/rancher-sandbox/rd-spin-hello-world:0.1.0
```

</TabItem>
</Tabs>

### Running the Wasm Container

Running a Wasm container directly is currently only supported with the `moby` container engine; there is a bug in `nerdctl` that prevents it from working with `containerd`. Ensure you have selected `dockerd(moby)` as the container engine under [Preferences > Container Engine > General](../ui/preferences/container-engine/general.md) to work through the steps in this section.


The following command runs the `rd-spin-hello-world` sample `spin` application, built in the previous section, on the `moby` engine (note the final `/` on the last line; it is the command to run, and `docker run` will fail if it is omitted):

```console
docker run \
--detach \
--name spin-demo \
--runtime io.containerd.spin.v2 \
--platform wasi/wasm \
--publish 8080:80 \
ghcr.io/deislabs/containerd-wasm-shims/examples/spin-rust-hello:v0.11.1 \
ghcr.io/rancher-sandbox/rd-spin-hello-world:0.1.0 \
/
```

The internal port `80` has been mapped to `8080` and can be tested from the host:

```
$ curl http://localhost:8080/hello
Hello world from Spin!
```console
$ curl http://localhost:8080/
Hello from Wasm container!
```

## Running Wasm apps with Kubernetes
### Running Wasm Apps with Kubernetes

Running WebAssembly applications on Kubernetes is currently only supported with the `containerd` runtime; it doesn't work with the `cri-dockerd` shim used to run Kubernetes on top of `moby`.

Create a deployment for the `spin-rust-hello` sample app:
Create a deployment for the sample Wasm container image built in the previous section:

```console
kubectl apply --filename - <<EOF
Expand All @@ -75,7 +208,7 @@ spec:
runtimeClassName: spin
containers:
- name: hello-spin
image: ghcr.io/deislabs/containerd-wasm-shims/examples/spin-rust-hello:v0.11.1
image: ghcr.io/rancher-sandbox/rd-spin-hello-world:0.1.0
command: ["/"]
EOF
```
Expand Down Expand Up @@ -132,8 +265,8 @@ ingress.networking.k8s.io/hello-spin created
Testing it from the host:

```console
$ curl http://localhost/hello
Hello world from Spin!
$ curl http://localhost/
Hello from Wasm container!
```

### Ingress IP on Windows
Expand Down
155 changes: 144 additions & 11 deletions versioned_docs/version-1.13/tutorials/working-with-webassembly.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,144 @@ For now additional shims can be installed by the user into the `containerd-shims

Any shim installed there will automatically be copied into the VM and configured for the container engine when Rancher Desktop is started (installing a newer version of the `spin` shim will override the bundled version).

## Running Wasm apps with the container engine
## Developing Wasm applications with Rancher Desktop

Running WebAssembly applications directly is currently only supported with the `moby` container engine; there is a bug in `nerdctl` that prevents it from working with `containerd`.
Developing Wasm applications on your local machine on top of Rancher Desktop typically involves below steps:

The following command runs the `spin-rust-hello` sample `spin` application on the `moby` engine (note the final `/` on the last line; it is the command to run, and `docker run` will fail if it is omitted):
- Create an application in your programming language of choice. You can compile code written in many languages, such as C, C++, Rust, Go, and others, into Wasm modules
- Compile the code into a Wasm module
- Package the Wasm module as a OCI contianer image and push to a container registry
- Run the Wasm container and/or
- Deploy the Wasm container into Kubernetes

### Creating a simple app and compiling it into a Wasm module

You can use the Spin framework from Fermyon to quickly bootstrap a simple Wasm app. Install Spin on your machine following the instructions on the [Installing Spin](https://developer.fermyon.com/spin/v2/install) page.

Once you have successfully installed Spin, create a new app via the command `spin new`.

Select the lanaguage you would like to use for development.
```
$spin new
Pick a template to start your application with:
http-js (HTTP request handler using Javascript)
> http-ts (HTTP request handler using Typescript)
```

Give a name to your app
```
$spin new
Pick a template to start your application with: http-ts (HTTP request handler using Typescript)
Enter a name for your new application: rd-spin-hello-world
```

Provide an optional description and leave the API route path to default
```
$spin new
Pick a template to start your application with: http-ts (HTTP request handler using Typescript)
Enter a name for your new application: rd-spin-hello-world
Description []: This is a simple typescript app that will be compiled into a Wasm module and run as a Wasm container
HTTP path: /...
```

Once the command ran successfully, you should see a directory created with the boilerplate code for the Spin app.

Update the `index.ts` file to return a different message than the default.

```
import { HandleRequest, HttpRequest, HttpResponse } from "@fermyon/spin-sdk"
export const handleRequest: HandleRequest = async function (request: HttpRequest): Promise<HttpResponse> {
return {
status: 200,
headers: { "content-type": "text/plain" },
body: "Hello from Wasm container!"
}
}
```

Change to the app diretory and run the `spin build` command to compile the app code into a Wasm module.

```
$spin build
Building component rd-spin-hello-world with `npm run build`
$ [email protected] build
$ npx webpack --mode=production && mkdir -p target && spin js2wasm -o target/rd-spin-hello-world.wasm dist/spin.js
asset spin.js 4.57 KiB [compared for emit] (name: main)
runtime modules 670 bytes 3 modules
./src/index.ts 2.86 KiB [built] [code generated]
webpack 5.91.0 compiled successfully in 1355 ms
Starting to build Spin compatible module
Spin compatible module built successfully
Finished building all Spin components
```

Once the build command ran successfully, you should see the `rd-spin-hello-world.wasm` module created inside the `target` directory.

### Package the Wasm module as a OCI contianer image and push to a container registry

Create a `Dockerfile` with below code to package the `Wasm` module as a docker image.

```
FROM scratch
COPY spin.toml /spin.toml
COPY /target/rd-spin-hello-world.wasm /target/rd-spin-hello-world.wasm
```

Run the command below to package the Wasm module as a container image.

<Tabs groupId="container-runtime">
<TabItem value="nerdctl" default>

```
nerdctl build \
--namespace k8s.io \
--platform wasi/wasm \
-t ghcr.io/rancher-sandbox/rd-spin-hello-world:0.1.0 .
```

</TabItem>
<TabItem value="docker">

```
docker buildx build \
--load \
--platform wasi/wasm \
--provenance=false \
-t ghcr.io/rancher-sandbox/rd-spin-hello-world:0.1.0 .
```

</TabItem>
</Tabs>

Push the image to the container registry

<Tabs groupId="container-runtime">
<TabItem value="nerdctl" default>

```
nerdctl push ghcr.io/rancher-sandbox/rd-spin-hello-world:0.1.0
```

</TabItem>
<TabItem value="docker">

```
docker push ghcr.io/rancher-sandbox/rd-spin-hello-world:0.1.0
```

</TabItem>
</Tabs>

### Running the Wasm container

Running a Wasm container directly is currently only supported with the `moby` container engine; there is a bug in `nerdctl` that prevents it from working with `containerd`. Ensure you have selected `dockerd(moby)` as the container engine under [Preferences > Container Engine > General](../ui/preferences/container-engine/general.md) to work through the steps in this section.


The following command runs the `rd-spin-hello-world` sample `spin` application, built in the previous section, on the `moby` engine (note the final `/` on the last line; it is the command to run, and `docker run` will fail if it is omitted):

```
docker run \
Expand All @@ -39,22 +172,22 @@ docker run \
--runtime io.containerd.spin.v2 \
--platform wasi/wasm \
--publish 8080:80 \
ghcr.io/deislabs/containerd-wasm-shims/examples/spin-rust-hello:v0.11.1 \
ghcr.io/rancher-sandbox/rd-spin-hello-world:0.1.0 \
/
```

The internal port `80` has been mapped to `8080` and can be tested from the host:

```
$ curl http://localhost:8080/hello
Hello world from Spin!
$ curl http://localhost:8080/
Hello from Wasm container!
```

## Running Wasm apps with Kubernetes
### Running Wasm apps with Kubernetes

Running WebAssembly applications on Kubernetes is currently only supported with the `containerd` runtime; it doesn't work with the `cri-dockerd` shim used to run Kubernetes on top of `moby`.

Create a deployment for the `spin-rust-hello` sample app:
Create a deployment for the sample Wasm container image built in the previous section:

```console
kubectl apply --filename - <<EOF
Expand All @@ -75,7 +208,7 @@ spec:
runtimeClassName: spin
containers:
- name: hello-spin
image: ghcr.io/deislabs/containerd-wasm-shims/examples/spin-rust-hello:v0.11.1
image: ghcr.io/rancher-sandbox/rd-spin-hello-world:0.1.0
command: ["/"]
EOF
```
Expand Down Expand Up @@ -132,8 +265,8 @@ ingress.networking.k8s.io/hello-spin created
Testing it from the host:

```console
$ curl http://localhost/hello
Hello world from Spin!
$ curl http://localhost/
Hello from Wasm container!
```

### Ingress IP on Windows
Expand Down
Loading

0 comments on commit e771d5d

Please sign in to comment.