Dapr

CLI Basics

dapr init
dapr run --app-id myapp --app-port 3000 -- dotnet run
dapr stop --app-id myapp
dapr uninstall
dapr publish --publish-app-id myapp --pubsub pubsub --topic orders --data '{"orderId":"1"}'
dapr invoke --app-id myapp --method orders --verb POST --data '{"id":"1"}'
dapr list
dapr status -k

Service Invocation

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: myapp-config
spec:
  tracing:
    samplingRate: "1"
resp, err := client.InvokeMethod(ctx, "ordersvc", "orders/1", "get")
GET http://localhost:3500/v1.0/invoke/ordersvc/method/orders/1

State Management

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.redis
  metadata:
    - name: redisHost
      value: localhost:6379
    - name: redisPassword
      value: ""
POST http://localhost:3500/v1.0/state/statestore
Content-Type: application/json

[{"key": "order1", "value": {"itemId": "A", "qty": 3}}]
GET http://localhost:3500/v1.0/state/statestore/order1
DELETE http://localhost:3500/v1.0/state/statestore/order1

Pub/Sub

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: pubsub
spec:
  type: pubsub.redis
  metadata:
    - name: redisHost
      value: localhost:6379
    - name: redisPassword
      value: ""
POST http://localhost:3500/v1.0/publish/pubsub/orders
Content-Type: application/json

{"orderId": "1", "status": "new"}
POST http://localhost:3500/v1.0/publish/pubsub/orders?metadata.rawPayload=true

Bindings

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: queuebinding
spec:
  type: bindings.rabbitmq
  metadata:
    - name: queueName
      value: orders
    - name: host
      value: amqp://localhost:5672
POST http://localhost:3500/v1.0/bindings/queuebinding
Content-Type: application/json

{ "operation": "create", "data": { "orderId": "1" } }

Actors

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: myapp-config
spec:
  actorService:
    actorIdleTimeout: "30m"
    actorScanInterval: "30s"
    drainOngoingCallTimeout: "60s"
    drainRebalancedActors: true
POST http://localhost:3500/v1.0/actors/orderactor/1/method/submit
Content-Type: application/json

{"itemId": "A", "qty": 5}
GET http://localhost:3500/v1.0/actors/orderactor/1/state/status

Observability

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: tracing
spec:
  tracing:
    samplingRate: "1"
    otel:
      endpointAddress: "localhost:4317"
      isSecure: false
      protocol: grpc
  metrics:
    enabled: true
    http:
      increasedCardinality: false

Secret Stores

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: secretstore
spec:
  type: secretstores.local.file
  metadata:
    - name: secretsFile
      value: ./secrets.json
    - name: nestedSeparator
      value: ":"
GET http://localhost:3500/v1.0/secrets/secretstore/db-password
GET http://localhost:3500/v1.0/secrets/secretstore/bulk
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: aws-secretstore
spec:
  type: secretstores.aws.secretmanager
  metadata:
    - name: region
      value: us-east-1

Configuration API

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: appconfig
spec:
  type: configuration.redis
  metadata:
    - name: redisHost
      value: localhost:6379
    - name: redisPassword
      value: ""
GET http://localhost:3500/v1.0/configuration/appconfig?key=debugMode

Dapr Components

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: mystate
  namespace: default
spec:
  type: state.postgresql
  version: v1
  metadata:
    - name: connectionString
      value: "host=localhost user=postgres password=secret port=5432"
    - name: tableName
      value: state
  scopes:
    - myapp
    - anotherapp

Self-hosted Mode

dapr init --runtime-version 1.14.0
dapr init --slim
dapr run --app-id myapp --app-port 3000 --components-path ./components -- dotnet run
.
├── app.py
└── components/
    ├── statestore.yaml
    ├── pubsub.yaml
    └── queuebinding.yaml

Kubernetes Mode

dapr init -k --wait
dapr status -k
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    metadata:
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "myapp"
        dapr.io/app-port: "3000"
        dapr.io/config: "tracing"
    spec:
      containers:
        - name: myapp
          image: myapp:latest

Distributed Lock

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: lock
spec:
  type: lock.redis
  metadata:
    - name: redisHost
      value: localhost:6379
    - name: redisPassword
      value: ""
POST http://localhost:3500/v1.0-alpha/lock/lock
Content-Type: application/json

{ "resourceId": "order-1", "lockOwner": "node-A", "expiryInSeconds": 30 }
POST http://localhost:3500/v1.0-alpha/unlock/lock
Content-Type: application/json

{ "resourceId": "order-1", "lockOwner": "node-A" }

Workflow

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: orderworkflow
spec:
  type: workflow
  metadata: []
import "github.com/dapr/durabletask-go/task"

wf := task.NewWorkflow()
wf.AddActivity(task.Activity(func(ctx task.ActivityContext) (string, error) {
    var input string
    ctx.GetInput(&input)
    return "processed: " + input, nil
}))
POST http://localhost:3500/v1.0-alpha/workflows/dapr/orderworkflow/start
Content-Type: application/json

{ "instanceId": "order-1", "input": "{\"orderId\":\"1\"}" }
GET http://localhost:3500/v1.0-alpha/workflows/dapr/orderworkflow/order-1
POST http://localhost:3500/v1.0-alpha/workflows/dapr/orderworkflow/order-1/terminate
POST http://localhost:3500/v1.0-alpha/workflows/dapr/orderworkflow/order-1/pause
POST http://localhost:3500/v1.0-alpha/workflows/dapr/orderworkflow/order-1/resume

CLI 基础

