diff --git a/README.md b/README.md
index f4398ed..60ffeeb 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,686 @@
# Dapr with ASP.NET Core in Docker Compose and Kubernetes deployment test
-> Warning: This project is not yet complete to run in Kubernetes. It is still in development.
+The aim of this project is to provide a simple reference on how to perform local development ana then deploy a C# Dapr powered microservices application in Kubernetes. This project demonstrates the deployment of a sample application using RabbitMQ for messaging and Redis for state management, leveraging Dapr to simplify the development of distributed applications.
+
+## Project Structure
+
+The project includes the following components:
+
+* RabbitMQ: A message broker used for pub/sub messaging.
+* Redis: A key-value store used for state management.
+* Publisher App: A C# microservice that publishes messages to RabbitMQ and set Redis shared state.
+* Subscriber App: A C# microservice that subscribes to messages from RabbitMQ and read Redis shared state.
+
+## Requirements
+
+To deploy this C# microservices application in Kubernetes with Dapr support, you need the following:
+
+* Kubernetes: A running Kubernetes cluster (version 1.18 or later recommended).
+kubectl command-line tool configured to interact with your Kubernetes cluster.
+* Configured Storage Class: A configured storage class in your Kubernetes cluster to provision persistent storage for stateful components like Redis.
+* Dapr: Dapr CLI installed (version 1.0 or later). Dapr initialized in your Kubernetes cluster.
+
+In case you decide to build images from source code on your own, you also need:
+
+* Container registry: A configured container registry, such as Harbor or Docker Hub.
+
+In case of local development (no Kubernetes required):
+
+* Visual Studio 2022 Community: An integrated development environment (IDE) for developing C# applications.
+* .NET 8 SDK: The software development kit for building and running .NET applications.
+* Rancher Desktop or Docker Desktop: Tools for running Docker containers on your local machine.
+
+## Deployment
+
+The deployment is done using Kubernetes manifests for each component, including Dapr components for pub/sub and state management.
+Sample application can be installed via [Yaml](#yaml-deployment) or [Powershell](#powershell-deployment) deployment
+
+### Yaml deployment
+
+```yaml
+# RabbitMQ
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: rabbitmq
+ namespace: dapr-test
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: rabbitmq
+ template:
+ metadata:
+ labels:
+ app: rabbitmq
+ spec:
+ containers:
+ - name: rabbitmq
+ image: rabbitmq:3-management
+ ports:
+ - containerPort: 5672 # RabbitMQ port
+ - containerPort: 15672 # RabbitMQ management port
+ env:
+ - name: RABBITMQ_DEFAULT_USER
+ value: admin
+ - name: RABBITMQ_DEFAULT_PASS
+ value: password
+ - name: RABBITMQ_DEFAULT_VHOST
+ value: "/"
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: rabbitmq-service
+ namespace: dapr-test
+spec:
+ selector:
+ app: rabbitmq
+ ports:
+ - name: amqp
+ protocol: TCP
+ port: 5672
+ targetPort: 5672
+ - name: management
+ protocol: TCP
+ port: 15672
+ targetPort: 15672
+
+---
+
+# Redis
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: redis
+ namespace: dapr-test
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: redis
+ template:
+ metadata:
+ labels:
+ app: redis
+ spec:
+ containers:
+ - name: redis
+ image: redis:6.2.6
+ ports:
+ - containerPort: 6379
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: redis-service
+ namespace: dapr-test
+spec:
+ selector:
+ app: redis
+ ports:
+ - protocol: TCP
+ port: 6379
+ targetPort: 6379
+
+---
+
+# Publisher App
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: publisher
+ namespace: dapr-test
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: publisher
+ template:
+ metadata:
+ labels:
+ app: publisher
+ annotations:
+ dapr.io/enabled: "true"
+ dapr.io/app-id: "publisher"
+ dapr.io/app-port: "5000" # Adjust to your service port
+ spec:
+ containers:
+ - name: publisher
+ image: cr.maks-it.com/dapr-test/subscriber:latest
+ ports:
+ - containerPort: 5000 # Match your internal app port
+ env:
+ - name: ASPNETCORE_ENVIRONMENT
+ value: Development
+ - name: ASPNETCORE_HTTP_PORTS
+ value: 5000
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: publisher-service
+ namespace: dapr-test
+spec:
+ selector:
+ app: publisher
+ ports:
+ - protocol: TCP
+ port: 80
+ targetPort: 5000 # Match the internal port of the publisher service
+
+---
+
+# Subscriber App
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: subscriber
+ namespace: dapr-test
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: subscriber
+ template:
+ metadata:
+ labels:
+ app: subscriber
+ annotations:
+ dapr.io/enabled: "true"
+ dapr.io/app-id: "subscriber"
+ dapr.io/app-port: "5000" # Adjust to match the subscriber service port
+ spec:
+ containers:
+ - name: subscriber
+ image: cr.maks-it.com/dapr-test/subscriber:latest
+ ports:
+ - containerPort: 5000 # Match the internal port of the subscriber service
+ env:
+ - name: ASPNETCORE_ENVIRONMENT
+ value: Development
+ - name: ASPNETCORE_HTTP_PORTS
+ value: 5000
+
+---
+
+# Dapr PubSub
+
+apiVersion: dapr.io/v1alpha1
+kind: Component
+metadata:
+ name: pubsub
+ namespace: dapr-test
+spec:
+ type: pubsub.rabbitmq
+ version: v1
+ metadata:
+ - name: connectionString
+ value: "amqp://admin:password@rabbitmq:5672"
+ - name: durable
+ value: "false"
+ - name: deletedWhenUnused
+ value: "false"
+ - name: autoAck
+ value: "true"
+ - name: reconnectWait
+ value: "0"
+ - name: concurrency
+ value: parallel
+
+---
+
+# Dapr StateStore
+
+apiVersion: dapr.io/v1alpha1
+kind: Component
+metadata:
+ name: statestore
+ namespace: dapr-test
+spec:
+ type: state.redis
+ version: v1
+ metadata:
+ - name: redisHost
+ value: redis:6379
+ - name: keyPrefix
+ value: none
+
+---
+
+apiVersion: dapr.io/v1alpha1
+kind: Component
+metadata:
+ name: privatestatestore
+ namespace: dapr-test
+spec:
+ type: state.redis
+ version: v1
+ metadata:
+ - name: redisHost
+ value: redis:6379
+
+---
+
+apiVersion: dapr.io/v1alpha1
+kind: Component
+metadata:
+ name: actorsstatestore
+ namespace: dapr-test
+spec:
+ type: state.redis
+ version: v1
+ metadata:
+ - name: redisHost
+ value: redis:6379
+ - name: actorStateStore
+ value: "true"
+
+```
+
+### Powershell deployment
+
+```powershell
+kubectl create namespace dapr-test `
+
+# RabbitMQ
+@{
+ apiVersion = "apps/v1"
+ kind = "Deployment"
+ metadata = @{
+ name = "rabbitmq"
+ namespace = "dapr-test"
+ }
+ spec = @{
+ replicas = 1
+ selector = @{
+ matchLabels = @{
+ app = "rabbitmq"
+ }
+ }
+ template = @{
+ metadata = @{
+ labels = @{
+ app = "rabbitmq"
+ }
+ }
+ spec = @{
+ containers = @(
+ @{
+ name = "rabbitmq"
+ image = "rabbitmq:3-management"
+ ports = @(
+ @{
+ containerPort = 5672 # RabbitMQ port
+ },
+ @{
+ containerPort = 15672 # RabbitMQ management port
+ }
+ )
+ env = @(
+ @{
+ name = "RABBITMQ_DEFAULT_USER"
+ value = "admin"
+ },
+ @{
+ name = "RABBITMQ_DEFAULT_PASS"
+ value = "password"
+ },
+ @{
+ name = "RABBITMQ_DEFAULT_VHOST"
+ value = "/"
+ }
+ )
+ }
+ )
+ }
+ }
+ }
+} | ConvertTo-Json -Depth 10 | kubectl apply -f - `
+
+@{
+ apiVersion = "v1"
+ kind = "Service"
+ metadata = @{
+ name = "rabbitmq-service"
+ namespace = "dapr-test"
+ }
+ spec = @{
+ selector = @{
+ app = "rabbitmq"
+ }
+ ports = @(
+ @{
+ name = "amqp"
+ protocol = "TCP"
+ port = 5672
+ targetPort = 5672
+ },
+ @{
+ name = "management"
+ protocol = "TCP"
+ port = 15672
+ targetPort = 15672
+ }
+ )
+ }
+} | ConvertTo-Json -Depth 10 | kubectl apply -f - `
+
+# Redis
+@{
+ apiVersion = "apps/v1"
+ kind = "Deployment"
+ metadata = @{
+ name = "redis"
+ namespace = "dapr-test"
+ }
+ spec = @{
+ replicas = 1
+ selector = @{
+ matchLabels = @{
+ app = "redis"
+ }
+ }
+ template = @{
+ metadata = @{
+ labels = @{
+ app = "redis"
+ }
+ }
+ spec = @{
+ containers = @(
+ @{
+ name = "redis"
+ image = "redis:6.2.6"
+ ports = @(
+ @{
+ containerPort = 6379 # Redis port
+ }
+ )
+ }
+ )
+ }
+ }
+ }
+} | ConvertTo-Json -Depth 10 | kubectl apply -f - `
+
+@{
+ apiVersion = "v1"
+ kind = "Service"
+ metadata = @{
+ name = "redis-service"
+ namespace = "dapr-test"
+ }
+ spec = @{
+ selector = @{
+ app = "redis"
+ }
+ ports = @(
+ @{
+ protocol = "TCP"
+ port = 6379
+ targetPort = 6379
+ }
+ )
+ }
+} | ConvertTo-Json -Depth 10 | kubectl apply -f - `
+
+# Publisher App
+@{
+ apiVersion = "apps/v1"
+ kind = "Deployment"
+ metadata = @{
+ name = "publisher"
+ namespace = "dapr-test"
+ }
+ spec = @{
+ replicas = 1
+ selector = @{
+ matchLabels = @{
+ app = "publisher"
+ }
+ }
+ template = @{
+ metadata = @{
+ labels = @{
+ app = "publisher"
+ }
+ annotations = @{
+ "dapr.io/enabled" = "true"
+ "dapr.io/app-id" = "dapr-test-publisher"
+ "dapr.io/app-port" = "5000" # Adjust to your service port
+ }
+ }
+ spec = @{
+ containers = @(
+ @{
+ name = "publisher"
+ image = "cr.maks-it.com/dapr-test/publisher:latest" # Corrected image name
+ imagePullPolicy = "Always"
+ ports = @(
+ @{
+ containerPort = 5000 # Match your internal app port
+ }
+ )
+ env = @(
+ @{
+ name = "ASPNETCORE_HTTP_PORTS"
+ value = "5000"
+ },
+ @{
+ name = "ASPNETCORE_ENVIRONMENT"
+ value = "Development"
+ }
+ )
+ }
+ )
+ }
+ }
+ }
+} | ConvertTo-Json -Depth 10 | kubectl apply -f - `
+
+@{
+ apiVersion = "v1"
+ kind = "Service"
+ metadata = @{
+ name = "publisher-service"
+ namespace = "dapr-test"
+ }
+ spec = @{
+ selector = @{
+ app = "publisher"
+ }
+ ports = @(
+ @{
+ protocol = "TCP"
+ port = 80
+ targetPort = 5000 # Match the internal port of the publisher service
+ }
+ )
+ }
+} | ConvertTo-Json -Depth 10 | kubectl apply -f - `
+
+# Subscriber App
+@{
+ apiVersion = "apps/v1"
+ kind = "Deployment"
+ metadata = @{
+ name = "subscriber"
+ namespace = "dapr-test"
+ }
+ spec = @{
+ replicas = 1
+ selector = @{
+ matchLabels = @{
+ app = "subscriber"
+ }
+ }
+ template = @{
+ metadata = @{
+ labels = @{
+ app = "subscriber"
+ }
+ annotations = @{
+ "dapr.io/enabled" = "true"
+ "dapr.io/app-id" = "dapr-test-subscriber"
+ "dapr.io/app-port" = "5000" # Adjust to match the subscriber service port
+ }
+ }
+ spec = @{
+ containers = @(
+ @{
+ name = "subscriber"
+ image = "cr.maks-it.com/dapr-test/subscriber:latest"
+ imagePullPolicy = "Always"
+ ports = @(
+ @{
+ containerPort = 5000 # Match the internal port of the subscriber service
+ }
+ )
+ env = @(
+ @{
+ name = "ASPNETCORE_HTTP_PORTS"
+ value = "5000"
+ },
+ @{
+ name = "ASPNETCORE_ENVIRONMENT"
+ value = "Development"
+ }
+ )
+ }
+ )
+ }
+ }
+ }
+} | ConvertTo-Json -Depth 10 | kubectl apply -f - `
+
+# Dapr PubSub
+@{
+ apiVersion = "dapr.io/v1alpha1"
+ kind = "Component"
+ metadata = @{
+ name = "dapr-test-pubsub"
+ namespace = "dapr-test"
+ }
+ spec = @{
+ type = "pubsub.rabbitmq"
+ version = "v1"
+ metadata = @(
+ @{
+ name = "connectionString"
+ value = "amqp://admin:password@rabbitmq-service:5672"
+ },
+ @{
+ name = "durable"
+ value = "false"
+ },
+ @{
+ name = "deletedWhenUnused"
+ value = "false"
+ },
+ @{
+ name = "autoAck"
+ value = "true"
+ },
+ @{
+ name = "reconnectWait"
+ value = "0"
+ },
+ @{
+ name = "concurrency"
+ value = "parallel"
+ }
+ )
+ }
+} | ConvertTo-Json -Depth 10 | kubectl apply -f - `
+
+# Dapr StateStore
+@{
+ apiVersion = "dapr.io/v1alpha1"
+ kind = "Component"
+ metadata = @{
+ name = "dapr-test-statestore"
+ namespace = "dapr-test"
+ }
+ spec = @{
+ type = "state.redis"
+ version = "v1"
+ metadata = @(
+ @{
+ name = "redisHost"
+ value = "redis-service:6379"
+ },
+ @{
+ name = "keyPrefix"
+ value = "none"
+ }
+ )
+ }
+} | ConvertTo-Json -Depth 10 | kubectl apply -f - `
+
+@{
+ apiVersion = "dapr.io/v1alpha1"
+ kind = "Component"
+ metadata = @{
+ name = "dapr-test-privatestatestore"
+ namespace = "dapr-test"
+ }
+ spec = @{
+ type = "state.redis"
+ version = "v1"
+ metadata = @(
+ @{
+ name = "redisHost"
+ value = "redis-service:6379"
+ }
+ )
+ }
+} | ConvertTo-Json -Depth 10 | kubectl apply -f - `
+
+
+@{
+ apiVersion = "dapr.io/v1alpha1"
+ kind = "Component"
+ metadata = @{
+ name = "dapr-test-actorsstatestore"
+ namespace = "dapr-test"
+ }
+ spec = @{
+ type = "state.redis"
+ version = "v1"
+ metadata = @(
+ @{
+ name = "redisHost"
+ value = "redis-service:6379"
+ },
+ @{
+ name = "actorStateStore"
+ value = "true"
+ }
+ )
+ }
+} | ConvertTo-Json -Depth 10 | kubectl apply -f -
+```
+
+## Test
+
+* You have to port forward `publisher-service` and go to `/swagger` path in your browser.
+* Publish a sample mesessage
+* If everything is ok, you will see logs with your published message in subscriber service
+
+## Summary
+
+This project provides a reference for deploying a C# microservices application in Kubernetes with Dapr support. It includes configurations for RabbitMQ and Redis, as well as the publisher and subscriber applications. The Dapr components for pub/sub and state management are also configured to demonstrate how to leverage Dapr for building distributed applications.
## Contribution
diff --git a/src/Publisher/Dockerfile b/src/Publisher/Dockerfile
index fc87e77..5ed2d72 100644
--- a/src/Publisher/Dockerfile
+++ b/src/Publisher/Dockerfile
@@ -4,7 +4,7 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
-EXPOSE 8080
+EXPOSE 5000
# This stage is used to build the service project
diff --git a/src/Publisher/Properties/launchSettings.json b/src/Publisher/Properties/launchSettings.json
index dc1d7cd..61e3752 100644
--- a/src/Publisher/Properties/launchSettings.json
+++ b/src/Publisher/Properties/launchSettings.json
@@ -23,7 +23,7 @@
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
- "ASPNETCORE_HTTP_PORTS": "8080"
+ "ASPNETCORE_HTTP_PORTS": "5000"
},
"publishAllPorts": true,
"useSSL": false
diff --git a/src/Publisher/Publisher.csproj b/src/Publisher/Publisher.csproj
index ca00cd2..7fc660f 100644
--- a/src/Publisher/Publisher.csproj
+++ b/src/Publisher/Publisher.csproj
@@ -9,10 +9,10 @@
-
+
-
+
diff --git a/src/Subscriber/Dockerfile b/src/Subscriber/Dockerfile
index b78e470..9010474 100644
--- a/src/Subscriber/Dockerfile
+++ b/src/Subscriber/Dockerfile
@@ -4,7 +4,7 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
-EXPOSE 8080
+EXPOSE 5000
# This stage is used to build the service project
diff --git a/src/Subscriber/Properties/launchSettings.json b/src/Subscriber/Properties/launchSettings.json
index 000c480..a35bdf8 100644
--- a/src/Subscriber/Properties/launchSettings.json
+++ b/src/Subscriber/Properties/launchSettings.json
@@ -23,7 +23,7 @@
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
- "ASPNETCORE_HTTP_PORTS": "8080"
+ "ASPNETCORE_HTTP_PORTS": "5000"
},
"publishAllPorts": true,
"useSSL": false
diff --git a/src/Subscriber/Subscriber.csproj b/src/Subscriber/Subscriber.csproj
index 30bf233..e871b82 100644
--- a/src/Subscriber/Subscriber.csproj
+++ b/src/Subscriber/Subscriber.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/deployment.yaml b/src/deployment.yaml
index e93bbf6..d713b51 100644
--- a/src/deployment.yaml
+++ b/src/deployment.yaml
@@ -1,3 +1,98 @@
+# RabbitMQ
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: rabbitmq
+ namespace: dapr-test
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: rabbitmq
+ template:
+ metadata:
+ labels:
+ app: rabbitmq
+ spec:
+ containers:
+ - name: rabbitmq
+ image: rabbitmq:3-management
+ ports:
+ - containerPort: 5672 # RabbitMQ port
+ - containerPort: 15672 # RabbitMQ management port
+ env:
+ - name: RABBITMQ_DEFAULT_USER
+ value: admin
+ - name: RABBITMQ_DEFAULT_PASS
+ value: password
+ - name: RABBITMQ_DEFAULT_VHOST
+ value: "/"
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: rabbitmq-service
+ namespace: dapr-test
+spec:
+ selector:
+ app: rabbitmq
+ ports:
+ - name: amqp
+ protocol: TCP
+ port: 5672
+ targetPort: 5672
+ - name: management
+ protocol: TCP
+ port: 15672
+ targetPort: 15672
+
+---
+
+# Redis
+
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: redis
+ namespace: dapr-test
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: redis
+ template:
+ metadata:
+ labels:
+ app: redis
+ spec:
+ containers:
+ - name: redis
+ image: redis:6.2.6
+ ports:
+ - containerPort: 6379
+
+---
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: redis-service
+ namespace: dapr-test
+spec:
+ selector:
+ app: redis
+ ports:
+ - protocol: TCP
+ port: 6379
+ targetPort: 6379
+
+---
+
+# Publisher App
+
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -22,6 +117,11 @@ spec:
image: cr.maks-it.com/dapr-test/subscriber:latest
ports:
- containerPort: 5000 # Match your internal app port
+ env:
+ - name: ASPNETCORE_ENVIRONMENT
+ value: Development
+ - name: ASPNETCORE_HTTP_PORTS
+ value: 5000
---
@@ -40,6 +140,8 @@ spec:
---
+# Subscriber App
+
apiVersion: apps/v1
kind: Deployment
metadata:
@@ -64,3 +166,82 @@ spec:
image: cr.maks-it.com/dapr-test/subscriber:latest
ports:
- containerPort: 5000 # Match the internal port of the subscriber service
+ env:
+ - name: ASPNETCORE_ENVIRONMENT
+ value: Development
+ - name: ASPNETCORE_HTTP_PORTS
+ value: 5000
+
+---
+
+# Dapr PubSub
+
+apiVersion: dapr.io/v1alpha1
+kind: Component
+metadata:
+ name: pubsub
+ namespace: dapr-test
+spec:
+ type: pubsub.rabbitmq
+ version: v1
+ metadata:
+ - name: connectionString
+ value: "amqp://admin:password@rabbitmq:5672"
+ - name: durable
+ value: "false"
+ - name: deletedWhenUnused
+ value: "false"
+ - name: autoAck
+ value: "true"
+ - name: reconnectWait
+ value: "0"
+ - name: concurrency
+ value: parallel
+
+---
+
+# Dapr StateStore
+
+apiVersion: dapr.io/v1alpha1
+kind: Component
+metadata:
+ name: statestore
+ namespace: dapr-test
+spec:
+ type: state.redis
+ version: v1
+ metadata:
+ - name: redisHost
+ value: redis:6379
+ - name: keyPrefix
+ value: none
+
+---
+
+apiVersion: dapr.io/v1alpha1
+kind: Component
+metadata:
+ name: privatestatestore
+ namespace: dapr-test
+spec:
+ type: state.redis
+ version: v1
+ metadata:
+ - name: redisHost
+ value: redis:6379
+
+---
+
+apiVersion: dapr.io/v1alpha1
+kind: Component
+metadata:
+ name: actorsstatestore
+ namespace: dapr-test
+spec:
+ type: state.redis
+ version: v1
+ metadata:
+ - name: redisHost
+ value: redis:6379
+ - name: actorStateStore
+ value: "true"