Dapr 快速入门 是代码样本的教程集合,旨在让您从 Dapr 快速入门,每个教程都突出了不同的 Dapr 功能。
- 一合适的入门起点是 hello-world 快速入门,它演示了如何在本地机器上以自托管模式运行Dapr,并使用一个简单的应用程序中演示了状态管理和服务调用。
- 接下来,如果您熟悉Kubernetes,想了解如何在Kubernetes环境中运行相同的应用程序,请阅读hello-kubernetes快速入门。 其他的快速入门教程皆在探索Dapr的不同功能,如发布/订阅、绑定和分布式计算,同时教程内包括本地和Kubernetes上运行的说明,可以无序完成。 快速入门的完整列表可在下方找到。
- 您可以随时浏览 Dapr 文档或 SDK 特定例子,还可以尝试额外的快速入门。
- 当你完成所有入门后,可以考虑探索Dapr样例库,查看由社区贡献的更多的代码样本,其中展示Dapr的更多高阶或特定的用法。
下面演示下,演示如何在本地运行Dapr。 重点介绍服务调用和状态管理。
以下架构图说明了构成第一部分示例的组件:
稍后,您将部署一个 Python 应用程序来充当发布者。下面的架构图显示了新组件的添加:
必备条件
本快速入门要求您在计算机上安装以下内容:
- Docker
- Node.js version 8 or greater
- Python 3.x: Note: When running this quickstart on Windows, it best to install Python from python.org rather than from the Windows store.
- Postman [Optional]
Step 1 - Setup Dapr
按照dapr部署说明初始化 Dapr。
Step 2 - Understand the code
现在 Dapr 已在本地设置,克隆存储库,然后导航到 Hello World 快速入门的 Node.js 版本:
git clone [-b <dapr_version_tag>] https://github.com/dapr/quickstarts.git
cd quickstarts/hello-world/node
使用idea打开对应的项目:(需具备go语言基础)
注意:有关支持的标签,请参阅 https://github.com/dapr/quickstarts#supported-dapr-runtime-version。使用 dapr 运行时的边缘版本时,请使用 git clone https://github.com/dapr/quickstarts.git。
在 app.js 中,您会发现一个简单的 express 应用程序,它公开了一些路由和处理程序。首先,看一下文件的顶部:
const daprPort = process.env.DAPR_HTTP_PORT || 3500;
const stateStoreName = `statestore`;
const stateUrl = `http://localhost:${daprPort}/v1.0/state/${stateStoreName}`;
Dapr CLI 为 Dapr 端口创建一个环境变量,默认为 3500。您将在第 3 步中向系统发送 POST 消息时使用它。 stateStoreName 是给状态存储的名称。稍后您将返回到该名称以查看该名称是如何配置的。
接下来,看一下 neworder 处理程序:
app.post('/neworder', (req, res) => {
const data = req.body.data;
const orderId = data.orderId;
console.log("Got a new order! Order ID: " + orderId);
const state = [{
key: "order",
value: data
}];
fetch(stateUrl, {
method: "POST",
body: JSON.stringify(state),
headers: {
"Content-Type": "application/json"
}
}).then((response) => {
if (!response.ok) {
throw "Failed to persist state.";
}
console.log("Successfully persisted state.");
res.status(200).send();
}).catch((error) => {
console.log(error);
res.status(500).send({message: error});
});
});
在这里,应用程序公开了一个将接收和处理 neworder 消息的端点。它首先记录传入的消息,然后通过将状态数组发布到 /state/<state-store-name> 端点,将订单 ID 保存到 Redis 存储中。
或者,您可以通过简单地将状态与响应对象一起返回来保持状态:
res.json({
state: [{
key: "order",
value: order
}]
})
但是,这种方法不允许您验证消息是否成功持久化。
该应用程序还公开了一个 GET 端点 /order:
app.get('/order', (_req, res) => {
fetch(`${stateUrl}/order`)
.then((response) => {
if (!response.ok) {
throw "Could not get state.";
}
return response.text();
}).then((orders) => {
res.send(orders);
}).catch((error) => {
console.log(error);
res.status(500).send({message: error});
});
});
这会调用 Redis 缓存以检索“order”键的最新值,从而有效地使 Node.js 应用程序成为无状态的。
Step 3 - Run the Node.js app with Dapr
打开一个新终端并导航到 ./hello-world/node 目录并按照以下步骤操作:
1.Install dependencies:
npm install
这将安装 express 和 body-parser,package.json 中显示的依赖项。
2.使用 Dapr 运行 Node.js 应用程序:
dapr run --app-id nodeapp --app-port 3000 --dapr-http-port 3500 node app.js
输出内容:
ℹ️ Starting Dapr with id nodeapp. HTTP Port: 3500. gRPC Port: 53796
INFO[0000] starting Dapr Runtime -- version 1.7.1 -- commit 5fd38aeaaa9cf58f3f00f6f9bfc6c58d8cd82b87 app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] log level set to: info app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] metrics server started on :53797/ app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.metrics type=log ver=1.7.1
INFO[0000] standalone mode configured app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] app id: nodeapp app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] mTLS is disabled. Skipping certificate request and tls validation app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] local service entry announced: nodeapp -> 192.168.1.67:53801 app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.contrib type=log ver=1.7.1
INFO[0000] Initialized name resolution to mdns app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] loading components app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
== APP == Node App listening on port 3000!
INFO[0000] component loaded. name: pubsub, type: pubsub.redis/v1 app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] waiting for all outstanding components to be processed app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] detected actor state store: statestore app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] component loaded. name: statestore, type: state.redis/v1 app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] all outstanding components processed app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] gRPC proxy enabled app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] enabled gRPC tracing middleware app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime.grpc.api type=log ver=1.7.1
INFO[0000] enabled gRPC metrics middleware app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime.grpc.api type=log ver=1.7.1
INFO[0000] API gRPC server is running on port 53796 app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] enabled metrics http middleware app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime.http type=log ver=1.7.1
INFO[0000] enabled tracing http middleware app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime.http type=log ver=1.7.1
INFO[0000] http server is running on port 3500 app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] The request body size parameter is: 4 app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] enabled gRPC tracing middleware app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime.grpc.internal type=log ver=1.7.1
INFO[0000] enabled gRPC metrics middleware app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime.grpc.internal type=log ver=1.7.1
INFO[0000] internal gRPC server is running on port 53801 app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] application protocol: http. waiting on port 3000. This will block until the app is listening on that port. app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] application discovered on port 3000 app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
WARN[0000] [DEPRECATION NOTICE] Adding a default content type to incoming service invocation requests is deprecated and will be removed in the future. See https://docs.dapr.io/operations/support/support-preview-features/ for more details. You can opt into the new behavior today by setting the configuration option `ServiceInvocation.NoDefaultContentType` to true. app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] application configuration loaded app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30s app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime.actor type=log ver=1.7.1
INFO[0000] dapr initialized. Status: Running. Init Elapsed 212.087ms app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime type=log ver=1.7.1
INFO[0000] placement tables updated, version: 0 app_id=nodeapp instance=romandeMacBook-Pro.local scope=dapr.runtime.actor.internal.placement type=log ver=1.7.1
ℹ️ Updating metadata for app command: node app.js
✅ You're up and running! Both Dapr and your app logs will appear here.
注意:--app-port(应用程序运行的端口)是可配置的。 Node 应用程序恰好在端口 3000 上运行,但您可以将其配置为在任何其他端口上运行。另请注意,Dapr --app-port 参数是可选的,如果未提供,则使用随机可用端口。
说明:
dapr run 命令查找默认组件目录,对于 Linux/MacOS 是 $HOME/.dapr/components,对于 Windows 是 %USERPROFILE%\.dapr\components,它包含 Dapr 将在运行时使用的组件的 yaml 定义文件。在本地运行时,为本地开发环境提供默认定义的 yaml 文件放置在此默认组件目录中。查看 components 目录中的 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 文件将状态存储定义为 Redis,并将其命名为 statestore。这是在 app.js 中用于调用应用程序中的状态存储的名称:
const stateStoreName = `statestore`;
const stateUrl = `http://localhost:${daprPort}/v1.0/state/${stateStoreName}`;
虽然在本教程中使用了默认 yaml 文件,但通常开发人员会根据应用程序和场景修改它们或创建自定义 yaml 定义。
可选:现在是熟悉 Dapr 仪表板的好时机。这是一个方便的界面,可以检查在 Dapr 上运行的应用程序的状态和信息。以下命令将使其在 http://localhost:9999/ 上可用。
Step 4 - Post messages to the service
现在 Dapr 和 Node.js 应用程序正在运行,您可以使用不同的工具针对它发送 POST 消息。注意:这里 POST 消息发送到端口 3500 - 如果您使用不同的端口,请务必相应地更新您的 URL。
首先,在新终端中使用 Dapr cli 发布消息:
dapr invoke --app-id nodeapp --method neworder --data-file sample.json
或者,使用curl:
curl -XPOST -d @sample.json -H Content-Type:application/json http://localhost:3500/v1.0/invoke/nodeapp/method/neworder
或者,使用 Visual Studio Code Rest 客户端插件
sample.http:
POST http://localhost:3500/v1.0/invoke/nodeapp/method/neworder
{
"data": {
"orderId": "42"
}
}
您可以使用 Postman GUI。
打开 Postman 并针对 http://localhost:3500/v1.0/invoke/nodeapp/method/neworder 创建一个 POST 请求.
您的终端,您应该会看到指示已收到消息且状态已更新的日志:
Step 5 - Confirm successful persistence
现在,要验证订单是否成功保存到状态存储,请针对:http://localhost:3500/v1.0/invoke/nodeapp/method/order 创建一个 GET 请求。注意:同样,如果您选择了 3500 以外的端口,请务必反映正确的端口。
curl http://localhost:3500/v1.0/invoke/nodeapp/method/order
输出效果:
或者 使用 Dapr CLI
dapr invoke --app-id nodeapp --method order --verb GET
或使用 Visual Studio Code Rest 客户端插件
sample.http
GET http://localhost:3500/v1.0/invoke/nodeapp/method/order
或使用Postman
这将调用 /order 路由,该路由调用 Redis 存储以获取最新数据。观察预期结果!
Step 6 - Run the Python app with Dapr
查看 ./hello-world/python 目录中的 Python 应用程序,了解另一个应用程序如何通过 Dapr 调用 Node 应用程序,而无需知道目标的主机名或端口。在 app.py 文件中,您可以找到通过 Dapr 调用 Node App 的端点定义。
dapr_port = os.getenv("DAPR_HTTP_PORT", 3500)
dapr_url = "http://localhost:{}/v1.0/invoke/nodeapp/method/neworder".format(dapr_port)
注意 URL 中节点应用程序的名称 (nodeapp) 很重要,它将允许 Dapr 将请求重定向到正确的 API 端点。此名称需要与本练习前面用于运行节点应用程序的名称相匹配。
下面的代码块显示了 Python 应用程序如何每秒增量地发布一个新的 orderId,或者如果发布调用失败则打印一个异常。
n = 0
while True:
n += 1
message = {"data": {"orderId": n}}
try:
response = requests.post(dapr_url, json=message)
except Exception as e:
print(e)
time.sleep(1)
现在打开一个新终端并转到 ./hello-world/python 目录。
1.安装
pip3 install requests
2.启动
dapr run --app-id pythonapp python3 app.py
3.如果一切顺利,运行 Node 应用程序的另一个终端应该记录如下条目:
已知问题:如果您从 Microsoft Store 在 Windows 上运行 python3,您会收到以下错误消息:
exec: "python3": executable file not found in %!P(MISSING)ATH%!(NOVERB)
这是由于 golang 无法正确执行 Microsoft Store 别名。您可以使用以下命令代替上述命令:
dapr run --app-id pythonapp cmd /c "python3 app.py"
4.现在,执行几次 GET 请求,看看 orderId 每秒如何变化(将其输入到 Web 浏览器,使用 Postman 或 curl):
GET http://localhost:3500/v1.0/invoke/nodeapp/method/order
{
"orderId": 3
}
注意:不需要在第二个终端中运行 dapr init,因为 dapr 最初已经在您的本地计算机上设置,再次运行此命令将失败。
Step 7 - Cleanup
要停止您的服务运行,只需停止“dapr run”进程。或者,您可以使用 Dapr CLI“停止”命令关闭每个服务。例如,要关闭这两个服务,请在新终端中运行以下命令:
dapr stop --app-id nodeapp
dapr stop --app-id pythonapp
要查看服务已停止运行,请运行 dapr list,注意您的服务不再出现!
总结:以上是通过本地,进行dapr的体验。此种方式,将业务开发与架构解耦,大大减少双方的工作量,但对应架构人员要求较高。期待在不久的将来,掌握dapr,实现一套自有的运行时体系。后面也会分享对应dapr的深入研究。