乘风破浪,.Net Core遇见Dapr,为云原生而生的分布式应用运行时

image

Dapr是一个由微软主导的云原生开源项目,国内云计算巨头阿里云也积极参与其中,2019年10月首次发布,到今年2月正式发布V1.0版本。在不到一年半的时间内,github star数达到了1.2万,超过同期的kubernetes、istio、knative等,发展势头迅猛,业界关注度非常高。

什么是云原生

云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式API。

这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更。

云原生计算基金会(CNCF)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。

image

什么是Dapr

Dapr(Distributed Application Runtime)分布式应用运行时,是一个可移植的、事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的、无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架。

image

Dapr 愿景

可移植,事件驱动,弹性,有状态和无状态,云和边端,语言无关,框架无关。

Any language, Any framework, Anywhere

其核心是要提供一个有标准,可配置,包含各种分布式能力的运行时。

image

如今,我们正经历着上云浪潮。开发人员对Web+数据库应用结构(例如经典3层设计)非常熟悉,并且使用得手,但对本身能支持分布式的微服务应用结构却感觉陌生。成为分布式系统专家很难,并且你也不需要这么做。开发人员希望专注于业务逻辑,同时希望平台为其提供可伸缩的、弹性的、可维护性和云原生架构的其他功能。

这就是Dapr所要解决的。Dapr将构建微服务应用的最佳实践设计成开放、独立和模块化的方式,让你能够选择的任意开发语言和框架构建可移植应用程序。每个构建块都是完全独立的,您可以采用其中一个或多个或全部来构建你的应用。

此外,Dapr是和平台无关的,这意味着您可以在本地、Kubernetes群集或者其它集成Dapr的托管环境中运行应用程序。这使得您能够在云平台和边缘计算中运行微服务应用。

使用Dapr,您可以使用任何语言、任何框架轻松构建微服务应用,并运行在任何地方。

image

Dapr 发展历程

  • 2019年10月:微软在GitHub上开源了Dapr,发布0.1.0版本
  • 2021年2月:Daprv1.0版本发布

阿里巴巴深度参与Dapr项目,不仅仅以终端用户的身份成为Dapr的早期采用者,也通过全面参与Dapr的开源开发和代码贡献成为目前Dapr项目中的主要贡献公司之一,仅次于微软:

image

  • 2020年中:阿里巴巴开始参与Dapr项目,在内部试用功能并进行代码开发
  • 2020年底:阿里巴巴内部小规模试点Dapr,目前已经十几个应用在使用Dapr。

Dapr 引领云原生的未来

分布式应用所需:

  • 生命周期:包括部署,健康检查,水平扩展,配置管理等,目前这些需求的最佳实践,都陆续在kubernetes上有了落地。
  • 网络:网络方面的需求是service Mesh的主战场,比如istio可以满足这里绝大部分需求,除了pub/sub。
  • 状态:包括数据的读写,状态其实是非常难以管理的,涉及幂等,缓存,数据流等等。
  • 绑定:主要是指和系统外部资源的交互。

image

Multi runtime是由RedHat首席架构师Bilgin Ibryam提出的,实际上multi runtime和dapr并没有直接的关系,multi runtime的提出是在dapr开源之后。作者的文章重点对当今分布式应用的需求做了归类,并且分析了当前流行的云原生项目是如何满足这些分布式需求,包括kubernetes,istio,dapr等,最后,作者对分布式应用和中间件的未来发展,做了推导和预测,这就是multiruntime。

过去,我们对云原生的全景:

image

有了Dapr之后,我们对云原生的全景:

image

应用的期望就是中间件的方向:

  • 应用可以使用任意喜爱而适合的语言编写,可以快速开发和快速迭代。
  • 应用需要的能力都可以通过标准的API提供,无需关心底层具体实现。
  • 应用可以部署到任意的云端,不管是公有云、私有云还是混合云,没有平台和厂商限制,无需代码改造。
  • 应用可以根据流量弹性伸缩,顶住波峰的压力,也能在空闲时释放资源。

image

Service Mesh探索了Sidecar模式,Dapr将Sidecar模式推广到更大的领域:

  • 完善的多语言支持和应用轻量化的需求推动中间件将更多的能力从应用中分离出来
  • Sidecar模式会推广到更大的领域,越来越多的中间件产品会开始Mesh化,整合到Runtime。
  • 对厂商锁定的天然厌恶和规避,会加剧对可移植性的追求,从而进一步促使为下沉到Runtime中的分布式能力提供标准而业界通用的API。
  • API的标准化和社区认可,将成为Runtime普及的最大挑战,但同时也将推动各种中间件产品改进自身实现,实现中间件产品和社区标准API之间的磨合与完善。

image

预测未来:

image

Dapr 与Istio、Linkerd或OSM等服务网格相比如何?

Dapr不是一个服务网格。虽然服务网侧重于细粒度网络控制,但Dapr专注于帮助开发人员构建分布式应用程序。Dapr和服务网都使用sidecar模式,并随应用程序一起运行,它们确实具有一些重叠的功能,但也提供独特的优势。

虽然Dapr和服务网格确实提供了一些重叠功能,但dapr不是服务网格,其中服务网格被定义为网络的服务网格。与专注于网络问题的服务网格不同,Dapr专注于提供构建基块,使开发人员更容易将应用程序构建为微服务。Dapr以开发人员为中心,而服务网格以基础设施为中心。

在大多数情况下,开发人员不需要意识到他们正在构建的应用程序将部署在包括服务网格在内的环境中,因为服务网格会拦截网络流量。服务网格主要由系统操作员管理和部署。但是,Dapr构建块API旨在供开发人员在其代码中明确使用。

Dapr与服务网格共享的一些常见功能包括:

  • 使用mTLS加密实现安全的服务到服务通信
  • 服务到服务指标集合
  • 服务到服务分布式跟踪
  • 通过重试获得可恢复能力

重要的是,Dapr通过以开发人员为中心的关注点提供服务发现和调用。这意味着,通过Dapr的服务调用API,开发人员在服务名称上调用一种方法,而服务网格则处理网络概念,如IP和DNS地址。但是,Dapr不为路由或流量拆分等流量行为提供功能。流量路由通常使用应用程序的入口代理处理,并且不必使用服务网格。此外,Dapr还为状态管理、发布/订阅、Actor等提供了其他应用级别的构建块。

