Introduction
In the last part, we walk through the journey of how to build and run Spin Apps in a local environment with the support of .NET Aspire. If you haven't read it, I recommend you to check it out at Part 1: Orchestrating Distributed Apps (Spin/Rust and .NET/C#) with .NET Aspire/Dapr.
In this part, we will continue to deploy the apps in the previous part using SpinKube (Azure Kubernetes Service - AKS). To make it more easy to follow, I draw the deployment model below.
Source code: https://github.com/thangchung/dapr-labs/tree/main/aspire
Prerequisites
- az CLI
az version
{
"azure-cli": "2.67.0",
"azure-cli-core": "2.67.0",
"azure-cli-telemetry": "1.1.0",
"extensions": {}
}
- dapr CLI
dapr version
CLI version: 1.14.1
Runtime version: 1.14.4
- spin CLI
cargo --version
cargo 1.83.0 (5ffbef321 2024-10-29)
spin --version
spin 3.1.1 (aa919ce 2024-12-20)
- .NET 9 CLI
dotnet --list-sdks
9.0.100 [C:\Program Files\dotnet\sdk]
- kubectl CLI
kubectl version
Client Version: v1.32.0
Kustomize Version: v5.5.0
- helm CLI
helm version
version.BuildInfo{Version:"v3.16.1", GitCommit:"5a5449dc42be07001fd5771d56429132984ab3ab", GitTreeState:"clean", GoVersion:"go1.22.7"}
Provisioning AKS cluster
Follow the guidance at Deploy an Azure Kubernetes Service (AKS) cluster using Azure CLI to create the AKS cluster. Let's say its name is spinkube-azure-globalazure24
Provisioning SpinKube components
In the past, to make Spin work on the AKS cluster, we needed to install several components and did that manually. Its work might be hard and error-prone. Now, the Fermyon team has introduced SpinKube-Azure, it wraps every component into just one Helm chart, so we can run only 1 command to install those components into AKS as below.
git clone git@github.com:spinframework/azure.git
cd azure
helm install --wait spinkube .
Let's wait a second, then we are ready to go.
Provisioning Dapr components
If you remember in the previous part, we used RabbitMQ for Dapr's pub/sub. So let's work on it on AKS.
RabbitMQ cluster provisioning
helm install rabbit --set service.type=NodePort stable/rabbitmq
# Because of the demo, then we get it password and use it for the next step, not store it in the KeyVault.
echo $(kubectl get secret --namespace rabbit mu-rabbit-rabbitmq -o jsonpath="{.data.rabbitmq-password}" | base64 --decode)
Ref: https://gist.github.com/enesusta/e2ac956104dc0fa4130c795e7270bfc2
Dapr's RabbitMQ pubsub component
Create a Dapr's pub-sub component with the RabbitMQ configuration above.
kubectl apply -f - <<EOF
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: pubsub
namespace: default
spec:
type: pubsub.rabbitmq
version: v1
metadata:
- name: protocol
value: amqp
- name: hostname
value: rabbit-rabbitmq
- name: username
value: user
- name: password
value: <password above step>
EOF
Scaffolding SpinApp and .NET app
- Spin App
spin registry push ttl.sh/thangchung-test-spin:1h --build
- .NET App
dotnet publish ./WebApp/WebApp.csproj --os linux --arch x64 /t:PublishContainer -c Release
Deploy our apps into AKS
kubectl apply -f - <<EOF
apiVersion: core.spinkube.dev/v1alpha1
kind: SpinApp
metadata:
name: test-spin
spec:
image: "ttl.sh/thangchung-test-spin:1h"
executor: containerd-shim-spin
replicas: 1
podAnnotations:
dapr.io/enabled: "true"
dapr.io/app-id: "test-spin"
dapr.io/app-port: "80"
dapr.io/enable-api-logging: "true"
variables:
- name: dapr_url
value: http://localhost:3500
- name: loglevel
value: info
EOF
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
spec:
replicas: 1
selector:
matchLabels:
app: webapp
template:
metadata:
labels:
app: webapp
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "webapp"
dapr.io/app-port: "8080"
dapr.io/enable-api-logging: "true"
spec:
containers:
- name: webapp
image: ttl.sh/thangchung-webapp:1h
imagePullPolicy: Always
env:
- name: TestSpinApp
value: "test-spin"
resources:
# limit the resources to 128Mi of memory and 100m of CPU
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: webapp
spec:
type: LoadBalancer
ports:
- protocol: TCP
port: 5000
targetPort: 8080
selector:
app: webapp
EOF
kubectl apply -f - <<EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: store-front
spec:
ingressClassName: webapprouting.kubernetes.azure.com
rules:
- http:
paths:
- backend:
service:
name: webapp
port:
number: 5000
path: /
pathType: Prefix
EOF
Notes: Make sure you enable
approuting
in AKS, by using:az aks approuting enable --resource-group globalazure24 --name spinkube-azure-globalazure24
AKS Dashboard
Running the distributed apps
- Port forward the web-app
kubectl port-forward services/webapp 5000:5000 -n default
Notes: if you use the
ingress
setup above, then you cancurl
directly into the public IP:kubectl get ingress # it will show the public IP
- Create some traffic
curl http://localhost:5000/item-types
curl -d '{}' http://localhost:5000/ping
- Tail the test-spin-app logs
- Tail the web app logs
Conclusion
This post shows you that we can deploy and run hybrid apps (Spin App and .NET App) with Dapr in place. It is a good start to build up more complex apps in the next posts which I will work on. Thanks for reading it through. Happy deploying ^_^
Top comments (0)