Deploying WASM Applications to Kubernetes with SpinKube

Deploying WASM Applications to Kubernetes with SpinKube

2025.07.24

Introduction

image.png

SpinKube is an open-source platform that enables native execution of WebAssembly (wasm) applications on Kubernetes.
Unlike traditional container-based approaches, SpinKube leverages Wasm's fast startup and sandbox environment characteristics to provide new workload options in k8s.
This article explains everything from SpinKube's basic concepts to actual deployment.

SpinKube?

SpinKube is a platform for running Fermyon's Spin framework in Kubernetes environments.

By the way, my previous article about the Spin framework is available here.

SpinKube combines k8s, wasm, and spin to integrate wasm apps as native functions of k8s.

SpinKube's Main Components

SpinKube consists of the following components:

  1. Spin Operator
    Uses the k8s operator pattern to manage the lifecycle of Spin applications.
    An operator is a k8s extension program that automatically manages custom resources.

  2. SpinApp CRD
    A custom resource definition for defining Spin applications.
    CRD (Custom Resource Definition) is a mechanism for adding new resource types to k8s.

  3. SpinAppExecutor
    Defines how Spin applications are executed.
    There are two execution methods: containerd-shim-spin which executes WASM directly on the node.
    It's high-performance but complex to configure.
    Spintainer runs Spin in a container.
    This has the advantage of simpler configuration.

SpinKube's Features

SpinKube offers lightweight and fast startup benefits.
Being WASM, images are smaller than traditional ones, saving resources.
Startup is fast with no scaling issues.
Security is also ensured by the Wasm sandbox model.

Environment

  • MacBook Pro (14-inch, M3, 2023)
  • OS : MacOS 14.5
  • Node : 20.19.0
  • Kubernetes: v1.26+ (containerd v1.6.26+/v1.7.7+)

Required Tools

You need to install the following tools:

			
			# Kubernetes related
- kubectl (Kubernetes CLI)
- Helm v3 (Kubernetes package manager)

# Development tools
- Docker / Colima
- k3d or Kind (for local Kubernetes clusters)

# Spin tools
- spin CLI (for Spin application development)
- Rust toolchain (when developing Rust applications)

		

In this article, we will use k3d for local environment setup.

Setup

Let's begin setting up the SpinKube environment.### 1. Installing Required Tools

Install k8s-related tools.
Docker/colima are also required.

			
			% brew install kubectl helm k3d

# Docker / Colima
% brew install --cask docker
# or 
% brew install colima

		

Let's also install Spin and the Rust environment.

			
			# Spin CLI
% curl -fsSL https://developer.fermyon.com/downloads/install.sh | bash
% sudo mv spin /usr/local/bin/

# Rust (for Spin app development)
% curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

		

2. Creating a k3d Cluster

Create a k3d cluster. To avoid DNS resolution issues,
set the K3D_FIX_DNS=0 environment variable:

			
			% K3D_FIX_DNS=0 k3d cluster create spinkube-cluster \
  --port "8081:80@loadbalancer" \
  --agents 2

		

This command creates a standard k3d cluster.

3. Installing SpinKube

Set up the SpinKube environment.

cert-manager (Certificate Management)

cert-manager is a tool that automates certificate issuance and renewal within k8s.
It's necessary to ensure secure communication between SpinKube components.

			
			# Install cert-manager
% kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.5/cert-manager.yaml

# Wait for cert-manager to start
% kubectl wait --for=condition=ready --timeout=300s -n cert-manager pod --all

		

RuntimeClass (Execution Environment Definition)

RuntimeClass specifies which container runtime a Pod should use.
This defines how WASM workloads will be executed.

			
			# Apply RuntimeClass
# Specify containerd-shim-spin
% kubectl apply -f https://github.com/spinkube/containerd-shim-spin/releases/download/v0.19.0/runtime-class-manager.yaml

		

SpinApp CRD (Custom Resource Definition)

CRDs add new resource types to k8s.
This allows Spin apps to be treated as native k8s resources.

			
			# Apply CRDs
% kubectl apply -f https://github.com/spinkube/spin-operator/releases/download/v0.5.0/spin-operator.crds.yaml

		

Spin Operator (Application Management)

Spin Operator automatically manages the lifecycle of Spin applications.
Install it using Helm.

			
			# Install Spin Operator
% helm install spin-operator \
  oci://ghcr.io/spinkube/charts/spin-operator \
  --namespace spin-operator \
  --create-namespace \
  --version 0.5.0 \
  --wait
```### 4. Setting up the Spintainer Executor

We will configure an Executor to run Spin applications.

Previously, we specified containerd-shim-spin in the RuntimeClass.
This defines the execution environment available across the entire cluster.
The Executor specifies "the actual execution method" for each application.
In this case, we'll use `spintainer`.

Let's create the spintainer-executor.yaml.

```yaml
apiVersion: core.spinkube.dev/v1alpha1
kind: SpinAppExecutor
metadata:
  name: spintainer