Dapr和服务网之间的另一个区别是可观察性(跟踪和指标)。服务网格在网络级别运行,并跟踪服务之间的网络调用。Dapr通过服务调用来达到此操作,但Dapr也使用写入Cloud Events信封的跟踪Id在发布/订阅调用上提供可观察性(跟踪和指标)。这意味着Dapr的指标和跟踪比使用服务到服务调用和发布/订阅进行通信的应用程序的服务网格更为广泛。

下图捕获Dapr和服务网格提供的重叠功能和独特功能:

image

Dapr 三驾马车

Dapr的设计是典型的分层架构,其核心理念,是利用抽象层来实现应用关注点的分离,用以降低分布式应用的复杂性。

在Dapr的架构中,核心的三个组成部分:APIBuilding BlocksComponents

image

Dapr API

Dapr提供两种API,HTTP1.1/REST和HTTP2/gRPC,两者在功能上是对等的。

应用如何能使用到这些分布式能力,这是Dapr最核心的设计,也是dapr应用和非dapr应用最关键的区别: dapr利用标准API暴露各种分布式能力。API定义了应用所需的分布式能力。dapr提供两种API: HTTP1.1/RESTHTTP2/gRPC,两者在功能上是等价的。这些API是平台无关的,或者说是实现无关的,这是dapr能否流行的一个关键。

应用只需要按照API规范发起,不管是服务访问,还是存储,还是发布消息到队列里,都是HTTP接口。不管是操作redis还是mysql都是一样的API。在应用看来,一切所需的能力,都可以用HTTP协议来表示,这些能力的获取是标准化的,只要应用需要的分布式能力不变,那应用的代码就不需要改变。

将「分布式原语」映射到HttpAPI上,极大地减少了程序员心智的开销。在应用代码中不再需要引入相关的组件调用库,不需要去封装组件的具体调用方式,不需要对不同的实现做区分。

另外在用户应用侧,dapr还提供了多种语言的SDK,这些SDK的目的是用更便捷的方式来暴露buildingBlocks的API,用更加语义化的方法调用,来封装Http/gRPC的调用。

Dapr Building Blocks(构建块)

翻译为构建块,这是Dapr对外提供能力的基本单元,每个构建块对外提供一种分布式能力。

Dapr对外提供能力的基本单元,是对分布式能力的抽象和归类,包括以下几大类:

  • service-to-service invocation
  • State management
  • Publish and subscribe
  • Resource bindings
  • Actors
  • Observability
  • Secrets

Dapr目前已有的构建块和他们提供的能力的简单描述:

image

Building Block构建块是可以从您的代码中调用的HTTP或gRPC API,并且由一个或多个Dapr组件组成。

构建块解决了构建弹性微服务应用程序中的常见挑战,并编纂了最佳实践和模式。Dapr由一组构建块组成,并且具有可扩展性以添加新的构建块。

下图显示了构建块如何公开了可被代码调用的公共API,并使用组件来实现构建块的能力。

image

以下是Dapr提供的构建块类型:

image

每个构建块都是独立的,这意味着您可以采用其中一个或多个或全部来构建应用。在当前Dapr的初始版本中,提供了以下构建块:

构建块 描述
服务间调用 弹性的服务间调用能在远程服务上进行方法调用(包括检索),无论它们是否位于受支持的托管环境中的。
状态管理 对于存储键/值对的状态管理,长时间运行,高可用性,有状态服务可轻松写入应用程序中的无状态服务。状态存储是可插拔的,可以包括Azure Cosmos DB,Azure SQL Server,Postgre SQL,AWS Dynamo DB或Redis等。
发布订阅 发布活动并订阅主题
资源绑定 带触发器的资源绑定通过接收和发送事件到任何外部源(如数据库、队列、文件系统等)来进一步构建事件驱动架构,以实现扩展性和弹性。
Actors 一种用于有状态和无状态对象的模式,通过方法和状态的封装让并发变得简单。Dapr在其actor运行时提供了很多能力,包括并发,状态管理,用于actor激活/停用的生命周期管理,以及唤醒actor的计时器和提醒器。
可观测性 Dapr可以发出度量,日志和跟踪以调试和监控Dapr和用户应用程序。Dapr支持分布式跟踪,通过使用W3C跟踪上下文标准和OpenTelemetry发送到不同的监控工具,以方便诊断和服务于生产中的服务间调用。
秘密 Dapr提供秘密管理,并与公有云和本地秘密存储集成,以检索秘密,用于应用代码。

Dapr Components(组件)

组件层,这是Dapr的能力实现层,每个组件都会实现特定构建块的能力。

Components提供和各种分布式实现的对接,包括自建的,云上的,边缘等等。

理论上building block可以组合使用任意的components,一个component也可以被不同的building block使用。比如actor和state都会使用state component;另一个例子,service invocation会使用namere solution和middleware component,而且不同的场景下,可以选择不同的component实现。

Component类型和实现:在实现层面,每一种component类型定义了一系列接口(interface definition),每一种component类型有多种component实现,他们都实现了component类型要求的接口(interface)。

三驾马车的关系

image

  • Dapr Building Blocks提供“能力”
  • Dapr API提供对分布式能力的“抽象”,对外暴露Building Block的能力
  • Dapr Components是Building Block能力的具体“实现”

Dapr API如何实现

比如一个电商系统,需要持久化存储,传统的做法是,我们要先决策使用什么存储,mysql或者redis等,我们需要在代码里引入相应的SDK,编写各异的实现,未来如果应用想要切换存储类型,或者从本地存储迁移到云上,改动非常大。

假设这个系统的特征是读多写少,那我们倾向于用乐观锁来更新数据。业务提出来的「用乐观锁控制并发写入」这就是一个典型的分布式需求,而这种需求的实现在不同的存储系统中不尽相同,比如mysql是需要用户显式指定一个字段作为版本信息,用户写操作是需要把版本信息传回服务器,而redis乐观锁需要用户指定在redis server端watch某个key。类似的需求还有数据库一致性,是使用最终一致性还是强一致性,各种存储实现也不同。

image

如上图所示,如果接入使用dapr runtime,应用发起存储调用非常简单,不需要在应用代码里引入redis或者mysql的SDK,也不用关心实际存储使用是什么通信协议,应用代码里只需要使用分布式原语和dapr runtime通信,通信的协议是简单的Http或者gRPC,dapr runtime去实现这些分布式能力。

Dapr 服务调用(Service Invocation)

image

主要能力:

  • 服务发现
  • 通信安全
  • 失败重试
  • 可观测性

在kubernetes中使用dapr,dapr会为每个服务生成一个新的service(以-dapr结尾),sidecar之间的通信都是gRPC,每个应用需要指定一个app-id用于服务发现,应用需要显示的发起对runtimeAPI的调用,没有类似mesh的iptables透明拦截。

大家可以脑洞一下,如果dapr这种模式能大规模流行,那市面上大部分RPC是不是都不再需要了,如今大部分RPC虽然各有专长,但是大部分功能都是类似的,服务发现、编解码、网络传输,有的RPC框架还带服务治理的能力。大部分能力目前都可以由mesh或者dapr这类runtime来提供,这也是一个明显的趋势。

怎么理解这件事呢?

传统来说,从服务A调用服务B,一般是直接请求POST https://serverB.com:port/method-Name,但是在dapr中,将改成这样的格式:

POST/GET/PUT/DELETE http://daprHost:<daprPort>/v1.0/invoke/<appId>/method/<method-name>

dapr规范了服务之间的调用方式,这样的好处就是,实现对服务间网络通信的控制以完成诸如服务发现、流量控制、重试熔断、安全访问等,而这相关的网络控制功能就是集成在Dapr的Sidecar中,以对应用透明的方式集成进来的。

与Istio相比,都是通过Sidecar来实现,但是Dapr是以API的方式,而Istio是以代理的方式。

Dapr 状态管理(State Management)

image

Dapr以更友好的HTTP API的方式进行状态的存储和读取,同时支持通过ETags进行并发控制,并支持通过选项设置并发和一致性行为。

  • 存储:POST http://localhost:<daprPort>/v1.0/state/<storename>
  • 读取:GET http://localhost:<daprPort>/v1.0/state/<storename>/<key>
  • 删除:DELETE http://localhost:<daprPort>/v1.0/state/<storename>/<key>

主要能力:

  • CRUD,包括批量操作
  • 事务
  • 并发:
  • first-write-wins、last-write-wins
  • 一致性:
  • 最终一致、强一致性
  • 可插拔(Pluggablestatestores)

State提供一致的键值对存储抽象,这里不包括关系型或者其他类型的存储。总的来说,在云原生领域(以kubernetes和etcd为代表),键值对存储的适用范围更广。另外相比其他存储类型,键值对存储引擎的接口抽象更容易实现,即使是关系型数据库,也能轻松的实现对键值对API的支持。

但仍然不是所有的存储引擎都能提供等价的键值对存储能力。为了保证应用程序的可移植性,这里的确是需要一些适配工作。比如像Memcached,Cassandra这些是不支持事务的,而很多数据库也不能提供基于ETag的乐观锁能力。

对于并发控制,在API层,Dapr利用HTTP ETags来实现并发控制,类似kubernetes对象的resource version,具体地:Dapr在返回数据时,会带上Etag属性。如果用户需要使用乐观锁做更新操作,请求中需要带回Etag,只有当Etag和服务器上数据的相同时,更新操作才会成功。如果更新操作没有带上Etag,那并发模式将是last-write-wins

举例:

  • concurrency用于指定并发选项:first-write-wins / last-write-wins(以第一次写入为准/以最后一次写入为准),默认以最后一次写入为准。
  • consistency用于指定一致性选项:strong / eventual(强一致性/最终一致性),默认为最终一致性。
curl -X POST http://localhost:3500/v1.0/state/starwars \
  -H "Content-Type: application/json" \
  -d '[
        {
          "key": "weapon",
          "value": "DeathStar",
          "etag": "xxxxx",
          "options": {
            "concurrency": "first-write",
            "consistency": "strong"
          }
        }
      ]'

目前支持使用Azure CosmosDBAzure SQL ServerPostgreSQLAWS DynamoDBRedis作为状态存储介质。

Dapr 发布和订阅(Publish And Subscribe)

image

使用发布和订阅模式,微服务间可以充分的解耦。

  • 发布:POST http://localhost:<daprPort>/v1.0/publish/<pubsubname>/<topic>[?<metadata>]
  • 获取可订阅主题:GET http://localhost:<appPort>/dapr/subscribe
  • 订阅:POST http://localhost:<appPort>/<path>

Dapr提供了一致性的消息发布、订阅API,而无需关注具体使用的是何种Message Broker,从而和底层基础设施解耦。

主要能力:

  • 统一的消息格式:
  • CloudEvents
  • At-Least-Onceguarantees(消息绝不会丢,但可能会重复传递)
  • 支持消息过期时间(permessageTTL)
  • 支持topic可见性配置

Runtime不仅可以做能力的对接适配,还可以做增强,这是一个例子:如果消息组件原生支持消息有效期,那Runtime直接转发TTL相关操作,过期的行为由组件直接控制,而对于那些不支持消息有效期的组件,Dapr会在Runtime中补齐相关的过期功能。(Cloud Event里有Expiration)

Dapr 绑定(Bindings)

image

Dapr的Bindings与Azure Functions很类似,其是建立在事件驱动架构的基础之上的。通过建立触发器与资源的绑定,可以从任何外部源(例如数据库,队列,文件系统等)接收和发送事件,而无需借助消息队列,即可实现灵活的业务场景。Dapr的Bindings分为两种:

  • Input Bindings(输入绑定):当外部资源的事件发生时,借助输入绑定,你的应用即可通过特定的API:POST http://localhost:<appPort>/<name>收到外部资源的事件,用于处理特定逻辑。

  • Output Bindings(输出绑定):输出绑定允许你调用外部资源。比如,在订单处理场景中,在订单创建成功后,可以将订单信息通过Dapr的绑定API:POST/PUT http://localhost:<daprPort>/v1.0/bindings/<name>输出到Kafka特定队列上。

Bindings其实和之前的pub/sub非常类似,也是利用异步通信传递消息。它俩主要的区别是:pub/sub主要面向的是dapr内部应用,而bindings主要解决的和外部依赖系统的输入输出。

实际上它俩下层的components有很多是重叠的,比如说kafka,redis既可以作为内部消息传递,也可以作为外部消息传递。pub/sub基本可以等同于消息队列,但bindings主要是处理事件(trigger handler),比如twitter关键字事件,比如github webhooks等。

image

Dapr 并发模型(Actor)

image

  • 最基本的计算单元,封装了可以执行的行为和私有状态
  • 通过信箱异步通信
  • 内部单线程
  • 虚拟的:不需要显示创建,自动GC

Actor是一种并发编程的模型,Actor表示的是一个最基本的计算单元,封装了可以执行的行为和私有状态。actor之间相互隔离,它们并不互相共享内存,也就是说,一个actor能维持一个私有的状态,并且这个状态不可能被另一个actor所改变。在actor模型里每个actor都有地址(信箱),所以它们才能够相互发送消息。每个actor只能顺序地处理消息。单个actor不考虑并发。

Dapr中actor是虚拟的,它们并不一定要常驻内存。它们不需要显式创建或销毁。dapr actor runtime在第一次接收到该actor ID的请求时自动激活actor。如果该actor在一段时间内未被使用,那么runtime将回收内存对象。如果以后需要重新启动,它还将还原actor的一切原有数据。

Actor placement service为系统提供了actor分发和管理,placement会跟踪actor类型和所有实例的分区,并将这些分区信息同步到每个dapr实例中,并跟踪他们的创建和销毁。

image

简单来讲:Actor模型 = 状态 + 行为 + 消息。一个应用/服务由多个Actor组成,每个Actor都是一个独立的运行单元,拥有隔离的运行空间,在隔离的空间内,其有独立的状态和行为,不被外界干预,Actor之间通过消息进行交互,而同一时刻,每个Actor只能被单个线程执行,这样既有效避免了数据共享和并发问题,又确保了应用的伸缩性。

Actor模型大大简化了并发编程的复杂度,Dapr在Actor运行时中提供了许多功能,包括并发控制,状态管理,生命周期管理如Actor的激活/停用以及用于唤醒Actor的Timer(计时器)和Reminder(提醒)。这些功能同样也是通过API的方式予以提供。

  • 调用Actor 方法:POST/GET/PUT/DELETE http://localhost:3500/v1.0/actors/<actorType>/<actorId>/method/<method>
  • 创建Timer:POST/PUT http://localhost:3500/v1.0/actors/<actorType>/<actorId>/timers/<name>
  • 创建Reminder:POST/PUT http://localhost:3500/v1.0/actors/<actorType>/<actorId>/reminders/<name>

Dapr 遥测(Observability)

Dapr记录指标、日志、链路以调试和监视Dapr和用户应用的运行状况。 Dapr支持分布式跟踪,其使用W3C跟踪上下文标准和开放式遥测技术,可以轻松地诊断在生产环境中服务间的网络调用,并发送到不同的监视工具,如Prometheus。

Dapr 安全(Secrets)

Dapr 提供了Secret管理,不过不同于K8S中的Secret,其支持与公有云和本地的Secret存储集成,以供应用检索使用。

Dapr 中间件流水线(Middleware Pipelines)

image

注意middleware pipelines是一个component类型,而不是building block。

Dapr官方提供流量管控的能力比较弱,和istio相比的话,目前dapr只有重试,加密等少数的管控能力,但dapr提供一个扩展的方式:这就是middleware pipelines,用户可以按需编写不同的实现,并把他们级联起来使用。

其实这种方式在各种编程语言web框架中非常常见,只是叫法不同,有的叫装饰者模型,有的叫洋葱模型,其实模式都是一样:请求在路由到用户代码之前,会先按序执行middleware pipelines,请求经过应用处理后,再按相反顺序执行上述middleware pipeline。通常在前序中对request做相应的增强处理,在后续中对response做增强处理。

咋一看这可能是一个不太起眼的功能,但和传统web框架的middleware不一样,dapr runtime本身是在应用进程之外,所以不存在语言限制的问题。这使得middleware提供的功能可以跨语言共享。比如dapr原生没有提供限流和自定义鉴权的功能(呼声很高的2个场景),我们可以遵循middleware的接口按需实现,然后植入dapr运行时中。

image

Dapr 部署模式(托管方式)

Dapr可以托管在多种环境中,包括用于本地开发的自托管,或部署到一组VM、Kubernetes和边缘环境(如Azure IoT Edge)。

image

Dapr使用sidecar模式来暴露building blocks的能力,这里的sidecar除了包括sidecar container外,还可以是sidecar process。

在非容器化环境中,用户应用和dapr runtime都是独立的进程;而在kubernetes这种容器化环境中,dapr runtime作为sidecar container注入到业务pod中,这和service mesh sidecar模式是一致的。

自托管

在自托管模式下,Dapr作为单独的sidecar进程运行,服务代码可以通过HTTP或gRPC调用该进程。在自托管模式下,您还可以将Dapr部署到一组VM上。

image

Dapr可以配置为在开发人员本地计算机上以自托管模式运行。每个运行的服务都有一个Dapr运行时进程(或sidecar),配置为使用状态存储,pub/sub,绑定组件和其他构建块。

您可以使用Dapr CLI在本地机器上运行启用了Dapr的应用程序。

image

Kubernetes托管

在容器托管环境(如Kubernetes)中,Dapr作为sidecar容器运行,和应用程序容器在同一个pod中。

image

Dapr可以配置为在任何Kubernetes集群上运行。在Kubernetes中,dapr-sidecar-injector和dapr-operator服务提供一流的集成,以将Dapr作为sidecar容器启动在与服务容器相同的pod中,并为在集群中部署的Dapr组件提供更新通知。

dapr-sentry服务是一个认证中心,它允许Dapr sidecar实例之间的相互TLS进行安全数据加密。

image

Dapr 仪表盘(控制面板)

image

整个控制面还是一个微服务。和istio早期有点类似。

  • Sidecarinjector:利用kubernetes mutating webhook给业务pod注入dapr runtime sidecar容器,以及运行所需的环境变量,启动参数等。包括连接控制面operator的地址(control-plane-address)等。

  • Operator:会list watch用户定义的Component资源,并下发给数据面的dapr runtime。数据面runtime会持有一个Operator Client去连接控制面Operator。

  • Sentry: 为dapr系统中的工作负载提供基于mtls的安全通信。mtls能强制通信双方进行身份认证,同时在认证之后保证通信都走加密通道。Sentry的功能很类似istio里的Citadel(目前已经合并到istiod)。在整个过程中,sentry充当证书颁发机构(CA),处理dapr sidecar发起的签署证书请求,另外还要负责证书的轮转。除了dapr sidecar之间的自动mTLS之外,sidecar和dapr控制面服务之间也是强制性的mTLS。

  • Placement:用于跟踪actor的类型和实例分布,并同步给数据面的runtime。

Dapr Dashboard是一个WebUI,可帮助您可视化本地计算机或Kubernetes上运行的Dapr实例的信息。

image

Dapr 性能

sidecar模式会带来额外的性能开销。以我们使用service mesh的经验来看,这种模式的性能开销主要是2个方面,一个是流量经过sidecar的拦截、流量管控和转发损耗,另一个是sidecar需要从控制面同步管理数据,sidecar需要存储和处理这些数据,这可能会给数据面内存和CPU带来压力,特别是大规模场景下。

在官方对daprV1.0的性能测试数据看:在不开启mtls和遥测的情况下,延迟P90大概增加1.4ms,在开启mtls和0.1 tracingrate情况下,P90数据大概还会增加了3ms左右。

这个数据要比istio好,dapr sidecar没有太多的流量管控和修改的功能,也没有使用iptables拦截,开销相对较小。为了尽可能提高通信效率,dapr sidecar之间的通信固定使用gRPC协议。而且dapr从数据面同步的数据量也非常少,所以也不会有类似istio场景下频繁reload xDS的问题。

但相比service mesh,dapr sidecar管控了更多的流量类型,比如状态存储,应用系统对这类流量的延迟变化更加敏感,用户在接入dapr之前需要慎重评估。

Dapr 开发工具支持

多语言开发支持

Dapr Software Development Kits (SDKs)

语言 状态 客户端SDK 服务端扩展 Actor SDK
.NET Stable ASP.NET Core
Python Stable gRPC FastAPI
Flask
Java Stable Spring Boot
Go Stable
PHP Stable
C++ In development
Rust In development
Javascript In development

DotNet Core SDK

虽然Dapr独立于任何编程语言,但它可以轻松地集成到具有特定语言的SDK应用程序中。随着我们看到越来越多的开发人员使用Dapr,我们对这些SDK的投资已增加,以帮助简化Dapr集成。Dapr为爪哇脚本、Python、爪哇、.NET、Go以及最近添加的Rust和C++提供SDK。此外,根据社区反馈,Java SDK中增加了许多改进,包括虚拟角色、键入类和与Spring Boot Web框架的集成。对于.NET,还改进了类型类别,并与ASP.NET核心Web框架集成。作为未来路线图的一部分,计划为其他SDK提供类似的支持。

Visual Studio Code扩展

能够在没有任何云依赖的情况下开发本地机器上的应用程序,这对生产力和成本非常重要,也是Dapr的关键目标。Dapr视觉工作室代码(VS代码)预览扩展可帮助开发人员使用Dapr调试应用程序,与Dapr运行时间进行交互,并与DaprCLI合并。

image

Dapr 入门教程(阿里知行动手实验室)

十分钟快速领略开源分布式运行时Dapr应用的开发、部署过程

https://start.aliyun.com/course?id=gImrX5Aj

Windows下安装Dapr Cli

https://github.com/dapr/cli

0. 理想情况一键完成安装

正常流程应该通过PowerShell一条命令即可安装:

powershell -Command "iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1 | iex"

然后结果一地鸡毛,直接提示连raw.githubusercontent.com这个域名都解析不了,但是我们来看下具体的脚本内容,发现其实也就那么回事。

image

接下来我们就手工来完成。

1. 下载Dapr Cli的二进制文件

前往https://github.com/dapr/cli/releases 页面查看二进制发布包最新版本,截止到发稿时目前稳定版是v1.1.0,所以我们就直接下载dapr_windows_amd64.zip这个文件即可。

image

2. 给Dapr Cli文件创建目录

根据脚本示范,推荐在C盘创建一个叫dapr的目录,也就是c:\dapr

然后把第一步下载的压缩包解压,提取里面的dapr.exe文件,丢到c:\dapr目录中。

image

3. 将Dapr Cli目录添加到环境变量的Path中。

为了让系统终端能找到我们的刚才埋好的二进制文件,所以我们需要将它的位置告诉系统,那么我们点击Windows10的系统设置,切换到系统-关于-高级系统设置

image

点击进入环境变量编辑窗体。

image

找到系统变量组,找到Path项,点击进入编辑模式。

image

通过新建按钮,把c:\dapr这个目录值填进去保存即可,如果你放到其他位置了,那就跟着变就行。

image

4. 验证安装Dapr Cli

打开你的PowerShell终端界面,直接输入命令:

dapr

你看下有反应没,有反应那就是前面的步骤安装成功了。

image

还可以通过命令查看版本号:

dapr --version

image

5. 本地初始化Dapr

Dapr与您的应用程序一起作为sidecar运行,在自托管模式下,这意味着它是您本地机器上的一个进程。因此,初始化Dapr包括获取Dapr sidecar二进制文件并将其安装到本地.

此外,默认初始化过程还创建了一个开发环境,帮助简化Dapr的应用开发。这包括下列步骤:

  • 运行Redis container实例将被用作本地的状态存储和消息代理
  • 运行一个Zipkin容器实例用于观测性
  • 创建具有上述组件定义的默认组件文件夹
  • 运行用于本地演员支持的Daprplacement服务容器实例

执行命令:

dapr init

image

成功执行之后,将会看到:

image

这时候查看Docker的Dashboard会看到多了三个实例。

image

镜像中也多了redisdaprio/dapr镜像

image

6. 验证Dapr初始化

dapr --version

image

这时候我们已经安装了Runtime vesionv1.1.2了。

docker ps

image

在dapr init时,CLI还创建了一个默认组件文件夹,其中包括几个YAML文件,其中包含statestore、elevated和zipkin。Dapr sidecar,将读取这些文件。告诉它使用Redis容器进行状态管理和消息传递,以及Zipkin容器来收集跟踪。

  • Linux/MacOS中Dapr使用默认组件和文件的路径是$HOME.dapr
  • Windows中,Dapr初始化路径到%USERPROFILE%\.dapr\

验证的方式也很简单,打开你的资源管理器,在地址栏中输入:

%USERPROFILE%\.dapr\

会跳到对应的目录,我们会看到创建好的对应YAML文件和文件夹,即代表正常。

image

学习调用Dapr内置API保存和读取状态

运行了dapr init命令后,您的本地环境有Dapr sidecar二进制文件以及默认组件定义的状态管理和消息代理(都使用Redis)

image

在命令中没有自定义组件文件夹,这时候会使用Init的时候的默认配置。Dapr使用本地的Redis Docker容器作为状态存储和消息代理。

运行Dapr sidecar

运行以下命令以启动Dapr sidecar,它将在端口4500上监听名为mySideCar的空白应用程序:

dapr run --app-id mySideCar --dapr-http-port 4500

image

如果端口没有被占用呢,就会出现上图中的输出,最终运行成功。

通过服务调用保存状态

前面我们没有指定状态的组件,那就会默认用到我们Init创建的Redis实例,所以以下保存最终数据会存到Redis里面去。

  1. Base模式
curl -X POST -H "Content-Type: application/json" -d '[{ "key": "firstName", "value": "Taylor"}]' http://localhost:4500/v1.0/state/statestore
  1. PS 模式
Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{ "key": "firstName", "value": "Taylor"}]' -Uri 'http://localhost:4500/v1.0/state/statestore'

新建一个终端标签,执行上诉命令。

image

通过服务调用读取状态

  1. Base模式
curl http://localhost:4500/v1.0/state/statestore/firstName
  1. PS 模式
Invoke-RestMethod -Uri 'http://localhost:4500/v1.0/state/statestore/firstName'
  1. 浏览器模式

http://localhost:4500/v1.0/state/statestore/firstName

image

image

进入Redis查看键值对数据

docker exec -it dapr_redis redis-cli

image

进入dapr_redis这个容器,然后执行redis-cli的命令查看键值

hgetall "mySideCar||firstName"

image

exit

退出dapr_redis容器。

学习调用Dapr自定义组件写入和读取密钥

Dapr通过Dapr初始化时创建的默认组件定义文件,知道使用本地配置在机器上的Redis实例。

当构建一个应用程序时,你很可能会根据你想使用的构建块和特定的组件来创建自己的组件文件定义。

作为如何为您的应用程序定义自定义组件的一个例子,您现在将创建一个组件定义文件来与密钥构建块进行交互。

创建一个JSON密钥存储

在本地的JSON文件中加入您的密钥,首先保存下面的JSON内容到一个名为taylorSecrets.json的文件:

{
    "my-secret": "I'm Taylor"
}

image

创建一个自定义组件的文件夹

新建一个自定义组件的文件夹,这里我用my-secret-components,至于文件夹位置,可以自行选择。

image

在这个文件夹中创建一个yaml文件,它的名字必须是localSecretStore.yaml,其内容如下:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: my-secret-store
  namespace: default
spec:
  type: secretstores.local.file
  version: v1
  metadata:
  - name: secretsFile
    value: <PATH TO SECRETS FILE>/taylorSecrets.json
  - name: nestedSeparator
    value: ":"

这里需要自行替换<PATH TO SECRETS FILE>的内容,也就是指定完整的密钥Json文件位置。

其中type: secretstores.local.file告诉Dapr使用本地文件组件作为密钥存储。元数据字段提供了使用该组件所需的组件特定信息,比如secretsFile

运行Dapr sidecar

运行以下命令以启动Dapr sidecar,它将在端口5500上监听名为mySideCar的空白应用程序:

dapr run --app-id mySideCar --dapr-http-port 5500 --components-path xxxx/my-secret-components

这里和之前的命令相比,多了一个--components-path,用来指向我们刚才创建的自定义组件。

image

通过服务调用读取密钥

  1. Base模式
curl http://localhost:5500/v1.0/secrets/my-secret-store/my-secret
  1. PS 模式
Invoke-RestMethod -Uri 'http://localhost:5500/v1.0/secrets/my-secret-store/my-secret'
  1. 浏览器模式

http://localhost:5500/v1.0/secrets/my-secret-store/my-secret

image

image

Dapr支持对接的密钥仓库

关于密钥仓库组件的扩展

与其他构建块组件一样,密钥存储组件是可扩展的,就如上面的案例一样。

密钥存储组件的Yaml格式为:

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

在这个里面,其中metadataname属性值是这个组件的名字,这个是自定义的。

但是spec节点下的type是有约定的,基本格式为secretstores.<NAME>,在前面的案例中,因为我们加载的是本地的Json文件,所以我们采用的typesecretstores.local.file,这个代表本地文件类型,并且type后面紧跟的是针对这个type我们支持的version版本号,我们可以依此类推,举一反三。

每一个type都会对应不同的spec节点下的不同的metadata信息组合,用于描述这个type所需要的连接地址和其他元数据。

aws为例,那么如果是aws的密钥类型,其typesecretstores.aws.secretmanager,其metadata信息包括regionaccessKeysecretKeysessionToken,所以其yaml文件对应的示范为:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: awssecretmanager
  namespace: default
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]"

https://docs.dapr.io/zh-hans/reference/components-reference/supported-secret-stores/

下面我们来列举下目前已知的所有类型和对应的指南:

密钥仓库 - 通用

密码仓库名称 状态 (Status) 组件版本(Component version) 自从(Since) 类型(Type)
Local environment variables Beta v1 1.0 secretstores.local.env
Local file Beta v1 1.0 secretstores.local.file
HashiCorp Vault Alpha v1 1.0 secretstores.hashicorp.vault
Kubernetes secrets GA v1 1.0 N/A

1. 本地环境变量(Local environment variables)

这个Dapr密钥仓库组件不使用身份认证,而是使用本地定义的环境变量。这种密钥管理的方法不建议用于生产环境。

要设置本地环境变量密钥存储,请创建一个类型为secretstores.local.env的组件。 在你的./components目录下创建一个包含以下内容的文件:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: envvar-secret-store
  namespace: default
spec:
  type: secretstores.local.env
  version: v1
  metadata:

2. 本地文件(Local file)

这个Dapr密钥仓库组件不使用身份认证,而是读取JSON文本,这种密钥管理的方法不建议用于生产环境。

要设置基于本地文件密钥仓库,请创建一个类型为secretstores.local.file的组件。 在你的./components目录下创建一个包含以下内容的文件:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: local-secret-store
  namespace: default
spec:
  type: secretstores.local.file
  version: v1
  metadata:
  - name: secretsFile
    value: [path to the JSON file]
  - name: nestedSeparator
    value: ":"

元数据字段规范:

字段 必填 详情 示例
secretsFile Y 存储密钥的文件路径 "path/to/file.json"
nestedSeparator N 在将JSON层次结构扁平化为map时,被仓库使用 默认值为 ":" 默认值为 ":" ":"

Json文件内容举例:

{
    "redisPassword": "your redis password",
    "connectionStrings": {
        "sql": "your sql connection string",
        "mysql": "your mysql connection string"
    }
}

仓库将加载文件并创建一个具有以下键值对的map:

扁平键
redisPassword “your redis password”
connectionStrings:sql “your sql connection string”
connectionStrings:mysql “your mysql connection string”

使用扁平键 (connectionStrings:sql)来访问密钥。

image

3. HashiCorp Vault密钥仓库

HashiCorp于2012年成立,由Mitchell Hashimoto和Armon Dadgar创办,并陆续推出了Vagrant、Packer 、 Terraform、Consul , Vault 和 Nomad以满足不同的需求。Vault是一款企业级私密信息管理工具。

要设置HashiCorp Vault密钥仓库,请创建一个类型为secretstores.hashicorp.vault的组件。

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: vault
  namespace: default
spec:
  type: secretstores.hashicorp.vault
  version: v1
  metadata:
  - name: vaultAddr
    value: [vault_address] # Optional. Default: "https://127.0.0.1:8200"
  - name: caCert # Optional. This or caPath or caPem
    value: "[ca_cert]"
  - name: caPath # Optional. This or CaCert or caPem
    value: "[path_to_ca_cert_file]"
  - name: caPem # Optional. This or CaCert or CaPath
    value : "[encoded_ca_cert_pem]"
  - name: skipVerify # Optional. Default: false
    value : "[skip_tls_verification]"
  - name: tlsServerName # Optional.
    value : "[tls_config_server_name]"
  - name: vaultTokenMountPath # Required. Path to token file.
    value : "[path_to_file_containing_token]"
  - name: vaultKVPrefix # Optional. Default: "dapr"
    value : "[vault_prefix]"

元数据字段规范:

字段 必填 详情 示例
vaultAddr N Vault服务器的地址 默认值为 "https://127.0.0.1:8200" "https://127.0.0.1:8200"
caCert N Certificate Authority只使用其中一个选项。 要使用的加密cacerts "cacerts"
caPath N Certificate Authority只使用其中一个选项。 CA证书文件的路径 "path/to/cacert/file"
caPem N Certificate Authority只使用其中一个选项。 要是用的加密cacert pem "encodedpem"
skipVerify N 跳过TLS验证。 默认值为"false" "true", "false"
tlsServerName N TLS配置服务器名称 "tls-server"
vaultTokenMountPath Y 包含token的文件路径 "path/to/file"
vaultKVPrefix N 仓库前缀 默认值为 "dapr" "dapr", "myprefix"

设置Hashicorp Vault实例:

4. Kubernetes密钥仓库

Kubernetes有一个内置的密钥仓库,Dapr组件可以使用它来检索密钥。 设置Kubernetes密钥仓库不需要特殊的配置,你能够从http://localhost:3500/v1.0/secrets/kubernetes/[my-secret]这个 URL中检索密钥。

举例:

image

密钥仓库 - Amazon Web Services (AWS)

密码仓库名称 状态 (Status) 组件版本(Component version) 自从(Since) 类型(Type)
AWS Secrets Manager Alpha v1 1.0 secretstores.aws.secretmanager
AWS SSM Parameter Store Alpha v1 1.1 secretstores.aws.parameterstore

1. AWS Secrets Manager密钥仓库

要设置AWS Secrets Manager密钥仓库,请创建一个类型为secretstores.aws.secretmanager的组件

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: awssecretmanager
  namespace: default
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]"

示例将Secret明文存储。建议将密钥存储在本地,如Kubernetes密钥仓库或本地文件来安全地存储密钥。

元数据字段规范:

字段 必填 详情 示例
region Y AWS Secrets Manager实例所部署的特定AWS 区域 "us-east-1"
accessKey Y 要访问此资源的AWS访问密钥 "key"
secretKey Y 要访问此资源的AWS密钥访问Key "secretAccessKey"
sessionToken N 要使用的AWS会话令牌 "sessionToken"

AWS文档设置AWS Secrets Manager:

https://docs.aws.amazon.com/secretsmanager/latest/userguide/tutorials_basic.html

2. AWS SSM Parameter Store密钥仓库

要设置AWS SSM Parameter Store密钥仓库,请创建一个类型为secretstores.aws.parameterstore的组件

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: awsparameterstore
  namespace: default
spec:
  type: secretstores.aws.parameterstore
  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]"

示例将Secret明文存储。建议将密钥存储在本地,如Kubernetes密钥仓库或本地文件来安全地存储密钥。

元数据字段规范:

字段 必填 详情 示例
region Y The specific AWS region the AWS SSM Parameter Store instance is deployed in "us-east-1"
accessKey Y 要访问此资源的 AWS 访问密钥 "key"
secretKey Y 要访问此资源的 AWS 密钥访问 Key "secretAccessKey"
sessionToken N 要使用的 AWS 会话令牌 "sessionToken"

AWS文档设置AWS SSM Parameter Store:

https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-parameter-store.html

密钥仓库 - Google Cloud Platform (GCP)

密码仓库名称 状态 (Status) 组件版本(Component version) 自从(Since) 类型(Type)
GCP Secret Manager Alpha v1 1.0 secretstores.gcp.secretmanager
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: gcpsecretmanager
  namespace: default
spec:
  type: secretstores.gcp.secretmanager
  version: v1
  metadata:
  - name: type
    value: <replace-with-account-type>
  - name: project_id
    value: <replace-with-project-id>
  - name: private_key_id
    value: <replace-with-private-key-id>
  - name: client_email
    value: <replace-with-email>
  - name: client_id
    value: <replace-with-client-id>
  - name: auth_uri
    value: <replace-with-auth-uri> 
  - name: token_uri
    value: <replace-with-token-uri> 
  - name: auth_provider_x509_cert_url
    value: <replace-with-auth-provider-cert-url> 
  - name: client_x509_cert_url
    value: <replace-with-client-cert-url> 
  - name: private_key
    value: <replace-with-private-key>

示例将Secret明文存储。建议将密钥存储在本地,如Kubernetes密钥仓库或本地文件来安全地存储密钥。

元数据字段规范:

字段 必填 详情 示例
type Y 账户类型 "serviceAccount"
project_id Y 与此组件相关联的项目 ID。 "project_id"
private_key_id N 私钥ID "privatekey"
client_email Y 客户端电子邮件地址 "client@example.com"
client_id N 客户端的 ID "11111111"
auth_uri N 认证URI "https://accounts.google.com/o/oauth2/auth"
token_uri N 认证token URI "https://oauth2.googleapis.com/token"
auth_provider_x509_cert_url N 认证提供者的证书URL "https://www.googleapis.com/oauth2/v1/certs"
client_x509_cert_url N 客户端的证书 URL https://www.googleapis.com/robot/v1/metadata/x509/<project-name>.iam.gserviceaccount.com
private_key Y 认证用的私钥 "privateKey"

GCP文档设置 GCP Secret Manager:

https://cloud.google.com/secret-manager/docs/quickstart

密钥仓库 - Microsoft Azure

密码仓库名称 状态 (Status) 组件版本(Component version) 自从(Since) 类型(Type)
Azure Managed Identity Alpha v1 1.0 secretstores.azure.keyvault
Azure Key Vault GA v1 1.0 secretstores.azure.keyvault

1. Azure Managed Identity

配置Azure Key Vault和Kubernetes以使用Azure Managed Identities来获取密钥

设置Azure Key Vault密钥仓库,请创建一个类型为secretstores.azure.keyvault的组件。

在Kubernetes中,将服务主体的证书存储到Kubernetes Secret Store中,然后用Kubernetes secretstore中的这个证书启用Azure Key Vault密钥仓库。

组件yaml使用你的密钥仓库的名称和托管标识的Cliend ID来配置密钥仓库。

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: azurekeyvault
  namespace: default
spec:
  type: secretstores.azure.keyvault
  version: v1
  metadata:
  - name: vaultName
    value: [your_keyvault_name]
  - name: spnClientId
    value: [your_managed_identity_client_id]

示例将Secret明文存储。建议将密钥存储在本地,如Kubernetes密钥仓库或本地文件来安全地存储密钥。

元数据字段规范:

字段 必填 详情 示例
vaultName Y Azure Key Vault名称 "mykeyvault"
spnClientId Y 你的托管标识客户端ID "yourId"

设置Managed Identity和 Azure Key Vault:

https://docs.dapr.io/zh-hans/reference/components-reference/supported-secret-stores/azure-keyvault-managed-identity/

2. Azure Key Vault

要设置Azure Key Vault密钥仓库,请创建一个类型为secretstores.azure.keyvault的组件。

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: azurekeyvault
  namespace: default
spec:
  type: secretstores.azure.keyvault
  version: v1
  metadata:
  - name: vaultName
    value: [your_keyvault_name]
  - name: spnTenantId
    value: "[your_service_principal_tenant_id]"
  - name: spnClientId
    value: "[your_service_principal_app_id]"
    value : "[pfx_certificate_contents]"
  - name: spnCertificateFile
    value : "[pfx_certificate_file_fully_qualified_local_path]"

元数据字段规范:

  1. 自托管
字段 必填 详情 示例
vaultName Y Azure Key Vault名称 "mykeyvault"
spnTenantId Y Service Principal Tenant Id "spnTenantId"
spnClientId Y Service Principal App Id "spnAppId"
spnCertificateFile Y PFX证书文件路径, PFX证书文件路径,
对于Windows, [pfx_certificate_file_fully_qualified_local_path] 值必须使用转义的反斜杠,即双反斜杠。 例如 "C:\folder1\folder2\certfile.pfx"
对于Linux,你可以使用单斜杠。
对于Linux,你可以使用单斜杠。 例如 "/folder1/folder2/certfile.pfx" 例如 "/folder1/folder2/certfile.pfx"
  1. Kubernetes
字段 必填 详情 示例
vaultName Y Azure Key Vault名称 "mykeyvault"
spnTenantId Y Service Principal Tenant Id "spnTenantId"
spnClientId Y Service Principal App Id "spnAppId"
spnCertificate Y PKCS 12 encoded bytes of the certificate. See configure the component for details on encoding this in a Kubernetes secret. secretKeyRef: ...

设置Key Vault和服务主体:

https://docs.dapr.io/zh-hans/reference/components-reference/supported-secret-stores/azure-keyvault/

参考

posted @ 2021-05-05 01:34  TaylorShi  阅读(1541)  评论(1编辑  收藏  举报