1 - 认证生命周期

从提交到生产就绪的组件认证生命周期

概述

Dapr 采用模块化设计,功能以组件形式交付。每个组件都有一个接口定义。所有组件都是可互换的,因此在理想情况下,您可以用具有相同接口的另一个组件替换某个组件。生产环境中使用的每个组件都需要维护一定的技术要求,以确保功能兼容性和健壮性。

通常,组件需要满足:

  • 符合定义的 Dapr 接口
  • 功能正确且健壮
  • 文档完善且得到维护

为了确保组件符合 Dapr 制定的标准,需要在 Dapr 维护者管理的环境中对组件运行一系列测试。一旦测试持续通过,就可以确定组件的成熟度级别。

认证级别

级别如下:

Alpha

  • 组件实现了所需的接口,并按照规范中的描述工作
  • 组件具有文档
  • 组件可能存在错误,或在集成时暴露错误
  • 组件可能无法通过所有一致性测试
  • 组件可能没有一致性测试
  • 由于后续版本可能存在不兼容的更改,建议仅用于非业务关键用途

所有组件都从 Alpha 阶段开始。

Beta

  • 组件必须通过满足组件规范所定义的所有组件一致性测试
  • 组件一致性测试已在 Dapr 维护者管理的环境中运行
  • 组件包含由 Dapr 维护者审核和批准的一致性测试结果记录,并注明特定的 components-contrib 版本
  • 由于后续版本可能存在不兼容的更改,建议仅用于非业务关键用途

Stable

  • 组件必须具有组件认证测试,用于验证功能和弹性
  • 组件由 Dapr 维护者维护,并由社区支持
  • 组件文档完善且经过测试
  • 组件在之前至少 1 个 Dapr runtime 次版本发布中已作为 Alpha 或 Beta 提供
  • 维护者将根据 Dapr 支持策略处理组件安全性、核心功能和测试问题,并发布包含修补后的稳定组件的补丁版本

之前的正式发布(GA)组件

任何之前认证为 GA 的组件即使不满足新要求,也允许进入 Stable 级别。

一致性测试

components-contrib 仓库中的每个组件都需要遵守 Dapr 定义的一组接口。一致性测试是在这些组件定义上运行的测试,连同其关联的后端服务,以测试组件是否符合 Dapr 接口规范和行为。

一致性测试是为以下构建块定义的:

  • 状态存储
  • 密钥存储
  • 绑定
  • 发布订阅

要了解更多信息,请参阅此处的 readme

测试要求

  • 测试应根据组件规范验证组件的功能行为和健壮性
  • 重现测试所需的所有详细信息都应作为组件一致性测试文档的一部分添加

认证测试

components-contrib 仓库中的每个稳定组件都必须具有认证测试计划和自动化认证测试,用于验证组件通过 Dapr 支持的所有功能。

稳定组件的测试计划应包括以下场景:

  • 客户端重新连接:如果客户端库暂时无法连接到服务,Dapr 边车不应在服务重新上线后要求重启。
  • 身份验证选项:验证组件可以使用所有支持的选项进行身份验证。
  • 验证资源预配:验证组件是否在初始化时自动预配资源(如适用)。
  • 与相应构建块和组件相关的所有场景。

测试计划必须由 Dapr 维护者批准,并与组件代码一起发布在 README.md 文件中。

测试要求

  • 测试应根据组件规范验证组件的功能行为和健壮性,反映测试计划中的场景
  • 测试必须作为 components-contrib 仓库持续集成的一部分成功运行

组件认证流程

为了对组件进行认证,测试在 Dapr 项目维护的环境中运行。

新组件认证:Alpha->Beta

对于需要从 Alpha 更改为 Beta 认证的新组件,组件认证请求遵循以下步骤:

  • 请求者在 components-contrib 仓库中创建组件认证的 issue,注明当前和新的认证级别
  • 请求者提交 PR 将组件与定义的一致性测试套件集成(如果尚未包含)
    • 用户在创建的 issue 中详细说明环境设置,以便 Dapr 维护者可以在托管环境中设置服务
    • 环境设置完成后,Dapr 维护者审核 PR,如果批准则合并该 PR
  • 请求者在 docs 仓库中提交 PR,更新组件的认证级别

新组件认证:Beta->Stable

