title | description | categories | tags | weight | ||
---|---|---|---|---|---|---|
Publish-Subscribe With Redis |
Learn how to create a Spin application that responds to messages on pub-sub Redis channels and runs in Kubernetes |
|
|
100 |
For this tutorial, we will be using:
- Spin to build and deploy our event-driven WebAssembly application,
- Redis to generate events in our real-time messaging scenario, and
- Rancher Desktop to manage Kubernetes on our Desktop. (This page documents integrating Rancher Desktop and SpinKube.)
First, we create our Kubernetes cluster:
k3d cluster create wasm-cluster --image ghcr.io/spinkube/containerd-shim-spin/k3d:v0.13.1 -p "8081:80@loadbalancer" --agents 2
Next, we apply the necessary Custom Resource Definitions (CRDs) to our Kubernetes cluster:
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.runtime-class.yaml
kubectl apply -f https://github.com/spinkube/spin-operator/releases/download/v0.1.0/spin-operator.shim-executor.yaml
Then, we install Spin Operator which handles the SpinApp
application that we are about to create:
helm install spin-operator \
--namespace spin-operator \
--create-namespace \
--version 0.1.0 \
--wait \
oci://ghcr.io/spinkube/charts/spin-operator
Let's dive in and get Redis sorted because we are going to need information about our Redis installation in our Spin application's config. We will use the following helm
commands to get the job done:
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm install my-redis bitnami/redis
The helm
installation process from above prints a lot of useful information to the terminal. For example, the endpoints to communicate with Redis (read/write vs read-only):
my-redis-master.default.svc.cluster.local for read/write operations (port 6379)
my-redis-replicas.default.svc.cluster.local for read-only operations (port 6379)
In addition, there are pre-written commands that you can cut and paste. For example:
export REDIS_PASSWORD=$(kubectl get secret --namespace default my-redis -o jsonpath="{.data.redis-password}" | base64 -d)
Go ahead and run the command above to set the password. And, if need be, you can run the following command to see the actual password printed in your terminal:
echo $REDIS_PASSWORD
We use Spin's convenient redis-rust
template to scaffold our Rust-based Redis message handler:
spin new -t redis-rust redis-message-handler
The command above will provide the prompts for you to add the Description, Redis address and Redis channel (We use the my-redis-master.default.svc.cluster.local
from above to help configure the Redis address, and the channel is arbitrary i.e. channel-one
):
Description: Redis message handler using Rust
Redis address[redis://localhost:6379]: redis://my-redis-master.default.svc.cluster.local:6379
Redis channel: channel-one
We change into our application directory, and can see the layout that Spin has scaffolded for us:
cd redis-message-handler
tree .
The above tree .
command, produces the following output:
.
├── Cargo.toml
├── spin.toml
└── src
└── lib.rs
If we open the application manifest (spin.toml
file) we see that Spin has already pre-populated the Redis trigger configuration:
// --snip --
[application.trigger.redis]
address = "redis://my-redis-master.default.svc.cluster.local:6379"
[[trigger.redis]]
channel = "channel-one"
component = "redis-message-handler"
// --snip --
By default, Spin does not authenticate to Redis. You can work around this by providing the password in the redis://
URL. For example: address = "redis://:p4ssw0rd@localhost:6379"
Do not use passwords in code committed to version control systems.
In this example, we want to write the logic for our Spin application to listen to messages published on channel-one
. So, we open the src/lib.rs
file and paste the following code:
use anyhow::Result;
use bytes::Bytes;
use spin_sdk::redis_component;
use std::str::from_utf8;
/// A simple Spin Redis component.
#[redis_component]
fn on_message(message: Bytes) -> Result<()> {
println!("{}", from_utf8(&message)?);
Ok(())
}
With the logic and configuration in place, we can build the Spin application:
spin build
We will now push the application image to a registry. You can use any container registry you prefer (like DockerHub). But for this tutorial, we’ll use a simple one that does not require authentication:
spin registry push ttl.sh/redis-message-handler:0.1.0
To read the configuration we can use the spin scaffold
command:
spin kube scaffold --from ttl.sh/redis-message-handler:0.1.0
As we can see, our SpinApp
is all set and using the containerd-shim-spin
executor:
apiVersion: core.spinoperator.dev/v1alpha1
kind: SpinApp
metadata:
name: redis-message-handler
spec:
image: "ttl.sh/redis-message-handler:0.1.0"
executor: containerd-shim-spin
replicas: 2
We deploy our application to our cluster using the spin kube
command:
spin kube deploy --from ttl.sh/redis-message-handler:0.1.0
We want to run the Redis server and publish a message. First, we run the Redis container image:
kubectl run --namespace default redis-client --restart='Never' --env REDIS_PASSWORD=$REDIS_PASSWORD --image docker.io/bitnami/redis:7.2.4-debian-12-r9 --command -- sleep infinity
Then, we want to attach to the pod:
kubectl exec --tty -i redis-client --namespace default -- bash
And, access the Redis CLI from inside the cluster:
REDISCLI_AUTH="$REDIS_PASSWORD" redis-cli -h my-redis-master
Which then provides us with the prompt (my-redis-master:6379>
) at which point we can publish our message:
my-redis-master:6379> PUBLISH channel-one message-one