A hands-on tutorial covering every Dapr building block with two .NET 8 microservices communicating via request/response (service invocation) and pub/sub (Kafka). Progress from standalone mode for rapid learning to a full Kubernetes deployment with Let's Encrypt TLS.
OrderService <--- Service Invocation (request/response) ---> InventoryService
| |
|--- Pub/Sub (Kafka) --- "orders" topic ---- subscribes ------>|
|<-- Pub/Sub (Kafka) --- "order-status" topic -- publishes ----|
| |
|--- State Store (Redis) --- orders |--- State Store (Redis) --- inventory
|--- Secret Store --- credentials |
|--- Output Binding --- notifications |--- Input Binding --- cron schedule
- What is Dapr?
- Dapr Architecture
- All Dapr Building Blocks
- Project Structure
- Prerequisites
- Part 1: Standalone Mode (Local Development)
- Part 2: Kubernetes Deployment
- Part 3: Let's Encrypt TLS with cert-manager
- Playground Exercises
- Troubleshooting
- Deep Dive Documentation
Dapr (Distributed Application Runtime) is a portable, event-driven runtime that makes it easy to build resilient, stateless and stateful microservices. Dapr runs as a sidecar next to your application and provides building blocks via HTTP/gRPC APIs.
Key idea: Your app talks to the local Dapr sidecar (localhost) — Dapr handles the distributed systems complexity (service discovery, retries, pub/sub routing, state consistency, secret management, tracing, etc.).
| Problem | Without Dapr | With Dapr |
|---|---|---|
| Service-to-service calls | Manually manage URLs, load balancing, retries | daprClient.InvokeMethodAsync("service-id", "method") |
| Pub/Sub messaging | Import Kafka/RabbitMQ SDK, manage connections | daprClient.PublishEventAsync("pubsub", "topic", data) |
| State management | Import Redis/Cosmos SDK, handle serialization | daprClient.SaveStateAsync("store", "key", value) |
| Secrets | Import Vault/Key Vault SDK per provider | daprClient.GetSecretAsync("store", "name") |
| Observability | Instrument each service manually | Automatic distributed tracing via sidecars |
| Portability | Locked to specific cloud services | Swap components via YAML — no code changes |
┌─────────────────────────────────────────────────────────┐
│ YOUR APPLICATION │
│ (OrderService:5100) │
│ │
│ app code ──HTTP/gRPC──► Dapr Sidecar (daprd:3500) │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ │ │ │ │
│ State Store Pub/Sub Service │
│ (Redis) (Kafka) Invocation │
│ │ │
│ InventoryService │
│ Sidecar:3501 │
└─────────────────────────────────────────────────────────┘
| Aspect | Standalone Mode | Kubernetes Mode |
|---|---|---|
| Sidecar | dapr run starts daprd process |
Sidecar injector adds daprd container to pods |
| Service Discovery | mDNS (local machine) | Kubernetes DNS + Dapr name resolution |
| Components | YAML files in local folder | Kubernetes CRDs in a namespace |
| mTLS | Not available | Automatic mTLS between all sidecars |
| Secrets | Local file or env vars | Kubernetes Secrets, Vault, Cloud KMS |
| Scaling | Manual | Kubernetes HPA + Dapr autoscaling |
Dapr provides these building blocks. This tutorial demonstrates each one:
- What: Call methods on other services by name, without knowing their address.
- How:
daprClient.InvokeMethodAsync("inventory-service", "api/inventory/LAPTOP-001") - Features: Service discovery, mTLS, retries, access control, tracing.
- In this project: OrderService calls InventoryService to check stock and reserve inventory.
- What: Key/value CRUD with consistency and concurrency guarantees.
- How:
daprClient.SaveStateAsync("statestore", "order-123", orderObj) - Supported stores: Redis, Cosmos DB, PostgreSQL, DynamoDB, MongoDB, Cassandra, and 20+ more.
- Features: First-write/last-write wins, transactions, bulk ops, encryption, TTL.
- In this project: Both services store data in Redis via the Dapr state API.
- What: Event-driven messaging between services.
- How: Publish:
daprClient.PublishEventAsync("pubsub", "orders", event)/ Subscribe:[Topic("pubsub", "orders")]attribute. - Supported brokers: Kafka, Redis Streams, RabbitMQ, NATS, Azure Service Bus, AWS SNS/SQS, GCP Pub/Sub, Pulsar.
- Features: At-least-once delivery, CloudEvents format, dead-letter topics, bulk subscribe.
- In this project: OrderService publishes
OrderCreatedto Kafka; InventoryService subscribes and publishes backOrderStatusUpdated.
- What: Trigger apps from or invoke external systems without their SDKs.
- Input Bindings: External event → your app (e.g., cron schedule, Kafka consumer, queue).
- Output Bindings: Your app → external system (e.g., send email, write to S3, call webhook).
- In this project: Cron input binding triggers periodic inventory checks; HTTP output binding sends notifications.
- What: Secure API to retrieve secrets from any secrets store.
- How:
daprClient.GetSecretAsync("secretstore", "api-key") - Supported stores: Local file, Kubernetes Secrets, HashiCorp Vault, Azure Key Vault, AWS Secrets Manager, GCP Secret Manager.
- In this project: OrderService reads secrets from a local JSON file (standalone) or Kubernetes Secrets (K8s).
- What: Read application configuration from a config store and subscribe to changes.
- Supported stores: Redis, PostgreSQL, Azure App Configuration.
- Use case: Feature flags, dynamic settings without redeployment.
- What: Mutual exclusion across distributed instances.
- Supported stores: Redis, ZooKeeper, etcd.
- Use case: Ensure only one instance processes a critical section.
- What: Single-threaded, stateful objects with automatic activation/deactivation.
- Based on: The Virtual Actor pattern (Orleans/Akka style).
- Use case: IoT device management, game state, workflow orchestration.
- Note: Requires
actorStateStore: trueon the state store component (configured in this project).
- What: Orchestrate multi-step, long-running business processes with automatic state persistence.
- Features: Fan-out/fan-in, timers, external event waiting, sub-workflows.
- Use case: Order processing pipeline, approval workflows.
- What: Perform crypto operations (encrypt, decrypt, sign, verify) via Dapr.
- Supported: Azure Key Vault, local keys.
- Use case: Encrypt sensitive data before storing, sign JWTs.
- What: Automatic distributed tracing, metrics, and logging.
- Tracing: Zipkin, Jaeger, OpenTelemetry Collector, Application Insights.
- Metrics: Prometheus endpoints on every sidecar.
- In this project: Zipkin tracing is configured; every service invocation and pub/sub message is traced.
- What: Declarative retry, timeout, and circuit-breaker policies.
- Applied to: Service invocations, component operations, actor calls.
- In this project: Configured via
resiliency.yaml— retry with exponential backoff, circuit breaker on InventoryService.
- What: HTTP middleware pipeline for cross-cutting concerns.
- Examples: Rate limiting, OAuth2, OpenID Connect, bearer token auth, CORS.
- In this project: Rate limit middleware example provided (inactive by default).
DaprTutorial/
├── DaprTutorial.sln # .NET solution file
├── docker-compose.yaml # Local infrastructure (Redis, Kafka, Zipkin)
├── README.md # This file
│
├── src/
│ ├── OrderService/ # .NET 8 Web API — places orders
│ │ ├── Controllers/
│ │ │ └── OrderController.cs # Service invocation, state, pub/sub, secrets, bindings
│ │ ├── Models/
│ │ ├── Events/
│ │ ├── Program.cs # App startup with Dapr middleware
│ │ ├── Dockerfile
│ │ └── OrderService.csproj
│ │
│ └── InventoryService/ # .NET 8 Web API — manages inventory
│ ├── Controllers/
│ │ └── InventoryController.cs # Service invocation target, pub/sub subscriber
│ ├── Models/
│ ├── Events/
│ ├── Program.cs
│ ├── Dockerfile
│ └── InventoryService.csproj
│
├── dapr/
│ ├── config.yaml # Dapr sidecar configuration (tracing, mTLS, access control)
│ ├── secrets.json # Local secrets for development
│ ├── components/ # Standalone mode components
│ │ ├── statestore.yaml # Redis state store
│ │ ├── pubsub-kafka.yaml # Kafka pub/sub
│ │ ├── pubsub-redis.yaml.example # Redis Streams pub/sub (alternative)
│ │ ├── secretstore.yaml # Local file secret store
│ │ ├── binding-cron.yaml # Cron input binding
│ │ ├── binding-output.yaml # HTTP output binding
│ │ ├── resiliency.yaml # Retry, timeout, circuit breaker policies
│ │ └── middleware-ratelimit.yaml.example # Rate limiting middleware
│ │
│ └── components-k8s/ # Kubernetes mode components
│ ├── statestore.yaml
│ ├── pubsub-kafka.yaml
│ ├── secretstore-k8s.yaml # Kubernetes Secrets
│ ├── resiliency.yaml
│ └── config.yaml
│
├── k8s/
│ ├── namespace.yaml
│ ├── infrastructure/ # Redis, Kafka, Zipkin K8s deployments
│ │ ├── redis.yaml
│ │ ├── kafka.yaml
│ │ └── zipkin.yaml
│ ├── apps/ # Application deployments with Dapr annotations
│ │ ├── order-service.yaml
│ │ └── inventory-service.yaml
│ ├── cert-manager/ # Let's Encrypt TLS
│ │ ├── cluster-issuer.yaml
│ │ └── certificate.yaml
│ └── ingress/
│ └── ingress.yaml # NGINX Ingress with TLS termination
│
└── scripts/
├── start-standalone.sh # Launch everything in standalone mode
├── stop-standalone.sh # Stop standalone mode
├── test-apis.sh # Exercise all Dapr building blocks
├── deploy-k8s.sh # Deploy to Kubernetes
└── teardown-k8s.sh # Remove from Kubernetes
- kubectl — Install
- A Kubernetes cluster — minikube, kind, Docker Desktop K8s, or a cloud cluster
# macOS (Homebrew)
brew install dapr/tap/dapr-cli
# Linux
wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash
# Windows (PowerShell)
powershell -Command "iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1 | iex"
# Verify
dapr --versionStandalone mode runs Dapr sidecars as local processes alongside your .NET apps. This is perfect for development and learning.
# This installs daprd binary, default components, and a local Redis + Zipkin via Docker
dapr init
# Verify
dapr --version
# CLI version: 1.14.x
# Runtime version: 1.14.x
# Check what Dapr installed
docker ps
# You should see: dapr_redis, dapr_zipkin, dapr_placementWhat dapr init installs:
daprd— the Dapr sidecar runtime- A Redis container for default state store and pub/sub
- A Zipkin container for default tracing
- Default component definitions in
~/.dapr/components/
# Start Redis, Kafka, Zipkin, and Kafka UI
docker compose up -d
# Verify everything is running
docker compose ps| Service | URL | Purpose |
|---|---|---|
| Redis | localhost:6379 | State store |
| Kafka | localhost:9092 | Pub/Sub broker |
| Zipkin | http://localhost:9411 | Distributed tracing |
| Kafka UI | http://localhost:8080 | Browse Kafka topics/messages |
Option A: Use the startup script
./scripts/start-standalone.shOption B: Run manually in separate terminals
Terminal 1 — InventoryService:
dapr run \
--app-id inventory-service \
--app-port 5200 \
--dapr-http-port 3501 \
--dapr-grpc-port 50002 \
--resources-path ./dapr/components \
--config ./dapr/config.yaml \
-- dotnet run --project src/InventoryService --urls "http://localhost:5200"Terminal 2 — OrderService:
dapr run \
--app-id order-service \
--app-port 5100 \
--dapr-http-port 3500 \
--dapr-grpc-port 50001 \
--resources-path ./dapr/components \
--config ./dapr/config.yaml \
-- dotnet run --project src/OrderService --urls "http://localhost:5100"Understanding the dapr run flags:
| Flag | Meaning |
|---|---|
--app-id |
Unique name for this service (used for service invocation) |
--app-port |
Port your .NET app listens on |
--dapr-http-port |
Port the Dapr sidecar HTTP API listens on |
--dapr-grpc-port |
Port the Dapr sidecar gRPC API listens on |
--resources-path |
Folder containing component YAML files |
--config |
Dapr configuration file (tracing, access control) |
# Run the full test suite
./scripts/test-apis.shOr try individual operations:
# OrderService calls InventoryService through Dapr sidecar
curl http://localhost:5100/api/order/check-inventory/LAPTOP-001
# Direct Dapr sidecar invocation (bypasses your app, calls InventoryService directly)
curl http://localhost:3500/v1.0/invoke/inventory-service/method/api/inventory/LAPTOP-001How it works:
- Your app calls
daprClient.InvokeMethodAsync("inventory-service", "api/inventory/LAPTOP-001") - The Dapr SDK sends this to the local sidecar at
localhost:3500 - The local sidecar resolves "inventory-service" via name resolution (mDNS locally, K8s DNS in cluster)
- The local sidecar forwards the request to the target sidecar at the resolved address
- The target sidecar forwards the request to the InventoryService app at
localhost:5200 - Response flows back through the same path
# Seed inventory data
curl -X POST http://localhost:5200/api/inventory/seed
# Read state directly from Dapr sidecar
curl http://localhost:3500/v1.0/state/statestore/order-123
# Write state directly via Dapr sidecar
curl -X POST http://localhost:3500/v1.0/state/statestore \
-H "Content-Type: application/json" \
-d '[{"key": "test-key", "value": {"hello": "world"}}]'
# Read it back
curl http://localhost:3500/v1.0/state/statestore/test-key# Create an order — this triggers:
# 1. State save (Redis)
# 2. Publish "OrderCreated" event (Kafka)
# 3. InventoryService receives event, publishes "OrderStatusUpdated"
# 4. OrderService receives status update
curl -X POST http://localhost:5100/api/order \
-H "Content-Type: application/json" \
-d '{
"productId": "LAPTOP-001",
"productName": "Developer Laptop Pro",
"quantity": 2,
"unitPrice": 1299.99
}'
# Publish directly via Dapr sidecar
curl -X POST http://localhost:3500/v1.0/publish/orderpubsub/orders \
-H "Content-Type: application/json" \
-d '{"orderId": "test-123", "productId": "MOUSE-001", "quantity": 1}'# Read a secret via the app
curl http://localhost:5100/api/order/secret/api-key
# Read directly from Dapr sidecar
curl http://localhost:3500/v1.0/secrets/localsecretstore/api-key
# Get all secrets
curl http://localhost:3500/v1.0/secrets/localsecretstore/bulk# View registered components, subscriptions, and runtime info
curl http://localhost:5100/api/order/dapr-info
# Dapr sidecar metadata
curl http://localhost:3500/v1.0/metadata
# Health check
curl http://localhost:3500/v1.0/healthz
# Open Zipkin to see distributed traces
open http://localhost:9411
# Open Kafka UI to see topics and messages
open http://localhost:8080
# Dapr dashboard (run in a separate terminal)
dapr dashboard -p 8888
# Then open http://localhost:8888./scripts/stop-standalone.sh
# or
dapr stop --app-id order-service
dapr stop --app-id inventory-service
docker compose downOption A: minikube
minikube start --cpus=4 --memory=8192
minikube addons enable ingressOption B: kind
kind create cluster --name dapr-tutorialOption C: Docker Desktop Enable Kubernetes in Docker Desktop Settings.
# Install Dapr control plane (dapr-operator, sentry, placement, sidecar-injector)
dapr init -k --wait
# Verify
dapr status -kWhat dapr init -k installs:
| Component | Purpose |
|---|---|
dapr-operator |
Manages Dapr component CRDs and configuration |
dapr-sentry |
Certificate authority for mTLS between sidecars |
dapr-sidecar-injector |
Automatically injects daprd sidecar into annotated pods |
dapr-placement |
Manages actor placement tables |
dapr-dashboard |
Web UI for Dapr status (optional) |
./scripts/deploy-k8s.shOr step by step:
# 1. Create namespace
kubectl apply -f k8s/namespace.yaml
# 2. Deploy infrastructure
kubectl apply -f k8s/infrastructure/
# 3. Wait for infrastructure
kubectl wait --for=condition=ready pod -l app=redis -n dapr-tutorial --timeout=120s
kubectl wait --for=condition=ready pod -l app=kafka -n dapr-tutorial --timeout=180s
# 4. Apply Dapr components
kubectl apply -f dapr/components-k8s/
# 5. Build and load images
docker build -t dapr-tutorial/order-service:latest src/OrderService
docker build -t dapr-tutorial/inventory-service:latest src/InventoryService
# For minikube:
minikube image load dapr-tutorial/order-service:latest
minikube image load dapr-tutorial/inventory-service:latest
# For kind:
kind load docker-image dapr-tutorial/order-service:latest
kind load docker-image dapr-tutorial/inventory-service:latest
# 6. Deploy applications
kubectl apply -f k8s/apps/
# 7. Check status
kubectl get pods -n dapr-tutorial# Port-forward to services
kubectl port-forward svc/order-service 5100:80 -n dapr-tutorial &
kubectl port-forward svc/inventory-service 5200:80 -n dapr-tutorial &
kubectl port-forward svc/zipkin 9411:9411 -n dapr-tutorial &
# Now use the same curl commands from Part 1
curl http://localhost:5200/api/inventory/seed
curl http://localhost:5100/api/order/check-inventory/LAPTOP-001# See the Dapr sidecar container in each pod (2/2 containers)
kubectl get pods -n dapr-tutorial
# View sidecar logs
kubectl logs -l app=order-service -n dapr-tutorial -c daprd
# View app logs
kubectl logs -l app=order-service -n dapr-tutorial -c order-service
# Dapr dashboard
dapr dashboard -k -p 8888
# Check Dapr components
kubectl get components.dapr.io -n dapr-tutorial
# Check Dapr configurations
kubectl get configurations.dapr.io -n dapr-tutorial
# Check Dapr subscriptions (auto-discovered from [Topic] attributes)
kubectl get subscriptions.dapr.io -n dapr-tutorialThe pod annotations in k8s/apps/order-service.yaml control the Dapr sidecar:
annotations:
dapr.io/enabled: "true" # Inject sidecar
dapr.io/app-id: "order-service" # Service identity
dapr.io/app-port: "80" # App listens here
dapr.io/app-protocol: "http" # http or grpc
dapr.io/config: "dapr-tutorial-config" # Configuration CRD name
dapr.io/log-level: "info" # Sidecar log level
dapr.io/enable-metrics: "true" # Prometheus metrics
dapr.io/sidecar-cpu-request: "100m" # Sidecar resources
dapr.io/sidecar-memory-request: "128Mi"./scripts/teardown-k8s.shTLS certificates are provisioned automatically using cert-manager and Let's Encrypt.
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.yaml
# Wait for cert-manager to be ready
kubectl wait --for=condition=ready pod -l app.kubernetes.io/instance=cert-manager -n cert-manager --timeout=120sEdit k8s/cert-manager/cluster-issuer.yaml and set your email:
email: your-real-email@example.comkubectl apply -f k8s/cert-manager/cluster-issuer.yamlEdit k8s/cert-manager/certificate.yaml and set your domain:
dnsNames:
- your-domain.example.comkubectl apply -f k8s/cert-manager/certificate.yaml
# Check certificate status
kubectl get certificates -n dapr-tutorial
kubectl describe certificate dapr-tutorial-tls -n dapr-tutorialEdit k8s/ingress/ingress.yaml with your domain, then:
kubectl apply -f k8s/ingress/ingress.yaml
# For local testing with the staging issuer, the cert will be "fake" (browser warning)
# Switch to letsencrypt-prod for a real trusted certificate1. You create a Certificate resource
2. cert-manager creates a CertificateRequest
3. cert-manager contacts Let's Encrypt ACME server
4. Let's Encrypt issues an HTTP-01 challenge
5. cert-manager creates a temporary Ingress to answer the challenge
6. Let's Encrypt verifies domain ownership
7. cert-manager stores the signed cert in a Kubernetes Secret
8. Your Ingress references that Secret for TLS termination
9. cert-manager renews the cert before expiry (every ~60 days)
# In standalone mode:
mv dapr/components/pubsub-kafka.yaml dapr/components/pubsub-kafka.yaml.bak
cp dapr/components/pubsub-redis.yaml.example dapr/components/pubsub-redis.yaml
# Restart services — same code, different broker!curl -X POST http://localhost:5200/api/inventory \
-H "Content-Type: application/json" \
-d '{
"productId": "DESK-001",
"productName": "Standing Desk",
"quantityAvailable": 25,
"price": 599.99
}'- Create an order:
curl -X POST http://localhost:5100/api/order -H "Content-Type: application/json" -d '{"productId":"LAPTOP-001","productName":"Laptop","quantity":1,"unitPrice":999}' - Open Zipkin: http://localhost:9411
- Click "Run Query" — see the full trace across OrderService → InventoryService
- Notice how Dapr automatically propagates trace context
- Stop InventoryService:
dapr stop --app-id inventory-service - Make several requests to check inventory from OrderService
- Watch the circuit breaker trip after 3 failures (configured in resiliency.yaml)
- Restart InventoryService and observe recovery
# Every Dapr building block is accessible via the sidecar HTTP API:
# Metadata
curl http://localhost:3500/v1.0/metadata
# State
curl http://localhost:3500/v1.0/state/statestore/my-key
# Pub/Sub
curl -X POST http://localhost:3500/v1.0/publish/orderpubsub/my-topic \
-H "Content-Type: application/json" -d '{"test": true}'
# Secrets
curl http://localhost:3500/v1.0/secrets/localsecretstore/api-key
# Health
curl http://localhost:3500/v1.0/healthz
# Shutdown the sidecar (graceful)
curl -X POST http://localhost:3500/v1.0/shutdown# Scale InventoryService to 5 replicas
kubectl scale deployment inventory-service -n dapr-tutorial --replicas=5
# Dapr automatically load-balances service invocations across all replicas
# Create multiple orders and observe logs from different pods
kubectl logs -l app=inventory-service -n dapr-tutorial -c inventory-service -f| Issue | Solution |
|---|---|
dapr run fails: "address already in use" |
Another Dapr process is running. Run dapr list and dapr stop |
| Kafka connection refused | Ensure docker compose up -d has started Kafka |
| Service invocation 500 error | Check target service is running: dapr list |
| Pub/Sub messages not received | Check topic names match between publisher and subscriber |
| K8s pods stuck at 1/2 Ready | Sidecar is waiting for the app. Check app container logs |
| cert-manager challenge failing | Ensure DNS points to cluster. Use staging issuer first |
# Standalone: list running Dapr apps
dapr list
# Standalone: check Dapr sidecar logs
dapr logs --app-id order-service
# K8s: check sidecar logs
kubectl logs <pod-name> -n dapr-tutorial -c daprd
# K8s: check Dapr system services
kubectl get pods -n dapr-system
# K8s: describe Dapr components
kubectl describe component statestore -n dapr-tutorial
# Check which topics apps subscribe to
curl http://localhost:3500/v1.0/metadata | python3 -m json.tool| Component YAML | Dapr Building Block | Backend | Purpose |
|---|---|---|---|
statestore.yaml |
State Management | Redis | Persist orders and inventory |
pubsub-kafka.yaml |
Pub/Sub | Kafka | Event-driven messaging |
secretstore.yaml |
Secrets | Local file / K8s | Store credentials |
binding-cron.yaml |
Input Binding | Cron | Scheduled tasks |
binding-output.yaml |
Output Binding | HTTP | Send webhooks |
resiliency.yaml |
Resiliency | N/A | Retry, timeout, circuit breaker |
config.yaml |
Configuration | N/A | Tracing, mTLS, access control |
middleware-ratelimit.yaml |
Middleware | N/A | Rate limiting |
| Service | App Port | Dapr HTTP | Dapr gRPC | Notes |
|---|---|---|---|---|
| OrderService | 5100 | 3500 | 50001 | Places orders |
| InventoryService | 5200 | 3501 | 50002 | Manages inventory |
| Redis | 6379 | — | — | State store |
| Kafka | 9092 | — | — | Message broker |
| Zipkin | 9411 | — | — | Tracing UI |
| Kafka UI | 8080 | — | — | Topic browser |
| Dapr Dashboard | 8888 | — | — | dapr dashboard -p 8888 |
Staff-engineer-level deep dives for every Dapr concept. Each document covers internals, architecture diagrams, .NET code examples, decision matrices, and production guidance.
| # | Document | Topics Covered |
|---|---|---|
| 01 | Dapr Architecture | Sidecar pattern, data plane vs. control plane, component abstraction, name resolution, memory footprint, standalone vs. K8s |
| 02 | Service Invocation | Request flow, name resolution (mDNS/K8s/Consul), access control policies, load balancing, headers, performance |
| 03 | State Management | Consistency models (strong/eventual), ETags and optimistic concurrency, transactions, TTL, encryption, query API, backend comparison |
| 04 | Publish & Subscribe | CloudEvents format, at-least-once delivery, dead letter topics, content-based routing, bulk pub/sub, Kafka vs. Redis Streams, message ordering |
| 05 | Bindings | Input/output binding lifecycle, cron/HTTP/S3/email bindings, bindings vs. pub/sub decision guide |
| 06 | Secrets Management | Secret store types (local/K8s/Vault/KeyVault/AWS), scoping, rotation strategies, secret references in components |
| 07 | Virtual Actors | Actor model, turn-based concurrency, placement service, timers vs. reminders, state persistence, scaling, use cases |
| 08 | Workflows | Durable orchestration, activities, fan-out/fan-in, external events, sub-workflows, replay safety, management API |
| 09 | Resiliency | Retry policies (constant/exponential), timeouts, circuit breakers (states/trip expressions), target configuration, real-world scenarios |
| 10 | Observability | W3C Trace Context, Zipkin/OTEL, Prometheus metrics, structured logging, sampling rates, production monitoring stack |
| 11 | Security | mTLS with Sentry CA, SPIFFE identities, API token auth, access control policies, component scoping, threat model, hardening checklist |
| 12 | Configuration & Middleware | Configuration API with subscriptions, distributed locks, cryptography API, HTTP middleware pipeline (rate limit/OAuth2/OPA) |
| 13 | Dapr on Kubernetes | Control plane components, sidecar injection internals, CRDs, all annotations reference, HA mode, upgrades, debugging, multi-namespace |
| 14 | Production Readiness | HA checklist, HPA/KEDA scaling, monitoring dashboards, alerting rules, performance tuning, disaster recovery, cost analysis, migration strategy |