dapr init
dapr run --app-id myapp --app-port 3000 -- dotnet run
dapr stop --app-id myapp
dapr uninstall
dapr publish --publish-app-id myapp --pubsub pubsub --topic orders --data '{"orderId":"1"}'
dapr invoke --app-id myapp --method orders --verb POST --data '{"id":"1"}'
dapr list
dapr status -k

服务调用

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: myapp-config
spec:
  tracing:
    samplingRate: "1"
resp, err := client.InvokeMethod(ctx, "ordersvc", "orders/1", "get")
GET http://localhost:3500/v1.0/invoke/ordersvc/method/orders/1

状态管理

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.redis
  metadata:
    - name: redisHost
      value: localhost:6379
    - name: redisPassword
      value: ""
POST http://localhost:3500/v1.0/state/statestore
Content-Type: application/json

[{"key": "order1", "value": {"itemId": "A", "qty": 3}}]
GET http://localhost:3500/v1.0/state/statestore/order1
DELETE http://localhost:3500/v1.0/state/statestore/order1

发布订阅

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: pubsub
spec:
  type: pubsub.redis
  metadata:
    - name: redisHost
      value: localhost:6379
    - name: redisPassword
      value: ""
POST http://localhost:3500/v1.0/publish/pubsub/orders
Content-Type: application/json

{"orderId": "1", "status": "new"}
POST http://localhost:3500/v1.0/publish/pubsub/orders?metadata.rawPayload=true

绑定

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: queuebinding
spec:
  type: bindings.rabbitmq
  metadata:
    - name: queueName
      value: orders
    - name: host
      value: amqp://localhost:5672
POST http://localhost:3500/v1.0/bindings/queuebinding
Content-Type: application/json

{ "operation": "create", "data": { "orderId": "1" } }

Actor 模型

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: myapp-config
spec:
  actorService:
    actorIdleTimeout: "30m"
    actorScanInterval: "30s"
    drainOngoingCallTimeout: "60s"
    drainRebalancedActors: true
POST http://localhost:3500/v1.0/actors/orderactor/1/method/submit
Content-Type: application/json

{"itemId": "A", "qty": 5}
GET http://localhost:3500/v1.0/actors/orderactor/1/state/status

可观测性

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: tracing
spec:
  tracing:
    samplingRate: "1"
    otel:
      endpointAddress: "localhost:4317"
      isSecure: false
      protocol: grpc
  metrics:
    enabled: true
    http:
      increasedCardinality: false

密钥存储

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: secretstore
spec:
  type: secretstores.local.file
  metadata:
    - name: secretsFile
      value: ./secrets.json
    - name: nestedSeparator
      value: ":"
GET http://localhost:3500/v1.0/secrets/secretstore/db-password
GET http://localhost:3500/v1.0/secrets/secretstore/bulk
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: aws-secretstore
spec:
  type: secretstores.aws.secretmanager
  metadata:
    - name: region
      value: us-east-1

配置 API

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: appconfig
spec:
  type: configuration.redis
  metadata:
    - name: redisHost
      value: localhost:6379
    - name: redisPassword
      value: ""
GET http://localhost:3500/v1.0/configuration/appconfig?key=debugMode

Dapr 组件

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: mystate
  namespace: default
spec:
  type: state.postgresql
  version: v1
  metadata:
    - name: connectionString
      value: "host=localhost user=postgres password=secret port=5432"
    - name: tableName
      value: state
  scopes:
    - myapp
    - anotherapp

自托管模式

dapr init --runtime-version 1.14.0
dapr init --slim
dapr run --app-id myapp --app-port 3000 --components-path ./components -- dotnet run
.
├── app.py
└── components/
    ├── statestore.yaml
    ├── pubsub.yaml
    └── queuebinding.yaml

Kubernetes 模式

dapr init -k --wait
dapr status -k
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    metadata:
      annotations:
        dapr.io/enabled: "true"
        dapr.io/app-id: "myapp"
        dapr.io/app-port: "3000"
        dapr.io/config: "tracing"
    spec:
      containers:
        - name: myapp
          image: myapp:latest

分布式锁

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: lock
spec:
  type: lock.redis
  metadata:
    - name: redisHost
      value: localhost:6379
    - name: redisPassword
      value: ""
POST http://localhost:3500/v1.0-alpha/lock/lock
Content-Type: application/json

{ "resourceId": "order-1", "lockOwner": "node-A", "expiryInSeconds": 30 }
POST http://localhost:3500/v1.0-alpha/unlock/lock
Content-Type: application/json

{ "resourceId": "order-1", "lockOwner": "node-A" }

工作流

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: orderworkflow
spec:
  type: workflow
  metadata: []
import "github.com/dapr/durabletask-go/task"

wf := task.NewWorkflow()
wf.AddActivity(task.Activity(func(ctx task.ActivityContext) (string, error) {
    var input string
    ctx.GetInput(&input)
    return "processed: " + input, nil
}))
POST http://localhost:3500/v1.0-alpha/workflows/dapr/orderworkflow/start
Content-Type: application/json

{ "instanceId": "order-1", "input": "{\"orderId\":\"1\"}" }
GET http://localhost:3500/v1.0-alpha/workflows/dapr/orderworkflow/order-1
POST http://localhost:3500/v1.0-alpha/workflows/dapr/orderworkflow/order-1/terminate
POST http://localhost:3500/v1.0-alpha/workflows/dapr/orderworkflow/order-1/pause
POST http://localhost:3500/v1.0-alpha/workflows/dapr/orderworkflow/order-1/resume