对于需要从 Beta 更改为 Stable 认证的新组件,组件认证请求遵循以下步骤:

  • 请求者在 components-contrib 仓库中创建组件认证的 issue,注明当前和新的认证级别
  • 请求者为测试计划提交 PR,作为组件源代码目录中的 README.md 文件
    • 请求者在创建的 PR 中详细说明测试环境要求,包括任何手动步骤或所需的凭据
    • Dapr 维护者审核测试计划,提供反馈或批准,并最终合并 PR
  • 请求者为自动化认证测试提交 PR,包括在适用时预配资源的脚本
  • 测试环境设置完成并预配凭据后,Dapr 维护者审核 PR,如果批准则合并 PR
  • 请求者在 docs 仓库中提交 PR,更新组件的认证级别

2 - 更新组件

更新应用程序使用的已部署组件

当对应用程序使用的现有已部署组件进行更新时,除非启用了 HotReload 特性门控,否则 Dapr 不会自动更新组件。 需要重启 Dapr 边车以获取组件的最新版本。 具体操作方式取决于托管环境。

Kubernetes

在 Kubernetes 中运行时,更新组件的过程包含两个步骤:

  1. 将新的组件 YAML 应用到目标命名空间
  2. 除非启用了 HotReload 特性门控,否则在你的部署上执行 rollout restart 操作 以获取最新组件

自托管模式

除非启用了 HotReload 特性门控,否则更新组件的过程需要单个步骤:停止并重启 daprd 进程以获取最新组件。

热重载(预览功能)

此功能目前处于预览阶段。 热重载通过 HotReload 特性门控 启用。

Dapr 可以"热重载"组件,即无需重启 Dapr 边车进程或 Kubernetes pod 即可自动获取组件更新。 这意味着在运行时创建、更新或删除组件清单会反映在 Dapr 边车中。

除以下类型外,所有组件都支持热重载。 对于这些组件类型的任何创建、更新或删除操作都会被边车忽略,需要重启才能获取更改。

延伸阅读

3 - 操作指南:将组件限定到一个或多个应用程序

限制组件只能被特定的 Dapr 实例访问

Dapr 组件具有命名空间(与 Kubernetes 命名空间概念是独立的),这意味着 Dapr 运行时实例只能访问部署到同一命名空间的组件。

当 Dapr 运行时,它会将其自身配置的命名空间与组件的命名空间进行匹配,并仅加载和初始化与其命名空间匹配的组件。不同命名空间中的所有其他组件都不会被加载。

命名空间

命名空间可用于限制组件只能被特定的 Dapr 实例访问。

在自托管模式下,开发者可以通过设置 NAMESPACE 环境变量为 Dapr 实例指定命名空间。 如果设置了 NAMESPACE 环境变量,Dapr 将不会加载任何在元数据中未指定相同命名空间的组件。

例如,给定以下位于 production 命名空间中的组件

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
  namespace: production
spec:
  type: state.redis
  version: v1
  metadata:
  - name: redisHost
    value: redis-master:6379

要告知 Dapr 其部署到的命名空间,请设置环境变量:

MacOS/Linux:

export NAMESPACE=production
# 像往常一样运行 Dapr

Windows:

setx NAMESPACE "production"
# 像往常一样运行 Dapr

让我们考虑 Kubernetes 中的以下组件:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
  namespace: production
spec:
  type: state.redis
  version: v1
  metadata:
  - name: redisHost
    value: redis-master:6379

在此示例中,Redis 组件仅可由运行在 production 命名空间内的 Dapr 实例访问。

使用作用域控制应用程序对组件的访问

开发者和操作员可能希望限制某个应用程序或特定的一组应用程序访问某个数据库。 为了实现这一点,Dapr 允许你在组件 YAML 上指定 scopes。添加到组件的应用程序作用域仅允许具有特定 ID 的应用程序使用该组件。

以下示例展示了如何为两个启用了 Dapr 的应用程序授予访问名为 statestore 的 Redis 组件的权限,这两个应用程序的 app ID 分别为 app1app2,而该组件本身位于 production 命名空间中

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
  namespace: production
spec:
  type: state.redis
  version: v1
  metadata:
  - name: redisHost
    value: redis-master:6379
scopes:
- app1
- app2

社区电话演示

在服务调用中使用命名空间

阅读跨命名空间的服务调用以了解更多关于在服务间调用时使用命名空间的信息。

在发布订阅中使用命名空间

阅读使用多个命名空间配置发布订阅组件以了解更多关于在发布订阅中使用命名空间的信息。

相关链接

4 - 操作指南:在组件中引用密钥

如何安全地从组件定义中引用密钥

概述

组件可以引用组件定义中 spec.metadata 部分的密钥。

为了引用密钥,你需要设置 auth.secretStore 字段来指定保存密钥的密钥存储的名称。

在 Kubernetes 中运行时,如果 auth.secretStore 为空,则假定为 Kubernetes 密钥存储。

支持的密钥存储

访问此链接查看 Dapr 支持的所有密钥存储,以及有关如何配置和使用它们的信息。

引用密钥

虽然你可以选择使用纯文本密钥(如 MyPassword),如下面的 yaml 中 redisPasswordvalue 所示,但不建议在生产环境中这样做:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.redis
  version: v1
  metadata:
  - name: redisHost
    value: localhost:6379
  - name: redisPassword
    value: MyPassword

相反,你应在密钥存储中创建密钥并在组件定义中引用它。下面显示了两种情况——“密钥包含嵌入的键"和"密钥是字符串”。

“密钥包含嵌入的键"的情况适用于密钥中嵌入有键的情况,即密钥不是完整的连接字符串。这在以下组件定义 yaml 中显示。

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.redis
  version: v1
  metadata:
  - name: redisHost
    value: localhost:6379
  - name: redisPassword
    secretKeyRef:
      name: redis-secret
      key:  redis-password
auth:
  secretStore: <SECRET_STORE_NAME>

SECRET_STORE_NAME 是配置的密钥存储组件的名称。在 Kubernetes 中运行并使用 Kubernetes 密钥存储时,字段 auth.SecretStore 默认为 kubernetes,可以留空。

上面的组件定义告诉 Dapr 从定义的 secretStore 中提取名为 redis-secret 的密钥,并将嵌入在密钥中的 redis-password 键关联的值分配给组件中的 redisPassword 字段。这种情况的一个用途是当你的代码正在构造连接字符串时,例如将 URL、密钥以及其他必要的信息组合成一个字符串。

另一方面,下面的"密钥是字符串"的情况适用于密钥中没有嵌入键的情况。相反,密钥只是一个字符串。因此,在 secretKeyRef 部分中,密钥 name 和密钥 key 将是相同的。这种情况适用于密钥本身是一个完整的连接字符串,没有嵌入的需要提取其值的键的情况。通常,连接字符串由连接信息、某种允许连接的密钥,可能还有其他信息组成,不需要单独的"密钥”。这种情况在以下组件定义 yaml 中显示。

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: servicec-inputq-azkvsecret-asbqueue
spec:
  type: bindings.azure.servicebusqueues
  version: v1
  metadata:
  - name: connectionString
    secretKeyRef:
      name: asbNsConnString
      key: asbNsConnString
  - name: queueName
    value: servicec-inputq
auth:
  secretStore: <SECRET_STORE_NAME>

上面的"密钥是字符串"情况 yaml 告诉 Dapr 从定义的 secretStore 中提取名为 asbNsConnstring 的连接字符串,并将该值分配给组件中的 connectionString 字段,因为 secretStore 中的"密钥"中没有嵌入键,因为它是一个纯字符串。这要求密钥 name 和密钥 key 相同。

示例

引用 Kubernetes 密钥

以下示例向你展示如何创建 Kubernetes 密钥来保存 Event Hubs 绑定的连接字符串。

  1. 首先,创建 Kubernetes 密钥:

    kubectl create secret generic eventhubs-secret --from-literal=connectionString=*********
    
  2. 接下来,在你的绑定中引用密钥:

    apiVersion: dapr.io/v1alpha1
    kind: Component
    metadata:
      name: eventhubs
    spec:
      type: bindings.azure.eventhubs
      version: v1
      metadata:
      - name: connectionString
        secretKeyRef:
          name: eventhubs-secret
          key: connectionString
    
  3. 最后,将组件应用到 Kubernetes 集群:

    kubectl apply -f ./eventhubs.yaml
    

限制对密钥的访问

Dapr 可以使用其配置限制对密钥存储中的密钥的访问。阅读操作指南:使用密钥范围操作指南:限制可以从密钥存储读取的密钥以获取更多信息。这是使用 Dapr 限制对密钥的访问的推荐方法。

Kubernetes 权限

默认命名空间

在 Kubernetes 中运行时,Dapr 在安装期间为 default 命名空间中的 Kubernetes 密钥存储的密钥访问定义默认的 Role 和 RoleBinding。对于从 default 命名空间获取密钥的 Dapr 启用应用程序,可以定义密钥并在组件中引用它,如上面的示例所示。

非默认命名空间

如果你的 Dapr 启用应用程序使用的组件从非默认命名空间获取密钥,请将以下资源应用于该命名空间:

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: secret-reader
  namespace: <NAMESPACE>
rules:
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list"]
---

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: dapr-secret-reader
  namespace: <NAMESPACE>
subjects:
- kind: ServiceAccount
  name: default
roleRef:
  kind: Role
  name: secret-reader
  apiGroup: rbac.authorization.k8s.io

这些资源授予 Dapr 从 Role 和 RoleBinding 中定义的命名空间的 Kubernetes 密钥存储获取密钥的权限。

相关链接

5 - 状态存储组件

为 Dapr 状态管理设置不同状态存储的指南

Dapr 与现有数据库集成,为应用提供状态管理能力,支持 CRUD 操作、事务等。它还支持每个应用配置多个命名的状态存储组件。

状态存储是可扩展的,可以在 components-contrib repo 中找到。

Dapr 中的状态存储使用 Component 文件描述:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: statestore
spec:
  type: state.<DATABASE>
  version: v1
  metadata:
  - name: <KEY>
    value: <VALUE>
  - name: <KEY>
    value: <VALUE>
...

数据库类型由 type 字段决定,连接字符串和其他元数据放在 .metadata 部分。 尽管元数据值可以包含明文密钥,但建议您使用 secret store

访问此指南了解如何配置状态存储组件。

支持的状态存储

访问此参考查看 Dapr 中所有支持的状态存储。

相关主题

6 - 发布订阅代理

为 Dapr 发布订阅配置不同消息代理的指南

Dapr 与发布订阅消息总线集成,为应用程序提供创建事件驱动、松耦合架构的能力,在这种架构中,生产者通过主题向消费者发送事件。

Dapr 支持为每个应用配置多个命名的发布订阅组件。每个发布订阅组件都有一个名称,在发布消息主题时会使用该名称。有关如何发布和订阅主题的详细信息,请参阅 API 参考

发布订阅组件是可扩展的。支持的发布订阅组件列表可以在这里找到,实现可以在 components-contrib 仓库中找到。

组件文件

发布订阅通过 Component 文件进行描述:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: pubsub
  namespace: default
spec:
  type: pubsub.<NAME>
  version: v1
  metadata:
  - name: <KEY>
    value: <VALUE>
  - name: <KEY>
    value: <VALUE>
...

发布订阅的类型由 type 字段决定,连接字符串等属性和其他元数据放置在 .metadata 部分。 尽管元数据值可以明文形式包含密钥,但建议您使用 secretKeyRef 来引用密钥存储

虽然所有发布订阅组件都支持 consumerID 元数据,但如果您不提供,运行时会创建一个消费者 ID。所有组件元数据字段值都可以携带模板化元数据值,这些值在 Dapr 边车启动时解析。 例如,您可以选择使用 {namespace} 作为 consumerGroup,以便在不同命名空间中使用相同的 appId 和相同的主题,如本文所述。

访问本指南以获取配置和使用发布订阅组件的说明。

相关链接

6.1 - HowTo: 配置多命名空间的发布订阅组件

在多命名空间中使用 Dapr 发布订阅

在某些场景中,应用程序可以分布在多个命名空间中,并通过 PubSub 共享队列或主题。在这种情况下,必须在每个命名空间中配置 PubSub 组件。

本示例使用 PubSub 示例。Redis 安装和订阅者位于 namespace-a 中,而发布者 UI 位于 namespace-b 中。如果 Redis 安装在另一个命名空间中,或者您使用托管云服务(如 Azure ServiceBus、AWS SNS/SQS 或 GCP PubSub),此解决方案也可以工作。

这是使用命名空间的示例图。



下表显示了哪些资源部署到哪些命名空间:

资源namespace-anamespace-b
Redis master
Redis replicas
Dapr 的 PubSub 组件
Node 订阅者
Python 订阅者
React UI 发布者

前置条件

设置 namespace-a