spec:
  createDeployment: true
  deploymentConfig:
    installDefaultCACerts: true
    spinImage: ghcr.io/fermyon/spin:v3.0.0

		

Let's apply the Executor.

			
			
% kubectl apply -f spintainer-executor.yaml

		

5. Installing the spin kube plugin

Install the plugin needed for developing and deploying Spin applications.

			
			% spin plugins install kube --yes

		

Try

Now, let's create and run an actual Spin application.

1. Creating a Spin application

Let's create a simple HTTP app.

			
			% spin new -t http-rust hello-spinkube --accept-defaults

		

2. Implementation

Implement the API endpoint in src/lib.rs.
This is a simple Hello World level example.

			
			use spin_sdk::http::{IntoResponse, Request, Response};
use spin_sdk::http_component;

#[http_component]
fn handle_hello_spinkube(req: Request) -> anyhow::Result<impl IntoResponse> {
    let path = req.uri().path();
    
    let response = match path {
        "/" => "Welcome to SpinKube!",
        "/hello" => "Hello from WebAssembly running on Kubernetes!",
        "/health" => "OK",
        _ => "Not Found",
    };
    
    Ok(Response::builder()
        .status(200)
        .header("content-type", "text/plain")
        .body(response)
        .build())
}

		

3. Building & pushing the app

Add the WASM target if you haven't already done so.
After that, build and push to the OCI repository.

			
			# Add WASM target (first time only)
% rustup target add wasm32-wasip1

# Build
% spin build

# Push to OCI registry (ttl.sh is a registry valid for 1h)
% export IMAGE_NAME=ttl.sh/hello-spinkube-$(uuidgen):1h
% spin registry push $IMAGE_NAME
```### 4. Generating k8s manifests

Let's generate the manifest (YAML describing k8s configuration).

```bash
% spin kube scaffold --from $IMAGE_NAME > spinapp.yaml

		

Edit the generated manifest as follows:
(Change executor to spintainer)

			
			apiVersion: core.spinkube.dev/v1alpha1
kind: SpinApp
metadata:
  name: hello-spinkube
spec:
  image: "ttl.sh/hello-spinkube-xxx:1h"  # Replace with your actual image name
  executor: spintainer  # Changed from containerd-shim-spin
  replicas: 2

		

5. Testing functionality

Let's run it locally.

			
			% spin up --listen 127.0.0.1:3000

		

Verify with curl. You should see something like this:

			
			% curl http://127.0.0.1:3000/

Welcome to SpinKube!

% curl http://127.0.0.1:3000/hello

Hello from WebAssembly running on Kubernetes!

% curl http://127.0.0.1:3000/health
OK

		

6. Deploy to SpinKube

Now let's deploy the Spin app to k8s.

			
			# Deploy SpinApp
% kubectl apply -f spinapp.yaml

		
			
			% kubectl get spinapp
% kubectl get pods -l core.spinkube.dev/app-name=hello-spinkube

		

Wait for the Pod to start up.

			
			% kubectl wait --for=condition=ready pod -l \
core.spinkube.dev/app-name=hello-spinkube --timeout=120s

		

7. Access

Let's create an ingress.yaml to access the application.

Ingress controls access from outside the cluster to Services within the cluster.
The following configuration sets up domains, paths, and forwarding information.

			
			# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-spinkube
  annotations:
    ingress.kubernetes.io/ssl-redirect: "false"
spec:
  rules:
  - host: hello-spinkube.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: hello-spinkube
            port:
              number: 80

		

The above configuration means that when there's an access to:
http://hello-spinkube.local
it will be forwarded to the hello-spinkube service within the cluster.

Don't forget to apply:

			
			% kubectl apply -f ingress.yaml

		

Let's verify with curl.
This confirms that the Spin app is running properly on k8s.

			
			% curl -H "Host: hello-spinkube.local" http://localhost:8081/

Welcome to SpinKube! Your WebAssembly app is running on Kubernetes!
```## Summary

SpinKube is a platform for running WASM apps in k8s.
By combining WASM and k8s, you can build applications with excellent
performance and security.

As a new alternative to traditional container technology,
please consider SpinKube.

## References

- [SpinKube](https://www.spinkube.dev/)
- [Introducing Spin](https://developer.fermyon.com/spin/index)
- [WASI.dev](https://wasi.dev/)
- [SpinKube GitHub Repository](https://github.com/spinkube/spin-operator)
- [Kubernetes Documentation](https://kubernetes.io/docs/home/)
- [containerd-shim-spin](https://github.com/spinkube/containerd-shim-spin)
- [Fermyon Blog: Introducing SpinKube](https://www.fermyon.com/blog/introducing-spinkube-fermyon-platform-for-k8s)
		

Share this article

FacebookHatena blogX

Related articles