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
approutingin 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
ingresssetup above, then you cancurldirectly 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)