Introduction
Just a couple of days ago, Fermyon Labs published SpinKube, and it gained traction a lot in the community. And Fermyon guys promised to bring WebAssembly/WASI (Spin) to the Kubernetes ecosystem, and they did it. If you don't read about the really exciting news then please read it at Introducing SpinKube and Fermyon Platform for Kubernetes. And then they are also generous enough to submit it to CNCF as a sandbox project.
If you have followed me for enough long, then you will know I supported WebAssembly/WASI when it released the standard, check this repository for my work. And so not long after, I also experimented with Spin by Fermyon and ran it on Kubernetes with sidecar mode enabled (Dapr). And around last year, I felt the future of serverless computing was near after made Spin run on Kubernetes with Dapr enabled run very smoothly.
I came to the meet-up in Vietnam (Ho Chi Minh city) to talk about it in November last year. My topic was WebAssembly/WASI, Docker container, Dapr, and Kubernetes better together
, and look at what I thought about how WebAssembly/WASI fits with Kubernetes and Dapr in the picture below.
Some tweets by the WebAssembly/WASI community after that:
SpinKube architecture
That is cool, right? We can publish the wasm
file using the OCI
standard, we don't need to put it into Dockerfile
anymore, and from that, we can scaffold the wasm
and deploy it into Kubernetes. It makes developer experience handy. And I think the guys at Fermyon, Microsoft Deis Labs, Liquid Reply and SUSE Corporation did excellent work here. Developers who developed the Wasm/Wasi application will benefit from that. Kudos to you, guys ❤️
Just a few days ago, when watching the news from CNCF 2024 organized in France just happened, and saw how SpinKube was announced in this event, I stumbled into their repository and read the docs as well as did some experiments and recognized that that is super easy to get started with SpinApp on Kubernetes 👀
Curiosity, I came to their document to find out if there is any way to run SpinApp with Daprizing App. I found the issue on GitHub at https://github.com/spinkube/documentation/pull/29, struggled to deep dive into the spin-operator
code a bit, and found out the way to run Dapr
on SpinApp, check it out https://github.com/spinkube/spin-operator/issues/192.
So I started to update my example code: the coffeeshop
into the Component Model (blog it later), and try to run it on SpinKube
.
This leads me to sum up what I did in this post below. Now let's get started...
Setup SpinKube and Dapr
Setup SpinKube
as the guidance below (or you can go to https://www.spinkube.dev/docs/spin-operator/quickstart/).
> kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.3/cert-manager.yaml
> kubectl apply -f https://github.com/spinkube/spin-operator/releases/download/v0.1.0/spin-operator.runtime-class.yaml
> kubectl apply -f https://github.com/spinkube/spin-operator/releases/download/v0.1.0/spin-operator.crds.yaml
> kubectl apply -f https://github.com/spinkube/spin-operator/releases/download/v0.1.0/spin-operator.shim-executor.yaml
Install spin-operator
into your Kubernetes cluster:
> helm install spin-operator \
--namespace spin-operator \
--create-namespace \
--version 0.1.0 \
--wait \
oci://ghcr.io/spinkube/charts/spin-operator
Let's install Dapr
into this cluster as well.
# for dev local only otherwise you need to install the Dapr operator on your dev, staging or production environment
> dapr init -k
Install Redis
, because it needs for Dapr:
> helm install my-redis oci://registry-1.docker.io/bitnamicharts/redis --set architecture=standalone --set global.redis.password=P@ssw0rd
Then, install Dapr components into the cluster:
> kubectl apply -f - <<EOF
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: my-redis-master:6379
- name: redisPassword
value: "P@ssw0rd"
- name: actorStateStore
value: "true"
---
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: pubsub
namespace: default
spec:
type: pubsub.redis
version: v1
metadata:
- name: redisHost
value: my-redis-master:6379
- name: redisPassword
value: "P@ssw0rd"
EOF
> kubectl get components
NAME AGE
pubsub 3d4h
statestore 3d4h
Setup and deploy SpinApp (Sidecar with Dapr)
My setup project to start as below:
I write down the product-api
with Rust on WebAssembly Component Model
using Spin to run.
Now, let's deploy it.
> cd product-api
> spin registry push --build ttl.sh/coffeeshop-product-api-spin:24h
Deploy product-api
(SpinApp):
> kubectl apply -f - <<EOF
apiVersion: core.spinoperator.dev/v1alpha1
kind: SpinApp
metadata:
name: product-app
spec:
image: "ttl.sh/coffeeshop-product-api-spin:24h"
executor: containerd-shim-spin
replicas: 1
podAnnotations:
dapr.io/enabled: "true"
dapr.io/app-id: "product-app"
dapr.io/app-port: "80"
dapr.io/enable-api-logging: "true"
EOF
> kubectl get po
NAME READY STATUS RESTARTS AGE
product-app-54d4798948-z55dz 2/2 Running 7 (55m ago) 3d4h
my-redis-master-0 1/1 Running 2 (55m ago) 3d4h
Look at the 2/2
in READY column above. It has 2 containers run on this deployment (one for product-api
, and another one is daprd). It's very easy and cool, right?
Now make an ingress for it, then we are ready to go.
> kubectl apply -f - <<EOF
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: strip-prefix
spec:
stripPrefix:
forceSlash: false
prefixes:
- /p
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: wasm-ingress
annotations:
ingress.kubernetes.io/ssl-redirect: "false"
traefik.ingress.kubernetes.io/router.middlewares: default-strip-prefix@kubernetescrd
spec:
ingressClassName: traefik
rules:
- http:
paths:
- path: /p
pathType: Prefix
backend:
service:
name: product-app
port:
number: 80
EOF
Final step, we curl
it:
> curl http://localhost:8081/p/v1-get-item-types | jq .
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 898 0 898 0 0 211k 0 --:--:-- --:--:-- --:--:-- 292k
[
{
"image": "img/CAPPUCCINO.png",
"item_type": "Cappuccino",
"name": "CAPPUCCINO",
"price": 4.5
},
{
"image": "img/COFFEE_BLACK.png",
"item_type": "CoffeeBlack",
"name": "COFFEE_BLACK",
"price": 3
},
{
"image": "img/COFFEE_WITH_ROOM.png",
"item_type": "CoffeeWithRoom",
"name": "COFFEE_WITH_ROOM",
"price": 3
},
{
"image": "img/ESPRESSO.png",
"item_type": "Espresso",
"name": "ESPRESSO",
"price": 3.5
},
{
"image": "img/ESPRESSO_DOUBLE.png",
"item_type": "EspressoDouble",
"name": "ESPRESSO_DOUBLE",
"price": 4.5
},
{
"image": "img/LATTE.png",
"item_type": "Latte",
"name": "LATTE",
"price": 4.5
},
{
"image": "img/CAKEPOP.png",
"item_type": "Cakepop",
"name": "CAKEPOP",
"price": 2.5
},
{
"image": "img/CROISSANT.png",
"item_type": "Croissant",
"name": "CROISSANT",
"price": 3.25
},
{
"image": "img/MUFFIN.png",
"item_type": "Muffin",
"name": "MUFFIN",
"price": 3
},
{
"image": "img/CROISSANT_CHOCOLATE.png",
"item_type": "CroissantChocolate",
"name": "CROISSANT_CHOCOLATE",
"price": 3.5
}
]
Conclusion
Now, we can use SpinKube
to run any SpinApp
workload, and it will be more effective because we can run some kind of polyglot workload in one Kubernetes cluster (container apps in the CNCF ecosystem and WASM/WASI together). I will continue to work on the coffeeshop
to explore more possibilities in the next couple of weeks. There is far more than this awaiting you in my next posts.
Thanks for your reading ❤️
Top comments (4)
Loved the post Thang! Excellent stuff.
thanks, Sohan. How is your FOSSASIA presentation in Hanoi?
I unfortunately had to decline the talk as I couldn't make it :(
Maybe next year 🤞
What issues does this stack resolve?