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)