This builds directly on Part 7.
The main series focused on local development and the core Dapr building blocks. This appendix shifts to production‑oriented Kubernetes configuration, showing the shape of real-world-deployments without overwhelming you with every possible scenario.
We’ll cover:
- Deployments with Dapr sidecars
- State stores using Kubernetes secrets
- Pub/Sub components for real brokers
- Storage bindings for cloud providers
- Secret stores
- Namespace scoping
- Notes on mTLS and the control plane
- A production-ready checklist
- Common mistakes to avoid
Companion GitHub repository: dapr-by-example.
These examples complement the main series without changing its local‑first learning flow.
1. Deploying a Dapr‑Enabled Service in Kubernetes
Dapr integrates with Kubernetes using annotations.
Here’s a minimal Deployment for the .NET Order Service from Part 7:
apiVersion: apps/v1
kind: Deployment
metadata:
name: orderservice-dotnet
spec:
replicas: 1
selector:
matchLabels:
app: orderservice-dotnet
template:
metadata:
labels:
app: orderservice-dotnet
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "orderservice-dotnet"
dapr.io/app-port: "8080"
dapr.io/config: "tracing"
dapr.io/enable-metrics: "true"
dapr.io/metrics-port: "9090"
spec:
containers:
- name: orderservice-dotnet
image: localhost:5000/orderservice-dotnet:v1.0
ports:
- containerPort: 8080
env:
- name: ASPNETCORE_URLS
value: "http://+:8080"
What this does
- Injects the Dapr sidecar automatically
- Assigns the app ID (
orderservice) - Exposes the app port to the sidecar
- Enables Dapr logs and tracing
No SDKs. No infrastructure code.
Just annotations.
2. State Store: Postgres with Kubernetes Secrets
A production state store should never embed credentials directly.
Here’s a Postgres component using secretKeyRef
Dapr Component
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
labels:
component: statestore
spec:
type: state.postgresql
version: v1
metadata:
- name: connectionString
secretKeyRef:
name: pg-secret
key: conn
- name: tableName
value: "dapr_state"
- name: schema
value: "public"
- name: cleanupIntervalInSeconds
value: "3600"
- name: actorStateStore
value: "true"
scopes:
- orderservice-dotnet
- inventoryservice-dotnet
- orderservice-go
- inventoryservice-go
Notes:
scopes:ensures only the Order Service can use this component- The connection string lives in a Kubernetes Secret
- Dapr handles retries, serialization, and concurrency
- Components must live in the same namespace as the workloads that use them
3. Pub/Sub: Kafka Component for Production
Here’s a Kafka pub/sub component suitable for real clusters:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: pubsub
labels:
component: pubsub
spec:
type: pubsub.kafka
version: v1
metadata:
- name: brokers
value: "my-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092"
- name: consumerGroup
value: "orderservice"
- name: authType
value: "none"
- name: initialOffset
value: "newest"
- name: maxMessageBytes
value: "1048576"
- name: disableTls
value: "true"
scopes:
- orderservice-dotnet
- inventoryservice-dotnet
- orderservice-go
- inventoryservice-go
Notes:
- Dapr manages consumer groups
- Ordering is not guaranteed
- At‑least‑once delivery is the default
- Scopes restrict which services can publish/subscribe
- Pub/Sub and input bindings use CloudEvents by default
4. Storage Binding: AWS S3
Bindings expose simple operations (create, get, delete).
Here’s an S3 binding using IAM credentials stored in Kubernetes.
Dapr Component
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: storage
labels:
component: storage
spec:
type: bindings.aws.s3
version: v1
metadata:
- name: bucket
value: "order-receipts"
- name: region
value: "eu-west-2"
- name: endpoint
value: "s3.eu-west-2.amazonaws.com"
- name: accessKey
secretKeyRef:
name: s3-creds
key: accessKey
- name: secretKey
secretKeyRef:
name: s3-creds
key: secretKey
- name: decodeBase64
value: true
scopes:
- orderservice-dotnet
- orderservice-go
Notes:
- Works with the same Go and .NET code from Part 7
- Credentials stay out of application code
- Bindings intentionally expose limited operations
5. Secret Stores: Kubernetes, Azure Key Vault, AWS Secrets Manager, and more
Dapr supports multiple secret stores.
Here are the three most common.
5.1 Kubernetes Secret Store (default)
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: kubernetes
spec:
type: secretstores.kubernetes
version: v1
This is automatically available in most clusters.
5.2 Azure Key Vault
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: azurekeyvault
spec:
type: secretstores.azure.keyvault
version: v1
metadata:
- name: vaultName
value: "my-vault"
- name: azureTenantId
value: "tenant-guid"
- name: azureClientId
value: "client-guid"
- name: azureClientSecret
secretKeyRef:
name: keyvault-creds
key: clientSecret
5.3 AWS Secrets Manager
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: aws-secrets
spec:
type: secretstores.aws.secretsmanager
version: v1
metadata:
- name: region
value: "eu-west-1"
- name: accessKey
secretKeyRef:
name: aws-creds
key: accessKey
- name: secretKey
secretKeyRef:
name: aws-creds
key: secretKey
6. Namespaces and Component Scoping
In multi‑team clusters, scoping is essential.
Best practices
- Put components in the same namespace as the services that use them
- Use
scopes:to restrict access - Use separate namespaces for staging vs production
- Avoid global components unless absolutely necessary
- Keep secrets and components close to the workloads that depend on them
7. mTLS and the Dapr Control Plane
Dapr enables mTLS by default in Kubernetes.
This means:
- All service‑to‑service traffic via Dapr is encrypted
- Certificates rotate automatically
- No application code changes are required
The control plane includes:
- Operator — injects sidecars
- Sentry — issues and rotates certificates
- Placement — manages actors
You rarely need to configure these unless customising certificate lifetimes or issuers.
8. Putting It All Together
A real‑world Dapr deployment typically includes:
- A Deployment with Dapr annotations
- A state store component using secrets
- A pub/sub component for Kafka or Service Bus
- A storage binding for S3 or Azure Blob
- A secret store (Kubernetes, Key Vault, or Secrets Manager)
- Scopes to restrict component access
- Automatic mTLS from the control plane
Your application code, whether Go, .NET, Python, or Java, etc., stays clean and infrastructure‑agnostic.
Production Architecture Diagram
Kubernetes Pod
├─ Your Application
└─ Dapr Sidecar
├─ State Store (Postgres / Redis)
├─ Pub/Sub Broker (Kafka / Service Bus)
├─ Storage Provider (S3 / Blob)
└─ Secret Store (K8s / Vault / AWS SM)
Dapr becomes the consistent interface between your service and the platform.
Common Mistakes to Avoid
1. Putting components in the wrong namespace
Components must live in the same namespace as the workloads that use them.
2. Forgetting to use scopes
Without scopes, components may be unintentionally shared across services.
3. Embedding secrets directly in components
Always use secretKeyRef or a secret store.
4. Assuming local and Kubernetes behavior are identical
Local mode does not hot‑reload components; Kubernetes does.
5. Ignoring sidecar resource limits
Set CPU/memory limits to avoid noisy‑neighbor issues.
6. Forgetting CloudEvent envelopes
Pub/Sub and input bindings wrap messages in CloudEvents unless disabled.
Production‑Ready Checklist
Application
- [ ] Dapr annotations applied
- [ ] App ID defined
- [ ] App port exposed
- [ ] Resource limits set for both app and sidecar
Components
- [ ] Components placed in correct namespace
- [ ] Scopes applied
- [ ] Secrets referenced via
secretKeyRef - [ ] Pub/Sub configured with consumer groups
- [ ] State store configured with proper consistency/concurrency modes
Security
- [ ] mTLS enabled (default)
- [ ] Secret store configured
- [ ] No credentials in code or components
Observability
- [ ] Tracing sampling configured via Dapr Configuration
- [ ] Prometheus scraping enabled
- [ ] Logs aggregated centrally
Operations
- [ ] Resiliency policies defined (timeouts, retries, circuit breakers)
- [ ] Health probes configured
- [ ] Versioned components stored in Git
Final Thoughts
This appendix isn’t meant to be exhaustive.
It’s meant to show the shape of real‑world Dapr usage:
- Clean separation of concerns
- Infrastructure defined declaratively
- Secrets handled securely
- Sidecars injected automatically
- Observability built in
- Polyglot services sharing the same building blocks
If the main series showed how Dapr simplifies distributed systems, this appendix shows how those same patterns scale into production.