DigitalOcean is a cloud infrastructure provider catering to developers, offering scalable virtual servers, storage solutions, networking services, and managed Kubernetes clusters. It simplifies application deployment, management, and scaling through its intuitive user interface and CLI (doctl
), allowing developers to efficiently utilize cloud resources for their projects.
As part of this article, you'll learn how to
- Provision a new Kubernetes cluster on DigitalOcean
- Deploy SpinKube
- Create a simple WebAssembly app using Spin 💫 and Rust 🦀
- Deploy the Spin App to Kubernetes using an OCI compliant registry
What is SpinKube
SpinKube is an open-source project that allows you to run WebAssembly workloads on top of Kubernetes. Essentially, SpinKube is a stack that consists of the following components:
In addition to running WebAssembly workloads side-by-side with containers, you can run workloads more efficiently and with higher density. Because of WebAssembly’s portability, you can run the same WebAssembly workload on different architectures to reduce cloud spendings even more by using - for example - arm64 worker nodes 🚀.
At KubeCon EU 2024 - The application for contributing SpinKube to the Cloud Native Computing Foundation (CNCF) has been filed. Click here to watch the keynote recording.
Prerequisites
To follow along this article, the following software must be installed on your local machine:
- The Spin CLI (
spin
)- See installation instructions
- The
kube
plugin forspin
- Install it via
spin plugins install kube
- Install it via
- Rust
- See installation instructions
- The
wasm32-wasi
target- Install it via
rustup target add wasm32-wasi
- Install it via
- A DigitalOcean Account & the DigitalOcean CLI (
doctl
) - The Kubernetes CLI (
kubectl
) - The Helm CLI (
helm
)
Although the DigitalOcean account itself is free, you have to provide payment information and you will be charged for allocating resources and renting services - such as the Managed Kubernetes Cluster we will create as part of this article.
1. Provision a Managed Kubernetes Cluster in DigitalOcean
Although the DigitalOcean Control Panel is an easy to grasp UI for provisioning cloud resources, we will use doctl
CLI and its doctl kubernetes cluster create
command to provision the managed Kubernetes cluster. Execute the following command, to provision a cluster consisting of two worker nodes:
# Variables
location=fra1
node_size=s-4vcpu-8gb-intel
# Create a new Kubernetes cluster
doctl kubernetes cluster create my-spinkube-cluster \
--region $location \
--count 2 \
--size $node_size \
--set-current-context \
--wait
DigitalOcean provides different regions and machine sizes for managed Kubernetes clusters. Use
doctl kubernetes options regions
to get a list of all regions. By running
doctl kubernetes options sizes
you get a list of all supported machine sizes for Kubernetes worker nodes.
Once the managed Kubernetes cluster is provisioned, we can double-check if the corresponding context has been added to kubectl
and is marked as the current context:
# List all contexts of kubectlkubectl config get-contexts
CURRENT NAME CLUSTER
* my-spinkube-cluster my-spinkube-cluster
k3d-wasm-cluster k3d-wasm-cluster
# Set current context to my-spinkube-cluster (if not already)
kubectl config use-context my-spinkube-cluster
Switched to context "my-spinkube-cluster".
2. Install SpinKube
On top of its core components, SpinKube depends on cert-manager. cert-Manager
is responsible for provisioning and managing TLS certificates that are used by the admission webhook system of the Spin Operator. Let’s install cert-manager
and KWasm
using the commands shown here:
# Install cert-manager CRDs
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.crds.yaml
# Add Helm repositories jetstack and KWasm
helm repo add jetstack https://charts.jetstack.io
helm repo add kwasm http://kwasm.sh/kwasm-operator
# Update Helm repositories
helm repo update
# Install cert-manager using Helm
helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.14.4
# Install KWasm operator
helm install \
kwasm-operator kwasm/kwasm-operator \
--namespace kwasm \
--create-namespace \
--set kwasmOperator.installerImage=ghcr.io/spinkube/containerd-shim-spin/node-installer:v0.13.1
KWasm will install containerd-shim-spin
on Kubernetes nodes annotated with kwasm.sh/kwasm-node=true
. For the sake of this article, we will annotate all nodes of our cluster using the following command:
# Annotate all Kubernetes nodes with kwasm.sh/kwasm-node=true
kubectl annotate node --all kwasm.sh/kwasm-node=true
Finally, we can install the Spin Operator on the Kubernetes cluster along with necessary Custom Resource Definitions (CRDs), the RuntimeClass
and the SpinAppExecutor
:
# Install SpinKube CRDs
kubectl apply -f https://github.com/spinkube/spin-operator/releases/download/v0.1.0/spin-operator.crds.yaml
# Install a RuntimeClass for wasmtime-spin-v2
kubectl apply -f https://github.com/spinkube/spin-operator/releases/download/v0.1.0/spin-operator.runtime-class.yaml
# Install the containerd-spin-shim SpinAppExecutor
kubectl apply -f https://github.com/spinkube/spin-operator/releases/download/v0.1.0/spin-operator.shim-executor.yaml
# Install Spin Operator with Helm
helm install spin-operator \
--namespace spin-operator \
--create-namespace \
--version 0.1.0 \
--wait \
oci://ghcr.io/spinkube/charts/spin-operator
3. Create a Spin App
Having SpinKube installed on our managed Kubernetes cluster, we can build a simple Spin App for verification purposes. We will use the http-rust
template and apply some small changes to the app generated by spin
:
# Create a new Spin App
spin new -t http-rust --accept-defaults hello-do-k8s
# Move into the Spin App
cd hello-do-k8s
Modify the implementation ( in ./src/lib.rs
) to match the following:
use spin_sdk::http::{IntoResponse, Request, Response};
use spin_sdk::http_component;
#[http_component]
fn handle_hello_do_k8s(req: Request) -> anyhow::Result<impl IntoResponse> {
println!("Handling request to {:?}", req.header("spin-full-url"));
Ok(Response::builder()
.status(200)
.header("content-type", "text/plain")
.body("Hello from DigitalOcean Kubernetes")
.build())
}
With this, we expect our Spin App to respond on incoming HTTP requests with an HTTP 200
, a Content-Type of text/plain
and payload of Hello from DigitalOcean Kubernetes
.
Compile the Spin App using spin build
and use spin up
to test your app locally:
# Build the Spin App
spin build
## snip
Finished release [optimized] target(s) in 8.92s
Finished building all Spin components
# Run the Spin App locally
spin up
Logging component stdio to ".spin/logs/"Serving http://127.0.0.1:3000
Available Routes:
hello-do-k8s: http://127.0.0.1:3000 (wildcard)
# You can terminate the app at any time using CTRL+C
You can test the Spin App locally, by sending an HTTP request to localhost:3000
from within a new terminal instance:
# Send a HTTP GET request to localhost:3000
curl -iX GET http://localhost:3000
HTTP/1.1 200 OK
content-type: text/plain
transfer-encoding: chunked
date: Tue, 25 Mar 2024 11:40:28 GMT
Hello from DigitalOcean Kubernetes
4. Deploy the Spin App via OCI compliant registry
Spin Apps are distributed as OCI artifacts, meaning we can choose from many different container registries for distributing them. For demonstration purposes, we will use ttl.sh (an anonymous and ephemeral Docker image registry) in which the tag of an artifact defines how long the artifact remains available (TTL).
We use the spin registry push
command for distributing Spin Apps through OCI compliant registries.
You can also use the
spin registry login
command to authenticate with private registries and distribute your Spin Apps without making them publicly available at all.
# Build the Spin App
spin build
# Publish the Spin App as OCI artifact
# The artifact will remain accessible for 24 hours (24h tag)
spin registry push ttl.sh/hello-do-k8s:24h
Pushing app to the
Pushed with digest sha256:b77b7cd7644be0b32613cbec1be5049eb96c7e536377165c4c08e1467c4087b2
Finally, we deploy our Spin App to the managed Kubernetes cluster running on DigitalOcean. Again, we use the spin
CLI to scaffold the necessary Kubernetes manifests and pipe them to kubectl
which will interact with Kubernetes API server and provision the SpinApp
custom resource (CR):
# Deploy Spin App to Kubernetes
spin kube scaffold -f ttl.sh/hello-do-k8s:24h | kubectl apply -f -
spinapp.core.spinoperator.dev/hello-do-k8s created
Let’s use kubectl
and take a closer look at what we got:
# List Spin Apps in the default namespacekubectl get spinapps
NAME READY DESIRED EXECUTOR
hello-do-k8s 2 2 containerd-shim-spin
# List Deploymentskubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
hello-do-k8s 2/2 2 2 103s
# List Pods (wide)kubectl get pods -o wide
NAME READY STATUS AGE IP
hello-do-k8s-665676d5bd-9gt4s 1/1 Running 2m14s 10.42.0.7
hello-do-k8s-665676d5bd-5fjpm 1/1 Running 2m14s 10.42.1.7
# List all Services and their Endpointskubectl get services,endpoints
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/hello-do-k8s ClusterIP 10.43.75.164 <none> 80/TCP 4m7s
NAME ENDPOINTS AGE
endpoints/hello-do-k8s 10.42.0.7:80,10.42.1.7:80 4m7s
As you can see, the Spin Operator takes care of all the Kubernetes primitives for running and accessing our Spin App.
Testing the Spin App running on Kubernetes
Let’s configure port forwarding, to access the Spin App using curl
from our local machine:
# Start port-forwarding
kubectl port-forward services/hello-do-k8s 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Use a new terminal instance and send an HTTP request to locahost:8080
and verify receiving the expected response back:
# Send an HTTP GET request to localhost:8080
curl -iX GET http://localhost:8080
HTTP/1.1 200 OK
content-type: text/plain
transfer-encoding: chunked
date: Tue, 25 Mar 2024 11:48:21 GMT
Hello from DigitalOcean Kubernetes
Cleaning up the Cloud Resources
To remove the cloud infrastructure we created as part of this article from your DigitalOcean account, run the following command:
# Delete the DigitalOcean managed Kubernetes cluster
doctl kubernetes cluster delete my-spinkube-cluster --force
Conclusion
By deploying SpinKube onto your managed Kubernetes clusters in DigitalOcean, you can run WebAssembly workloads right beside containers. As WebAssembly apps are way smaller than containers, you can run more workloads on the same amount of compute resources. As you’ve learned in this article, the deployment of SpinKube is simple and requires only a couple of steps.
If you want to learn more about SpinKube, consider reading the SpinKube documentation. There are plenty of tutorials, like, for example: