Dapr 是一个可移植的、事件驱动的运行时,它使任何开发人员能够轻松构建出弹性的、无状态和有状态的应用程序,并可运行在云平台或边缘计算中,它同时也支持多种编程语言和开发框架。Dapr 确保开发人员专注于编写业务逻辑,不必分神解决分布式系统难题,从而显著提高了生产力。Dapr 降低了构建微服务架构类现代云原生应用的门槛。
MacOS & Dapr 1.8:
sudo curl -fsSL https://raw.githubusercontent.com/dapr/cli/master/install/install.sh | /bin/bash
Linux/Windows 安装方式:
https://docs.dapr.io/getting-started/install-dapr-cli/
Dapr 初始化包括:
dapr init
验证 Dapr 版本
dapr -v CLI version: 1.8.0 Runtime version: 1.8.0
如前所述,dapr init
命令会启动几个容器,这些容器将帮助您开始使用 Dapr
。 验证您有运行 daprio/dapr
、openzipkin/zipkin
和 redis
映像的容器实例:
在 dapr init
上,CLI
还会创建一个默认组件文件夹,其中包含几个 YAML
文件,其中包含状态存储、Pub/sub
和 Zipkin
的定义。Dapr sidecar
将读取这些组件并使用:
通过打开您的组件目录进行验证:
%UserProfile%\.dapr
下~/.dapr
下ls $HOME/.dapr bin components config.yaml
运行 Dapr sidecar 并试用 state API
dapr run
命令启动一个应用程序,以及一个 sidecar。
启动一个 Dapr sidecar,它将在端口 3500 上侦听名为 myapp
的空白应用程序:
dapr run --app-id myapp --dapr-http-port 3500
由于没有使用上述命令定义自定义组件文件夹,因此 Dapr 使用在 dapr init
流程期间创建的默认组件定义。
使用对象更新状态。新状态将如下所示:
[ { "key": "name", "value": "Bruce Wayne" } ]
请注意,包含在状态中的每个对象都有一个分配有值为 name
的 key
。您将在下一步中使用该 key
。
使用以下命令保存新的状态对象:
curl -X POST -H "Content-Type: application/json" -d '[{ "key": "name", "value": "Bruce Wayne"}]' http://localhost:3500/v1.0/state/statestore
使用带有 key 为 name
的状态检索您刚刚存储在 state 中的对象。在同一终端窗口中,运行以下命令:
curl http://localhost:3500/v1.0/state/statestore/name
查看状态如何存储在 Redis 中
docker exec -it dapr_redis redis-cli
列出 Redis 键以查看 Dapr 如何使用您提供给 dapr run 的 app-id 作为 key
的前缀创建键值对:
keys * "myapp||name"
运行以下命令查看状态值:
hgetall "myapp||name" 1) "data" 2) "\"Bruce Wayne\"" 3) "version" 4) "1"
使用以下命令退出 Redis CLI:
exit
在同一终端窗口中,从状态存储中删除 name
状态对象。
curl -v -X DELETE -H "Content-Type: application/json" http://localhost:3500/v1.0/state/statestore/name
所有官方示例笔者均在 MacOS/NodeJs v16.16.0
下实战完成。
使用 Dapr 的服务调用构建块,您的应用程序可以与其他应用程序可靠且安全地通信。
git clone https://github.com/dapr/quickstarts.git
从 quickstarts 的根目录导航到 order-processor
目录。
cd service_invocation/javascript/http/order-processor
安装依赖项:
npm install
与 Dapr sidecar 一起运行 order-processor
服务。
dapr run --app-port 5001 --app-id order-processor --app-protocol http --dapr-http-port 3501 -- npm start
app.post('/orders', (req, res) => { console.log("Order received:", req.body); res.sendStatus(200); });
在新的终端窗口中,从 quickstarts 根目录导航到 checkout
目录。
cd service_invocation/javascript/http/checkout
安装依赖项:
npm install
与 Dapr sidecar 一起运行 checkout
服务。
dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- npm start
在 checkout
服务中,您会注意到无需重写您的应用程序代码即可使用 Dapr 的服务调用。您可以通过简单地添加 dapr-app-id
header 来启用服务调用,该 header 指定目标服务的 ID。
let axiosConfig = { headers: { "dapr-app-id": "order-processor" } }; const res = await axios.post(`${DAPR_HOST}:${DAPR_HTTP_PORT}/orders`, order , axiosConfig); console.log("Order passed: " + res.config.data);
Dapr 在任何 Dapr 实例上调用应用程序。在代码中,sidecar 编程模型鼓励每个应用程序与其自己的 Dapr 实例通信。Dapr 实例随后发现并相互通信。
checkout
& order-processor
服务输出:
让我们看一下 Dapr 的状态管理构建块。您将使用 Redis 进行状态存储,来保存、获取和删除你的状态,您也可以将其换成任何一种受 Dapr 支持的状态存储。
在终端窗口中,导航到 order-processor
目录。
cd state_management/javascript/sdk/order-processor
安装依赖项,其中将包括 JavaScript SDK 中的 dapr-client
包:
npm install
验证您在服务目录中包含以下文件:
package.json
package-lock.json
与 Dapr sidecar 一起运行 order-processor
服务。
dapr run --app-id order-processor --components-path ../../../components/ -- npm run start
order-processor
服务将 orderId key/value
写入、读取和删除到 statestore.yaml
组件中定义的 statestore
实例。一旦服务启动,它就会执行一个循环。
const client = new DaprClient(DAPR_HOST, DAPR_HTTP_PORT); // 将 state 保存到 state store 中 client.state.save(STATE_STORE_NAME, [ { key: orderId.toString(), value: order } ]); console.log("Saving Order: ", order); // 从 state store 中获取 state var result = client.state.get(STATE_STORE_NAME, orderId.toString()); result.then(function(val) { console.log("Getting Order: ", val); }); // 从 state store 中删除 state client.state.delete(STATE_STORE_NAME, orderId.toString()); result.then(function(val) { console.log("Deleting Order: ", val); });
请注意,正如上面代码中所指定的,代码将应用程序状态保存
在 Dapr 状态存储中,读取
它,然后将其删除
。
Order-processor 输出:
statestore.yaml
组件文件
当你运行 dapr init
时,Dapr 会创建一个默认的 Redis statestore.yaml 并在你的本地机器上运行一个 Redis 容器,它位于:
%UserProfile%\.dapr\components\statestore.yaml
~/.dapr/components/statestore.yaml
使用 statestore.yaml
组件,您可以轻松切换状态存储,而无需更改代码。
本快速入门包含的 Redis statestore.yaml
文件包含以下内容:
apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: statestore spec: type: state.redis version: v1 metadata: - name: redisHost value: localhost:6379 - name: redisPassword value: "" - name: actorStateStore value: "true"
在 YAML 文件中:
metadata/name
是您的应用程序与组件对话的方式(在代码示例中称为 DAPR_STORE_NAME
)。spec/metadata
定义到组件使用的 Redis 实例的连接。开始使用 Dapr 的发布和订阅构建块
让我们看一下 Dapr 的发布和订阅 (Pub/sub) 构建块。您将运行发布者微服务和订阅者微服务,以演示 Dapr 如何启用发布/订阅模式。
在终端窗口中,从 quickstarts 根目录导航到 order-processor 目录。
cd pub_sub/javascript/sdk/order-processor
安装依赖项,其中将包括 JavaScript SDK 中的 dapr-client 包:
npm install
验证您在服务目录中包含以下文件:
package.json
package-lock.json
与 Dapr sidecar 一起运行 order-processor subscriber 服务。
dapr run --app-port 5001 --app-id order-processing --app-protocol http --dapr-http-port 3501 --components-path ../../../components -- npm run start
在 order-processor 订阅者中,我们订阅名为 order_pub_sub 的 Redis 实例(如 pubsub.yaml 组件中所定义)和 topic orders。这使您的应用程序代码能够通过 Dapr sidecar 与 Redis 组件实例通信。
server.pubsub.subscribe("order_pub_sub", "orders", (data) => console.log("Subscriber received: " + JSON.stringify(data)));
在新的终端窗口中,从 Quickstarts 克隆目录的根目录导航到 checkout 目录。
cd pub_sub/javascript/sdk/checkout
安装依赖项,其中将包括 JavaScript SDK 中的 dapr-client 包:
npm install
验证您在服务目录中包含以下文件:
package.json
package-lock.json
与 Dapr sidecar 一起运行 checkout 发布者服务。
dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 --components-path ../../../components -- npm run start
在 checkout
发布者服务中,我们将 orderId 消息发布到名为 order_pub_sub
的 Redis 实例(在 pubsub.yaml 组件中定义)和 topic orders
。服务一启动,就会循环发布:
const client = new DaprClient(DAPR_HOST, DAPR_HTTP_PORT); await client.pubsub.publish(PUBSUB_NAME, PUBSUB_TOPIC, order); console.log("Published data: " + JSON.stringify(order));
请注意,正如上面代码中所指定的,发布者将一个随机数推送到 Dapr sidecar,而订阅者接收它。
发布者 & 订阅者输出:
pubsub.yaml 组件文件
当你运行 dapr init
时,Dapr
会创建一个默认的 Redis pubsub.yaml
并在你的本地机器上运行一个 Redis 容器,它位于:
在 Windows 上,在 %UserProfile%\.dapr\components\pubsub.yaml
下在 Linux/MacOS 上,在 ~/.dapr/components/pubsub.yaml
下
使用 pubsub.yaml
组件,您可以轻松更换底层组件,而无需更改应用程序代码。
本快速入门包含的 Redis pubsub.yaml
文件包含以下内容:
apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: order_pub_sub spec: type: pubsub.redis version: v1 metadata: - name: redisHost value: localhost:6379 - name: redisPassword value: ""
在 YAML 文件中:
metadata/name
是您的应用程序与组件对话的方式。spec/metadata
定义与组件实例的连接。scopes
指定哪个应用程序可以使用该组件。开始使用 Dapr 的 Binding 构建块
让我们看一下 Dapr 的 Bindings 构建块。使用绑定,您可以:
接下来您将使用输入 Cron binding 安排批处理脚本每 10 秒运行一次。该脚本使用 PostgreSQL Dapr binding 处理 JSON 文件并将数据输出到 SQL 数据库。
在您机器上的 Docker 容器中本地运行 PostgreSQL 实例。示例包含一个 Docker Compose 文件,用于在本地自定义、构建、运行和初始化带有默认 orders
表的 postgres 容器。
在终端窗口中,从 quickstarts 根目录导航到 bindings/db
目录。
cd bindings/db
运行以下命令来设置容器:
docker compose up
安排一个 Cron job 并写入数据库
在新的终端窗口中,导航到 SDK 目录。
cd bindings/javascript/sdk/batch
安装依赖项:
npm install
与 Dapr sidecar 一起运行 batch-sdk 服务。
dapr run --app-id batch-sdk --app-port 5002 --dapr-http-port 3500 --components-path ../../../components -- node index.js
process_batch 函数内的代码每 10 秒执行一次(在 components 目录的 binding-cron.yaml 中定义)。绑定触发器在 Dapr sidecar 的 Flask 应用程序中查找通过 HTTP POST 调用的路由。
async function start() { await server.binding.receive(cronBindingName,processBatch); await server.start(); }
batch-sdk 服务使用 binding-postgres.yaml 组件中定义的 PostgreSQL 输出绑定将 OrderId、Customer 和 Price 记录插入到 orders
表中。
async function processBatch(){ const loc = '../../orders.json'; fs.readFile(loc, 'utf8', (err, data) => { const orders = JSON.parse(data).orders; orders.forEach(order => { let sqlCmd = `insert into orders (orderid, customer, price) values (${order.orderid}, '${order.customer}', ${order.price});`; let payload = `{ "sql": "${sqlCmd}" } `; console.log(payload); client.binding.send(postgresBindingName, "exec", "", JSON.parse(payload)); }); console.log('Finished processing batch'); }); return 0; }
请注意,如上所述,代码使用 OrderId、Customer 和 Price 作为 payload 调用输出绑定。
你的输出绑定的 print 语句输出:
在新终端中,验证是否已将相同的数据插入到数据库中。
cd bindings/db
启动交互式 Postgres CLI:
docker exec -i -t postgres psql --username postgres -p 5432 -h localhost --no-password
在 admin=#
提示符下,更改为 orders
表:
\c orders;
在 orders=#
提示符下,选择所有行:
select * from orders;
输出应如下所示:
当您执行 dapr run 命令并指定组件路径时,Dapr sidecar:
binding-cron.yaml 文件包含以下内容:
apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: cron namespace: quickstarts spec: type: bindings.cron version: v1 metadata: - name: schedule value: "@every 10s"
注意:binding-cron.yaml 的元数据部分包含一个 Cron 表达式,用于指定调用绑定的频率。
component\binding-postgres.yaml 组件文件
当您执行 dapr run 命令并指定组件路径时,Dapr sidecar:
使用 binding-postgres.yaml 组件,您可以轻松换出后端数据库绑定,而无需更改代码。
本快速入门包含的 PostgreSQL binding-postgres.yaml 文件包含以下内容:
apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: sqldb namespace: quickstarts spec: type: bindings.postgres version: v1 metadata: - name: url value: "user=postgres password=docker host=localhost port=5432 dbname=orders pool_min_conns=1 pool_max_conns=10"
在 YAML 文件中:
开始使用 Dapr 的 Secrets Management 构建块
Dapr 提供了一个专用的 secrets API,允许开发人员从 secrets store 中检索 secrets。接下来:
在终端窗口中,导航到 order-processor
目录。
cd secrets_management/javascript/sdk/order-processor
安装依赖项:
npm install
与 Dapr sidecar 一起运行 order-processor 服务。
dapr run --app-id order-processor --components-path ../../../components/ -- npm start
在幕后
请注意下面的 order-processor 服务如何指向:
// index.js const DAPR_SECRET_STORE = "localsecretstore"; const SECRET_NAME = "secret"; async function main() { // ... const secret = await client.secret.get(DAPR_SECRET_STORE, SECRET_NAME); console.log("Fetched Secret: " + JSON.stringify(secret)); }
DAPR_SECRET_STORE 定义在 local-secret-store.yaml 组件文件中,位于 secrets_management/components 中:
apiVersion: dapr.io/v1alpha1 kind: Component metadata: name: localsecretstore namespace: default spec: type: secretstores.local.file version: v1 metadata: - name: secretsFile value: secrets.json - name: nestedSeparator value: ":"
在 YAML 文件中:
metadata/name
是您的应用程序引用组件的方式(在代码示例中称为 DAPR_SECRET_STORE)。spec/metadata
定义与组件使用的 secret 的连接。secrets.json 文件
SECRET_NAME
在位于 secrets_management/javascript/sdk/order-processor
的 secrets.json
文件中定义:
{ "secret": "YourPasskeyHere"}
查看 order-processor 输出
正如上面的应用程序代码中所指定的,order-processor 服务通过 Dapr secret 存储检索 secret 并将其显示在控制台中。