创建命名空间并切换 kubectl 以使用它。

kubectl create namespace namespace-a
kubectl config set-context --current --namespace=namespace-a

namespace-a 上安装 Redis(主节点和从节点),按照这些说明进行操作。

现在,配置 deploy/redis.yaml,注意包含 namespace-a 的主机名。

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: pubsub
spec:
  type: pubsub.redis
  version: v1
  metadata:
  - name: "redisHost"
    value: "redis-master.namespace-a.svc:6379"
  - name: "redisPassword"
    value: "YOUR_PASSWORD"

将资源部署到 namespace-a

kubectl apply -f deploy/redis.yaml
kubectl apply -f deploy/node-subscriber.yaml
kubectl apply -f deploy/python-subscriber.yaml

设置 namespace-b

创建命名空间并切换 kubectl 以使用它。

kubectl create namespace namespace-b
kubectl config set-context --current --namespace=namespace-b

将资源部署到 namespace-b,包括 Redis 组件:

kubectl apply -f deploy/redis.yaml
kubectl apply -f deploy/react-form.yaml

现在,找到 react-form 的 IP 地址,在浏览器中打开它并向每个主题(A、B 和 C)发布消息。

kubectl get service -A

确认订阅者收到消息。

切换回 namespace-a

kubectl config set-context --current --namespace=namespace-a

查找 POD 名称:

kubectl get pod # 复制 POD 名称并在下一个命令中使用。

显示日志:

kubectl logs node-subscriber-XYZ node-subscriber
kubectl logs python-subscriber-XYZ python-subscriber

在浏览器上发布的消息应显示在相应订阅者的日志中。Node.js 订阅者接收类型为 “A” 和 “B” 的消息,而 Python 订阅者接收类型为 “A” 和 “C” 的消息。

清理

kubectl delete -f deploy/redis.yaml  --namespace namespace-a
kubectl delete -f deploy/node-subscriber.yaml  --namespace namespace-a
kubectl delete -f deploy/python-subscriber.yaml  --namespace namespace-a
kubectl delete -f deploy/react-form.yaml  --namespace namespace-b
kubectl delete -f deploy/redis.yaml  --namespace namespace-b
kubectl config set-context --current --namespace=default
kubectl delete namespace namespace-a
kubectl delete namespace namespace-b

相关链接

7 - 密钥存储组件

关于设置不同密钥存储组件的指导

Dapr 与密钥存储集成,为应用程序和其他组件提供访问密钥(如访问密钥和密码)的安全存储和访问方式。每个密钥存储组件都有一个名称,在访问密钥时使用该名称。

与其他构建块组件一样,密钥存储组件是可扩展的,可以在 components-contrib 仓库 中找到。

Dapr 中的密钥存储使用 Component 文件描述,包含以下字段:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: secretstore
spec:
  type: secretstores.<NAME>
  version: v1
  metadata:
  - name: <KEY>
    value: <VALUE>
  - name: <KEY>
    value: <VALUE>
...

密钥存储的类型由 type 字段决定,连接字符串和其他元数据等内容放在 .metadata 部分中。

不同的支持的密钥存储将具有不同的需要配置的具体字段。例如,当配置使用 AWS Secrets Manager 的密钥存储时,文件将如下所示:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: awssecretmanager
spec:
  type: secretstores.aws.secretmanager
  version: v1
  metadata:
  - name: region
    value: "[aws_region]"
  - name: accessKey
    value: "[aws_access_key]"
  - name: secretKey
    value: "[aws_secret_key]"
  - name: sessionToken
    value: "[aws_session_token]"

应用配置

创建组件的 YAML 文件后,根据您的托管环境按照以下说明应用它:

要在本地运行,请创建一个包含 YAML 文件的 components 目录,并使用标志 --resources-pathdapr run 命令提供该路径。

要在 Kubernetes 中部署,假设您的组件文件名为 secret-store.yaml,请运行:

kubectl apply -f secret-store.yaml

支持的密钥存储

访问密钥存储参考以获取支持的密钥存储的完整列表。

相关链接

8 - Binding 组件

设置 Dapr binding 组件的指南

Dapr 与外部资源集成,允许应用既可以被外部事件触发,也可以与这些资源进行交互。每个 binding 组件都有一个名称,在与该资源交互时使用这个名称。

与其他构建块组件一样,binding 组件是可扩展的,可以在 components-contrib repo 中找到。

Dapr 中的 binding 使用 Component 文件描述,包含以下字段:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: <NAME>
  namespace: <NAMESPACE>
spec:
  type: bindings.<NAME>
  version: v1
  metadata:
  - name: <KEY>
    value: <VALUE>
  - name: <KEY>
    value: <VALUE>
...

binding 的类型由 type 字段决定,连接字符串和其他元数据等项放在 .metadata 部分。

不同的支持的 binding会有不同的特定字段需要配置。例如,为 Azure Blob Storage配置 binding 时,文件会像这样:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: <NAME>
spec:
  type: bindings.azure.blobstorage
  version: v1
  metadata:
  - name: storageAccount
    value: myStorageAccountName
  - name: storageAccessKey
    value: ***********
  - name: container
    value: container1
  - name: decodeBase64
    value: <bool>
  - name: getBlobRetryCount
    value: <integer>

应用配置

创建组件的 YAML 文件后,根据你的托管环境按照以下说明进行配置:

要在本地运行,创建一个包含 YAML 文件的 components 目录,并通过 --resources-path 标志向 dapr run 命令提供该路径。

要在 Kubernetes 中部署,假设你的组件文件名为 mybinding.yaml,运行:

kubectl apply -f mybinding.yaml

支持的 binding

访问 binding 参考获取支持的资源完整列表。

相关链接

9 - How-To: 注册可插拔组件

了解如何注册可插拔组件

组件注册流程

基于 gRPC 的可插拔组件 通常作为容器或进程运行,需要通过 Unix Domain Socket(简称 UDS)与 Dapr 运行时通信。它们通过以下步骤在运行时中被自动发现和注册:

  1. 组件监听位于共享卷上的 Unix Domain Socket
  2. Dapr 运行时列出共享卷中的所有 Unix Domain Socket
  3. Dapr 运行时与每个 socket 建立连接,并使用 gRPC 反射从给定构建块 API 中发现该组件实现的所有 proto 服务。

单个组件可以同时实现多个组件接口。

虽然 Dapr 的内置组件随运行时一起包含,但可插拔组件需要一些设置步骤才能与 Dapr 一起使用。

  1. 可插拔组件需要在 Dapr 本身启动之前启动并准备好接收请求。
  2. 用于可插拔组件通信的 Unix Domain Socket 文件需要使 Dapr 和可插拔组件都能访问。

在独立模式下,可插拔组件作为进程或容器运行。在 Kubernetes 上,可插拔组件作为容器运行,并由 Dapr 的边车注入器自动注入到应用程序的 pod 中,允许通过标准的 Kubernetes Container spec 进行自定义。

这也会改变在 Dapr 和可插拔组件之间共享 Unix Domain Socket 文件的方式。

选择您的环境以开始使您的组件可被发现。

运行组件

在 Dapr 启动之前,您的组件和 Unix Socket 必须都在运行。

默认情况下,Dapr 边车会在 /tmp/dapr-components-sockets 中查找作为 Unix Domain Socket 文件的组件。

此文件夹中的文件名对于组件注册很重要。它们必须通过将组件的名称附加您选择的文件扩展名来构成,更常见的是 .sock。例如,文件名 my-component.sock 是名为 my-component 的组件的有效 Unix Domain Socket 文件名。

由于您在与组件相同的主机上运行 Dapr,因此请验证此文件夹及其中的文件可被您的组件和 Dapr 访问和写入。如果您使用 Dapr 的边车注入器功能,则会自动创建并挂载此卷。

组件发现和多路复用

可通过 Unix Domain Socket(UDS)访问的可插拔组件可以托管多个不同的组件 API。在组件的初始发现过程中,Dapr 使用反射来枚举 UDS 后面的所有组件 API。上面示例中的 my-component 可插拔组件可以同时包含状态存储(state)和发布订阅(pubsub)组件 API。

通常,可插拔组件为实现单个组件 API 以进行打包和部署。但是,以增加其依赖关系和扩大其安全攻击面为代价,可插拔组件可以实现多个组件 API。这样做可以减轻部署和监控的负担。对于隔离、容错和安全的最佳实践是每个可插拔组件实现单个组件 API。

定义组件

使用组件规范定义您的组件。组件的 spec.type 值是通过将以下 2 个部分用 . 连接起来构成的:

  1. 组件的 API(statepubsubbindings 等)
  2. 组件的名称,源自 Unix Domain Socket 文件名,不带文件扩展名。

您需要为可插拔组件的 Unix Domain Socket 公开的每个 API 定义一个组件规范。上一个示例中的 Unix Domain Socket my-component.sock 公开了一个名为 my-component 的可插拔组件,它同时具有 statepubsub API。需要两个组件规范,每个都在自己的 YAML 文件中,放置在 resources-path 中:一个用于 state.my-component,另一个用于 pubsub.my-component

例如,state.my-component 的组件规范可以是:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: my-production-state-store
spec:
  type: state.my-component
  version: v1
  metadata:

在上面的示例中,请注意以下内容:

  • 字段 spec.type 的内容是 state.my-component,指的是作为名为 my-component 的可插拔组件公开的状态存储。
  • 字段 metadata.name 是此处定义的状态存储的名称,与可插拔组件名称无关。

将此文件作为 component.yaml 保存到 Dapr 的组件配置文件夹中。就像 metadata.name 字段的内容一样,此 YAML 文件的文件名没有影响,也不依赖于可插拔组件名称。

运行 Dapr

初始化 Dapr,并确保您的组件文件放置在正确的文件夹中。

就是这样!现在您可以通过 Dapr API 调用状态存储 API。通过运行以下命令查看实际效果。将 $PORT 替换为 Dapr HTTP 端口:

curl -X POST -H "Content-Type: application/json" -d '[{ "key": "name", "value": "Bruce Wayne", "metadata": {}}]' http://localhost:$PORT/v1.0/state/prod-mystore

检索值,将 $PORT 替换为 Dapr HTTP 端口:

curl http://localhost:$PORT/v1.0/state/prod-mystore/name

为可插拔组件构建并发布容器

确保您的组件作为容器运行,首先已发布并且您的 Kubernetes 集群可以访问。

在 Kubernetes 集群上部署 Dapr

按照 在 Kubernetes 集群上部署 Dapr 文档中提供的步骤进行操作。

在部署中添加可插拔组件容器

可插拔组件作为容器部署在与您的应用程序相同的 pod 中。

由于可插拔组件由 Unix Domain Sockets 支持,因此使可插拔组件创建的 socket 可被 Dapr 运行时访问。将部署规范配置为:

  1. 挂载卷
  2. 向 Dapr 提示已挂载的 Unix socket 卷位置
  3. 将卷附加到您的可插拔组件容器

在以下示例中,您配置的可插拔组件作为容器部署在与您的应用程序容器相同的 pod 中。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
  labels:
    app: app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app
  template:
    metadata:
      labels:
        app: app
      annotations:
        # 建议自动注入可插拔组件。
        dapr.io/inject-pluggable-components: "true" 
        dapr.io/app-id: "my-app"
        dapr.io/enabled: "true"
    spec:
      containers:
      # 您的应用程序的容器规范,照常。
        - name: app
           image: YOUR_APP_IMAGE:YOUR_APP_IMAGE_VERSION

建议将 dapr.io/inject-pluggable-components 注解设置为 “true”,表示 Dapr 的边车注入器此应用程序的 pod 将具有用于可插拔组件的其他容器。

或者,您可以跳过 Dapr 的边车注入功能,手动添加可插拔组件的容器并注释您的 pod,告诉 Dapr 该 pod 中的哪些容器是可插拔组件,如下面的示例所示:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
  labels:
    app: app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app
  template:
    metadata:
      labels:
        app: app
      annotations:
        dapr.io/pluggable-components: "component" ## 可插拔组件容器的名称用 `,` 分隔,例如 "componentA,componentB"。
        dapr.io/app-id: "my-app"
        dapr.io/enabled: "true"
    spec:
      containers:
      ### --------------------- 您的应用程序容器放在这里 -----------
        - name: app
           image: YOUR_APP_IMAGE:YOUR_APP_IMAGE_VERSION
      ### --------------------- 您的可插拔组件容器放在这里 -----------
        - name: component
          image: YOUR_IMAGE_GOES_HERE:YOUR_IMAGE_VERSION

在应用部署之前,让我们再添加一个配置:组件规范。

定义组件

可插拔组件使用组件规范定义。组件 type 派生自 socket 名称(不带文件扩展名)。在以下示例 YAML 中,替换:

  • your_socket_goes_here 替换为您的组件 socket 名称(无扩展名)
  • your_component_type 替换为您的组件类型
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: prod-mystore
  # 在 Kubernetes 上运行并自动容器注入时,添加以下注解:
  annotations:
    dapr.io/component-container: >
      {
        "name": "my-component",
        "image": "<registry>/<image_name>:<image_tag>"
      }
spec:
  type: your_component_type.your_socket_goes_here
  version: v1
  metadata:
scopes:
  - backend

当您希望 Dapr 的边车注入器为可插拔组件处理容器和卷注入时,dapr.io/component-container 注解在 Kubernetes 上是必需的。至少,您需要为 Dapr 的边车注入器提供 nameimage 属性,以便成功将容器添加到应用程序的 pod 中。Unix Domain Socket 的卷由 Dapr 的边车注入器自动创建和挂载。

范围限定您的组件,以确保只有目标应用程序可以连接到可插拔组件,因为它只会在其部署中运行。否则,运行时在初始化组件时会失败。

就是这样!将创建的清单应用到您的 Kubernetes 集群,并通过 Dapr API 调用状态存储 API。

使用 Kubernetes pod 转发器 访问 daprd 运行时。

通过运行以下命令查看实际效果。将 $PORT 替换为 Dapr HTTP 端口:

curl -X POST -H "Content-Type: application/json" -d '[{ "key": "name", "value": "Bruce Wayne", "metadata": {}}]' http://localhost:$PORT/v1.0/state/prod-mystore

检索值,将 $PORT 替换为 Dapr HTTP 端口:

curl http://localhost:$PORT/v1.0/state/prod-mystore/name

后续步骤

使用此示例代码开始开发 .NET 可插拔组件

10 - 配置中间件组件

通过添加中间件组件自定义处理管道

Dapr 允许通过链式串联一系列中间件组件来定义自定义处理管道。可以在两个位置使用中间件管道:

  1. 构建块 API - 调用任何 Dapr HTTP API 时执行 HTTP 中间件组件。
  2. 服务到服务调用 - 将 HTTP 中间件组件应用于服务到服务调用。

配置 API 中间件管道

启动时,Dapr 边车会为传入的 HTTP 调用构建一个中间件处理管道。默认情况下,该管道由 追踪 和 CORS 中间件组成。可以通过 Dapr 配置 添加额外的中间件,并按定义的顺序添加到管道中。该管道应用于所有 Dapr API 端点,包括状态、发布订阅、服务调用、绑定、密钥、配置、分布式锁等。

请求在路由到用户代码之前会经过所有定义的中间件组件,然后在返回给客户端之前,以相反的顺序经过定义的中间件,如下图所示。

Diagram showing the flow of a request and a response through the middlewares, as described in the paragraph above

使用 httpPipeline 配置调用 Dapr HTTP API 时,会执行 HTTP 中间件组件。

以下配置示例定义了一个使用 OAuth 2.0 中间件大写中间件组件 的自定义管道。在这种情况下,所有请求都通过 OAuth 2.0 协议进行授权,并在转发到用户代码之前转换为大写文本。

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: pipeline
  namespace: default
spec:
  httpPipeline:
    handlers:
      - name: oauth2
        type: middleware.http.oauth2
      - name: uppercase
        type: middleware.http.uppercase

与其他组件一样,中间件组件可以在支持的中间件参考dapr/components-contrib 仓库 中找到。

查看所有中间件组件

配置应用中间件管道

在进行服务到服务调用时,您也可以使用任何中间件组件。例如,在零信任环境中添加令牌验证、为特定应用端点转换请求或应用 OAuth 策略。

服务到服务调用中间件组件应用于从 Dapr 边车到接收应用程序(服务)的所有传出调用,如下图所示。

Diagram showing the flow of a service invocation request. Requests from the callee Dapr sidecar to the callee application go through the app middleware pipeline as described in the paragraph above.

任何可用作 HTTP 中间件的中间件组件都可以使用 appHttpPipeline 配置作为中间件组件应用于服务到服务调用调用。下面的示例为从 Dapr 边车(服务调用的目标)到应用此配置的应用程序的所有传出调用添加 uppercase 中间件组件。

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: pipeline
  namespace: default
spec:
  appHttpPipeline:
    handlers:
      - name: uppercase
        type: middleware.http.uppercase

相关链接