diff --git a/.github/crowdin-download.yml b/.github/crowdin-download.yml index 3f5f0d5af..d74334c16 100644 --- a/.github/crowdin-download.yml +++ b/.github/crowdin-download.yml @@ -2,7 +2,7 @@ name: Download translation from Crowdin on: schedule: - - cron: "0 0 * * *" + - cron: "10 1 * * *" workflow_dispatch: push: branches: @@ -12,26 +12,15 @@ on: jobs: synchronize-with-crowdin: runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - version_tag: - - v1.5 - - v1.4 - - v1.3 - - v1.2 - - v1.1 - - v1.0 - steps: - name: Checkout uses: actions/checkout@v2 - with: - ref: ${{ matrix.version_tag }}/translate_site - - name: sleep + - name: remove old files run: | - # sleep some time according to the version tag. e.g. v1.5 will sleep for 5*30 seconds - sleep $(($(echo ${{ matrix.version_tag }} | sed -e 's/v//' -e 's/\.//g')*30)) + cd src + rm -rf translated_content + mkdir -p translated_content/zh_CN + cp -r content/* translated_content/zh_CN - name: crowdin action uses: crowdin/github-action@v1.19.0 with: @@ -39,11 +28,10 @@ jobs: upload_translations: false download_translations: true dryrun_action: false - crowdin_branch_name: ${{ matrix.version_tag }}_translate_site # This is the name of the git branch that Crowdin will create when opening a pull request. # This branch does NOT need to be manually created. It will be created automatically by the action. - localization_branch_name: l10n_crowdin_action_${{ matrix.version_tag }} + localization_branch_name: l10n_crowdin_action create_pull_request: false push_translations: false pull_request_title: "New Crowdin translations" @@ -51,7 +39,7 @@ jobs: pull_request_labels: "translation update, automated pr" # This is the name of the git branch to with pull request will be created. # If not specified default repository branch will be used. - pull_request_base_branch_name: ${{ matrix.version_tag }}/translate_site + pull_request_base_branch_name: main env: GITHUB_TOKEN: ${{ secrets.REPO_SCOPED_TOKEN }} CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} @@ -70,16 +58,12 @@ jobs: commit-message: "New Crowdin translations" signoff: false delete-branch: true - branch: l10n_crowdin_action_${{ matrix.version_tag }} - base: ${{ matrix.version_tag }}/translate_site + branch: l10n_crowdin_action + base: main title: "New Crowdin translations" labels: | automated pr - ${{ matrix.version_tag }} assignees: | newbe36524 reviewers: | newbe36524 - team-reviewers: | - owners - maintainers diff --git a/.github/crowdin-update-source.yml b/.github/crowdin-update-source.yml index f17c7c4ac..5ad908e58 100644 --- a/.github/crowdin-update-source.yml +++ b/.github/crowdin-update-source.yml @@ -2,7 +2,7 @@ name: Update source to crowdin on: schedule: - - cron: "0 0 * * *" + - cron: "10 0 * * *" workflow_dispatch: push: branches: @@ -11,22 +11,9 @@ on: jobs: synchronize-with-crowdin: runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - version_tag: - - v1.5 - - v1.4 - - v1.3 - - v1.2 - - v1.1 - - v1.0 - steps: - name: Checkout uses: actions/checkout@v2 - with: - ref: ${{ matrix.version_tag }}/translate_site - name: crowdin action uses: crowdin/github-action@v1.19.0 with: @@ -35,7 +22,6 @@ jobs: upload_translations: false download_translations: false dryrun_action: false - crowdin_branch_name: ${{ matrix.version_tag }}_translate_site env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/crowdin-download.yml b/.github/workflows/crowdin-download.yml deleted file mode 100644 index d74334c16..000000000 --- a/.github/workflows/crowdin-download.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: Download translation from Crowdin - -on: - schedule: - - cron: "10 1 * * *" - workflow_dispatch: - push: - branches: - - crowdin - - "crowdin_test" - -jobs: - synchronize-with-crowdin: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: remove old files - run: | - cd src - rm -rf translated_content - mkdir -p translated_content/zh_CN - cp -r content/* translated_content/zh_CN - - name: crowdin action - uses: crowdin/github-action@v1.19.0 - with: - upload_sources: false - upload_translations: false - download_translations: true - dryrun_action: false - - # This is the name of the git branch that Crowdin will create when opening a pull request. - # This branch does NOT need to be manually created. It will be created automatically by the action. - localization_branch_name: l10n_crowdin_action - create_pull_request: false - push_translations: false - pull_request_title: "New Crowdin translations" - pull_request_body: "New Crowdin pull request with translations" - pull_request_labels: "translation update, automated pr" - # This is the name of the git branch to with pull request will be created. - # If not specified default repository branch will be used. - pull_request_base_branch_name: main - env: - GITHUB_TOKEN: ${{ secrets.REPO_SCOPED_TOKEN }} - CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - - - name: permissions - # https://stackoverflow.com/questions/11774397/git-push-error-unable-to-unlink-old-permission-denied/26950991#26950991 - run: | - sudo chmod -R 777 . - git config core.filemode false - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v3 - with: - token: ${{ secrets.REPO_SCOPED_TOKEN }} - commit-message: "New Crowdin translations" - signoff: false - delete-branch: true - branch: l10n_crowdin_action - base: main - title: "New Crowdin translations" - labels: | - automated pr - assignees: | - newbe36524 - reviewers: | - newbe36524 diff --git a/.github/workflows/crowdin-update-source.yml b/.github/workflows/crowdin-update-source.yml deleted file mode 100644 index 5ad908e58..000000000 --- a/.github/workflows/crowdin-update-source.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Update source to crowdin - -on: - schedule: - - cron: "10 0 * * *" - workflow_dispatch: - push: - branches: - - crowdin - -jobs: - synchronize-with-crowdin: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: crowdin action - uses: crowdin/github-action@v1.19.0 - with: - upload_sources: true - upload_sources_args: "--delete-obsolete" - upload_translations: false - download_translations: false - dryrun_action: false - - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} diff --git a/src/translated_content/zh_CN/contributing/dotnet-contributing.md b/src/translated_content/zh_CN/contributing/dotnet-contributing.md new file mode 100644 index 000000000..311d75e4a --- /dev/null +++ b/src/translated_content/zh_CN/contributing/dotnet-contributing.md @@ -0,0 +1,82 @@ +--- +type: docs +title: "为 .NET SDK 贡献" +linkTitle: ".NET SDK" +weight: 3000 +description: 为 Dapr .NET SDK 贡献的指南 +--- + +# 欢迎! +如果你正在阅读这篇文章,说明你可能对为 Dapr 和/或 Dapr .NET SDK 做出贡献感兴趣。欢迎加入这个项目,感谢你对贡献的兴趣! + +请查看文档,了解 Dapr 的定义及其目标,并通过 [Discord](https://bit.ly/dapr-discord) 联系我们。告诉我们你想如何贡献,我们很乐意提供想法和建议。 + +有很多方式可以为 Dapr 做出贡献: +- 为 [Dapr 运行时](https://github.com/dapr/dapr/issues/new/choose) 或 [Dapr .NET SDK](https://github.com/dapr/dotnet-sdk/issues/new/choose) 提交错误报告 +- 提出新的 [运行时功能](https://github.com/dapr/proposals/issues/new/choose) 或 [SDK 功能](https://github.com/dapr/dotnet-sdk/issues/new/choose) +- 改进 [Dapr 大项目](https://github.com/dapr/docs) 或 [Dapr .NET SDK 专门](https://github.com/dapr/dotnet-sdk/tree/master/daprdocs) 的文档 +- 添加新的或改进现有的 [组件](https://github.com/dapr/components-contrib/),以实现各种构建块 +- 增强 [.NET 可插拔组件 SDK 功能](https://github.com/dapr-sandbox/components-dotnet-sdk) +- 改进 Dapr .NET SDK 代码库和/或修复错误(详见下文) + +如果你是代码库的新手,请在 Discord 的 #dotnet-sdk 频道中询问如何进行更改或提出一般性问题。你不需要获得许可即可进行任何工作,但请注意,如果某个问题已分配给某人,这表明可能已经有人开始处理它了。特别是如果自上次活动以来已经有一段时间,请随时联系他们,看看他们是否仍然有兴趣继续,或者你是否可以接手,并提交你的实现的 pull request。 + +如果你想将自己分配给一个问题,请在对话中回复 "/assign",机器人会将你分配给它。 + +我们将一些问题标记为 `good-first-issue` 或 `help wanted`,表明这些问题可能是小的、独立的更改。 + +如果你不确定你的实现,请将其创建为草稿 pull request,并通过标记 `@dapr/maintainers-dotnet-sdk` 向 [.NET 维护者](https://github.com/orgs/dapr/teams/maintainers-dotnet-sdk) 征求反馈,并提供一些关于你需要帮助的上下文。 + +# 贡献规则和最佳实践 + +在为 [.NET SDK](https://github.com/dapr/dotnet-sdk) 贡献时,应遵循以下规则和最佳实践。 + +## Pull Requests +仅包含格式更改的 pull request 通常不被鼓励。pull request 应该寻求修复错误、添加新功能或改进现有功能。 + +请尽量将你的 pull request 限制在单个问题上。涉及许多文件的广泛 PR 不太可能在短时间内被审查或接受。在单个 PR 中处理许多不同的问题使得很难确定你的代码是否完全解决了潜在问题,并使代码审查复杂化。 + +## 测试 +所有 pull request 应包括单元和/或集成测试,以反映所添加或更改的内容,以便明确功能按预期工作。避免使用自动生成的测试,这些测试会多次重复测试相同的功能。相反,寻求通过验证更改的每个可能路径来提高代码覆盖率,以便未来的贡献者可以更轻松地导航你的逻辑轮廓,并更容易识别限制。 + +## 示例 + +`examples` 目录包含用户可以运行的代码示例,以尝试各种 Dapr .NET SDK 包和扩展的特定功能。在编写新的和更新的示例时,请记住: + +- 所有示例应可在 Windows、Linux 和 MacOS 上运行。虽然 .NET Core 代码在操作系统之间是一致的,但任何前/后示例命令应通过 [codetabs]({{< ref "contributing-docs.md#tabbed-content" >}}) 提供选项 +- 包含下载/安装任何所需先决条件的步骤。一个全新操作系统安装的用户应该能够开始示例并完成它而不会出错。链接到外部下载页面是可以的。 + +## 文档 + +`daprdocs` 目录包含渲染到 [Dapr Docs](https://docs.dapr.io) 网站的 markdown 文件。当文档网站构建时,此仓库被克隆并配置,以便其内容与文档内容一起渲染。在编写文档时,请记住: + + - 除了这些规则外,还应遵循 [文档指南]({{< ref contributing-docs.md >}}) 中的所有规则。 + - 所有文件和目录应以 `dotnet-` 为前缀,以确保所有文件/目录名称在所有 Dapr 文档中都是全局唯一的。 + +所有 pull request 应努力包括代码中的 XML 文档,清楚地指明功能的作用和原因,以及对已发布文档的更改,以便为其他开发人员澄清你的更改如何改进 Dapr 框架。 + +## GitHub Dapr Bot 命令 + +查看 [daprbot 文档](https://docs.dapr.io/contributing/daprbot/) 以获取你可以在此仓库中运行的常见任务的 Github 命令。例如,你可以在问题上评论 `/assign` 来将其分配给自己。 + +## 提交签署 +提交到 Dapr .NET SDK 的所有代码必须由编写它的开发人员签署。这意味着每个提交必须以以下内容结尾: +> Signed-off-by: First Last + +姓名和电子邮件地址必须与提交更改的用户的注册 GitHub 姓名和电子邮件地址匹配。我们使用一个机器人在 pull request 中检测这一点,如果此检查未能验证,我们将无法合并 PR。 + +如果你注意到 PR 因 DCO 检查失败而未能验证,请考虑在本地压缩 PR 并重新提交,以确保签署声明包含在提交历史中。 + +# 语言、工具和流程 +Dapr .NET SDK 中的所有源代码都是用 C# 编写的,并针对最新的语言版本可用于最早支持的 .NET SDK。截至 v1.15,这意味着因为 .NET 6 仍然受支持,最新的语言版本是 [C# 版本 10](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history#c-version-10)。 + +截至 v1.15,支持以下 .NET 版本: + +| 版本 | 备注 | +| --- |-----------------------------------------------------------------| +| .NET 6 | 将在 v1.16 中停止支持 | +| .NET 7 | 仅在 Dapr.Workflows 中支持,将在 v1.16 中停止支持 | +| .NET 8 | 将在 v1.16 中继续支持 | +| .NET 9 | 将在 v1.16 中继续支持 | + +欢迎贡献者使用他们最熟悉的 IDE 进行开发,但请不要提交 IDE 特定的偏好文件,因为这些文件将被拒绝。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/contributing/go-contributing.md b/src/translated_content/zh_CN/contributing/go-contributing.md new file mode 100644 index 000000000..ec69493e6 --- /dev/null +++ b/src/translated_content/zh_CN/contributing/go-contributing.md @@ -0,0 +1,23 @@ +--- +type: docs +title: "为 Go SDK 贡献" +linkTitle: "Go SDK" +weight: 3000 +description: 为 Dapr Go SDK 贡献的指南 +--- + +在为 [Go SDK](https://github.com/dapr/go-sdk) 贡献时,贡献者应该遵循以下规则和最佳实践。 + +## 示例 + +`examples` 目录包含用户可以运行的代码示例,以尝试各种 Go SDK 包和扩展的特定功能。在编写新的和更新的示例时,请注意: + +- 所有示例应能在 Windows、Linux 和 MacOS 上运行。虽然 Go 代码在不同操作系统之间是一致的,但任何示例的前置/后置命令应通过 [codetabs]({{< ref "contributing-docs.md#tabbed-content" >}}) 提供不同的选项。 +- 包含下载和安装任何必要前提条件的步骤。即使是刚安装操作系统的用户,也应该能够顺利开始并完成示例而不出现错误。可以链接到外部下载页面。 + +## 文档 + +`daprdocs` 目录包含被渲染到 [Dapr Docs](https://docs.dapr.io) 网站的 markdown 文件。当文档网站构建时,此仓库会被克隆并配置,以便其内容与文档内容一起呈现。在编写文档时,请注意: + +- 除了这些规则外,还应遵循 [docs guide]({{< ref contributing-docs.md >}}) 中的所有规则。 +- 所有文件和目录应以 `go-` 为前缀,以确保在所有 Dapr 文档中文件和目录名称的全局唯一性。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/contributing/java-contributing.md b/src/translated_content/zh_CN/contributing/java-contributing.md new file mode 100644 index 000000000..850e32727 --- /dev/null +++ b/src/translated_content/zh_CN/contributing/java-contributing.md @@ -0,0 +1,23 @@ +--- +type: docs +title: "为 Java SDK 贡献" +linkTitle: "Java SDK" +weight: 3000 +description: 为 Dapr Java SDK 贡献的指南 +--- + +贡献 [Java SDK](https://github.com/dapr/java-sdk) 时,应该遵循以下规则和最佳实践。 + +## 示例 + +`examples` 目录中包含用户可以运行的代码示例,用于尝试各种 Java SDK 包和扩展的特定功能。在编写或更新示例时,请注意: + +- 所有示例应能在 Windows、Linux 和 MacOS 上运行。虽然 Java 代码在不同操作系统上是一致的,但任何示例的前置或后续命令应通过 [codetabs]({{< ref "contributing-docs.md#tabbed-content" >}}) 提供不同的选项。 +- 包含下载和安装所有必要前提条件的步骤。即使是全新安装操作系统的用户,也应该能够顺利开始并完成示例。可以链接到外部下载页面。 + +## 文档 + +`daprdocs` 目录中包含的 markdown 文件会被渲染到 [Dapr Docs](https://docs.dapr.io) 网站上。当文档网站构建时,此仓库会被克隆并配置,以便其内容与文档内容一起渲染。在编写文档时,请注意: + +- 除了这些规则外,还应遵循 [docs guide]({{< ref contributing-docs.md >}}) 中的所有规则。 +- 所有文件和目录名称应以 `java-` 为前缀,以确保在所有 Dapr 文档中具有全局唯一性。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/contributing/js-contributing.md b/src/translated_content/zh_CN/contributing/js-contributing.md new file mode 100644 index 000000000..96cb91ece --- /dev/null +++ b/src/translated_content/zh_CN/contributing/js-contributing.md @@ -0,0 +1,116 @@ +--- +type: docs +title: "贡献到 JavaScript SDK" +linkTitle: "JavaScript SDK" +weight: 3000 +description: 为 Dapr JavaScript SDK 贡献的指南 +--- + +在为 [JavaScript SDK](https://github.com/dapr/js-sdk) 贡献时,应遵循以下规则和最佳实践。 + +💡 你可以运行 `npm pretty-fix` 来格式化所有文件 + +## 提交指南 + +Dapr JavaScript SDK 遵循 [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) 规范。自动生成的变更日志工具会根据提交信息自动生成变更日志。以下是编写提交信息的指南: + +### 格式 + +``` +type(scope)!: subject +``` + +- `type`: 提交的类型是以下之一: + + - `feat`: 新功能。 + - `fix`: 错误修复。 + - `docs`: 文档更改。 + - `refactor`: 重构特定代码部分,不引入新功能或错误修复。 + - `style`: 代码风格改进。 + - `perf`: 性能改进。 + - `test`: 测试套件的更改。 + - `ci`: CI 系统的更改。 + - `build`: 构建系统的更改(我们目前没有,所以不适用)。 + - `chore`: 其他不符合上述类型的更改。这不会出现在变更日志中。 + +- `scope`: 提交更改的代码库部分。如果更改了多个部分,或没有特定部分被修改,则留空,不加括号。 + 示例: + + - 添加 `test` 的提交: + + ``` + test(actors): add an actor test + ``` + + - 一次更改多项的提交: + + ``` + style: adopt eslint + ``` + + 对于示例的更改,范围应为示例名称,前缀为 `examples/`: + + - ❌ `fix(agnoster): commit subject` + - ✅ `fix(examples/http/actor): commit subject` + +- `!`: 这个符号放在 `scope`(或 `type` 如果范围为空)之后,表示提交引入了重大更改。 + + 你可以选择性地添加一条消息,变更日志工具会向用户显示这条消息,以说明更改了什么以及如何处理。你可以使用多行来输入此消息;变更日志解析器会继续读取,直到提交信息结束或找到空行。 + + 示例(虚构的): + + ``` + style(agnoster)!: change dirty git repo glyph + + BREAKING CHANGE: the glyph to indicate when a git repository is dirty has + changed from a Powerline character to a standard UTF-8 emoji. + + Fixes #420 + + Co-authored-by: Username + ``` + +- `subject`: 对更改的简要描述。这将在变更日志中显示。如果需要指定其他详细信息,可以使用提交正文,但它不会被显示。 + + 提交主题可以包括以下内容: + + - 通过编写 `#issue` 链接到相关问题或 PR。这将由变更日志工具突出显示: + + ``` + feat(archlinux): add support for aura AUR helper (#9467) + ``` + + - 使用反引号格式化内联代码:反引号之间的文本也将由变更日志工具突出显示: + ``` + feat(shell-proxy): enable unexported `DEFAULT_PROXY` setting (#9774) + ``` + +### 风格 + +尽量保持第一行提交信息简短。使用这种提交风格更难做到这一点,但尽量简洁,如果需要更多空间,可以使用提交正文。确保提交主题清晰明了,以便用户仅通过查看变更日志就能知道更改了什么。 + +## Github Dapr Bot 命令 + +查看 [daprbot 文档](https://docs.dapr.io/contributing/daprbot/) 以获取可以在此仓库中运行的 Github 命令以完成常见任务。例如,你可以运行 `/assign`(作为问题的评论)来将问题分配给用户或用户组。 + +## 编码规则 + +为了确保源代码的一致性,请在工作时牢记以下规则: + +- 所有功能或错误修复**必须通过**一个或多个规范(单元测试)进行测试。 +- 所有公共 API 方法**必须被记录**。 +- 我们遵循 [ESLint 推荐规则](https://eslint.org/docs/rules/)。 + +## 示例 + +`examples` 目录包含供用户运行的代码示例,以尝试各种 JavaScript SDK 包和扩展的特定功能。在编写新的和更新的示例时,请记住: + +- 所有示例应可在 Windows、Linux 和 MacOS 上运行。虽然 JavaScript 代码在操作系统之间是一致的,但任何前/后示例命令应通过 [codetabs]({{< ref "contributing-docs.md#tabbed-content" >}}) 提供选项。 +- 包含下载/安装任何所需前提条件的步骤。一个全新操作系统安装的用户应该能够开始示例并完成它而不会出错。链接到外部下载页面是可以的。 + +## 文档 + +`daprdocs` 目录包含渲染到 [Dapr Docs](https://docs.dapr.io) 网站的 markdown 文件。当文档网站构建时,此仓库被克隆并配置,以便其内容与文档内容一起渲染。在编写文档时,请记住: + +- 除了这些规则外,还应遵循 [docs guide]({{< ref contributing-docs.md >}}) 中的所有规则。 +- 所有文件和目录应以 `js-` 为前缀,以确保所有文件/目录名称在所有 Dapr 文档中都是全局唯一的。 diff --git a/src/translated_content/zh_CN/contributing/python-contributing.md b/src/translated_content/zh_CN/contributing/python-contributing.md new file mode 100644 index 000000000..385c16499 --- /dev/null +++ b/src/translated_content/zh_CN/contributing/python-contributing.md @@ -0,0 +1,27 @@ +--- +type: docs +title: "为 Python SDK 贡献" +linkTitle: "Python SDK" +weight: 3000 +description: 为 Dapr Python SDK 贡献的指南 +--- + +在贡献 [Python SDK](https://github.com/dapr/python-sdk) 时,应该遵循以下规则和最佳实践。 + +## 示例 + +`examples` 目录包含用户可以运行的代码示例,以体验各种 Python SDK 包和扩展的特定功能。在编写或更新示例时,请注意: + +- 所有示例应在 Windows、Linux 和 MacOS 上均可运行。虽然 Python 代码在不同操作系统之间是一致的,但任何示例的前置或后续命令应通过 [codetabs]({{< ref "contributing-docs.md#tabbed-content" >}}) 提供不同操作系统的选项。 +- 包含下载和安装所有必要前提条件的步骤。即使是刚安装操作系统的人也应该能够顺利开始并完成示例,而不会遇到错误。可以链接到外部下载页面。 + +## 文档 + +`daprdocs` 目录包含会被渲染到 [Dapr Docs](https://docs.dapr.io) 网站的 markdown 文件。当文档网站构建时,此仓库会被克隆并配置,以便其内容与文档内容一起呈现。在编写文档时,请注意: + +- 除了这些规则外,还应遵循 [docs guide]({{< ref contributing-docs.md >}}) 中的所有规则。 +- 所有文件和目录名称应以 `python-` 为前缀,以确保在所有 Dapr 文档中具有唯一性。 + +## Github Dapr Bot 命令 + +请查看 [daprbot 文档](https://docs.dapr.io/contributing/daprbot/) 以了解您可以在此仓库中使用的 Github 命令来完成常见任务。例如,您可以在问题的评论中运行 `/assign` 来将问题分配给某个用户或用户组。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/contributing/rust-contributing.md b/src/translated_content/zh_CN/contributing/rust-contributing.md new file mode 100644 index 000000000..85db2e919 --- /dev/null +++ b/src/translated_content/zh_CN/contributing/rust-contributing.md @@ -0,0 +1,37 @@ +--- +type: docs +title: "贡献 Rust SDK" +linkTitle: "Rust SDK" +weight: 3000 +description: 为 Dapr Rust SDK 贡献的指南 +--- + +在您为 [Rust SDK](https://github.com/dapr/rust-sdk) 贡献时,请遵循以下规则和最佳实践。 + +## 示例 + +`examples` 目录包含用户可以运行的代码示例,以尝试各种 Rust SDK 包和扩展的特定功能。它还包含用于验证的组件示例。在编写或更新示例时,请注意以下几点: + +- 所有示例应能在 Windows、Linux 和 MacOS 上运行。虽然 Rust 代码在不同操作系统之间基本一致,但由于少量操作系统功能限制,任何示例的前置/后置命令都应通过 [codetabs]({{< ref "contributing-docs.md#tabbed-content" >}}) 提供不同选项。 +- 包含下载和安装所有必要前提条件的步骤。刚安装操作系统的人应该能够顺利开始并完成示例而不出错。可以链接到外部下载页面。 +- 示例应经过验证,并包含自动化的 markdown 步骤,并添加到验证工作流 [TBA](#)。 + +## 文档 + +`daprdocs` 目录包含将被渲染到 [Dapr Docs](https://docs.dapr.io) 网站的 markdown 文件。当文档网站构建时,此仓库会被克隆并配置,以便其内容与文档内容一起渲染。在编写文档时,请注意: + + - 除了这些规则外,还应遵循 [docs guide]({{< ref contributing-docs.md >}}) 中的所有规则。 + - 所有文件和目录应以 `rust-` 为前缀,以确保在所有 Dapr 文档中文件/目录名称的全局唯一性。 + +## 更新 Protobufs + +要从 `dapr/dapr` 仓库中提取 protobufs,您可以在仓库根目录运行以下脚本: + +```bash +./update-protos.sh +``` + +默认情况下,脚本从 Dapr 仓库的 master 分支获取最新的 proto 更新。如果您需要选择特定的发布或版本,请使用 -v 标志: + +```bash +./update-protos.sh -v v1.13.0 diff --git a/src/translated_content/zh_CN/docs/_index.md b/src/translated_content/zh_CN/docs/_index.md new file mode 100644 index 000000000..5671a2983 --- /dev/null +++ b/src/translated_content/zh_CN/docs/_index.md @@ -0,0 +1,200 @@ +--- +type: docs +no_list: true +--- +# Dapr 文档 + +欢迎来到 Dapr 文档站点! + +{{% alert title="什么是 Dapr?" color="primary" %}} +Dapr 是一个便携的事件驱动运行时环境,帮助开发者轻松构建在云端和边缘运行的高可用、无状态和有状态应用程序,并支持多种编程语言和开发框架。通过利用 sidecar 架构的优势,Dapr 帮助您解决构建微服务时的挑战,并保持代码与平台无关。 +{{< button text="开始使用" page="getting-started" >}} +{{% /alert %}} + +### 开始使用 Dapr 进行开发 + +
+
+
+
入门指南
+

几分钟内在您的环境中启动并运行 Dapr 的方法。

+ +
+
+
+
+
快速入门
+

一系列带有代码示例的教程,帮助您快速上手 Dapr。

+ +
+
+
+
+
概念
+

深入了解 Dapr 的主要功能和特性。

+ +
+
+
+ +### 了解更多关于 Dapr 的信息 + +
+
+
+
开发应用程序
+

工具、技巧和信息,帮助您使用 Dapr 构建应用程序。

+ +
+
+
+
+
构建块
+

解决分布式应用程序常见开发挑战的功能。

+ +
+
+
+
+
操作
+

托管选项、最佳实践以及其他指南,帮助您在 Dapr 上运行应用程序。

+ +
+
+
+ +### 其他信息 + +
+
+
+
参考资料
+

关于 Dapr API、CLI、绑定等的详细文档。

+ +
+
+
+
+
贡献
+

如何为 Dapr 项目和各种代码库做出贡献。

+ +
+
+
+
+
路线图
+

了解 Dapr 的发展路线和变更流程。

+ +
+
+
+ +### 工具和资源 + +
+
+
+
+ Visual studio code 图标 + IDE 集成 +
+

+ 了解如何在您喜欢的集成开发环境中启动并运行 Dapr。 +

+ +
+
+
+
+
+
+
+
+ 代码图标 + 语言 SDKs +
+

+ 使用 Dapr SDKs 在您喜欢的语言中创建 Dapr 应用程序。 +

+ +
+
+
+
+
+
+
+
+ .NET 标志 + .NET +
+

+ 了解更多关于 .NET SDK 的信息。 +

+ +
+
+
+
+
+ Python 标志 + Python +
+

+ 了解更多关于 Python SDK 的信息。 +

+ +
+
+
+
+
+ JS 标志 + JavaScript +
+

+ 了解更多关于 JavaScript SDK 的信息。 +

+ +
+
+
+
+
+
+
+
+ Java 标志 + Java +
+

+ 了解更多关于 Java SDK 的信息。 +

+ +
+
+
+
+
+ Go 标志 + Go +
+

+ 了解更多关于 Go SDK 的信息。 +

+ +
+
+
+
+
+ PHP 标志 + PHP +
+

+ 了解更多关于 PHP SDK 的信息。 +

+ +
+
+
\ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/concepts/_index.md b/src/translated_content/zh_CN/docs/concepts/_index.md new file mode 100644 index 000000000..05043c501 --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/_index.md @@ -0,0 +1,14 @@ +--- +type: docs +title: "Dapr 概念" +linkTitle: "概念" +weight: 10 +description: "了解 Dapr 的主要功能和能力" +--- + +欢迎阅读 Dapr 概念指南! + +{{% alert title="开始使用 Dapr" color="primary" %}} +如果您准备好开始使用 Dapr,欢迎访问[入门指南]({{}})。 +{{< button text="安装 Dapr" page="getting-started" >}} +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/concepts/building-blocks-concept.md b/src/translated_content/zh_CN/docs/concepts/building-blocks-concept.md new file mode 100644 index 000000000..9ac737a3e --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/building-blocks-concept.md @@ -0,0 +1,34 @@ +--- +type: docs +title: "构建模块" +linkTitle: "构建模块" +weight: 200 +description: "通过标准 HTTP 或 gRPC API 访问的模块化最佳实践" +--- + +[构建模块]({{< ref building-blocks >}}) 是一个 HTTP 或 gRPC API,可以从您的代码中调用,并使用一个或多个 Dapr 组件。Dapr 由一组 API 构建模块组成,并且可以扩展以添加新的构建模块。Dapr 的构建模块: +- 解决构建弹性微服务应用程序中的常见挑战 +- 编码最佳实践和模式 + +下图展示了构建模块如何通过公共 API 暴露,并从您的代码中调用,使用组件来实现其功能。 + + + +Dapr 提供以下构建模块: + + + +| 构建模块 | 端点 | 描述 | +|----------------|----------|-------------| +| [**服务间调用**]({{< ref "service-invocation-overview.md" >}}) | `/v1.0/invoke` | 服务调用使应用程序能够通过 HTTP 或 gRPC 消息形式的已知端点相互通信。Dapr 提供一个端点,结合内置服务发现的反向代理,同时利用分布式追踪和错误处理。 +| [**发布和订阅**]({{< ref "pubsub-overview.md" >}}) | `/v1.0/publish` `/v1.0/subscribe`| 发布/订阅是一种松耦合的消息传递模式,发送者(或发布者)将消息发布到主题,订阅者订阅该主题。Dapr 支持应用程序之间的发布/订阅模式。 +| [**工作流**]({{< ref "workflow-overview.md" >}}) | `/v1.0/workflow` | 工作流 API 允许您定义长时间运行的、持久的流程或数据流,这些流程或数据流跨越多个微服务,使用 Dapr 工作流或工作流组件。工作流 API 可以与其他 Dapr API 构建模块结合使用。例如,工作流可以通过服务调用调用另一个服务或检索 secret,提供灵活性和可移植性。 +| [**状态管理**]({{< ref "state-management-overview.md" >}}) | `/v1.0/state` | 应用程序状态是应用程序希望在单个会话之外保留的任何内容。Dapr 提供基于键/值的状态和查询 API,具有可插拔的状态存储以实现持久性。 +| [**绑定**]({{< ref "bindings-overview.md" >}}) | `/v1.0/bindings` | 绑定提供与外部云/本地服务或系统的双向连接。Dapr 允许您通过 Dapr 绑定 API 调用外部服务,并允许您的应用程序被连接服务发送的事件触发。 +| [**Actors**]({{< ref "actors-overview.md" >}}) | `/v1.0/actors` | actor 是一个隔离的、独立的计算和状态单元,具有单线程执行。Dapr 提供基于虚拟 actor 模式的 actor 实现,提供单线程编程模型,并且当不使用时,actor 会被垃圾回收。 +| [**Secrets**]({{< ref "secrets-overview.md" >}}) | `/v1.0/secrets` | Dapr 提供一个 secret 构建模块 API,并与 secret 存储集成,如公共云存储、本地存储和 Kubernetes 来存储 secret。服务可以调用 secret API 来检索 secret,例如获取数据库的连接字符串。 +| [**配置**]({{< ref "configuration-api-overview.md" >}}) | `/v1.0/configuration` | 配置 API 使您能够检索和订阅支持的配置存储的应用程序配置项。这使应用程序能够在启动时或在存储中进行配置更改时检索特定的配置信息。 +| [**分布式锁**]({{< ref "distributed-lock-api-overview.md" >}}) | `/v1.0-alpha1/lock` | 分布式锁 API 使您能够对资源进行锁定,以便应用程序的多个实例可以在不发生冲突的情况下访问资源,并提供一致性保证。 +| [**加密**]({{< ref "cryptography-overview.md" >}}) | `/v1.0-alpha1/crypto` | 加密 API 使您能够执行加密操作,例如加密和解密消息,而不将密钥暴露给您的应用程序。 +| [**作业**]({{< ref "jobs-overview.md" >}}) | `/v1.0-alpha1/jobs` | 作业 API 使您能够调度和编排作业。示例场景包括:
  • 安排批处理作业在每个工作日运行
  • 安排各种维护脚本进行清理
  • 安排 ETL 作业在特定时间(每小时、每天)运行以获取新数据,处理它,并使用最新信息更新数据仓库。
+| [**对话**]({{< ref "conversation-overview.md" >}}) | `/v1.0-alpha1/conversation` | 对话 API 使您能够提供提示与不同的大型语言模型(LLM)进行对话,并包括提示缓存和个人身份信息(PII)模糊化等功能。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/concepts/components-concept.md b/src/translated_content/zh_CN/docs/concepts/components-concept.md new file mode 100644 index 000000000..deb68ad9f --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/components-concept.md @@ -0,0 +1,146 @@ +--- +type: docs +title: "组件" +linkTitle: "组件" +weight: 300 +description: "由构建块和应用程序使用的模块化功能" +--- + +Dapr 采用模块化设计,功能以组件形式提供。每个组件都有一个接口定义。所有组件都是可互换的,因此您可以用具有相同接口的另一个组件替换掉一个组件。 + +您可以通过以下方式贡献实现并扩展 Dapr 的组件接口功能: + +- [components-contrib 仓库](https://github.com/dapr/components-contrib) +- [可插拔组件]({{< ref "components-concept.md#built-in-and-pluggable-components" >}})。 + +一个构建块可以使用任意组合的组件。例如,[actors]({{< ref "actors-overview.md" >}}) 和 [state management]({{< ref "state-management-overview.md" >}}) 构建块都使用 [state 组件](https://github.com/dapr/components-contrib/tree/master/state)。 + +另一个例子是,[pub/sub]({{< ref "pubsub-overview.md" >}}) 构建块使用 [pub/sub 组件](https://github.com/dapr/components-contrib/tree/master/pubsub)。 + +您可以使用 `dapr components` CLI 命令获取当前在托管环境中可用的组件列表。 + +{{% alert title="注意" color="primary" %}} +对于任何向应用程序返回数据的组件,建议相应地设置 Dapr sidecar 的内存容量(进程或容器)以避免潜在的内存不足崩溃。例如,在 Docker 中使用 `--memory` 选项。在 Kubernetes 中,使用 `dapr.io/sidecar-memory-limit` 注释。对于进程,这取决于操作系统和/或进程编排工具。 +{{% /alert %}} + +## 组件规范 + +每个组件都有一个规范(或称为 spec)。组件在设计时通过一个 YAML 文件进行配置,该文件存储在以下位置之一: + +- 您解决方案中的 `components/local` 文件夹,或 +- 在调用 `dapr init` 时创建的 `.dapr` 文件夹中全局存储。 + +这些 YAML 文件遵循通用的 [Dapr 组件架构]({{< ref "component-schema.md" >}}),但每个文件都特定于组件规范。 + +重要的是要理解组件规范值,特别是规范 `metadata`,在相同组件类型的不同组件之间可能会有所不同,例如在不同的 state 存储之间,并且某些设计时规范值可以在运行时通过向组件的 API 发出请求来覆盖。因此,强烈建议查看 [组件的规范]({{< ref "components-reference" >}}),特别注意用于设置与组件交互的元数据的请求示例负载。 + +下图显示了每种组件类型的一些组件示例 + + +## 内置和可插拔组件 + +Dapr 具有作为运行时一部分包含的内置组件。这些是由社区开发和捐赠的公共组件,并在每个版本中可用。 + +Dapr 还允许用户创建自己的私有组件,称为可插拔组件。这些组件是自托管的(进程或容器),不需要用 Go 编写,存在于 Dapr 运行时之外,并能够“插入”到 Dapr 中以利用构建块 API。 + +在可能的情况下,鼓励将内置组件捐赠给 Dapr 项目和社区。 + +然而,可插拔组件在您希望创建不包含在 Dapr 项目中的私有组件的场景中是理想的。 +例如: +- 您的组件可能特定于您的公司或存在知识产权问题,因此无法包含在 Dapr 组件仓库中。 +- 您希望将组件更新与 Dapr 发布周期解耦。 + +有关更多信息,请阅读 [可插拔组件概述]({{< ref "pluggable-components-overview" >}}) + +## 热重载 + +启用 [`HotReload` 功能]({{< ref "support-preview-features.md" >}})后,组件可以在运行时“热重载”。 +这意味着您可以在不重启 Dapr 运行时的情况下更新组件配置。 +当在 Kubernetes API 中创建、更新或删除组件资源时,或者在自托管模式下更改 `resources` 目录中的文件时,会发生组件重载。 +当组件更新时,组件首先关闭,然后使用新配置重新初始化。 +在重载和重新初始化期间,组件在短时间内不可用。 + +## 可用组件类型 + +以下是 Dapr 提供的组件类型: + +### 名称解析 + +名称解析组件与 [service-invocation]({{< ref "service-invocation-overview.md" >}}) 构建块一起使用,以与托管环境集成并提供服务到服务的发现。例如,Kubernetes 名称解析组件与 Kubernetes DNS 服务集成,自托管使用 mDNS,VM 集群可以使用 Consul 名称解析组件。 + +- [名称解析组件列表]({{< ref supported-name-resolution >}}) +- [名称解析实现](https://github.com/dapr/components-contrib/tree/master/nameresolution) + +### Pub/sub 代理 + +Pub/sub 代理组件是消息代理,可以作为 [发布和订阅]({{< ref pubsub-overview.md >}}) 构建块的一部分传递消息到/从服务。 + +- [Pub/sub 代理列表]({{< ref supported-pubsub >}}) +- [Pub/sub 代理实现](https://github.com/dapr/components-contrib/tree/master/pubsub) + +### 工作流 + +[工作流]({{< ref workflow-overview.md >}}) 是定义可靠业务流程或数据流的自定义应用程序逻辑。工作流组件是运行该工作流的业务逻辑并将其状态存储到 state 存储中的工作流运行时(或引擎)。 + + + +### 状态存储 + +状态存储组件是数据存储(数据库、文件、内存),作为 [state management]({{< ref "state-management-overview.md" >}}) 构建块的一部分存储键值对。 + +- [状态存储列表]({{< ref supported-state-stores >}}) +- [状态存储实现](https://github.com/dapr/components-contrib/tree/master/state) + +### 绑定 + +外部资源可以连接到 Dapr,以便触发应用程序上的方法或作为 [bindings]({{< ref bindings-overview.md >}}) 构建块的一部分从应用程序调用。 + +- [支持的绑定列表]({{< ref supported-bindings >}}) +- [绑定实现](https://github.com/dapr/components-contrib/tree/master/bindings) + +### 秘密存储 + +[秘密]({{< ref "secrets-overview.md" >}}) 是您希望防止未经授权访问的任何私密信息。秘密存储用于存储可以在应用程序中检索和使用的秘密。 + +- [支持的秘密存储列表]({{< ref supported-secret-stores >}}) +- [秘密存储实现](https://github.com/dapr/components-contrib/tree/master/secretstores) + +### 配置存储 + +配置存储用于保存应用程序数据,应用程序实例可以在启动时读取这些数据或在发生更改时收到通知。这允许动态配置。 + +- [支持的配置存储列表]({{< ref supported-configuration-stores >}}) +- [配置存储实现](https://github.com/dapr/components-contrib/tree/master/configuration) + +### 锁 + +锁组件用作分布式锁,以提供对资源(如队列或数据库)的互斥访问。 + +- [支持的锁列表]({{< ref supported-locks >}}) +- [锁实现](https://github.com/dapr/components-contrib/tree/master/lock) + +### 加密 + +[加密]({{< ref cryptography-overview.md >}}) 组件用于执行加密操作,包括加密和解密消息,而不将密钥暴露给您的应用程序。 + +- [支持的加密组件列表]({{< ref supported-cryptography >}}) +- [加密实现](https://github.com/dapr/components-contrib/tree/master/crypto) + +### 对话 + +Dapr 为开发人员提供了一种抽象与大型语言模型(LLMs)交互的方法,具有内置的安全性和可靠性功能。使用 [conversation]({{< ref conversation-overview.md >}}) 组件将提示发送到不同的 LLMs,以及对话上下文。 + +- [支持的对话组件列表]({{< ref supported-conversation >}}) +- [对话实现](https://github.com/dapr/components-contrib/tree/main/conversation) + +### 中间件 + +Dapr 允许自定义 [中间件]({{< ref "middleware.md" >}}) 插入到 HTTP 请求处理管道中。中间件可以在 HTTP 请求被路由到用户代码之前或响应返回给客户端之前对其执行额外的操作(如身份验证、加密和消息转换)。中间件组件与 [service-invocation]({{< ref "service-invocation-overview.md" >}}) 构建块一起使用。 + +- [支持的中间件组件列表]({{< ref supported-middleware >}}) +- [中间件实现](https://github.com/dapr/components-contrib/tree/master/middleware) + +{{% alert title="注意" color="primary" %}} +由于可插拔组件不需要用 Go 编写,因此它们遵循与内置 Dapr 组件不同的实现过程。有关开发内置组件的更多信息,请阅读 [开发新组件](https://github.com/dapr/components-contrib/blob/master/docs/developing-component.md)。 +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/concepts/configuration-concept.md b/src/translated_content/zh_CN/docs/concepts/configuration-concept.md new file mode 100644 index 000000000..f063a339e --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/configuration-concept.md @@ -0,0 +1,59 @@ +--- +type: docs +title: "应用和控制平面配置" +linkTitle: "配置" +weight: 400 +description: "调整 Dapr 应用程序的 sidecar 或 Dapr 控制平面系统服务的全局行为" +--- + +通过 Dapr 配置,您可以通过设置和策略来更改: +- 单个 Dapr 应用程序的行为 +- Dapr 控制平面系统服务的全局行为 + +例如,您可以在应用程序的 sidecar 配置中设置采样率策略,以指定哪些方法可以被其他应用程序调用。如果您在 Dapr 控制平面配置中设置策略,您可以调整部署到应用程序 sidecar 实例的所有证书的更新周期。 + +配置以 YAML 文件的形式定义并部署。以下是一个应用程序配置示例,其中设置了一个跟踪端点,用于发送指标信息,并捕获所有的跟踪样本。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: daprConfig + namespace: default +spec: + tracing: + samplingRate: "1" + zipkin: + endpointAddress: "http://localhost:9411/api/v2/spans" +``` + +上述 YAML 配置用于记录指标的跟踪。您可以通过以下方式在本地自托管模式中加载它: +- 编辑 `.dapr` 目录中的默认配置文件 `config.yaml`,或 +- 使用 `kubectl/helm` 将其应用到您的 Kubernetes 集群。 + +以下示例展示了在 `dapr-system` 命名空间中名为 `daprsystem` 的 Dapr 控制平面配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: daprsystem + namespace: dapr-system +spec: + mtls: + enabled: true + workloadCertTTL: "24h" + allowedClockSkew: "15m" +``` + +默认情况下,安装 Dapr 控制平面系统服务时会有一个名为 `daprsystem` 的单一配置文件。此配置文件应用全局控制平面设置,并在 Dapr 部署到 Kubernetes 时设置。 + +[了解更多关于配置选项的信息。]({{< ref "configuration-overview.md" >}}) + +{{% alert title="重要" color="warning" %}} +Dapr 应用程序和控制平面配置不应与 [配置构建块 API]({{< ref configuration-api-overview >}}) 混淆,后者使应用程序能够从配置存储组件中检索键/值数据。 +{{% /alert %}} + +## 下一步 + +{{< button text="了解更多关于配置的信息" page="configuration-overview" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/concepts/dapr-services/_index.md b/src/translated_content/zh_CN/docs/concepts/dapr-services/_index.md new file mode 100644 index 000000000..bb57f51c9 --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/dapr-services/_index.md @@ -0,0 +1,26 @@ +--- +type: docs +title: "Dapr 服务概述" +linkTitle: "Dapr 服务" +weight: 800 +description: "了解构成 Dapr 运行时的服务" +--- + +Dapr 是一个开源项目,旨在简化微服务应用程序的构建过程。它提供了一系列构建模块,这些模块通过标准化的 API 进行访问,使开发人员能够轻松实现常见的分布式系统模式。 + +Dapr 的核心服务包括: + +- **Actor**:Dapr 支持 actor 模型,方便开发人员实现有状态的 actor。 +- **Secret**:Dapr 提供与机密信息存储的集成,帮助开发人员安全管理应用程序的敏感信息。 +- **Configuration**:Dapr 提供配置管理功能,允许应用程序动态获取和更新配置。 +- **Service Invocation**:Dapr 支持服务调用,使服务之间可以通过 HTTP 或 gRPC 进行通信。 +- **Pub/Sub**:Dapr 支持发布/订阅模式,简化事件驱动的应用程序开发。 +- **Workflow**:Dapr 提供工作流支持,帮助开发人员编排复杂的业务流程。 +- **Cryptography**:Dapr 提供加密功能,帮助开发人员实现数据加密和解密。 +- **Bindings**:Dapr 提供与外部系统的绑定集成,简化与外部服务的交互。 +- **Timer 和 Reminder**:Dapr 提供定时器和提醒功能,帮助开发人员实现定时任务和提醒。 +- **Job**:Dapr 支持任务调度,帮助开发人员管理和执行后台任务。 +- **Conversation**:Dapr 提供对话支持,帮助开发人员实现对话式应用程序。 +- **State**:Dapr 提供状态管理功能,帮助开发人员管理应用程序的状态。 + +通过这些服务,Dapr 使开发人员能够专注于业务逻辑,而不必担心底层基础设施的细节。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/concepts/dapr-services/operator.md b/src/translated_content/zh_CN/docs/concepts/dapr-services/operator.md new file mode 100644 index 000000000..cfbbd53e6 --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/dapr-services/operator.md @@ -0,0 +1,47 @@ +--- +type: docs +title: "Dapr Operator 控制平面服务概述" +linkTitle: "Operator" +description: "Dapr Operator 服务概述" +--- + +在 [Kubernetes 模式]({{< ref kubernetes >}})下运行 Dapr 时,一个运行 Dapr Operator 服务的 pod 负责管理 [Dapr 组件]({{< ref components >}})的更新,并为 Dapr 提供 Kubernetes 服务端点。 + +## 运行 Operator 服务 + +Operator 服务是 `dapr init -k` 部署过程的一部分,或者可以通过 Dapr Helm charts 部署。有关在 Kubernetes 上运行 Dapr 的更多信息,请访问 [Kubernetes 托管页面]({{< ref kubernetes >}})。 + +## 其他配置选项 + +Operator 服务提供了一些额外的配置选项。 + +### 注入器监控功能 + +Operator 服务包含一个 _注入器监控功能_,它会定期检查 Kubernetes 集群中所有运行的 pod,确保那些标记了 `dapr.io/enabled=true` 的 pod 中正确注入了 Dapr sidecar。这个功能主要用于解决 [注入器服务]({{< ref sidecar-injector >}})未能成功将 sidecar(`daprd` 容器)注入 pod 的问题。 + +注入器监控功能在以下情况下可能会很有帮助: + +- 从完全停止的 Kubernetes 集群中恢复。当集群完全停止后再启动时(包括在集群完全故障的情况下),pod 会以随机顺序重启。如果您的应用程序在 Dapr 控制平面(特别是注入器服务)准备好之前重启,Dapr sidecar 可能不会注入到您的应用程序的 pod 中,导致应用程序行为异常。 + +- 解决 sidecar 注入器可能出现的随机故障,例如注入器服务中的瞬时故障。 + +如果监控功能发现某个 pod 缺少 sidecar,而它本应该有一个,它会删除该 pod。然后 Kubernetes 会重新创建该 pod,并再次调用 Dapr sidecar 注入器。 + +注入器监控功能**默认是禁用的**。 + +您可以通过向 `operator` 命令传递 `--watch-interval` 标志来启用它,该标志可以取以下值之一: + +- `--watch-interval=0`:禁用注入器监控功能(如果省略该标志,则为默认值)。 +- `--watch-interval=`:启用注入器监控功能,并在给定的间隔检查所有 pod;间隔的值是一个包含单位的字符串。例如:`--watch-interval=10s`(每 10 秒)或 `--watch-interval=2m`(每 2 分钟)。 +- `--watch-interval=once`:注入器监控功能仅在 Operator 服务启动时运行一次。 + +如果您使用 Helm,可以使用 [`dapr_operator.watchInterval` 选项](https://github.com/dapr/dapr/blob/master/charts/dapr/README.md#dapr-operator-options)配置注入器监控功能,该选项的值与命令行标志相同。 + +> 当 Operator 服务以 HA(高可用性)模式运行且有多个副本时,注入器监控功能是安全的。在这种情况下,Kubernetes 会自动选举一个“领导”实例,该实例是唯一运行注入器监控服务的实例。 + +> 然而,在 HA 模式下,如果您将注入器监控功能配置为“once”运行,则每次 Operator 服务的一个实例被选为领导时,监控功能都会启动。这意味着,如果 Operator 服务的领导崩溃并选出新的领导,这将再次触发注入器监控功能。 + +观看此视频以了解注入器监控功能的概述: + +
+ \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/concepts/dapr-services/placement.md b/src/translated_content/zh_CN/docs/concepts/dapr-services/placement.md new file mode 100644 index 000000000..52669ddcb --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/dapr-services/placement.md @@ -0,0 +1,98 @@ +--- +type: docs +title: "Dapr Placement 控制平面服务概述" +linkTitle: "Placement" +description: "Dapr Placement 服务概述" +--- + +Dapr Placement 服务用于计算和分发用于定位的分布式哈希表,以便在[自托管模式]({{< ref self-hosted >}})或[Kubernetes]({{< ref kubernetes >}})上运行的[Dapr actor]({{< ref actors >}})能够被正确定位。哈希表按命名空间分组,将actor类型映射到相应的pod或进程,以便Dapr应用程序可以与actor进行通信。每当Dapr应用程序激活一个Dapr actor时,Placement服务会更新哈希表以反映最新的actor位置。 + +## 自托管模式 + +在自托管模式下,Placement服务的Docker容器会在执行[`dapr init`]({{< ref self-hosted-with-docker.md >}})时自动启动。如果您使用[slim-init模式]({{< ref self-hosted-no-docker.md >}}),也可以手动将其作为进程运行。 + +## Kubernetes模式 + +在Kubernetes模式下,Placement服务可以通过执行`dapr init -k`或使用Dapr Helm图表进行部署。您可以选择在高可用性(HA)模式下运行Placement服务。[了解更多关于在Kubernetes中设置HA模式的信息。]({{< ref "kubernetes-production.md#individual-service-ha-helm-configuration" >}}) + +有关在Kubernetes上运行Dapr的更多信息,请访问[Kubernetes托管页面]({{< ref kubernetes >}})。 + +## Placement表 + +Placement服务提供了一个HTTP API `/placement/state`,用于公开placement表的信息。该API与sidecar的healthz端口相同。这个端点默认是禁用的且不需要身份验证。要启用它,您需要将`DAPR_PLACEMENT_METADATA_ENABLED`环境变量或`metadata-enabled`命令行参数设置为true。如果您使用helm,只需将`dapr_placement.metadataEnabled`设置为true。 + +{{% alert title="重要" color="warning" %}} +当actor被部署到不同的命名空间时,如果您希望防止从所有命名空间检索actor信息,建议禁用`metadata-enabled`。元数据端点的范围覆盖所有命名空间。 +{{% /alert %}} + +### 用例: +placement表API可用于检索当前的placement表,其中包含所有命名空间中注册的actor信息。这对于调试和工具提取、呈现actor信息非常有帮助。 + +### HTTP请求 + +``` +GET http://localhost:/placement/state +``` + +### HTTP响应代码 + +代码 | 描述 +---- | ----------- +200 | 返回placement表信息 +500 | Placement无法返回placement表信息 + +### HTTP响应体 + +**Placement表API响应对象** + +名称 | 类型 | 描述 +---- | ---- | ----------- +tableVersion | int | placement表版本 +hostList | [Actor Host Info](#actorhostinfo)[] | 注册的actor主机信息的json数组。 + +**Actor主机信息** + +名称 | 类型 | 描述 +---- | ---- | ----------- +name | string | actor的主机:端口地址。 +appId | string | 应用程序ID。 +actorTypes | json string array | 它托管的actor类型列表。 +updatedAt | timestamp | actor注册/更新的时间戳。 + +### 示例 + +```shell + curl localhost:8080/placement/state +``` + +```json +{ + "hostList": [{ + "name": "198.18.0.1:49347", + "namespace": "ns1", + "appId": "actor1", + "actorTypes": ["testActorType1", "testActorType3"], + "updatedAt": 1690274322325260000 + }, + { + "name": "198.18.0.2:49347", + "namespace": "ns2", + "appId": "actor2", + "actorTypes": ["testActorType2"], + "updatedAt": 1690274322325260000 + }, + { + "name": "198.18.0.3:49347", + "namespace": "ns2", + "appId": "actor2", + "actorTypes": ["testActorType2"], + "updatedAt": 1690274322325260000 + } + ], + "tableVersion": 1 +} +``` + +## 相关链接 + +[了解更多关于Placement API的信息。]({{< ref placement_api.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/concepts/dapr-services/scheduler.md b/src/translated_content/zh_CN/docs/concepts/dapr-services/scheduler.md new file mode 100644 index 000000000..834e07f3e --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/dapr-services/scheduler.md @@ -0,0 +1,32 @@ +--- +type: docs +title: "Dapr Scheduler 控制平面服务概述" +linkTitle: "Scheduler" +description: "Dapr Scheduler 服务概述" +--- + +Dapr Scheduler 服务用于作业调度,可以在[自托管模式]({{< ref self-hosted >}})或[Kubernetes]({{< ref kubernetes >}})上运行。 + +下图展示了如何通过作业 API 从您的应用程序调用 Scheduler 服务。Scheduler 服务跟踪的所有作业都存储在嵌入式 Etcd 数据库中。 + +展示 Scheduler 控制平面服务和作业 API 的图示 + +## actor 提醒 + +在 Dapr v1.15 之前,[actor 提醒]({{< ref "actors-timers-reminders.md#actor-reminders" >}})是通过 Placement 服务运行的。现在,默认情况下,[`SchedulerReminders` 功能标志]({{< ref "support-preview-features.md#current-preview-features" >}})被设置为 `true`,您创建的所有新 actor 提醒都通过 Scheduler 服务运行,以提高其可扩展性。 + +当您部署 Dapr v1.15 时,所有现有的 actor 提醒会从 Placement 服务迁移到 Scheduler 服务。这是针对每种 actor 类型的一次性迁移操作。您可以通过在 actor 类型的应用程序配置文件中将 `SchedulerReminders` 标志设置为 `false` 来阻止此迁移。 + +## 自托管模式 + +Scheduler 服务的 Docker 容器作为 `dapr init` 的一部分自动启动。如果您在[精简初始化模式]({{< ref self-hosted-no-docker.md >}})下运行,也可以手动作为进程运行。 + +## Kubernetes 模式 + +Scheduler 服务作为 `dapr init -k` 的一部分或通过 Dapr Helm 图表部署。您可以在高可用性模式下运行 Scheduler。[了解更多关于在 Kubernetes 服务中设置高可用性模式的信息。]({{< ref "kubernetes-production.md#individual-service-ha-helm-configuration" >}}) + +有关在 Kubernetes 上运行 Dapr 的更多信息,请访问[Kubernetes 托管页面]({{< ref kubernetes >}})。 + +## 相关链接 + +[了解更多关于作业 API 的信息。]({{< ref jobs_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/concepts/dapr-services/sentry.md b/src/translated_content/zh_CN/docs/concepts/dapr-services/sentry.md new file mode 100644 index 000000000..de80265b8 --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/dapr-services/sentry.md @@ -0,0 +1,28 @@ +--- +type: docs +title: "Dapr Sentry 控制平面服务概述" +linkTitle: "Sentry" +description: "Dapr Sentry 服务概述" +--- + +Dapr Sentry 服务负责管理服务之间的 mTLS,并作为证书颁发机构。它生成 mTLS 证书并将其分发给所有正在运行的 sidecar。这样,sidecar 可以通过加密的 mTLS 流量进行通信。有关更多信息,请阅读 [sidecar-to-sidecar 通信概述]({{< ref "security-concept.md#sidecar-to-sidecar-communication" >}})。 + +## 自托管模式 + +Sentry 服务的 Docker 容器不会作为 [`dapr init`]({{< ref self-hosted-with-docker.md >}}) 的一部分自动启动。不过,您可以按照 [mutual TLS]({{< ref "mtls.md#self-hosted" >}}) 的设置说明手动启动。 + +如果您在 [slim-init 模式]({{< ref self-hosted-no-docker.md >}}) 下运行,也可以手动以进程的方式启动。 + + + +## Kubernetes 模式 + +Sentry 服务可以通过 `dapr init -k` 或使用 Dapr Helm Chart 部署。有关在 Kubernetes 上运行 Dapr 的更多信息,请访问 [Kubernetes 托管页面]({{< ref kubernetes >}})。 + + + +## 进一步阅读 + +- [安全概述]({{< ref security-concept.md >}}) +- [自托管模式]({{< ref self-hosted-with-docker.md >}}) +- [Kubernetes 模式]({{< ref kubernetes >}}) diff --git a/src/translated_content/zh_CN/docs/concepts/dapr-services/sidecar-injector.md b/src/translated_content/zh_CN/docs/concepts/dapr-services/sidecar-injector.md new file mode 100644 index 000000000..fe312a405 --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/dapr-services/sidecar-injector.md @@ -0,0 +1,12 @@ +--- +type: docs +title: "Dapr Sidecar Injector 控制平面服务概述" +linkTitle: "Sidecar 注入器" +description: "Dapr Sidecar 注入器过程概述" +--- + +在 [Kubernetes 模式]({{< ref kubernetes >}}) 下运行 Dapr 时,会创建一个运行 Dapr Sidecar Injector 服务的 pod。该服务会识别那些使用 [Dapr 注解]({{< ref arguments-annotations-overview.md >}}) 初始化的 pod,并为这些 pod 中的 [daprd 服务]({{< ref sidecar >}}) 创建额外的容器。 + +## 运行 Sidecar 注入器 + +Sidecar 注入器服务可以通过执行 `dapr init -k` 部署,或者通过 Dapr 的 Helm chart 进行部署。有关在 Kubernetes 上运行 Dapr 的更多信息,请访问 [Kubernetes 托管页面]({{< ref kubernetes >}})。 diff --git a/src/translated_content/zh_CN/docs/concepts/dapr-services/sidecar.md b/src/translated_content/zh_CN/docs/concepts/dapr-services/sidecar.md new file mode 100644 index 000000000..d434560ca --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/dapr-services/sidecar.md @@ -0,0 +1,80 @@ +--- +type: docs +title: "Dapr sidecar (daprd) 概述" +linkTitle: "Sidecar" +weight: 100 +description: "Dapr sidecar 进程概述" +--- + +Dapr 采用 [sidecar 模式]({{< ref "concepts/overview.md#sidecar-architecture" >}}),这意味着 Dapr API 运行在一个独立的进程中,即 Dapr sidecar,并与您的应用程序一起运行。Dapr sidecar 进程命名为 `daprd`,并根据托管环境以不同的方式启动。 + +Dapr sidecar 提供以下功能: + +- 应用程序业务逻辑使用的 [构建块 API]({{}}) +- 用于发现功能和设置属性的 [元数据 API]({{}}) +- 用于检查健康状态和 sidecar 准备及存活状态的 [健康 API]({{}}) + +当应用程序在其配置的端口上可访问时,Dapr sidecar 即达到准备状态。在应用程序启动或初始化期间,应用程序暂时无法访问 Dapr 组件。 + + + +应用程序通过本地 http 或 gRPC 端点调用 sidecar API。 + + +## 使用 `dapr run` 的自托管 + +在 [自托管模式]({{}}) 下安装 Dapr 时,`daprd` 二进制文件会被下载并放置在用户主目录下(Linux/macOS 为 `$HOME/.dapr/bin`,Windows 为 `%USERPROFILE%\.dapr\bin\`)。 + +在自托管模式下,使用 Dapr CLI 的 [`run` 命令]({{< ref dapr-run.md >}}) 会启动 `daprd` 可执行文件,并运行您提供的应用程序可执行文件。这是在本地进行开发和测试等场景中运行 Dapr sidecar 的推荐方式。 + +您可以在 [Dapr run 命令参考]({{}}) 中找到 CLI 提供的用于配置 sidecar 的各种参数。 + +## 在 Kubernetes 中使用 `dapr-sidecar-injector` + +在 [Kubernetes]({{< ref kubernetes.md >}}) 上,Dapr 控制平面包括 [dapr-sidecar-injector 服务]({{< ref kubernetes-overview.md >}}),它监视带有 `dapr.io/enabled` 注释的新 pod,并在 pod 内注入一个包含 `daprd` 进程的容器。在这种情况下,可以通过注释传递 sidecar 参数,如 [此表]({{}}) 中的 **Kubernetes 注释** 列所述。 + +## 直接运行 sidecar + +在大多数情况下,您不需要显式运行 `daprd`,因为 sidecar 要么由 [CLI]({{}})(自托管模式)启动,要么由 dapr-sidecar-injector 服务(Kubernetes)启动。对于高级用例(如调试、脚本化部署等),可以直接启动 `daprd` 进程。 + +要获取所有可用参数的详细列表,请运行 `daprd --help` 或查看 [此表]({{< ref arguments-annotations-overview.md >}}),该表概述了 `daprd` 参数与 CLI 参数和 Kubernetes 注释的关系。 + +### 示例 + +1. 通过指定其唯一 ID 启动与应用程序一起的 sidecar。 + + **注意:** `--app-id` 是必填字段,且不能包含点。 + + ```bash + daprd --app-id myapp + ``` + +1. 指定您的应用程序正在监听的端口 + + ```bash + daprd --app-id myapp --app-port 5000 + ``` + +1. 如果您使用了多个自定义资源并希望指定资源定义文件的位置,请使用 `--resources-path` 参数: + + ```bash + daprd --app-id myapp --resources-path + ``` + +1. 如果您已将组件和其他资源(例如,弹性策略、订阅或配置)组织到单独的文件夹或共享文件夹中,您可以指定多个资源路径: + + ```bash + daprd --app-id myapp --resources-path --resources-path + ``` + +1. 在运行应用程序时启用 Prometheus 指标收集 + + ```bash + daprd --app-id myapp --enable-metrics + ``` + +1. 仅监听 IPv4 和 IPv6 回环 + + ```bash + daprd --app-id myapp --dapr-listen-addresses '127.0.0.1,[::1]' + ``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/concepts/faq/_index.md b/src/translated_content/zh_CN/docs/concepts/faq/_index.md new file mode 100644 index 000000000..fda440dd2 --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/faq/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "常见问题与解答" +linkTitle: "常见问题" +weight: 1100 +description: "通过常见问题了解更多关于Dapr的概念" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/concepts/faq/faq.md b/src/translated_content/zh_CN/docs/concepts/faq/faq.md new file mode 100644 index 000000000..58992b27e --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/faq/faq.md @@ -0,0 +1,41 @@ +--- +type: docs +title: "Dapr 常见问题解答" +linkTitle: "常见问题" +weight: 100 +description: "关于 Dapr 的常见问题" +--- + +## Dapr 与 Istio、Linkerd 或 OSM 等服务网格有何不同? +Dapr 并非服务网格。服务网格主要关注细粒度的网络控制,而 Dapr 则致力于帮助开发人员构建分布式应用程序。Dapr 和服务网格都采用 sidecar 模式,与应用程序共同运行。虽然它们有一些功能重叠,但各自也提供了独特的优势。有关更多信息,请阅读 [Dapr & 服务网格]({{}}) 概念页面。 + +## 性能基准 +由于 Dapr 作为应用程序的 sidecar,Dapr 项目对性能非常重视。请参阅 [此处]({{< ref perf-service-invocation.md >}}) 以获取最新的性能数据。 + +## actors + +### Dapr、Orleans 和 Service Fabric Reliable Actors 之间有什么关系? + +Dapr 中的 actors 源于 [Orleans](https://www.microsoft.com/research/project/orleans-virtual-actors/) 的虚拟 actor 概念,这意味着它们在被调用时会激活,并在一段时间后自动停用。如果您熟悉 Orleans,Dapr 的 C# actors 会让您感到熟悉。Dapr 的 C# actors 基于 [Service Fabric Reliable Actors](https://docs.microsoft.com/azure/service-fabric/service-fabric-reliable-actors-introduction)(同样源于 Orleans),这使得您可以将 Service Fabric 中的 Reliable Actors 迁移到其他托管平台,如 Kubernetes 或其他本地环境。此外,Dapr 不仅仅局限于 actors。它为您提供了一套最佳实践的构建模块,可以集成到任何微服务应用程序中。请参阅 [Dapr 概述]({{< ref overview.md >}})。 + +### Dapr 与其他 actor 框架有何区别? + +虚拟 actor 功能是 Dapr 运行时提供的众多构建模块之一。由于 Dapr 是编程语言无关的,并提供 http/gRPC API,因此可以从任何语言调用 actors。这允许用一种语言编写的 actors 调用用不同语言编写的 actors。 + +创建新的 actor 类似于本地调用,例如 `http://localhost:3500/v1.0/actors///…`。例如,`http://localhost:3500/v1.0/actors/myactor/50/method/getData` 调用新创建的 `myactor` 的 `getData` 方法,id 为 `50`。 + +Dapr 运行时 SDK 提供了特定语言的 actor 框架。例如,.NET SDK 提供了 C# actors。目标是让所有 Dapr 语言 SDK 都具备 actor 框架。目前 .NET、Java、Go 和 Python SDK 已具备 actor 框架。 + +### 如果我想使用特定的编程语言或框架,Dapr 是否有任何 SDK 可以使用? + +为了使 Dapr 在不同语言中使用更自然,它包括 Go、Java、JavaScript、.NET、Python、PHP、Rust 和 C++ 的[特定语言 SDK]({{}})。这些 SDK 通过类型化语言 API 而不是直接调用 http/gRPC API 来提供 Dapr 构建模块的功能,例如保存状态、发布事件或创建 actor。这使您能够用您选择的语言编写无状态和有状态函数及 actors 的组合。并且由于这些 SDK 共享 Dapr 运行时,您可以获得跨语言的 actor 和函数支持。 + +### Dapr 可以与哪些框架集成? +Dapr 可以与任何开发者框架集成。例如,在 Dapr .NET SDK 中,您可以找到 ASP.NET Core 集成,它提供了响应其他服务的发布/订阅事件的有状态路由控制器。 + +Dapr 集成了以下框架: + +- 使用 Dapr 的函数 [Azure Functions 扩展](https://github.com/dapr/azure-functions-extension) +- Java SDK 中的 Spring Boot Web 应用 +- .NET SDK 中的 ASP.NET Core +- [Azure API 管理](https://cloudblogs.microsoft.com/opensource/2020/09/22/announcing-dapr-integration-azure-api-management-service-apim/) diff --git a/src/translated_content/zh_CN/docs/concepts/faq/service-mesh.md b/src/translated_content/zh_CN/docs/concepts/faq/service-mesh.md new file mode 100644 index 000000000..4661e4122 --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/faq/service-mesh.md @@ -0,0 +1,45 @@ +--- +type: docs +title: "Dapr与服务网格" +linkTitle: "服务网格" +weight: 200 +description: > + Dapr与服务网格的比较及协作 +--- + +Dapr 采用 sidecar 架构,作为独立进程与应用程序并行运行,提供服务调用、网络安全和[分布式追踪](https://middleware.io/blog/what-is-distributed-tracing/)等功能。这常常引发一个问题:Dapr 与 Linkerd、Istio 和 Open Service Mesh 等服务网格解决方案相比如何? + +## Dapr与服务网格的比较 +虽然 Dapr 和服务网格确实有一些功能重叠,但**Dapr 不是一个服务网格**。服务网格主要关注网络层面的问题,而 Dapr 则专注于为开发者提供构建微服务的工具。Dapr 是以开发者为中心的,而服务网格则是以基础设施为中心的。 + +通常情况下,开发者无需关心应用程序是否部署在包含服务网格的环境中,因为服务网格会自动处理网络流量。服务网格主要由系统运维人员管理和部署,而 Dapr 的构建块 API 则是供开发者在代码中直接使用的。 + +Dapr 与服务网格共享的一些常见功能包括: +- 使用 mTLS 加密进行安全的服务间通信 +- 服务间的指标收集 +- 服务间的分布式追踪 +- 通过重试实现的弹性 + +值得注意的是,Dapr 提供基于名称的服务发现和调用,这对开发者来说非常友好。通过 Dapr 的 service-invocation API,开发者可以直接调用服务名称,而服务网格则处理 IP 地址和 DNS 地址等网络细节。然而,Dapr 不提供流量路由或流量拆分等功能,这些通常由应用程序的入口代理来解决。此外,Dapr 还提供其他应用程序级别的构建块,如状态管理、发布订阅消息传递、actor 模型等。 + +Dapr 与服务网格在可观测性(追踪和指标)方面也有所不同。服务网格在网络层面操作,追踪服务之间的网络调用,而 Dapr 则通过 service-invocation 实现这一点。此外,Dapr 通过将追踪 ID 写入 Cloud Events 信封,提供对发布订阅调用的可观测性。这意味着对于同时使用服务间调用和发布订阅进行通信的应用程序,Dapr 的指标和追踪范围更广。 + +下图展示了 Dapr 和服务网格提供的重叠功能和独特能力: + + + +## 将Dapr与服务网格一起使用 +Dapr 可以与服务网格协同工作。在两者同时部署的情况下,Dapr 和服务网格的 sidecar 都在应用程序环境中运行。在这种情况下,建议仅配置 Dapr 或服务网格来执行 mTLS 加密和分布式追踪。 + +观看这些来自 Dapr 社区电话会议的录音,展示了 Dapr 与不同服务网格一起运行的演示: +- [Dapr 和 Linkerd](https://youtu.be/xxU68ewRmz8?t=142)的概述和演示 +- 运行 [Dapr 和 Istio](https://youtu.be/ngIDOQApx8?t=335)的演示 + +## 何时使用Dapr或服务网格或两者 +您应该使用 Dapr、服务网格还是两者?这取决于您的具体需求。例如,如果您希望使用 Dapr 的一个或多个构建块,如状态管理或发布订阅,并且仅考虑使用服务网格来增强网络安全或可观测性,您可能会发现仅使用 Dapr 就足够了。 + +通常,您会在有公司政策要求所有应用程序的网络流量必须加密的情况下,将服务网格与 Dapr 一起使用。例如,您可能仅在应用程序的一部分中使用 Dapr,而其他未使用 Dapr 的服务和进程也需要加密流量。在这种情况下,服务网格是更好的选择,您可能需要在服务网格上启用 mTLS 和分布式追踪,并在 Dapr 上禁用这些功能。 + +如果您需要流量拆分以进行 A/B 测试,使用服务网格会更有利,因为 Dapr 不提供这些功能。 + +在某些情况下,当您需要两者的独特功能时,您会发现同时利用 Dapr 和服务网格是有益的;如上所述,使用它们在一起没有限制。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/concepts/isolation-concept.md b/src/translated_content/zh_CN/docs/concepts/isolation-concept.md new file mode 100644 index 000000000..89c36daf7 --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/isolation-concept.md @@ -0,0 +1,45 @@ +--- +type: docs +title: "隔离" +linkTitle: "隔离" +weight: 700 +description: Dapr 如何提供命名空间和隔离 +--- + +Dapr 的命名空间功能提供了隔离和多租户支持,增强了安全性。通常,应用程序和组件会被部署到命名空间中,以便在特定环境中实现隔离,例如在 Kubernetes 中。 + +Dapr 支持在以下场景中使用命名空间:应用程序之间的服务调用、访问组件、在消费者组中发送 pubsub 消息以及 actor 类型的部署。无论是在自托管模式还是 Kubernetes 模式下,命名空间隔离都受到支持。 + +要开始使用,请先创建并配置您的命名空间。 + +{{< tabs "自托管" "Kubernetes">}} + +{{% codetab %}} + +在自托管模式下,通过设置 `NAMESPACE` 环境变量为 Dapr 实例指定命名空间。 + +{{% /codetab %}} + +{{% codetab %}} + +在 Kubernetes 上,创建并配置命名空间: + +```bash +kubectl create namespace namespaceA +kubectl config set-context --current --namespace=namespaceA +``` + +然后将您的应用程序部署到此命名空间中。 + +{{% /codetab %}} + +{{< /tabs >}} + +了解如何在 Dapr 中全面使用命名空间: + +- [服务调用命名空间]({{< ref service-invocation-namespaces.md >}}) +- [如何设置 pubsub 命名空间消费者组]({{< ref howto-namespace.md >}}) +- 组件: + - [如何配置具有多个命名空间的 pubsub 组件]({{< ref pubsub-namespaces.md >}}) + - [将组件限定到一个或多个应用程序]({{< ref component-scopes.md >}}) +- [命名空间的 actor]({{< ref namespaced-actors.md >}}) diff --git a/src/translated_content/zh_CN/docs/concepts/observability-concept.md b/src/translated_content/zh_CN/docs/concepts/observability-concept.md new file mode 100644 index 000000000..8943ff605 --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/observability-concept.md @@ -0,0 +1,74 @@ +--- +type: docs +title: "可观测性" +linkTitle: "可观测性" +weight: 500 +description: > + 通过追踪、指标、日志和健康检查来观察应用程序 +--- + +在构建应用程序时,理解系统行为是操作应用程序的重要且具有挑战性的部分,例如: +- 观察应用程序的内部调用 +- 评估其性能 +- 在问题发生时立即意识到 + +对于由多个微服务组成的分布式系统来说,这尤其具有挑战性,因为一个由多个调用组成的流程可能在一个微服务中开始并在另一个微服务中继续。 + +在生产环境中,应用程序的可观测性至关重要,并且在开发过程中也很有用,以便: +- 理解瓶颈 +- 提高性能 +- 在微服务范围内进行基本调试 + +虽然可以从底层基础设施(如内存消耗、CPU使用率)中收集一些关于应用程序的数据点,但其他有意义的信息必须从“应用程序感知层”收集——这个层可以显示重要调用系列如何在微服务之间执行。通常,您需要添加一些代码来对应用程序进行检测,这些代码将收集的数据(如追踪和指标)发送到可观测性工具或服务,这些工具或服务可以帮助存储、可视化和分析所有这些信息。 + +维护这些检测代码(它们不是应用程序核心逻辑的一部分)需要理解可观测性工具的API,使用额外的SDK等。这种检测也可能为您的应用程序带来可移植性挑战,要求根据应用程序的部署位置进行不同的检测。例如: +- 不同的云提供商提供不同的可观测性工具 +- 本地部署可能需要自托管解决方案 + +## 使用Dapr实现应用程序的可观测性 + +当您利用Dapr API构建块进行服务间调用、发布/订阅消息传递和其他API时,Dapr在[分布式追踪]({{< ref tracing >}})方面提供了优势。由于这种服务间通信通过Dapr运行时(或“sidecar”)流动,Dapr处于一个独特的位置,可以减轻应用程序级别检测的负担。 + +### 分布式追踪 + +Dapr可以使用广泛采用的[Open Telemetry (OTEL)](https://opentelemetry.io/)和[Zipkin](https://zipkin.io)协议[配置以发出追踪数据]({{< ref setup-tracing.md >}})。这使得它可以轻松集成到多个可观测性工具中。 + +使用Dapr的分布式追踪 + +### 自动追踪上下文生成 + +Dapr使用[W3C追踪]({{< ref tracing >}})规范作为追踪上下文的一部分,包含在Open Telemetry (OTEL)中,用于生成和传播应用程序的上下文头或传播用户提供的上下文头。这意味着您可以默认获得Dapr的追踪功能。 + +## Dapr sidecar和控制平面的可观测性 + +您还可以通过以下方式观察Dapr本身: +- 生成由Dapr sidecar和Dapr控制平面服务发出的日志 +- 收集性能、吞吐量和延迟的指标 +- 使用健康端点探测来指示Dapr sidecar的健康状态 + +Dapr sidecar的指标、日志和健康检查 + +### 日志记录 + +Dapr生成[日志]({{< ref logs.md >}})以: +- 提供对sidecar操作的可见性 +- 帮助用户识别问题并进行调试 + +日志事件包含由Dapr系统服务生成的警告、错误、信息和调试消息。您还可以配置Dapr将日志发送到收集器,如[Open Telemetry Collector]({{< ref otel-collector >}})、[Fluentd]({{< ref fluentd.md >}})、[New Relic]({{< ref "operations/observability/logging/newrelic.md" >}})、[Azure Monitor]({{< ref azure-monitor.md >}})和其他可观测性工具,以便可以搜索和分析日志以提供见解。 + +### 指标 + +指标是一系列测量值和计数,随着时间的推移被收集和存储。[Dapr指标]({{< ref metrics >}})提供监控能力,以理解Dapr sidecar和控制平面的行为。例如,Dapr sidecar和用户应用程序之间的指标显示调用延迟、流量失败、请求错误率等。 + +Dapr [控制平面指标](https://github.com/dapr/dapr/blob/master/docs/development/dapr-metrics.md)显示sidecar注入失败和控制平面服务的健康状况,包括CPU使用率、actor放置的数量等。 + +### 健康检查 + +Dapr sidecar公开了一个HTTP端点用于[健康检查]({{< ref sidecar-health.md >}})。通过这个API,用户代码或托管环境可以探测Dapr sidecar以确定其状态并识别sidecar准备就绪的问题。 + +相反,Dapr可以配置为探测[您的应用程序的健康状况]({{< ref app-health.md >}}),并对应用程序健康状况的变化做出反应,包括停止pub/sub订阅和短路服务调用。 + +## 下一步 + +- [了解更多关于使用Dapr进行开发的可观测性]({{< ref tracing >}}) +- [了解更多关于使用Dapr进行操作的可观测性]({{< ref tracing >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/concepts/overview.md b/src/translated_content/zh_CN/docs/concepts/overview.md new file mode 100644 index 000000000..c57d3c409 --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/overview.md @@ -0,0 +1,159 @@ +--- +type: docs +title: "概述" +linkTitle: "概述" +weight: 100 +description: > + 分布式应用运行时简介 +--- + +Dapr 是一个便于移植的事件驱动运行时,帮助开发者轻松构建在云和边缘环境中运行的弹性应用,无论是无状态还是有状态的,并支持多种编程语言和开发框架。 + +
+ +
+ +## 支持任何语言、框架和环境 + + + +随着云技术的普及,传统的 Web + 数据库应用架构(如经典的三层设计)正逐渐向微服务架构转变,这些架构本质上是分布式的。开发微服务应用不应要求您成为分布式系统的专家。 + +这正是 Dapr 的优势所在。Dapr 将构建微服务应用的*最佳实践*转化为开放且独立的 API,称为[构建块]({{< ref "#microservice-building-blocks-for-cloud-and-edge" >}})。Dapr 的构建块: +- 允许您使用任意语言和框架构建可移植的应用。 +- 完全独立 +- 在应用中使用的数量没有限制 + +通过 Dapr,您可以逐步将现有应用迁移到微服务架构,采用云原生模式,如扩展/缩减、弹性和独立部署。 + +Dapr 是平台无关的,这意味着您可以在以下环境中运行您的应用: +- 本地 +- 任何 Kubernetes 集群 +- 虚拟或物理机器 +- Dapr 集成的其他托管环境 + +这使您能够构建可以在云和边缘运行的微服务应用。 + +## 云和边缘的微服务构建块 + + + +Dapr 提供分布式系统构建块,使您能够以标准方式构建微服务应用并部署到任何环境。 + +每个构建块 API 都是独立的,这意味着您可以在应用中使用任意数量的它们。 + +| 构建块 | 描述 | +|----------------|-------------| +| [**服务间调用**]({{< ref "service-invocation-overview.md" >}}) | 提供弹性的服务间调用功能,无论远程服务位于何处,都可以进行方法调用,包括重试。 +| [**发布和订阅**]({{< ref "pubsub-overview.md" >}}) | 在服务之间发布事件和订阅主题,简化事件驱动架构的水平扩展并增强其故障弹性。Dapr 提供至少一次消息传递保证、消息 TTL、消费者组和其他高级功能。 +| [**工作流**]({{< ref "workflow-overview.md" >}}) | 工作流 API 可以与其他 Dapr 构建块结合使用,定义跨多个微服务的长时间运行、持久化的流程或数据流,使用 Dapr 工作流或工作流组件。 +| [**状态管理**]({{< ref "state-management-overview.md" >}}) | 通过状态管理存储和查询键/值对,您可以轻松地在应用中编写长时间运行、高可用的有状态服务和无状态服务。状态存储是可插拔的,示例包括 AWS DynamoDB、Azure Cosmos DB、Azure SQL Server、GCP Firebase、PostgreSQL 或 Redis 等。 +| [**资源绑定**]({{< ref "bindings-overview.md" >}}) | 资源绑定与触发器在事件驱动架构上进一步构建,以通过接收和发送事件到任何外部源(如数据库、队列、文件系统等)来实现扩展和弹性。 +| [**Actors**]({{< ref "actors-overview.md" >}}) | 一种用于有状态和无状态对象的模式,使并发变得简单,具有方法和状态封装。Dapr 在其 actor 运行时中提供许多功能,包括并发、状态和生命周期管理,用于 actor 激活/停用,以及定时器和提醒以唤醒 actor。 +| [**Secrets**]({{< ref "secrets-overview.md" >}}) | 秘密管理 API 与公共云和本地秘密存储集成,以检索用于应用代码的秘密。 +| [**Configuration**]({{< ref "configuration-api-overview.md" >}}) | 配置 API 使您能够从配置存储中检索和订阅应用配置项。 +| [**分布式锁**]({{< ref "distributed-lock-api-overview.md" >}}) | 分布式锁 API 使您的应用能够获取任何资源的锁,从而在锁被应用释放或租约超时发生之前,给予其独占访问权限。 +| [**Cryptography**]({{< ref "cryptography-overview.md" >}}) | 加密 API 提供了一个在安全基础设施(如密钥库)之上的抽象层。它包含允许您执行加密操作的 API,如加密和解密消息,而不将密钥暴露给您的应用。 +| [**Jobs**]({{< ref "jobs-overview.md" >}}) | 作业 API 使您能够在特定时间或间隔安排作业。 +| [**Conversation**]({{< ref "conversation-overview.md" >}}) | 对话 API 使您能够抽象与大型语言模型(LLM)交互的复杂性,并包括提示缓存和个人身份信息(PII)模糊化等功能。使用[对话组件]({{< ref supported-conversation >}}),您可以提供提示与不同的 LLM 进行对话。 + +### 跨领域 API + +除了其构建块,Dapr 还提供适用于您使用的所有构建块的跨领域 API。 + +| 构建块 | 描述 | +|----------------|-------------| +| [**弹性**]({{< ref "resiliency-concept.md" >}}) | Dapr 提供通过弹性规范定义和应用容错弹性策略的能力。支持的规范定义了弹性模式的策略,如超时、重试/回退和断路器。 +| [**可观测性**]({{< ref "observability-concept.md" >}}) | Dapr 发出指标、日志和跟踪以调试和监控 Dapr 和用户应用。Dapr 支持分布式跟踪,以便使用 W3C Trace Context 标准和 Open Telemetry 轻松诊断和服务生产中的服务间调用,并发送到不同的监控工具。 +| [**安全性**]({{< ref "security-concept.md" >}}) | Dapr 支持使用 Dapr 控制平面 Sentry 服务在 Dapr 实例之间的通信进行传输加密。您可以引入自己的证书,或让 Dapr 自动创建和持久化自签名根和颁发者证书。 + +## Sidecar 架构 + +Dapr 以 sidecar 架构暴露其 HTTP 和 gRPC API,作为容器或进程,不需要应用代码包含任何 Dapr 运行时代码。这使得从其他运行时集成 Dapr 变得容易,同时提供应用逻辑的分离以提高支持性。 + + + +## 托管环境 + +Dapr 可以在多种环境中托管,包括: +- 在 Windows/Linux/macOS 机器上自托管用于本地开发和生产 +- 在 Kubernetes 或物理或虚拟机集群上用于生产 + +### 自托管本地开发 + +在[自托管模式]({{< ref self-hosted-overview.md >}})中,Dapr 作为一个独立的 sidecar 进程运行,您的服务代码可以通过 HTTP 或 gRPC 调用。每个运行的服务都有一个 Dapr 运行时进程(或 sidecar),配置为使用状态存储、pub/sub、绑定组件和其他构建块。 + +您可以使用 [Dapr CLI](https://github.com/dapr/cli#launch-dapr-and-your-app) 在本地机器上运行启用 Dapr 的应用。在下图中,Dapr 的本地开发环境通过 CLI `init` 命令进行配置。通过[入门示例]({{< ref getting-started >}})尝试一下。 + +Dapr 自托管模式的架构图 + +### Kubernetes + +Kubernetes 可以用于: +- 本地开发(例如,使用 [minikube](https://minikube.sigs.k8s.io/docs/) 和 [k3S](https://k3s.io/)),或 +- 在[生产]({{< ref kubernetes >}})中。 + +在 Kubernetes 等容器托管环境中,Dapr 作为 sidecar 容器与应用容器在同一个 pod 中运行。 + +Dapr 的 `dapr-sidecar-injector` 和 `dapr-operator` 控制平面服务提供一流的集成: +- 在与服务容器相同的 pod 中启动 Dapr 作为 sidecar 容器 +- 提供集群中 Dapr 组件更新的通知 + + +`dapr-sentry` 服务是一个证书颁发机构,启用 Dapr sidecar 实例之间的相互 TLS 以实现安全数据加密,并通过 [Spiffe](https://spiffe.io/) 提供身份。有关 `Sentry` 服务的更多信息,请阅读[安全概述]({{< ref "security-concept.md#dapr-to-dapr-communication" >}}) + + +将启用 Dapr 的应用部署并运行到您的 Kubernetes 集群中,只需在部署方案中添加几个注释即可。访问 [Dapr on Kubernetes 文档]({{< ref kubernetes >}})。 + +Dapr 在 Kubernetes 模式下的架构图 + +### 物理或虚拟机集群 + +Dapr 控制平面服务可以在生产中以高可用性(HA)模式部署到物理或虚拟机集群中。在下图中,actor `Placement` 和安全 `Sentry` 服务在三台不同的虚拟机上启动,以提供 HA 控制平面。为了为集群中运行的应用提供使用 DNS 的名称解析,Dapr 默认使用多播 DNS,但也可以选择支持 [Hashicorp Consul 服务]({{< ref setup-nr-consul >}})。 + +Dapr 控制平面和 Consul 部署到高可用性模式下的虚拟机的架构图 + +## 开发者语言 SDK 和框架 + +Dapr 提供多种 SDK 和框架,使您能够轻松地用您喜欢的语言开始使用 Dapr 进行开发。 + +### Dapr SDK + +为了使 Dapr 在不同语言中使用更自然,它还包括[特定语言的 SDK]({{< ref sdks >}}): +- Go +- Java +- JavaScript +- .NET +- PHP +- Python + +这些 SDK 通过类型化语言 API 暴露 Dapr 构建块的功能,而不是调用 http/gRPC API。这使您能够用您选择的语言编写无状态和有状态函数和 actor 的组合。由于这些 SDK 共享 Dapr 运行时,您可以获得跨语言的 actor 和函数支持。 + +### 开发者框架 + +Dapr 可以从任何开发者框架中使用。以下是一些已与 Dapr 集成的框架: + +#### Web + +| 语言 | 框架 | 描述 | +|----------|------------|-------------| +| [.NET]({{< ref dotnet >}}) | [ASP.NET Core](https://github.com/dapr/dotnet-sdk/tree/master/examples/AspNetCore) | 提供响应来自其他服务的 pub/sub 事件的有状态路由控制器。还可以利用 [ASP.NET Core gRPC 服务](https://docs.microsoft.com/aspnet/core/grpc/)。 +| [Java]({{< ref java >}}) | [Spring Boot](https://spring.io/) | 使用 Dapr API 构建 Spring Boot 应用 +| [Python]({{< ref python >}}) | [Flask]({{< ref python-flask.md >}}) | 使用 Dapr API 构建 Flask 应用 +| [JavaScript](https://github.com/dapr/js-sdk) | [Express](https://expressjs.com/) | 使用 Dapr API 构建 Express 应用 +| [PHP]({{< ref php >}}) | | 您可以使用 Apache、Nginx 或 Caddyserver 提供服务。 + +#### 集成和扩展 + +访问[集成]({{< ref integrations >}})页面,了解 Dapr 对各种框架和外部产品的一流支持,包括: +- 公共云服务,如 Azure 和 AWS +- Visual Studio Code +- GitHub + +## 为操作而设计 + +Dapr 是为[操作]({{< ref operations >}})和安全性而设计的。Dapr 的 sidecar、运行时、组件和配置都可以轻松且安全地管理和部署,以满足您组织的需求。 + +通过 Dapr CLI 安装的[仪表板](https://github.com/dapr/dashboard)提供了一个基于 Web 的 UI,使您能够查看信息、查看日志等,以运行 Dapr 应用。 + +Dapr 支持[监控工具]({{< ref observability >}}),以便更深入地了解 Dapr 系统服务和 sidecar,而 Dapr 的[可观测性功能]({{< ref "observability-concept.md" >}})提供了对您的应用的洞察,如跟踪和指标。 diff --git a/src/translated_content/zh_CN/docs/concepts/resiliency-concept.md b/src/translated_content/zh_CN/docs/concepts/resiliency-concept.md new file mode 100644 index 000000000..76f817783 --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/resiliency-concept.md @@ -0,0 +1,46 @@ +--- +type: docs +title: "弹性" +linkTitle: "弹性" +weight: 400 +description: "配置策略并监控应用和sidecar的健康状况" +--- + +分布式应用程序通常由许多微服务组成,这些微服务在底层基础设施上可以扩展到数十个甚至数百个实例。随着这些分布式解决方案的规模和复杂性增加,系统故障的可能性也随之增加。服务实例可能由于硬件故障、意外的吞吐量或应用程序生命周期事件(如扩展和重启)等多种问题而失败或无响应。因此,设计和实施能够检测、缓解和响应故障的自愈解决方案至关重要。 + +## 弹性策略 +显示应用于Dapr API的弹性的图表 + +Dapr允许您为应用程序定义和应用容错的弹性策略。您可以为以下弹性模式设定策略: + +- 超时 +- 重试/退避 +- 断路器 + +这些策略可以在调用具有[弹性规范]({{< ref resiliency-overview >}})的组件时应用于任何Dapr API调用。 + +## 应用健康检查 +显示应用健康功能的图表。启用应用健康运行Dapr会导致Dapr定期探测应用的健康状况 + +应用程序可能由于多种原因变得无响应,例如过于繁忙无法接受新任务、崩溃或死锁。有时这些问题可能是暂时的,也可能是持久的。 + +Dapr提供了一种通过探测来检查应用程序健康状况并对状态变化做出反应的机制。当检测到应用不健康时,Dapr会停止为该应用分配新任务。 + +阅读更多关于如何将[应用健康检查]({{< ref app-health >}})应用于您的应用程序。 + +## Sidecar健康检查 +显示应用健康功能的图表。启用应用健康运行Dapr会导致Dapr定期探测应用的健康状况 + +Dapr提供了一种通过[HTTP `/healthz` 端点]({{< ref health_api.md >}})来确定其健康状况的方法。通过此端点,*daprd*进程或sidecar可以: + +- 检查其健康状况 +- 确定其准备就绪状态和存活状态 + +阅读更多关于如何将[dapr健康检查]({{< ref sidecar-health >}})应用于您的应用程序。 + +## 下一步 + +- [了解更多关于弹性]({{< ref resiliency-overview.md >}}) +- 尝试其中一个弹性快速入门: + - [弹性:服务到服务]({{< ref resiliency-serviceinvo-quickstart.md >}}) + - [弹性:状态管理]({{< ref resiliency-state-quickstart.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/concepts/security-concept.md b/src/translated_content/zh_CN/docs/concepts/security-concept.md new file mode 100644 index 000000000..12190efac --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/security-concept.md @@ -0,0 +1,288 @@ +--- +type: docs +title: "安全性" +linkTitle: "安全性" +weight: 600 +description: Dapr在设计中如何考虑安全性 +--- + +安全性是Dapr的核心。本文介绍了在分布式应用中使用Dapr时的安全特性和功能。这些可以分为以下几类: + +- 使用service-invocation和pubsub API进行安全通信。 +- 通过配置应用于组件的安全策略。 +- 操作安全实践。 +- 状态安全,专注于静态数据。 + +一个示例应用程序用于说明Dapr中可用的多种安全特性。 + +# 安全通信 + +Dapr通过service-invocation API提供端到端的安全性,支持应用程序身份验证并设置访问策略。下图展示了这一点。 + + + +## service-invocation范围访问策略 + +Dapr应用程序可以被限定在命名空间中进行部署和安全管理。您可以在不同命名空间的服务之间进行调用。阅读[跨命名空间的service-invocation]({{< ref "service-invocation-namespaces.md" >}})以获取更多信息。 + +Dapr应用程序可以限制哪些操作可以被调用,包括哪些应用程序被允许(或拒绝)调用它。阅读[如何:为service-invocation应用访问控制列表配置]({{< ref invoke-allowlist.md >}})以获取更多信息。 + +## pubsub主题范围访问策略 + +对于pubsub组件,您可以限制哪些主题类型和应用程序被允许发布和订阅特定主题。阅读[范围pubsub主题访问]({{< ref "pubsub-scopes.md" >}})以获取更多信息。 + +## 使用mTLS加密数据 + +Dapr使用的一种加密传输中数据的安全机制是[双向认证TLS](https://en.wikipedia.org/wiki/Mutual_authentication)或mTLS。mTLS为应用程序内部的网络流量提供了一些关键特性: + +- **双向认证**,客户端和服务器相互验证身份。 +- **加密通道**,用于所有在途通信,在建立双向认证后。 + +mTLS在几乎所有场景中都很有用,尤其是对于需要遵循法规的系统,如[HIPAA](https://en.wikipedia.org/wiki/Health_Insurance_Portability_and_Accountability_Act)和[PCI](https://en.wikipedia.org/wiki/Payment_Card_Industry_Data_Security_Standard)。 + +## Dapr之间的安全通信 + +在生产系统中,Dapr无需额外代码或复杂配置即可启用mTLS。此外,Dapr sidecar默认只允许`localhost`访问,阻止其他IP地址,除非明确配置。 + +Dapr包含一个“默认开启”的自动mTLS,为Dapr sidecar之间的流量提供在途加密。为实现这一点,Dapr利用一个名为`Sentry`的系统服务,该服务充当证书颁发机构(CA)/身份提供者,并签署来自Dapr sidecar的工作负载(应用程序)证书请求。 + +默认情况下,工作负载证书有效期为24小时,时钟偏差设置为15分钟。 + +除非您提供了现有的根证书,否则Sentry服务会自动创建并持久化有效期为一年的自签名根证书。Dapr管理工作负载证书的轮换;如果您自带证书,Dapr会在不影响应用程序正常运行的情况下进行。 + +当根证书被替换时(Kubernetes模式下为secret,自托管模式下为文件系统),Sentry会获取它们并重建信任链,无需重启且对Sentry无停机时间。 + +当一个新的Dapr sidecar初始化时,它会检查是否启用了mTLS。如果是,则生成一个ECDSA私钥和证书签名请求,并通过gRPC接口发送给Sentry。Dapr sidecar和Sentry之间的通信使用信任链证书进行认证,该证书由Dapr Sidecar Injector系统服务注入到每个Dapr实例中。 + +### 配置mTLS + +可以通过编辑Dapr部署的默认配置中的`spec.mtls.enabled`字段来开启/关闭mTLS。 + +[您可以在Kubernetes和自托管模式下进行此操作]({{< ref mtls.md >}})。 + +#### 自托管模式下的mTLS + +下图显示了Sentry系统服务如何根据操作员提供的或由Sentry服务生成并存储在文件中的根/颁发者证书为应用程序颁发证书。 + + + +#### Kubernetes模式下的mTLS + +在Kubernetes集群中,保存根证书的secret是: + +- 限定在部署Dapr组件的命名空间中。 +- 仅由Dapr控制平面系统pod访问。 + +Dapr在Kubernetes上部署时还支持强身份验证,依赖于作为证书签名请求(CSR)一部分发送给Sentry的pod的服务账户令牌。 + +下图显示了Sentry系统服务如何根据操作员提供的或由Sentry服务生成并存储为Kubernetes secret的根/颁发者证书为应用程序颁发证书。 + + + +### 防止Dapr被IP地址访问 + +为了防止Dapr sidecar在任何IP地址上被调用(尤其是在Kubernetes等生产环境中),Dapr将其监听IP地址限制为`localhost`。如果您需要启用外部地址的访问,请使用[dapr-listen-addresses]({{}})设置。 + +## 安全的Dapr到应用程序通信 + +Dapr sidecar通过`localhost`运行在应用程序附近,建议在与应用程序相同的网络边界内运行。虽然许多现代云原生系统将pod级别(例如在Kubernetes上)视为可信的安全边界,但Dapr通过令牌为应用程序提供API级别的身份验证。此功能保证,即使在`localhost`上: + +- 只有经过身份验证的应用程序可以调用Dapr +- 应用程序可以检查Dapr是否在回调它 + +有关配置API令牌安全性的更多详细信息,请阅读: + +- [使用API令牌对来自应用程序到Dapr的请求进行身份验证]({{< ref api-token.md >}})。 +- [使用API令牌对来自Dapr到应用程序的请求进行身份验证]({{< ref app-api-token.md >}}) + +## 安全的Dapr到控制平面通信 + +除了Dapr sidecar之间的自动mTLS,Dapr还提供以下之间的强制mTLS: + +- Dapr sidecar +- Dapr控制平面系统服务,即: + - Sentry服务(证书颁发机构) + - Placement服务(actor放置) + - Kubernetes Operator服务 + +当启用mTLS时,Sentry将根和颁发者证书写入限定在安装控制平面的命名空间的Kubernetes secret中。在自托管模式下,Sentry将证书写入可配置的文件系统路径。 + +在Kubernetes中,当Dapr系统服务启动时,它们会自动挂载并使用包含根和颁发者证书的secret来保护Dapr sidecar使用的gRPC服务器。在自托管模式下,每个系统服务可以挂载到文件系统路径以获取凭据。 + +当Dapr sidecar初始化时,它使用挂载的叶证书和颁发者私钥对系统pod进行身份验证。这些作为环境变量挂载在sidecar容器上。 + +### Kubernetes中到系统服务的mTLS + +下图显示了Dapr sidecar与Dapr Sentry(证书颁发机构)、Placement(actor放置)和Kubernetes Operator系统服务之间的安全通信。 + + +
+ +# 操作安全 + +Dapr设计用于让操作员管理mTLS证书并强制执行OAuth策略。 + +## mTLS证书部署和轮换 + +虽然操作员和开发人员可以将自己的证书引入Dapr,但Dapr会自动创建并持久化自签名的根和颁发者证书。阅读[设置和配置mTLS证书]({{< ref mtls.md >}})以获取更多信息。 + +## 使用OAuth进行中间件端点授权 + +使用Dapr OAuth 2.0中间件,您可以在Dapr端点上为您的API启用OAuth授权。阅读[使用OAuth配置端点授权]({{< ref oauth.md >}})以获取详细信息。Dapr还有其他中间件组件,您可以用于OpenID Connect和OPA策略。有关更多详细信息,请[阅读支持的中间件]({{< ref supported-middleware.md >}})。 + +## 网络安全 + +您可以采用常见的网络安全技术,如网络安全组(NSG)、非军事区(DMZ)和防火墙,为您的网络资源提供多层保护。例如,除非配置为与外部绑定目标通信,否则Dapr sidecar不会打开到互联网的连接,并且大多数绑定实现仅使用出站连接。您可以设计防火墙规则,仅通过指定端口允许出站连接。 + +# 安全策略 + +Dapr有一套广泛的安全策略,您可以应用于您的应用程序。您可以通过sidecar配置中的策略设置或组件规范来限定它们能够做什么。 + +## API访问策略 + +在某些场景中,例如在零信任网络中或通过前端将Dapr sidecar暴露给外部流量时,建议仅启用应用程序当前使用的Dapr sidecar API。这减少了攻击面,并将Dapr API限定在应用程序的实际需求范围内。您可以通过在配置中设置API允许列表来控制哪些API对应用程序可访问,如下图所示。 + + + +阅读[如何:选择性启用Dapr sidecar上的Dapr API]({{< ref api-allowlist.md >}})以获取更多信息。 + +## secret范围访问策略 + +为了限制Dapr应用程序对secret的访问,您可以定义secret范围。在应用程序配置中添加一个secret范围策略,具有限制性权限。阅读[如何:使用secret范围]({{< ref secret-scope.md >}})以获取更多信息。 + +## 组件应用程序范围访问策略和secret使用 + +Dapr组件可以被命名空间化。这意味着一个Dapr sidecar实例只能访问部署到相同命名空间的组件。阅读[如何:使用命名空间将组件限定到一个或多个应用程序]({{< ref component-scopes.md >}})以获取更多信息。 + +Dapr通过允许您指定哪些应用程序可以使用特定组件并拒绝其他应用程序来提供组件的应用程序级别范围。阅读[使用范围限制应用程序对组件的访问]({{< ref "component-scopes.md#application-access-to-components-with-scopes" >}})以获取更多信息。 + +Dapr组件可以使用Dapr的内置secret管理功能来管理secret。阅读[secret存储概述]({{< ref secrets-overview.md >}})和[如何:在组件中引用secret]({{< ref component-secrets.md >}})以获取更多信息。 + +## 绑定安全性 + +与绑定目标的身份验证由绑定的配置文件配置。通常,您应该配置最低所需的访问权限。例如,如果您只从绑定目标读取,您应该将绑定配置为使用具有只读访问权限的帐户。 + +# 状态安全 + +## 状态存储静态加密 + +默认情况下,Dapr不会转换来自应用程序的状态数据。这意味着: + +- Dapr不会尝试加密/解密状态数据 +- 您的应用程序可以采用您选择的加密/解密方法,其中状态数据对Dapr保持不透明。 + +Dapr组件可以使用配置的身份验证方法与底层状态存储进行身份验证。许多状态存储实现使用官方客户端库,这些库通常使用与服务器的安全通信通道。 + +然而,应用程序状态通常需要在静态时加密,以在企业工作负载或受监管环境中提供更强的安全性。Dapr提供基于AES256的自动客户端状态加密。阅读[如何:加密应用程序状态]({{< ref howto-encrypt-state.md >}})以获取更多信息。 + +## Dapr运行时状态 + +Dapr运行时不存储任何静态数据,这意味着Dapr运行时对其操作没有任何状态存储的依赖,可以被视为无状态。 + +# 在示例应用程序中使用安全功能 + +下图显示了在Kubernetes上托管的示例应用程序中放置的许多安全功能。在示例中,Dapr控制平面、Redis状态存储和每个服务都被部署到它们自己的命名空间中。在Kubernetes上部署时,您可以使用常规的Kubernetes RBAC来控制管理活动的访问。 + +在应用程序中,请求由运行在其旁边的Dapr sidecar的入口反向代理接收。从反向代理开始,Dapr使用service-invocation调用服务A,然后将消息发布到服务B。服务B检索一个secret以读取和保存到Redis状态存储。 + + + +让我们逐一介绍每个安全功能,并描述它们如何保护此应用程序。 + +1. API令牌身份验证确保反向代理知道它正在与正确的Dapr sidecar实例通信。这可以防止将消息转发到除此Dapr sidecar之外的任何地方。 +2. service-invocation mTLS用于反向代理和服务A之间的身份验证。服务A上配置的服务访问策略限制其仅接收来自反向代理的特定端点的调用,而不是其他服务。 +3. 服务B使用pubsub主题安全策略来指示它只能接收从服务A发布的消息。 +4. Redis组件定义使用组件范围安全策略来表示只有服务B被允许调用它。 +5. 服务B限制Dapr sidecar仅使用pubsub、状态管理和secret API。所有其他API调用(例如,service-invocation)将失败。 +6. 在配置中设置的secret安全策略限制了服务B可以访问的secret。在这种情况下,服务B只能读取连接到Redis状态存储组件所需的secret,而不能读取其他secret。 +7. 服务B被部署到命名空间“B”,这进一步将其与其他服务隔离。即使在其上启用了service-invocation API,也不能因为与服务A在同一命名空间中而被意外调用。服务B必须在其组件YAML文件中显式设置Redis主机命名空间以调用“Redis”命名空间,否则此调用也会失败。 +8. Redis状态存储中的数据在静态时被加密,并且只能使用正确配置的Dapr Redis状态存储组件读取。 + +# 威胁模型 + +威胁建模是一个过程,通过该过程: + +- 可以识别和列举潜在威胁,如结构性漏洞或缺乏适当的保护措施。 +- 可以优先考虑缓解措施。 + +Dapr的威胁模型如下。 + +Dapr威胁模型 + +## 安全审计 + +### 2023年9月 + +2023年9月,Dapr完成了由Ada Logics进行的安全审计。 + +审计是一次全面的安全审计,目标如下: + +- 形式化Dapr的威胁模型 +- 执行手动代码审查 +- 根据形式化的威胁模型评估Dapr的模糊测试套件 +- 进行Dapr的SLSA审查。 + +您可以在[这里](/docs/Dapr-september-2023-security-audit-report.pdf)找到完整报告。 + +审计发现了7个问题,其中没有一个是高或关键严重性。一个CVE是由于Dapr组件贡献中的第三方依赖问题而分配的。 + +### 2023年6月 + +2023年6月,Dapr完成了由Ada Logics进行的模糊测试审计。 + +审计实现了以下目标: + +- OSS-Fuzz集成 +- 为Dapr创建了39个新的模糊测试器 +- Dapr运行时、Kit和组件贡献的模糊测试覆盖 +- 所有模糊测试器在审计完成后持续运行 + +您可以在[这里](/docs/Dapr-june-2023-fuzzing-audit-report.pdf)找到完整报告。 + +审计期间发现了3个问题。 + +### 2021年2月 + +2021年2月,Dapr进行了由Cure53针对其1.0版本的第二次安全审计。 + +测试重点如下: + +- 自上次审计以来的Dapr运行时代码库评估 +- 访问控制列表 +- secret管理 +- 渗透测试 +- 验证先前高/中问题的修复 + +您可以在[这里](/docs/Dapr-february-2021-security-audit-report.pdf)找到完整报告。 + +在测试期间检测到并修复了一个高问题。 + +截至2021年2月16日,Dapr有0个关键问题,0个高问题,0个中问题,2个低问题,2个信息问题。 + +### 2020年6月 + +2020年6月,Dapr接受了来自Cure53的安全审计,这是一家CNCF批准的网络安全公司。 + +测试重点如下: + +- Dapr运行时代码库评估 +- Dapr组件代码库评估 +- Dapr CLI代码库评估 +- 权限提升 +- 流量欺骗 +- secret管理 +- RBAC +- 验证基本假设:mTLS、范围、API身份验证 +- 编排加固(Kubernetes) +- DoS攻击 +- 渗透测试 + +完整报告可以在[这里](/docs/Dapr-july-2020-security-audit-report.pdf)找到。 + +## 报告安全问题 + +访问[此页面]({{< ref support-security-issues.md >}})向Dapr维护者报告安全问题。 + +## 相关链接 + +[操作安全]({{< ref "security.md" >}}) diff --git a/src/translated_content/zh_CN/docs/concepts/terminology.md b/src/translated_content/zh_CN/docs/concepts/terminology.md new file mode 100644 index 000000000..f545a5f90 --- /dev/null +++ b/src/translated_content/zh_CN/docs/concepts/terminology.md @@ -0,0 +1,23 @@ +--- +type: docs +title: "Dapr术语和定义" +linkTitle: "术语" +weight: 1000 +description: Dapr文档中常见术语和缩写的定义 +--- + +本页面详细介绍了您可能在Dapr文档中遇到的所有常见术语。 + +| 术语 | 定义 | 更多信息 | +|:-----|------------|------------------| +| 应用程序 | 一个正在运行的服务或程序,通常是由用户创建和运行的。 | +| 构件 | Dapr为用户提供的API,帮助创建微服务和应用程序。 | [Dapr构件]({{< ref building-blocks-concept.md >}}) +| 组件 | 模块化的功能单元,可以单独使用或与其他组件结合使用,由Dapr构件调用。 | [Dapr组件]({{< ref components-concept.md >}}) +| 配置 | 一个YAML文件,用于声明所有Dapr边车或Dapr控制平面的设置。在这里,您可以配置控制平面的mTLS设置,或应用程序实例的跟踪和中间件设置。 | [Dapr配置]({{< ref configuration-concept.md >}}) +| Dapr | 分布式应用运行时。 | [Dapr概述]({{< ref overview.md >}}) +| Dapr控制平面 | 一组服务,是在托管平台(如Kubernetes集群)上安装Dapr的一部分。这使得启用Dapr的应用程序可以在平台上运行,并处理Dapr功能,如actor放置、Dapr边车注入或证书签发/轮换。 | [自托管概述]({{< ref self-hosted-overview >}})
[Kubernetes概述]({{< ref kubernetes-overview >}}) +| HTTPEndpoint | HTTPEndpoint是一个Dapr资源,用于识别通过服务调用API访问的非Dapr端点。 | [服务调用API]({{< ref service_invocation_api.md >}}) +| 命名空间 | Dapr中的命名空间提供隔离功能,从而支持多租户。 | 了解更多关于命名空间的[组件]({{< ref component-scopes.md >}})、[服务调用]({{< ref service-invocation-namespaces.md >}})、[发布/订阅]({{< ref pubsub-namespaces.md >}})和[actors]({{< ref namespaced-actors.md >}}) +| 自主管理 | 在Windows/macOS/Linux机器上运行应用程序的能力,使用Dapr。Dapr提供在“自主管理”模式下运行的能力。 | [自主管理模式]({{< ref self-hosted-overview.md >}}) +| 服务 | 一个正在运行的应用程序或程序。这可以指您的应用程序或Dapr应用程序。 | +| sidecar | 一个与您的应用程序一起运行的程序,作为一个单独的进程或容器。 | [边车模式](https://docs.microsoft.com/azure/architecture/patterns/sidecar) diff --git a/src/translated_content/zh_CN/docs/contributing/_index.md b/src/translated_content/zh_CN/docs/contributing/_index.md new file mode 100644 index 000000000..0c6f7ba1f --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "为Dapr项目做贡献" +linkTitle: "贡献指南" +weight: 60 +description: 如何为Dapr项目做出贡献 +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/contributing/codespaces.md b/src/translated_content/zh_CN/docs/contributing/codespaces.md new file mode 100644 index 000000000..585b110e5 --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/codespaces.md @@ -0,0 +1,99 @@ +--- +type: docs +title: "使用 GitHub Codespaces 进行贡献" +linkTitle: "GitHub Codespaces" +weight: 60 +description: "如何使用 GitHub Codespaces 为 Dapr 项目做出贡献" +aliases: + - "/zh-hans/contributing/codespaces/" + - "/zh-hans/developing-applications/ides/codespaces/" +--- + +[GitHub Codespaces](https://github.com/features/codespaces) 是为 Dapr 仓库做出贡献的最简单方式。只需点击一下,您就可以在浏览器中获得一个已准备好的环境,包含所有必要的前置条件。 + +## 功能 + +- **一键运行**:获取一个专用且沙盒化的环境,所有必需的框架和包都已准备就绪。 +- **按使用计费**:只需为您在 Codespaces 中开发的时间付费。当不使用时,环境会自动关闭。 +- **便携性**:可以在浏览器中运行,也可以在 Visual Studio Code 中运行,或使用 SSH 连接。 + +## 在 Codespace 中打开 Dapr 仓库 + +要在 Codespace 中打开 Dapr 仓库,请从仓库主页选择“Code”并选择“Open with Codespaces”: + +创建 Dapr Codespace 的截图 + +如果您还没有 fork 该仓库,创建 Codespace 时会自动为您创建一个 fork,并在 Codespace 中使用它。 + +## 支持的仓库 + +- [dapr/dapr](https://github.com/dapr/dapr) +- [dapr/components-contrib](https://github.com/dapr/components-contrib) +- [dapr/cli](https://github.com/dapr/cli) +- [dapr/docs](https://github.com/dapr/docs) +- [dapr/python-sdk](https://github.com/dapr/python-sdk) + +## 在 Codespace 中开发 Dapr 组件 + +开发新的 Dapr 组件需要同时处理 [dapr/components-contrib](https://github.com/dapr/components-contrib) 和 [dapr/dapr](https://github.com/dapr/dapr) 仓库。建议将这两个文件夹并排放置在 `/workspaces` 目录中。 + +### 如果您从 `dapr/dapr` 创建了 Codespace + +如果您的 Codespaces 是从 `dapr/dapr` 仓库或其 fork 启动的,您需要在 `/workspaces/components-contrib` 中克隆 `dapr/components-contrib` 仓库(或其 fork)。 + +首先,确保您已通过 GitHub CLI 进行身份验证: + +```sh +# 运行此命令并按照提示进行操作 +# 大多数用户应接受默认选择 +gh auth login +``` + +克隆仓库: + +```sh +# 如果您想使用您 fork 的 dapr/components-contrib,请将其替换为您的 fork(例如 "yourusername/components-contrib") +# 确保在执行此操作之前已 fork 该仓库 +REPO=dapr/components-contrib +cd /workspaces +gh repo clone "$REPO" /workspaces/components-contrib +``` + +然后,将文件夹添加到当前工作区: + +```sh +code -a /workspaces/components-contrib +``` + +### 如果您从 `dapr/components-contrib` 创建了 Codespace + +如果您的 Codespaces 是从 `dapr/components-contrib` 仓库或其 fork 启动的,您需要在 `/workspaces/dapr` 中克隆 `dapr/dapr` 仓库(或其 fork)。 + +首先,确保您已通过 GitHub CLI 进行身份验证: + +```sh +# 运行此命令并按照提示进行操作 +# 大多数用户应接受默认选择 +gh auth login +``` + +克隆仓库: + +```sh +# 如果您想使用您 fork 的 dapr/dapr,请将其替换为您的 fork(例如 "yourusername/dapr") +# 确保在执行此操作之前已 fork 该仓库 +REPO=dapr/dapr +cd /workspaces +gh repo clone "$REPO" /workspaces/dapr +``` + +然后,将文件夹添加到当前工作区: + +```sh +code -a /workspaces/dapr +``` + +## 相关链接 + +- [GitHub 文档](https://docs.github.com/codespaces/overview) + \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/contributing/contributing-overview.md b/src/translated_content/zh_CN/docs/contributing/contributing-overview.md new file mode 100644 index 000000000..9d0ea2991 --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/contributing-overview.md @@ -0,0 +1,119 @@ +--- +type: docs +title: "贡献概览" +linkTitle: "概览" +weight: 10 +description: > + 对Dapr项目的任何代码库进行贡献的一般指导 +--- + +感谢您对Dapr项目的关注! +本文档为您提供如何通过提交问题和拉取请求来为[Dapr项目](https://github.com/dapr)做出贡献的指南。您还可以通过其他方式参与,例如参加社区电话会议、对问题或拉取请求进行评论等。 + +有关社区参与和成员资格的更多信息,请参阅[Dapr社区代码库](https://github.com/dapr/community)。 + +## Dapr代码库索引 + +以下是Dapr组织下的代码库列表,您可以在这些代码库中进行贡献: + +1. **文档**:此[代码库](https://github.com/dapr/docs)包含Dapr的文档。您可以通过更新现有文档、修复错误或添加新内容来改善用户体验和清晰度。请参阅[文档贡献指南](https://github.com/dapr/docs/blob/master/CONTRIBUTING.md)。 + +2. **快速入门**:快速入门[代码库](https://github.com/dapr/quickstarts)提供简单的分步指南,帮助用户快速上手Dapr。您可以通过创建新的快速入门、改进现有的快速入门或确保它们与最新功能保持同步来贡献。[查看贡献指南](https://github.com/dapr/quickstarts/blob/master/CONTRIBUTING.md)。 + +3. **运行时**:Dapr运行时[代码库](https://github.com/dapr/dapr)包含核心运行时组件。您可以通过修复错误、优化性能、实现新功能或增强现有功能来贡献。 + +4. **组件贡献**:此[代码库](https://github.com/dapr/components-contrib)托管了Dapr的社区贡献组件集合。您可以通过添加新组件、改进现有组件或审查和测试社区的贡献来参与。 + +5. **SDKs**:Dapr SDKs为各种编程语言提供与Dapr交互的库。您可以通过改进SDK功能、修复错误或添加对新功能的支持来贡献。请参阅[SDK贡献指南](https://github.com/dapr/docs/blob/master/CONTRIBUTING.md)以获取特定SDK的详细信息。 + +6. **CLI**:Dapr CLI用于在本地开发机器或Kubernetes集群上设置Dapr以启动和管理Dapr实例。对CLI代码库的贡献包括添加新功能、修复错误、提高可用性,并确保与最新的Dapr版本兼容。请参阅[开发指南](https://github.com/dapr/cli/blob/master/docs/development/development.md)以获取有关开发Dapr CLI的帮助。 + +## 问题 + +### 问题类型 + +在大多数Dapr代码库中,通常有4种类型的问题: + +- 问题/错误:您发现了代码中的错误,并希望报告或创建一个问题来跟踪该错误。 +- 问题/讨论:您有一些想法,需要在讨论中获得他人的意见,然后最终形成提案。 +- 问题/提案:用于提出新想法或功能的项目。这允许在编写代码之前获得他人的反馈。 +- 问题/问题:如果您需要帮助或有问题,请使用此问题类型。 + +### 提交之前 + +在提交问题之前,请确保您已检查以下内容: + +1. 这是正确的代码库吗? + - Dapr项目分布在多个代码库中。如果您不确定哪个代码库是正确的,请查看[代码库列表](https://github.com/dapr)。 +1. 检查现有问题 + - 在创建新问题之前,请在[开放问题](https://github.com/dapr/dapr/issues)中搜索,查看该问题或功能请求是否已被提交。 + - 如果您发现您的问题已经存在,请进行相关评论并添加您的[反应](https://github.com/blog/2119-add-reaction-to-pull-requests-issues-and-comments)。使用反应: + - 👍 赞成 + - 👎 反对 +1. 对于错误 + - 检查这不是环境问题。例如,如果在Kubernetes上运行,请确保先决条件已到位。(state存储、bindings等) + - 您拥有尽可能多的数据。这通常以日志和/或堆栈跟踪的形式出现。如果在Kubernetes或其他环境中运行,请查看Dapr服务(运行时、operator、placement服务)的日志。有关如何获取日志的更多详细信息,请参阅[此处]({{< ref "logs-troubleshooting.md" >}})。 +1. 对于提案 + - 许多对Dapr运行时的更改可能需要对API进行更改。在这种情况下,讨论潜在功能的最佳地点是主要的[Dapr代码库](https://github.com/dapr/dapr)。 + - 其他示例可能包括bindings、state存储或全新的组件。 + +## 拉取请求 + +所有贡献都通过拉取请求提交。要提交建议的更改,请遵循以下工作流程: + +1. 确保已提出问题(错误或提案),以设定您即将进行的贡献的期望。 +1. 分叉相关代码库并创建新分支 + - 一些Dapr代码库支持[Codespaces]({{< ref codespaces.md >}}),为您提供即时环境以构建和测试您的更改。 + - 有关设置Dapr开发环境的更多信息,请参阅[开发Dapr文档](https://github.com/dapr/dapr/blob/master/docs/development/developing-dapr.md)。 +1. 创建您的更改 + - 代码更改需要测试 +1. 更新相关文档以反映更改 +1. 使用[DCO签署]({{< ref "contributing-overview.md#developer-certificate-of-origin-signing-your-work" >}})提交并打开PR +1. 等待CI过程完成并确保所有检查通过 +1. 项目的维护者将被分配,您可以在几天内期待审查 + +#### 使用草稿PR以获得早期反馈 + +在投入过多时间之前进行沟通的好方法是创建一个“草稿”PR并与您的审阅者分享。标准做法是在PR的标题中添加“[WIP]”前缀,并分配**do-not-merge**标签。这将让查看您PR的人知道它尚未成熟。 + +## 使用第三方代码 + +- 第三方代码必须包含许可证。 + +## 开发者来源证书:签署您的工作 +#### 每次提交都需要签署 + +开发者来源证书(DCO)是一种轻量级方式,供贡献者证明他们编写或以其他方式有权提交他们贡献给项目的代码。以下是[DCO](https://developercertificate.org/)的完整文本,经过重新格式化以提高可读性: +``` +通过对该项目进行贡献,我证明: + (a) 该贡献完全或部分由我创建,并且我有权根据文件中指明的开源许可证提交它;或者 + (b) 该贡献基于我所知的适当开源许可证覆盖的先前工作,并且我有权根据该许可证提交该工作及其修改,无论是由我完全或部分创建的,均根据相同的开源许可证(除非我被允许根据不同的许可证提交),如文件中所示;或者 + (c) 该贡献是由其他人直接提供给我的,他们证明了(a)、(b)或(c),而我没有修改它。 + (d) 我理解并同意该项目和贡献是公开的,并且贡献的记录(包括我提交的所有个人信息,包括我的签署)将被无限期地维护,并可能根据该项目或涉及的开源许可证进行再分发。 +``` +贡献者通过在提交消息中添加`Signed-off-by`行来签署他们遵守这些要求。 + +``` +这是我的提交消息 +Signed-off-by: Random J Developer +``` +Git甚至有一个`-s`命令行选项,可以自动将其附加到您的提交消息中: +``` +$ git commit -s -m '这是我的提交消息' +``` + +每个拉取请求都会检查拉取请求中的提交是否包含有效的Signed-off-by行。 + +#### 我没有签署我的提交,现在怎么办?! + +别担心 - 您可以轻松地重放您的更改,签署它们并强制推送它们! + +``` +git checkout +git commit --amend --no-edit --signoff +git push --force-with-lease +``` + +## 行为准则 + +请参阅[Dapr社区行为准则](https://github.com/dapr/community/blob/master/CODE-OF-CONDUCT.md)。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/contributing/daprbot.md b/src/translated_content/zh_CN/docs/contributing/daprbot.md new file mode 100644 index 000000000..b3d288648 --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/daprbot.md @@ -0,0 +1,29 @@ +--- +type: docs +title: "Dapr 机器人参考" +linkTitle: "Dapr 机器人" +weight: 70 +description: "Dapr 机器人的功能列表。" +--- + +Dapr 机器人通过一系列命令来帮助处理 Dapr 组织中的常见任务。它可以为每个代码库单独配置([示例](https://github.com/dapr/dapr/blob/master/.github/workflows/dapr-bot.yml)),并能够在特定事件发生时运行。以下是命令列表及其在各个代码库中的实现。 + +## 命令参考 + +| 命令 | 目标 | 描述 | 谁可以使用 | 代码库 | +| ----------------- | --------------------- | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------- | +| `/assign` | Issue | 将一个 issue 分配给一个或多个用户 | 任何人 | `dapr`, `docs`, `quickstarts`, `cli`, `components-contrib`, `go-sdk`, `js-sdk`, `java-sdk`, `python-sdk`, `dotnet-sdk`, `rust-sdk` | +| `/ok-to-test` | Pull request | `dapr`: 触发端到端测试
`components-contrib`: 触发一致性和认证测试 | 在 [bot](https://github.com/dapr/dapr/blob/master/.github/scripts/dapr_bot.js) 中授权的用户 | `dapr`, `components-contrib` | +| `/ok-to-perf` | Pull request | 触发性能测试。 | 在 [bot](https://github.com/dapr/dapr/blob/master/.github/scripts/dapr_bot.js) 中授权的用户 | `dapr` | +| `/make-me-laugh` | Issue 或 pull request | 发布一个随机笑话,增添趣味 | 在 [bot](https://github.com/dapr/dapr/blob/master/.github/scripts/dapr_bot.js) 中授权的用户 | `dapr`, `components-contrib` | + +## 标签参考 + +您可以通过使用 `created-by/dapr-bot` 标签查询由 Dapr 机器人创建的 issue([查询](https://github.com/search?q=org%3Adapr%20is%3Aissue%20label%3Acreated-by%2Fdapr-bot%20&type=issues))。 + +| 标签 | 目标 | 作用说明 | 代码库 | +| ------------------------- | --------------------- | ---------------------------------------------------------------- | -------------------- | +| `docs-needed` | Issue | 在 `dapr/docs` 中创建一个新的 issue 以跟踪文档工作 | `dapr` | +| `sdk-needed` | Issue | 在 SDK 仓库中创建新的 issue 以跟踪 SDK 工作 | `dapr` | +| `documentation required` | Issue 或 pull request | 在 `dapr/docs` 中创建一个新的 issue 以跟踪文档工作 | `components-contrib` | +| `new component` | Issue 或 pull request | 在 `dapr/dapr` 中创建一个新的 issue 以注册新组件 | `components-contrib` | diff --git a/src/translated_content/zh_CN/docs/contributing/docs-contrib/_index.md b/src/translated_content/zh_CN/docs/contributing/docs-contrib/_index.md new file mode 100644 index 000000000..3455aa5db --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/docs-contrib/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "文档贡献指南" +linkTitle: "文档" +weight: 80 +description: 如何为 Dapr 文档做出贡献 +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/contributing/docs-contrib/contributing-docs.md b/src/translated_content/zh_CN/docs/contributing/docs-contrib/contributing-docs.md new file mode 100644 index 000000000..e42909346 --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/docs-contrib/contributing-docs.md @@ -0,0 +1,466 @@ +--- +type: docs +title: "贡献者指南" +linkTitle: "贡献者指南" +weight: 10 +description: 开始为 Dapr 文档做贡献 +--- + +在本指南中,您将学习如何为 [Dapr 文档库](https://github.com/dapr/docs) 做出贡献。由于 Dapr 文档发布在 [docs.dapr.io](https://docs.dapr.io),您需要确保您的贡献能够正确编译和发布。 + + + +## 先决条件 + +在为 Dapr 文档做贡献之前: + +- 查看 [关于 Dapr 项目贡献的一般指导]({{< ref contributing-overview>}})。 +- 使用 [Hugo](https://gohugo.io/) 和 [Docsy](https://docsy.dev) 主题安装并设置您的本地环境。请按照库中的 [README.md](https://github.com/dapr/docs/blob/master/README.md#environment-setup) 中的说明进行操作。 +- 分叉并克隆 [文档库](https://github.com/dapr/docs)。 + +## 分支指导 + +Dapr 文档的分支管理与大多数代码库不同。没有主分支,每个分支都与运行时发布的主要和次要版本相匹配。完整列表请访问 [Docs repo](https://github.com/dapr/docs#branch-guidance)。 + +通常,您所有的文档更新都应提交到 [Dapr 最新版本的文档分支](https://github.com/dapr/docs)。最新版本是默认分支 [https://github.com/dapr/docs]。例如,如果您正在修复拼写错误、添加注释或澄清某个点,请将您的更改提交到默认的 Dapr 分支。 + +对于适用于候选发布或预发布版本的文档更改,请将您的更改指向该特定分支。例如,如果您正在记录即将对组件或运行时的更改,请将您的更改提交到预发布分支。 + +## 风格和语气 + +在所有 Dapr 文档中应遵循风格和语气惯例,以确保所有文档的一致性: + +| 风格/语气 | 指导 | +| ---------- | -------- | +| 大小写 | 仅在以下情况下使用大写:
  • 句子或标题的开头
  • 专有名词,包括技术名称(Dapr、Redis、Kubernetes 等)
| +| 标题和标题 | 标题和标题必须简洁,但描述性和清晰。 | +| 使用简单句子 | 写出易于阅读、可扫描的句子。提示:跳过正式语气,像直接与读者交谈一样写作。 | +| 避免使用第一人称 | 代替第一人称 "I"、"we" 和 "our",使用第二人称 "you" 和 "your"。 | +| 假设 "新开发者" 受众 | 对于经验丰富的开发者来说一些看似显而易见的步骤可能对新开发者并不那么明显。为读者提供更明确、详尽的说明。 | +| 使用现在时 | 避免使用诸如 "this command _will_ install Redis" 的句子。相反,使用 "This command installs Redis"。 | + +## 图表和图像 + +图表和图像是文档页面中无价的视觉辅助工具。使用 [Dapr 图表模板套件](https://github.com/dapr/docs/tree/v1.14/daprdocs/static/presentations) 中的图表样式和图标。 + +为您的文档创建图表的过程: + +1. 下载 [Dapr 图表模板套件](https://github.com/dapr/docs/tree/v1.14/daprdocs/static/presentations) 以使用图标和颜色。 +1. 添加新幻灯片并创建您的图表。 +1. 将图表截屏为高分辨率 PNG 文件并保存在 [images 文件夹](https://github.com/dapr/docs/tree/v1.14/daprdocs/static/images)中。 +1. 使用概念或构建块的命名约定命名您的 PNG 文件,以便它们被分组。 + - 例如:`service-invocation-overview.png`。 + - 有关使用短代码调用图像的更多信息,请参见下面的 [图像指导](#images) 部分。 +1. 使用 HTML `` 标签将图表添加到文档中的适当部分。 +1. 在您的 PR 中,评论图表幻灯片(而不是截屏),以便维护者可以审查并将其添加到图表套件中。 + +## 贡献新文档页面 + +如果您正在创建新文章,请确保您: + +- 将新文档放置在层次结构中的正确位置。 +- 避免创建新部分。大多数情况下,正确的位置已经在文档层次结构中。 +- 包含完整的 [Hugo front-matter](#front-matter)。 + +选择下面的主题类型以查看建议的模板,帮助您入门。 + +| 主题类型 | 它是什么? | +| ---------- | ----------- | +| [概念]({{< ref "concept-template.md" >}}) | 回答问题,“这能帮助我解决什么问题?”避免重复 API 或组件规范;提供更多细节。 | +| [快速入门]({{< ref "quickstart-template.md" >}}) | 提供 "五分钟到 _wow_" 的体验。快速引导读者通过一个功能或 API 以及它在受控示例中的工作方式。 | +| [操作指南]({{< ref "howto-template.md" >}}) | 提供通过 Dapr 功能或技术的详细、实用的分步指南。鼓励读者尝试自己的场景,而不是快速入门中提供的受控场景。 | + +## docs.dapr.io 的要求 + +确保您的贡献不会破坏网站构建。Hugo 构建网站的方式需要遵循以下指导: + +### 文件和文件夹名称 + +文件和文件夹名称应在全局范围内唯一。 + - `\service-invocation` + - `service-invocation-overview.md` + +### Front-matter + +[Front-matter](https://www.docsy.dev/docs/adding-content/content/#page-frontmatter) 是将常规 markdown 文件升级为 Hugo 兼容文档以呈现到导航栏和目录中的内容。 + +每个页面都需要在文档顶部有一个这样的部分: + +```yaml +--- +type: docs +title: "页面标题" +linkTitle: "导航栏短标题" +weight: (数字) +description: "1+ 句描述文章" +--- +``` + +#### 示例 + +```yaml +--- +type: docs +title: "服务调用概述" +linkTitle: "概述" +weight: 10 +description: "Dapr 服务调用的快速概述以及如何在应用程序中使用它来调用服务" +--- +``` + +> 权重决定了左侧边栏中页面的顺序,0 为最顶部。 + +Front-matter 应包括所有字段,包括 type、title、linkTitle、weight 和 description。 + +- `title` 应为 1 句,末尾无句号 +- `linkTitle` 应为 1-3 个词,除了 How-to 前缀。 +- `description` 应为 1-2 句,说明读者将在本文档中学习、完成或执行的内容。 + +根据 [样式惯例](#styling-conventions),标题应仅大写第一个词和专有名词,除了 "How-To:" + +- "开始使用 Dapr 服务调用" +- "How-To: 设置本地 Redis 实例" + +### 引用其他页面 + +Hugo `ref` 和 `relref` [短代码](https://gohugo.io/content-management/cross-references/) 用于引用其他页面和部分。这些短代码还允许在页面被错误重命名或删除时中断构建。 + +例如,这个短代码,与其余的 markdown 页面内联书写,将链接到该部分/文件夹名称的 _index.md: + +```md +{{}} +``` + +而这个短代码将链接到特定页面: + +```md +{{}} +``` + +所有页面和文件夹需要有 _全局唯一名称_ 以便 ref 短代码正常工作。如果有重复名称,构建将中断并抛出错误。 + +#### 引用其他页面中的部分 + +要引用其他页面中的特定部分,请在引用的末尾添加 `#section-short-name`。 + +一般规则是,部分短名称是部分标题的文本,全部小写,空格改为 "-". 您可以通过以下方式检查部分短名称: + +1. 访问网站页面。 +1. 点击部分旁边的链接图标 (🔗)。 +1. 查看 URL 在导航栏中的呈现方式。 +1. 复制 "#" 后的内容作为您的部分短名称。 + +例如,对于此特定部分,完整的页面和部分引用将是: + +```md +{{}} +``` + +## 短代码 + +以下是撰写 Dapr 文档的有用短代码 + +### 图像 + +Docsy 和 Hugo 使用的 markdown 规范没有提供使用 markdown 符号调整图像大小的选项。相反,使用原始 HTML。 + +首先将图像放在 `/daprdocs/static/images` 下,命名约定为 `[page-name]-[image-name].[png|jpg|svg]`。 + +然后链接到图像: + +```md +图像描述 +``` + +不要忘记设置 `alt` 属性以保持文档的可读性和可访问性。 + +#### 示例 + +此 HTML 将在 `overview.md` 页面上显示 `dapr-overview.png` 图像: + +```md +Dapr 及其构建块的概述图 +``` + +### 选项卡内容 + +选项卡通过 [Hugo 短代码](https://gohugo.io/content-management/shortcodes/) 实现。 + +整体格式是: + +``` +{{}} + +{{% codetab %}} +[Tab1 的内容] +{{% /codetab %}} + +{{% codetab %}} +[Tab2 的内容] +{{% /codetab %}} + +{{< /tabs */>}} +``` + +您撰写的所有内容都将被渲染为 markdown,因此您可以包含图像、代码块、YouTube 视频等。 + +#### 示例 + +```` +{{}} + +{{% codetab %}} +```powershell +powershell -Command "iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1 | iex" +``` +{{% /codetab %}} + +{{% codetab %}} +```bash +wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash +``` +{{% /codetab %}} + +{{% codetab %}} +```bash +brew install dapr/tap/dapr-cli +``` +{{% /codetab %}} + +{{< /tabs */>}} +```` + +此示例将呈现为: + +{{< tabs Windows Linux MacOS>}} + +{{% codetab %}} + +```powershell +powershell -Command "iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1 | iex" +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +brew install dapr/tap/dapr-cli +``` + +{{% /codetab %}} + +{{< /tabs >}} + +### 嵌入代码片段 + +使用 `code-snippet` 短代码引用 `static/code` 目录中的代码片段。 + +``` +{{}} +``` + +{{% alert title="警告" color="warning" %}} +所有 Dapr 示例代码应自包含在单独的文件中,而不是在 markdown 中。使用这些技术突出显示用户应关注的示例代码部分。 +{{% /alert %}} + +使用 `lang`(默认 `txt`)参数配置用于语法高亮的语言。 + +使用 `marker` 参数将嵌入的片段限制为示例文件的一部分。当您只想显示较大文件的一部分时,这很有用。通常,您可以通过以下方式实现: + +1. 用注释包围感兴趣的代码。 +1. 将注释文本传递给 `marker`。 + +下面的短代码和代码示例: + +``` +{{}} +``` + +```python +import json +import time + +from dapr.clients import DaprClient + +#SAMPLE +with DaprClient() as d: + req_data = { + 'id': 1, + 'message': 'hello world' + } + + while True: + # Create a typed message with content type and body + resp = d.invoke_method( + 'invoke-receiver', + 'my-method', + data=json.dumps(req_data), + ) + + # Print the response + print(resp.content_type, flush=True) + print(resp.text(), flush=True) + + time.sleep(2) +#SAMPLE +``` + +将产生以下输出: + +{{< code-snippet file="contributing-1.py" lang="python" marker="#SAMPLE" >}} + +使用 `replace-key-[token]` 和 `replace-value-[token]` 参数将嵌入的片段限制为示例文件的一部分。当您想要缩略代码示例的一部分时,这很有用。支持多个 `token` 的多个替换。 + +下面的短代码和代码示例: + +``` +{{}} +``` + +```python +#IMPORTS +import json +import time +#IMPORTS + +from dapr.clients import DaprClient + +with DaprClient() as d: + req_data = { + 'id': 1, + 'message': 'hello world' + } + + while True: + # Create a typed message with content type and body + resp = d.invoke_method( + 'invoke-receiver', + 'my-method', + data=json.dumps(req_data), + ) + + # Print the response + print(resp.content_type, flush=True) + print(resp.text(), flush=True) + + time.sleep(2) +``` + +将产生以下输出: + +{{< code-snippet file="./contributing-2.py" lang="python" replace-key-imports="#IMPORTS" replace-value-imports="# Import statements" >}} + +### YouTube 视频 + +Hugo 可以使用短代码自动嵌入 YouTube 视频: + +``` +{{}} +``` + +#### 示例 + +给定视频 https://youtu.be/dQw4w9WgXcQ + +短代码将是: + +``` +{{}} +``` + +### 按钮 + +要在网页中创建按钮,请使用 `button` 短代码。 + +可选的 "newtab" 参数将指示页面是否应在新选项卡中打开。选项为 "true" 或 "false"。默认值为 "false",页面将在同一选项卡中打开。 + +#### 链接到外部页面 + +``` +{{}} +``` + +{{< button text="我的按钮" link="https://example.com" >}} + +#### 链接到其他文档页面 + +您也可以在按钮中引用页面: + +``` +{{}} +``` + +{{< button text="我的按钮" page="contributing" newtab="true" >}} + +#### 按钮颜色 + +您可以使用 Bootstrap 颜色自定义颜色: + +``` +{{}} +{{}} +{{}} +{{}} +{{}} +{{}} +``` + +{{< button text="我的按钮" link="https://example.com" color="primary" >}} +{{< button text="我的按钮" link="https://example.com" color="secondary" >}} +{{< button text="我的按钮" link="https://example.com" color="success" >}} +{{< button text="我的按钮" link="https://example.com" color="danger" >}} +{{< button text="我的按钮" link="https://example.com" color="warning" >}} +{{< button text="我的按钮" link="https://example.com" color="info" >}} + +### 参考 + +[Docsy 撰写指南](https://www.docsy.dev/docs/adding-content/) + +## 翻译 + +Dapr 文档支持使用 git 子模块和 Hugo 内置语言支持将语言翻译添加到文档中。 + +您可以在 [PR 1286](https://github.com/dapr/docs/pull/1286) 中找到添加中文语言支持的示例 PR。 + +添加语言的步骤: + +- 在文档库中打开一个问题,请求创建一个新的语言特定文档库 +- 创建后,在文档库中创建一个 git 子模块: + + ```sh + git submodule add translations/ + ``` + +- 在 `daprdocs/config.toml` 中添加一个语言条目: + + ```toml + [languages.] + title = "Dapr 文档" + weight = 3 + contentDir = "content/" + languageName = "" + ``` + +- 在 `daprdocs/config.toml` 中创建一个挂载: + + ```toml + [[module.mounts]] + source = "../translations/docs-/content/" + target = "content" + lang = "" + ``` + +- 根据需要为所有其他翻译目录重复上述步骤。 + +## 下一步 + +通过复制并从 [Dapr 文档模板]({{< ref docs-templates >}}) 开始。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/contributing/docs-contrib/docs-templates/_index.md b/src/translated_content/zh_CN/docs/contributing/docs-contrib/docs-templates/_index.md new file mode 100644 index 000000000..933ca937a --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/docs-contrib/docs-templates/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "Dapr 文档模板建议" +linkTitle: "文档模板" +weight: 100 +description: 为新的 Dapr 文档文章提供模板建议 +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/contributing/docs-contrib/docs-templates/concept-template.md b/src/translated_content/zh_CN/docs/contributing/docs-contrib/docs-templates/concept-template.md new file mode 100644 index 000000000..a209496fb --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/docs-contrib/docs-templates/concept-template.md @@ -0,0 +1,100 @@ +--- +type: docs +title: "概念文章模板" +linkTitle: "概念模板" +weight: 10 +description: 创建概念文章的建议模板和指导 +--- + +## 贡献新的概念或概述文章 + +概念(或概述)文章旨在回答以下问题: + +- 为什么这个功能对你很重要? +- 它能帮助你解决哪些问题? + +尽管组件、API 或 SDK 规范可以帮助读者理解如何使用这些功能,概念文章则提供了更深入的背景和上下文。请链接到规范文章,但尽量避免简单重复规范内容。 + +在为你的概念文章命名时,确保其名称、参数和术语与规范保持一致。如有必要,请同时更新两者。 + +{{% alert title="注意" color="primary" %}} +此模板仅为建议。可以根据文档的目的进行调整。 +{{% /alert %}} + +了解更多关于[为 Dapr 文档做贡献]({{< ref contributing-docs.md >}})的信息,例如[前置内容]({{< ref "contributing-docs.md#front-matter" >}})和[短代码]({{< ref "contributing-docs.md#shortcodes" >}})。 + +### 模板 + +```md +--- +type: #必填; docs +title: #必填; 简洁明了的标题 +linkTitle: #必填; 简短标题 +weight: #必填; 根据层级使用正确的权重 +description: #必填; 对文章内容的简短描述 +--- + + + + + + + + + +## <章节 1 H2> + + + +## <章节 2 H2> + + + +## <章节 3 H2> + + + + + +## 体验 <概念> + + + +### 快速开始和教程 + +想要体验 Dapr <主题> API?通过以下快速开始和教程来了解 <主题> 的实际应用: + +| 快速开始/教程 | 描述 | +| ------------------- | ----------- | +| [<主题> 快速开始](link) | 快速开始的描述。 | +| [<主题> 教程](link) | 教程的描述。 | + +### 在你的应用中直接使用 <主题> + +想跳过快速开始?没问题。你可以在你的应用中直接使用 <主题> 构建块。在[Dapr 安装完成](link)后,你可以开始使用 <主题> API,从[<主题> 操作指南](link)开始。 + +--> + +## 下一步 + + +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/contributing/docs-contrib/docs-templates/howto-template.md b/src/translated_content/zh_CN/docs/contributing/docs-contrib/docs-templates/howto-template.md new file mode 100644 index 000000000..de121d21f --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/docs-contrib/docs-templates/howto-template.md @@ -0,0 +1,86 @@ +--- +type: docs +title: "操作指南模板" +linkTitle: "操作模板" +weight: 30 +description: 创建操作指南的建议模板和指导 +--- + +## 贡献新的操作指南 + +操作指南为读者提供逐步的实用指导,帮助他们实现以下目标: + +- 启用某个功能 +- 集成某项技术 +- 在特定场景中使用 Dapr + +操作指南相较于快速入门,是更高级别的自助文档。操作场景通常需要更长的时间,并且更容易应用于读者的个人项目或环境。 + +命名操作文档时,应在文件名中包含子目录名称。如果需要创建新的子目录,请确保其具有描述性,并包含相关组件或概念名称。例如,_pubsub-namespaces_。 + +{{% alert title="注意" color="primary" %}} +此模板仅为建议。可以根据文档的目的进行调整。 +{{% /alert %}} + +了解更多关于[贡献 Dapr 文档]({{< ref contributing-docs.md >}})的信息,例如[前置内容]({{< ref "contributing-docs.md#front-matter" >}})和[短代码]({{< ref "contributing-docs.md#shortcodes" >}})。 + +### 模板 + +```md +--- +type: #必填; docs +title: #必填; "如何:简洁明了的标题" +linkTitle: #必填; "如何:比常规标题更短,以便在目录中显示" +weight: #必填; 根据层级使用正确的权重 +description: #必填; 对文章内容的期望进行一句话描述 +--- + + + + + + + + + + + + + +## <操作或任务> + + + +## <操作或任务> + + + + + +## 后续步骤 + + + +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/contributing/docs-contrib/docs-templates/quickstart-template.md b/src/translated_content/zh_CN/docs/contributing/docs-contrib/docs-templates/quickstart-template.md new file mode 100644 index 000000000..ab8151e39 --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/docs-contrib/docs-templates/quickstart-template.md @@ -0,0 +1,92 @@ +--- +type: docs +title: "快速入门指南模板" +linkTitle: "快速入门模板" +weight: 20 +description: 创建快速入门指南的建议模板和指导 +--- + +## 贡献新的快速入门指南 + +Dapr 快速入门指南包含一些简明的指令,帮助读者完成一个预先准备好的快速入门项目,这些项目保存在 [dapr/quickstarts 仓库](https://github.com/dapr/quickstarts)中。这些快速入门将整个功能或构建块集中在一起,使读者能够轻松体验其工作原理,而不影响他们自己的项目。 + +快速入门指令应当简洁明了。快速入门指南的唯一目的是简单地指导读者完成准备好的快速入门。如果您想解释快速入门背后的概念,请将读者引导到相关的概念文章以获取更多背景信息。 + +{{% alert title="注意" color="primary" %}} +此模板仅为建议。可以根据文档的具体需求进行调整。 +{{% /alert %}} + +了解更多关于如何[贡献 Dapr 文档]({{< ref contributing-docs.md >}})的信息,例如[前置内容]({{< ref "contributing-docs.md#front-matter" >}})和[短代码]({{< ref "contributing-docs.md#shortcodes" >}})。 + +### 模板 + +```md +--- +type: #必填; docs +title: #必填; "快速入门:简洁明了的标题" +linkTitle: #必填; 这将在文档目录中显示 +weight: #必填; 根据层级使用正确的权重 +description: #必填; 一句话描述文章的预期内容 +--- + + + + + + + + + + + +## 前置条件 + + + +## 步骤 1:设置环境 + + + +## 步骤 2:<操作或任务> + + + + + +## 告诉我们您的想法! + +我们正在不断努力改进我们的快速入门示例,并重视您的反馈。您觉得这个快速入门有帮助吗?您有改进建议吗? + +欢迎加入我们的 [discord 频道](https://discord.gg/22ZtJrNe)进行讨论。 + + + +## 下一步 + + + + + +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/contributing/docs-contrib/maintainer-guide.md b/src/translated_content/zh_CN/docs/contributing/docs-contrib/maintainer-guide.md new file mode 100644 index 000000000..989cda2f6 --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/docs-contrib/maintainer-guide.md @@ -0,0 +1,411 @@ +--- +type: docs +title: "维护者指南" +linkTitle: "维护者指南" +weight: 20 +description: "成为 Dapr 文档维护者和审批者的入门指南。" +--- + +在本指南中,您将学习如何履行 Dapr 文档维护者和审批者的日常职责。要成功完成这些任务,您需要在 [`dapr/docs`](https://github.com/dapr/docs) 仓库中拥有审批者或维护者的权限。 + +如果您想了解如何为 Dapr 文档做出贡献,请查看 [贡献者指南]({{< ref contributing-docs.md >}})。 + +## 分支管理指南 + +Dapr 文档的分支管理与大多数代码仓库不同。没有 `main` 分支,每个分支都与运行时发布的主要和次要版本相对应。 + +完整的分支列表请访问 [文档仓库](https://github.com/dapr/docs#branch-guidance)。 + +阅读 [贡献者指南]({{< ref "contributing-docs.md#branch-guidance" >}}) 以获取有关发布分支的更多信息。 + +## 从当前发布分支合并到预发布分支 + +作为文档审批者或维护者,您需要定期进行合并操作,以确保预发布分支与当前发布分支保持同步。建议每周将当前分支的更新合并到预发布分支。 + +以下步骤中,将 `v1.0` 视为当前发布版本,将 `v1.1` 视为即将发布版本。 + +1. 在 Visual Studio Code 中打开 Dapr 文档仓库。 +1. 在本地仓库中,切换到最新分支 (`v1.0`) 并同步更改: + + ```bash + git pull upstream v1.0 + git push origin v1.0 + ``` + +1. 切换到即将发布的分支 (`v1.1`) 并同步更改: + + ```bash + git pull upstream v1.1 + git push origin v1.1 + ``` + +1. 基于即将发布的版本创建一个新分支: + + ```bash + git checkout -b upmerge_MM-DD + ``` + +1. 在终端中,从最新发布分支合并到新建的合并分支: + + ```bash + git merge --no-ff --no-commit v1.0 + ``` + +1. 在终端中,确保合并的文件准确无误。在 VS Code 中检查是否有合并冲突。删除不需要合并的配置更改或版本信息。 +1. 提交暂存的更改并推送到合并分支 (`upmerge_MM-DD`)。 +1. 从合并分支创建一个 PR 到即将发布的分支 (`v1.1`)。 +1. 审查 PR,确保没有意外更改被推送到合并分支。 + +## 发布流程 + +Dapr 文档必须与 Dapr 项目发布中包含的功能和更新保持一致。在 Dapr 发布日期之前,请确保: + +- 所有新功能或更新都已充分记录和审查。 +- 即将发布的文档 PR 指向发布分支。 + +以下步骤中,将 `v1.0` 视为最新发布版本,将 `v1.1` 视为即将发布版本。 + +文档的发布流程包括以下内容: + +- 将最新发布版本合并到即将发布的分支 +- 更新最新和即将发布的 Hugo 配置文件 +- 为下一个版本创建新的 Azure 静态 Web 应用 +- 为下一个版本的网站创建新的 DNS 条目 +- 为下一个版本创建新的 git 分支 + +### 合并操作 + +首先,从最新发布版本合并到即将发布的分支,执行 [文档合并操作](#upmerge-from-current-release-branch-to-the-pre-release-branch)。 + +### 更新 Hugo 配置 + +合并后,准备文档分支以进行发布。在两个单独的 PR 中,您需要: + +- 存档最新发布版本。 +- 将预览/发布分支作为文档的当前在线版本。 +- 创建一个新的预览分支。 + +#### 最新发布版本 + +这些步骤将准备最新发布分支以进行存档。 + +1. 在 VS Code 中打开 Dapr 文档仓库。 +1. 切换到最新分支 (`v1.0`) 并同步更改: + + ```bash + git pull upstream v1.0 + git push origin v1.0 + ``` + +1. 基于最新发布创建一个新分支: + + ```bash + git checkout -b release_v1.0 + ``` + +1. 在 VS Code 中,导航到 `/daprdocs/config.toml`。 +1. 在 `# Versioning` 部分(大约第 154 行)添加以下 TOML: + + ```toml + version_menu = "v1.0" + version = "v1.0" + archived_version = true + url_latest_version = "https://docs.dapr.io" + + [[params.versions]] + version = "v1.2 (preview)" + url = "v1-2.docs.dapr.io" + [[params.versions]] + version = "v1.1 (latest)" + url = "#" + [[params.versions]] + version = "v1.0" + url = "https://v1-0.docs.dapr.io" + ``` + +1. 删除 `.github/workflows/website-root.yml`。 +1. 提交暂存的更改并推送到您的分支 (`release_v1.0`)。 +1. 从 `release_v1.0` 打开一个 PR 到 `v1.0`。 +1. 让文档维护者或审批者进行审查。等待合并 PR 直到发布。 + +#### 即将发布版本 + +这些步骤将准备即将发布的分支以提升为最新发布。 + +1. 在 VS Code 中打开 Dapr 文档仓库。 +1. 切换到即将发布的分支 (`v1.1`) 并同步更改: + + ```bash + git pull upstream v1.1 + git push origin v1.1 + ``` + +1. 基于即将发布的版本创建一个新分支: + + ```bash + git checkout -b release_v1.1 + ``` + +1. 在 VS Code 中,导航到 `/daprdocs/config.toml`。 +1. 更新第 1 行为 `baseURL - https://docs.dapr.io/`。 +1. 更新 `# Versioning` 部分(大约第 154 行)以显示正确的版本和标签: + + ```toml + # Versioning + version_menu = "v1.1 (latest)" + version = "v1.1" + archived_version = false + url_latest_version = "https://docs.dapr.io" + + [[params.versions]] + version = "v1.2 (preview)" + url = "v1-2.docs.dapr.io" + [[params.versions]] + version = "v1.1 (latest)" + url = "#" + [[params.versions]] + version = "v1.0" + url = "https://v1-0.docs.dapr.io" + ``` + +1. 导航到 `.github/workflows/website-root.yml`。 +1. 更新触发工作流的分支: + + ```yml + name: Azure Static Web App Root + + on: + push: + branches: + - v1.1 + pull_request: + types: [opened, synchronize, reopened, closed] + branches: + - v1.1 + ``` + +1. 导航到 `/README.md`。 +1. 更新版本表: + +```markdown +| Branch | Website | Description | +| ------------------------------------------------------------ | -------------------------- | ------------------------------------------------------------------------------------------------ | +| [v1.1](https://github.com/dapr/docs) (primary) | https://docs.dapr.io | 最新 Dapr 发布文档。拼写错误修正、澄清和大多数文档都在这里。 | +| [v1.2](https://github.com/dapr/docs/tree/v1.2) (pre-release) | https://v1-2.docs.dapr.io/ | 预发布文档。仅适用于 v1.2+ 的文档更新在这里。 | +``` + +1. 更新 `dapr-latest-version.html` 短代码部分为新的次要/补丁版本(在此示例中为 `1.1.0` 和 `1.1`)。 +1. 提交暂存的更改并推送到您的分支 (`release_v1.1`)。 +1. 从 `release/v1.1` 打开一个 PR 到 `v1.1`。 +1. 让文档维护者或审批者进行审查。等待合并 PR 直到发布。 + +#### 未来预览分支 + +##### 创建预览分支 + +1. 在 GitHub UI 中,选择分支下拉菜单并选择 **查看所有分支**。 +1. 点击 **新建分支**。 +1. 在 **新分支名称** 中,输入预览分支版本号。在此示例中,它将是 `v1.2`。 +1. 选择 **v1.1** 作为来源。 +1. 点击 **创建新分支**。 + +##### 配置预览分支 + +1. 在终端窗口中,导航到 `docs` 仓库。 +1. 切换到即将发布的分支 (`v1.1`) 并同步更改: + + ```bash + git pull upstream v1.1 + git push origin v1.1 + ``` + +1. 基于 `v1.1` 创建一个新分支并命名为 `v1.2`: + + ```bash + git checkout -b release_v1.1 + ``` + +1. 重命名 `.github/workflows/website-v1-1.yml` 为 `.github/workflows/website-v1-2.yml`。 +1. 在 VS Code 中打开 `.github/workflows/website-v1-2.yml` 并更新名称、触发器和部署目标为 1.2: + + ```yml + name: Azure Static Web App v1.2 + + on: + push: + branches: + - v1.2 + pull_request: + types: [opened, synchronize, reopened, closed] + branches: + - v1.2 + + ... + + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_V1_2 }} + repo_token: ${{ secrets.GITHUB_TOKEN }} + + ... + + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_V1_2 }} + skip_deploy_on_missing_secrets: true + ``` + +1. 导航到 `daprdocs/config.toml` 并更新 `baseURL` 以指向新的预览网站: + + ```toml + baseURL = "https://v1-2.docs.dapr.io" + ``` + +1. 更新 `# GitHub Information` 和 `# Versioning` 部分(大约第 148 行)以显示正确的版本和标签: + + ```toml + # GitHub Information + github_repo = "https://github.com/dapr/docs" + github_project_repo = "https://github.com/dapr/dapr" + github_subdir = "daprdocs" + github_branch = "v1.2" + + # Versioning + version_menu = "v1.2 (preview)" + version = "v1.2" + archived_version = false + url_latest_version = "https://docs.dapr.io" + + [[params.versions]] + version = "v1.2 (preview)" + url = "#" + [[params.versions]] + version = "v1.1 (latest)" + url = "https://docs.dapr.io" + [[params.versions]] + version = "v1.0" + url = "https://v1-0.docs.dapr.io" + ``` + +1. 提交暂存的更改并推送到针对 v1.2 分支的新 PR。 +1. 在发布后以及其他 `v1.0` 和 `v1.1` PR 合并后再合并 PR。 + +### 为未来发布创建新网站 + +接下来,为未来的 Dapr 发布创建一个新网站。为此,您需要: + +- 部署一个 Azure 静态 Web 应用。 +- 通过 CNCF 请求配置 DNS。 + +#### 先决条件 +- 在 `dapr/docs` 仓库中拥有文档维护者身份。 +- 访问活动的 Dapr Azure 订阅,并具有创建资源的贡献者或所有者访问权限。 +- 在您的机器上安装 [Azure Developer CLI](https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd?tabs=winget-windows%2Cbrew-mac%2Cscript-linux&pivots=os-windows)。 +- 您自己的 [`dapr/docs` 仓库](https://github.com/dapr/docs) 的分叉已克隆到您的机器。 + +#### 部署 Azure 静态 Web 应用 + +为未来的 Dapr 发布部署一个新的 Azure 静态 Web 应用。在此示例中,我们使用 v1.1 作为未来发布。 + +1. 在终端窗口中,导航到 `dapr/docs` 目录中的 `iac/swa` 文件夹。 + + ```bash + cd .github/iac/swa + ``` + +1. 使用 Dapr Azure 订阅登录 Azure Developer CLI (`azd`)。 + + ```bash + azd login + ``` + +1. 在浏览器提示中,验证您正在以 Dapr 身份登录并完成登录。 + +1. 在新终端中,替换以下值为您偏好的网站值。 + + ```bash + export AZURE_RESOURCE_GROUP=rg-dapr-docs-test + export IDENTITY_RESOURCE_GROUP=rg-my-identities + export AZURE_STATICWEBSITE_NAME=daprdocs-latest + ``` + +1. 创建一个新的 [`azd` 环境](https://learn.microsoft.com/azure/developer/azure-developer-cli/faq#what-is-an-environment-name)。 + + ```bash + azd env new + ``` + +1. 当提示时,输入一个新的环境名称。在此示例中,您可以将环境命名为:`dapr-docs-v1-1`。 + +1. 环境创建完成后,使用以下命令将 Dapr 文档 SWA 部署到新环境中: + + ```bash + azd up + ``` + +1. 当提示时,选择一个 Azure 订阅和位置。将这些与 Dapr Azure 订阅匹配。 + +#### 在 Azure 门户中配置 SWA + +前往 [Azure 门户](https://portal.azure.com) 中的 Dapr 订阅,并验证您的新 Dapr 文档站点是否已部署。 + +可选地,使用门户中的 **静态 Web 应用** > **访问控制 (IAM)** 刀片授予正确的最小权限以进行入站发布和对依赖项的出站访问。 + +#### 配置 DNS + +1. 在 Azure 门户中,从您刚刚创建的新 SWA 中,导航到左侧菜单中的 **自定义域**。 +1. 复制 Web 应用的 "CNAME" 值。 +1. 使用您自己的帐户,[提交 CNCF 工单](https://jira.linuxfoundation.org/secure/Dashboard.jspa) 以创建一个新的域名映射到您复制的 CNAME 值。对于此示例,要为 Dapr v1.1 创建一个新域,您将请求映射到 `v1-1.docs.dapr.io`。 + + 请求解决可能需要一些时间。 + +1. 确认新域后,返回到门户中的静态 Web 应用。 +1. 导航到 **自定义域** 刀片并选择 **+ 添加**。 +1. 选择 **其他 DNS 上的自定义域**。 +1. 在 **域名** 下输入 `v1-1.docs.dapr.io`。点击 **下一步**。 +1. 将 **主机名记录类型** 保持为 `CNAME`,并复制 **值** 的值。 +1. 点击 **添加**。 +1. 导航到 `https://v1-1.docs.dapr.io` 并验证空白网站是否正确加载。 + +您可以为任何预览版本重复这些步骤。 + +### 在新的 Dapr 发布日期 + +1. 等待所有代码/容器/Helm 图表发布。 +1. 合并从 `release_v1.0` 到 `v1.0` 的 PR。删除 release/v1.0 分支。 +1. 合并从 `release_v1.1` 到 `v1.1` 的 PR。删除 release/v1.1 分支。 +1. 合并从 `release_v1.2` 到 `v1.2` 的 PR。删除 release/v1.2 分支。 + +恭喜发布新文档!🚀 🎉 🎈 + +## 拉取 SDK 文档更新 + +SDK 文档位于每个 SDK 仓库中。对 SDK 文档所做的更改会推送到相关的 SDK 仓库。例如,要更新 Go SDK 文档,您需要将更改推送到 `dapr/go-sdk` 仓库。在您将最新的 `dapr/go-sdk` 提交拉入 `dapr/docs` 当前版本分支之前,您的 Go SDK 文档更新不会反映在 Dapr 文档站点上。 + +要将 SDK 文档更新带到 Dapr 文档站点,您需要执行一个简单的 `git pull`。此示例涉及 Go SDK,但适用于所有 SDK。 + +1. 将最新的上游拉入您的本地 `dapr/docs` 版本分支。 + +1. 切换到 `dapr/docs` 目录的根目录。 + +1. 切换到 Go SDK 仓库。此命令将您从 `dapr/docs` 上下文切换到 `dapr/go-sdk` 上下文。 + + ```bash + cd sdkdocs/go + ``` + +1. 切换到 `dapr/go-sdk` 中的 `main` 分支。 + + ```bash + git checkout main + ``` + +1. 拉取最新的 Go SDK 提交。 + + ```bash + git pull upstream main + ``` + +1. 切换到 `dapr/docs` 上下文以提交、推送并创建 PR。 + +## 下一步 + +有关为 Dapr 文档做出贡献的指导,请阅读 [贡献者指南]({{< ref contributing-docs.md >}})。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/contributing/presentations.md b/src/translated_content/zh_CN/docs/contributing/presentations.md new file mode 100644 index 000000000..33dfdb971 --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/presentations.md @@ -0,0 +1,38 @@ +--- +type: docs +title: "Dapr 演讲指南" +linkTitle: "演讲" +weight: 20 +description: 如何进行 Dapr 演讲及示例 +--- + +我们欢迎社区成员分享关于 Dapr 的演讲,并推广 Dapr 的各种强大功能!我们提供了一个 PowerPoint 模板文件,帮助您快速开始。 + +{{< button text="下载 Dapr 演示文稿" link="/presentations/dapr-slidedeck.pptx.zip" >}} + +{{% alert color="primary" %}} +如果您在 MacOS 上使用 PowerPoint 模板,请安装 Space Grotesk 字体以确保文本正确显示: +```sh +brew install --cask font-space-grotesk +``` +{{% /alert %}} + +## 如何进行 Dapr 演讲 + +- 首先下载 [Dapr 演示文稿](/presentations/dapr-slidedeck.pptx.zip),其中包含您进行 Dapr 演讲所需的幻灯片和图表。 +- 接下来,查看文档以确保您理解 [概念]({{< ref concepts >}})。 +- 使用 Dapr [快速入门](https://github.com/dapr/quickstarts) 和 [示例](https://github.com/dapr/samples) 仓库,展示如何使用 Dapr。 + +## 过往的 Dapr 演讲 + +| 演讲 | 录音 | 幻灯片 | +|--------------|-----------|------| +| 在 Kubernetes 中运行事件驱动的 Pub/Sub 微服务与 Dapr | [链接](https://youtu.be/-4sHUvfk2Eg) | N/A +| Ignite 2019: Mark Russinovich 展示云原生应用的未来 | [链接](https://www.youtube.com/watch?v=LAUDVk8PaCY) | [链接](/presentations/2019IgniteCloudNativeApps.pdf) +| Azure Community Live: 使用 DAPR 构建微服务应用与 Mark Fussell | [链接](https://www.youtube.com/watch?v=CgqI7nen-Ng) | N/A +| Ready 2020: Mark Russinovich 展示云原生应用 | [链接](https://youtu.be/eJCu6a-x9uo?t=1614) | [链接](/presentations/2020ReadyCloudNativeApps.pdf) +| Ignite 2021: Mark Russinovich 发布 Dapr v1.0 | [链接](https://youtu.be/69PrhWQorEM?t=3789) | N/A + +## 其他资源 + +在 [社区](https://github.com/dapr/community) 仓库中可以找到更多 Dapr 资源。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/contributing/roadmap.md b/src/translated_content/zh_CN/docs/contributing/roadmap.md new file mode 100644 index 000000000..ebc106201 --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/roadmap.md @@ -0,0 +1,10 @@ +--- +type: docs +title: "Dapr 发展规划" +linkTitle: "发展规划" +description: "Dapr 发展规划为社区提供了对项目优先级的深入了解" +weight: 30 +no_list: true +--- + +请访问[此文档](https://github.com/dapr/community/blob/master/roadmap.md)以了解 Dapr 项目的发展规划。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/contributing/sdk-contrib/_index.md b/src/translated_content/zh_CN/docs/contributing/sdk-contrib/_index.md new file mode 100644 index 000000000..a8029544f --- /dev/null +++ b/src/translated_content/zh_CN/docs/contributing/sdk-contrib/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "SDK 贡献指引" +linkTitle: "SDKs" +weight: 80 +description: 如何为 Dapr SDK 文档做出贡献 +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/_index.md b/src/translated_content/zh_CN/docs/developing-applications/_index.md new file mode 100644 index 000000000..74602679f --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "使用 Dapr 进行应用程序开发" +linkTitle: "使用 Dapr 开发应用程序" +description: "提供使用 Dapr 构建应用程序的工具、技巧和相关信息" +weight: 30 +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/_index.md new file mode 100644 index 000000000..03a6d6097 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/_index.md @@ -0,0 +1,11 @@ +--- +type: docs +title: "构建模块" +linkTitle: "构建模块" +weight: 10 +description: "Dapr 提供的功能,旨在解决分布式应用程序开发中的常见挑战" +--- + +在**概念**部分中,您可以查看 Dapr 构建模块的高级[概述]({{< ref building-blocks-concept >}})。 + +展示不同 Dapr API 构建模块的图示 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/_index.md new file mode 100644 index 000000000..0aed56cdb --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/_index.md @@ -0,0 +1,14 @@ +--- +type: docs +title: "Actors" +linkTitle: "Actors" +weight: 60 +description: 将代码和数据封装在可重用的actor对象中,这是一种常见的微服务设计模式 +--- + +{{% alert title="更多关于Dapr Actors的信息" color="primary" %}} +了解如何使用Dapr Actors的更多信息: +- 尝试[Actors快速入门]({{< ref actors-quickstart.md >}})。 +- 使用任意一个[Dapr SDK]({{< ref sdks >}})来探索actors。 +- 查看[Actors API参考文档]({{< ref actors_api.md >}})。 +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actor-reentrancy.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actor-reentrancy.md new file mode 100644 index 000000000..32d0f2fa8 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actor-reentrancy.md @@ -0,0 +1,189 @@ +--- +type: docs +title: "如何:在Dapr中启用和使用actor重入" +linkTitle: "如何:actor重入" +weight: 80 +description: 了解更多关于actor重入的信息 +--- + +[虚拟actor模式](https://www.microsoft.com/research/project/orleans-virtual-actors/)的一个核心原则是actor的单线程执行特性。没有重入时,Dapr运行时会锁定所有actor请求。第二个请求必须等到第一个请求完成后才能启动。这意味着actor不能调用自身,也不能被另一个actor调用,即使它们属于同一调用链。 + +重入通过允许同一链或上下文的请求重新进入已锁定的actor来解决这个问题。这在以下场景中非常有用: +- 一个actor想要调用自身的方法 +- actor在工作流中用于执行任务,然后回调到协调actor。 + +重入允许的调用链示例如下: + +``` +Actor A -> Actor A +Actor A -> Actor B -> Actor A +``` + +通过重入,您可以执行更复杂的actor调用,而不影响虚拟actor的单线程特性。 + +显示协调工作流actor调用工作actor或actor调用自身方法的重入图示 + +`maxStackDepth`参数用于设置一个值,以控制对同一actor可以进行多少次重入调用。默认情况下,这个值为**32**,通常已经足够。 + +## 配置actor运行时以启用重入 + +要启用actor重入,必须提供适当的配置。这是通过actor的`GET /dapr/config`端点完成的,类似于其他actor配置元素。 + +{{< tabs ".NET" JavaScript Python Java Go >}} + +{{% codetab %}} + + +```csharp +public class Startup +{ + public void ConfigureServices(IServiceCollection services) + { + services.AddSingleton(); + services.AddActors(options => + { + options.Actors.RegisterActor(); + options.ReentrancyConfig = new Dapr.Actors.ActorReentrancyConfig() + { + Enabled = true, + MaxStackDepth = 32, + }; + }); + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```js +import { CommunicationProtocolEnum, DaprClient, DaprServer } from "@dapr/dapr"; + +// 使用DaprClientOptions配置actor运行时。 +const clientOptions = { + actor: { + reentrancy: { + enabled: true, + maxStackDepth: 32, + }, + }, +}; +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```python +from fastapi import FastAPI +from dapr.ext.fastapi import DaprActor +from dapr.actor.runtime.config import ActorRuntimeConfig, ActorReentrancyConfig +from dapr.actor.runtime.runtime import ActorRuntime +from demo_actor import DemoActor + +reentrancyConfig = ActorReentrancyConfig(enabled=True) +config = ActorRuntimeConfig(reentrancy=reentrancyConfig) +ActorRuntime.set_actor_config(config) +app = FastAPI(title=f'{DemoActor.__name__}Service') +actor = DaprActor(app) + +@app.on_event("startup") +async def startup_event(): + # 注册DemoActor + await actor.register_actor(DemoActor) + +@app.get("/MakeExampleReentrantCall") +def do_something_reentrant(): + # 在这里调用另一个actor,重入将自动处理 + return +``` +{{% /codetab %}} + +{{% codetab %}} + + +``` + +``` + +{{% /codetab %}} + +{{% codetab %}} + +以下是一个用Golang编写的actor代码片段,通过HTTP API提供重入配置。重入尚未包含在Go SDK中。 + +```go +type daprConfig struct { + Entities []string `json:"entities,omitempty"` + ActorIdleTimeout string `json:"actorIdleTimeout,omitempty"` + ActorScanInterval string `json:"actorScanInterval,omitempty"` + DrainOngoingCallTimeout string `json:"drainOngoingCallTimeout,omitempty"` + DrainRebalancedActors bool `json:"drainRebalancedActors,omitempty"` + Reentrancy config.ReentrancyConfig `json:"reentrancy,omitempty"` +} + +var daprConfigResponse = daprConfig{ + []string{defaultActorType}, + actorIdleTimeout, + actorScanInterval, + drainOngoingCallTimeout, + drainRebalancedActors, + config.ReentrancyConfig{Enabled: true, MaxStackDepth: &maxStackDepth}, +} + +func configHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(daprConfigResponse) +} +``` + +### 处理重入请求 + +处理重入请求的关键在于`Dapr-Reentrancy-Id`头。此头的值用于将请求与其调用链匹配,并允许它们绕过actor的锁。 + +此头由Dapr运行时为任何具有重入配置的actor请求生成。一旦生成,它用于锁定actor,并且必须传递给所有后续请求。以下是一个actor处理重入请求的示例: + +```go +func reentrantCallHandler(w http.ResponseWriter, r *http.Request) { + /* + * 省略。 + */ + + req, _ := http.NewRequest("PUT", url, bytes.NewReader(nextBody)) + + reentrancyID := r.Header.Get("Dapr-Reentrancy-Id") + req.Header.Add("Dapr-Reentrancy-Id", reentrancyID) + + client := http.Client{} + resp, err := client.Do(req) + + /* + * 省略。 + */ +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 演示 + +观看此[视频](https://www.youtube.com/watch?v=QADHQ5v-gww&list=PLcip_LgkYwzuF-OV6zKRADoiBvUvGhkao&t=674s)以了解如何使用actor重入。 + +
+ +
+ +## 下一步 + +{{< button text="Dapr SDK中的actor" page="developing-applications/sdks/#sdk-languages" >}} + +## 相关链接 + +- [actor API参考]({{< ref actors_api.md >}}) +- [actor概述]({{< ref actors-overview.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actors-features-concepts.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actors-features-concepts.md new file mode 100644 index 000000000..6286391d2 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actors-features-concepts.md @@ -0,0 +1,104 @@ +--- +type: docs +title: "Actor 的运行时特性" +linkTitle: "运行时特性" +weight: 20 +description: "了解 Dapr 中 Actor 的特性和概念" +aliases: + - "/zh-hans/developing-applications/building-blocks/actors/actors-background" +--- + +在您已经从高层次上了解了 [Actor 构建块]({{< ref "actors-overview.md" >}})之后,让我们深入探讨 Dapr 中 Actor 的特性和概念。 + +## Actor 的生命周期 + +Dapr 中的 Actor 是虚拟的,这意味着它们的生命周期与内存中的表示无关。因此,不需要显式地创建或销毁它们。Dapr 的 Actor 运行时会在首次收到某个 Actor ID 的请求时自动激活该 Actor。如果某个 Actor 在一段时间内未被使用,Dapr 的 Actor 运行时会对其进行垃圾回收,但会保留其存在的信息,以便在需要时重新激活。 + +调用 Actor 方法、定时器和提醒会重置 Actor 的空闲时间。例如,提醒的触发会保持 Actor 的活跃状态。 +- Actor 的提醒会在无论其活跃与否的情况下触发。如果提醒触发了一个不活跃的 Actor,它会先激活该 Actor。 +- Actor 的定时器触发会重置空闲时间;然而,定时器仅在 Actor 活跃时触发。 + +Dapr 运行时用于判断 Actor 是否可以被垃圾回收的空闲超时和扫描间隔是可配置的。当 Dapr 运行时调用 Actor 服务以获取支持的 Actor 类型时,可以传递此信息。 + +这种虚拟 Actor 生命周期的抽象带来了一些注意事项,尽管 Dapr 的 Actor 实现有时会偏离这种模型。 + +Actor 在首次向其 Actor ID 发送消息时会自动激活(即构建 Actor 对象)。经过一段时间后,Actor 对象会被垃圾回收。将来再次使用该 Actor ID 会导致构建新的 Actor 对象。Actor 的状态超越对象的生命周期,因为状态存储在为 Dapr 运行时配置的状态提供者中。 + +## 分布和故障转移 + +为了提供可扩展性和可靠性,Actor 实例分布在整个集群中,Dapr 会根据需要自动将它们从故障节点迁移到健康节点。 + +Actor 分布在 Actor 服务的实例中,这些实例分布在集群中的节点上。每个服务实例包含给定 Actor 类型的一组 Actor。 + +### Actor 放置服务 + +Dapr 的 Actor 运行时通过 Actor `Placement` 服务为您管理分布方案和键范围设置。当创建服务的新实例时: + +1. Sidecar 调用 Actor 服务以检索注册的 Actor 类型和配置设置。 +1. 相应的 Dapr 运行时注册它可以创建的 Actor 类型。 +1. `Placement` 服务计算给定 Actor 类型的所有实例的分区。 + +每个 Actor 类型的分区数据表在环境中运行的每个 Dapr 实例中更新和存储,并且可以随着 Actor 服务的新实例的创建和销毁而动态变化。 + + + +当客户端调用具有特定 ID 的 Actor(例如,Actor ID 123)时,客户端的 Dapr 实例对 Actor 类型和 ID 进行哈希,并使用信息调用可以为该特定 Actor ID 提供请求的相应 Dapr 实例。因此,对于任何给定的 Actor ID,总是调用相同的分区(或服务实例)。这在下图中显示。 + + + +这简化了一些选择,但也带来了一些考虑: + +- 默认情况下,Actor 随机放置到 Pod 中,导致均匀分布。 +- 由于 Actor 是随机放置的,因此应预期 Actor 操作总是需要网络通信,包括方法调用数据的序列化和反序列化,从而产生延迟和开销。 + +{{% alert title="注意" color="primary" %}} +注意:Dapr 的 Actor Placement 服务仅用于 Actor 放置,因此如果您的服务不使用 Dapr Actor,则不需要。Placement 服务可以在所有 [托管环境]({{< ref hosting >}}) 中运行,包括 selfhost 和 Kubernetes。 +{{% /alert %}} + +## Actor 的通信 + +您可以通过调用 HTTP 端点与 Dapr 交互以调用 Actor 方法。 + +```bash +POST/GET/PUT/DELETE http://localhost:3500/v1.0/actors/// +``` + +您可以在请求体中为 Actor 方法提供任何数据,请求的响应将在响应体中,这是来自 Actor 调用的数据。 + +另一种可能更方便的与 Actor 交互的方式是通过 SDK。Dapr 目前支持 [.NET]({{< ref "dotnet-actors" >}})、[Java]({{< ref "java#actors" >}}) 和 [Python]({{< ref "python-actor" >}}) 的 Actor SDK。 + +有关更多详细信息,请参阅 [Dapr Actor 特性]({{< ref howto-actors.md >}})。 + +### 并发 + +Dapr 的 Actor 运行时为访问 Actor 方法提供了简单的轮转访问模型。这意味着在任何时候,Actor 对象的代码中最多只能有一个线程处于活动状态。轮转访问极大地简化了并发系统,因为不需要同步机制来进行数据访问。这也意味着系统必须针对每个 Actor 实例的单线程访问特性进行特殊设计。 + +单个 Actor 实例不能同时处理多个请求。如果期望 Actor 实例处理并发请求,它可能会导致吞吐量瓶颈。 + +如果在两个 Actor 之间存在循环请求,同时对其中一个 Actor 发出外部请求,Actor 可能会相互死锁。Dapr 的 Actor 运行时会自动在 Actor 调用上超时,并向调用者抛出异常以中断可能的死锁情况。 + + + +#### 重入 + +要允许 Actor "重入" 并调用自身的方法,请参阅 [Actor 重入]({{}})。 + +### 轮转访问 + +轮转包括响应其他 Actor 或客户端请求的 Actor 方法的完整执行,或定时器/提醒回调的完整执行。即使这些方法和回调是异步的,Dapr 的 Actor 运行时也不会交错它们。一个轮转必须完全完成后,才允许新的轮转。换句话说,当前正在执行的 Actor 方法或定时器/提醒回调必须完全完成后,才允许对方法或回调的新调用。方法或回调被认为已完成,如果执行已从方法或回调返回,并且方法或回调返回的任务已完成。值得强调的是,即使在不同的方法、定时器和回调之间,也要尊重轮转并发性。 + +Dapr 的 Actor 运行时通过在轮转开始时获取每个 Actor 锁,并在轮转结束时释放锁来强制执行轮转并发性。因此,轮转并发性是在每个 Actor 的基础上强制执行的,而不是跨 Actor。Actor 方法和定时器/提醒回调可以代表不同的 Actor 同时执行。 + +以下示例说明了上述概念。考虑一个实现了两个异步方法(例如,Method1 和 Method2)、一个定时器和一个提醒的 Actor 类型。下图显示了代表属于此 Actor 类型的两个 Actor(ActorId1 和 ActorId2)的方法和回调执行时间线的示例。 + + + +## 下一步 + +{{< button text="定时器和提醒 >>" page="actors-timers-reminders.md" >}} + +## 相关链接 + +- [Actor API 参考]({{< ref actors_api.md >}}) +- [Actor 概述]({{< ref actors-overview.md >}}) +- [如何:在 Dapr 中使用虚拟 Actor]({{< ref howto-actors.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actors-overview.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actors-overview.md new file mode 100644 index 000000000..37df50f58 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actors-overview.md @@ -0,0 +1,132 @@ +--- +type: docs +title: "Actors 概述" +linkTitle: "概述" +weight: 10 +description: "Actors API 构建模块概述" +aliases: + - "/zh-hans/developing-applications/building-blocks/actors/actors-background" +--- + +[Actor 模型](https://en.wikipedia.org/wiki/Actor_model)将 actor 描述为“计算的基本单位”。换句话说,您可以将代码编写在一个自包含的单元中(称为 actor),该单元接收消息并一次处理一条消息,而无需任何形式的并发或线程。 + +当您的代码处理一条消息时,它可以向其他 actor 发送一条或多条消息,或创建新的 actor。底层运行时管理每个 actor 的运行方式、时间和位置,并在 actor 之间路由消息。 + +大量的 actor 可以同时执行,并且 actor 彼此独立执行。 + +## Dapr 中的 Actor 模型 + +Dapr 包含一个专门实现[虚拟 Actor 模型](https://www.microsoft.com/research/project/orleans-virtual-actors/)的运行时。通过 Dapr 的实现,您可以根据 Actor 模型编写 Dapr actor,Dapr 利用底层平台提供的可扩展性和可靠性保证。 + +每个 actor 都被定义为 actor 类型的一个实例,与对象是类的一个实例相同。例如,可能有一个实现计算器功能的 actor 类型,并且可能有许多此类型的 actor 分布在集群的各个节点上。每个这样的 actor 都由一个 actor ID 唯一标识。 + + + +[以下概述视频和演示](https://www.youtube.com/live/0y7ne6teHT4?si=dWNgtsp61f3Sjq0n&t=10797)展示了 Dapr 中的 actor 如何工作。 + + + +## Dapr Actors 与 Dapr Workflow + +Dapr actors 基于状态管理和服务调用 API 创建具有身份的有状态、长时间运行的对象。[Dapr Workflow]({{< ref workflow-overview.md >}}) 和 Dapr Actors 是相关的,workflow 基于 actor 提供更高层次的抽象来编排一组 actor,实现常见的 workflow 模式并代表您管理 actor 的生命周期。 + +Dapr actors 旨在提供一种在分布式系统中封装状态和行为的方法。actor 可以按需由客户端应用程序激活。当 actor 被激活时,它被分配一个唯一的身份,这使得它能够在多次调用中保持其状态。这使得 actor 在构建有状态、可扩展和容错的分布式应用程序时非常有用。 + +另一方面,Dapr Workflow 提供了一种定义和编排涉及多个服务和组件的复杂 workflow 的方法。workflow 允许您定义需要按特定顺序执行的一系列步骤或任务,并可用于实现业务流程、事件驱动的 workflow 和其他类似场景。 + +如上所述,Dapr Workflow 基于 Dapr Actors 管理其激活和生命周期。 + +### 何时使用 Dapr Actors + +与任何其他技术决策一样,您应该根据要解决的问题来决定是否使用 actor。例如,如果您正在构建一个聊天应用程序,您可能会使用 Dapr actors 来实现聊天室和用户之间的单个聊天会话,因为每个聊天会话都需要维护自己的状态并且具有可扩展性和容错性。 + +一般来说,如果您的问题空间涉及大量(数千个或更多)小型、独立和隔离的状态和逻辑单元,可以考虑使用 actor 模式来建模您的问题或场景。 + +- 您的问题空间涉及大量(数千个或更多)小型、独立和隔离的状态和逻辑单元。 +- 您希望使用单线程对象,这些对象不需要外部组件的显著交互,包括跨一组 actor 查询状态。 +- 您的 actor 实例不会通过发出 I/O 操作来阻塞调用者,导致不可预测的延迟。 + +### 何时使用 Dapr Workflow + +当您需要定义和编排涉及多个服务和组件的复杂 workflow 时,您可以使用 Dapr Workflow。例如,使用[前面提到的聊天应用程序示例]({{< ref "#when-to-use-dapr-actors" >}}),您可能会使用 Dapr Workflow 来定义应用程序的整体 workflow,例如如何注册新用户、如何发送和接收消息以及应用程序如何处理错误和异常。 + +[了解有关 Dapr Workflow 的更多信息以及如何在应用程序中使用 workflow。]({{< ref workflow-overview.md >}}) + +## Actor 类型和 Actor ID + +actor 被唯一定义为 actor 类型的一个实例,类似于对象是类的一个实例。例如,您可能有一个实现计算器功能的 actor 类型。可能有许多此类型的 actor 分布在集群的各个节点上。 + +每个 actor 都由一个 actor ID 唯一标识。actor ID 可以是您选择的任何字符串值。如果您不提供 actor ID,Dapr 会为您生成一个随机字符串作为 ID。 + +## 功能 + +### 命名空间化的 Actors + +Dapr 支持命名空间化的 actor。actor 类型可以部署到不同的命名空间中。您可以在同一命名空间中调用这些 actor 的实例。 + +[了解有关命名空间化的 actor 及其工作原理的更多信息。]({{< ref namespaced-actors.md >}}) + +### Actor 生命周期 + +由于 Dapr actors 是虚拟的,因此不需要显式创建或销毁。Dapr actor 运行时: +1. 一旦收到该 actor ID 的初始请求,就会自动激活 actor。 +1. 垃圾收集未使用的 actor 的内存对象。 +1. 维护 actor 的存在信息,以防它稍后被重新激活。 + +actor 的状态超出了对象的生命周期,因为状态存储在为 Dapr 运行时配置的状态提供者中。 + +[了解有关 actor 生命周期的更多信息。]({{< ref "actors-features-concepts.md#actor-lifetime" >}}) + +### 分布和故障转移 + +为了提供可扩展性和可靠性,actor 实例在整个集群中分布,Dapr 在整个集群中分布 actor 实例,并自动将它们迁移到健康的节点。 + +[了解有关 Dapr actor 放置的更多信息。]({{< ref "actors-features-concepts.md#actor-placement-service" >}}) + +### Actor 通信 + +您可以通过 HTTP 调用 actor 方法,如下面的通用示例所示。 + + + +1. 服务调用 sidecar 上的 actor API。 +1. 使用来自放置服务的缓存分区信息,sidecar 确定哪个 actor 服务实例将托管 actor ID **3**。调用被转发到适当的 sidecar。 +1. pod 2 中的 sidecar 实例调用服务实例以调用 actor 并执行 actor 方法。 + +[了解有关调用 actor 方法的更多信息。]({{< ref "actors-features-concepts.md#actor-communication" >}}) + +#### 并发 + +Dapr actor 运行时为访问 actor 方法提供了一个简单的轮流访问模型。轮流访问极大地简化了并发系统,因为不需要同步机制来进行数据访问。 + +- [了解有关 actor 重入的更多信息]({{< ref "actor-reentrancy.md" >}}) +- [了解有关轮流访问模型的更多信息]({{< ref "actors-features-concepts.md#turn-based-access" >}}) + +### 状态 + +事务性状态存储可以用于存储 actor 状态。无论您是否打算在 actor 中存储任何状态,您都必须在状态存储组件的元数据部分中将属性 `actorStateStore` 的值指定为 `true`。actor 状态以特定方案存储在事务性状态存储中,允许进行一致的查询。所有 actor 只能使用单个状态存储组件作为状态存储。阅读[状态 API 参考]({{< ref state_api.md >}})和[actors API 参考]({{< ref actors_api.md >}})以了解有关 actor 状态存储的更多信息。 + +### Actor 定时器和提醒 + +actor 可以通过注册定时器或提醒来安排定期工作。 + +定时器和提醒的功能非常相似。主要区别在于 Dapr actor 运行时在停用后不保留有关定时器的任何信息,而是使用 Dapr actor 状态提供者持久化有关提醒的信息。 + +这种区别允许用户在轻量级但无状态的定时器与更耗资源但有状态的提醒之间进行权衡。 + +[以下概述视频和演示](https://www.youtube.com/live/0y7ne6teHT4?si=2_xX6mkU3UCy2Plr&t=6607)展示了 actor 定时器和提醒如何工作。 + + + +- [了解有关 actor 定时器的更多信息。]({{< ref "actors-features-concepts.md#timers" >}}) +- [了解有关 actor 提醒的更多信息。]({{< ref "actors-features-concepts.md#reminders" >}}) +- [了解有关定时器和提醒错误处理及故障转移的更多信息。]({{< ref "actors-features-concepts.md#timers-and-reminders-error-handling" >}}) + +## 下一步 + +{{< button text="Actors 功能和概念 >>" page="actors-features-concepts.md" >}} + +## 相关链接 + +- [Actors API 参考]({{< ref actors_api.md >}}) +- 请参阅 [Dapr SDK 文档和示例]({{< ref "developing-applications/sdks/#sdk-languages" >}})。 diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actors-runtime-config.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actors-runtime-config.md new file mode 100644 index 000000000..53e0e5868 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actors-runtime-config.md @@ -0,0 +1,206 @@ +--- +type: docs +title: "actor 运行时配置参数" +linkTitle: "运行时配置" +weight: 30 +description: 修改默认 Dapr actor 运行时配置行为 +--- + +您可以使用以下配置参数来调整 Dapr actor 的默认运行时行为。 + +| 参数 | 描述 | 默认值 | +| --------- | ----------- | ------- | +| `entities` | 此主机支持的 actor 类型。 | N/A | +| `actorIdleTimeout` | 空闲 actor 的停用超时时间。每隔 `actorScanInterval` 时间间隔检查一次。 | 60 分钟 | +| `actorScanInterval` | 指定扫描空闲 actor 的时间间隔。超过 `actorIdleTimeout` 的 actor 将被停用。 | 30 秒 | +| `drainOngoingCallTimeout` | 在重新平衡 actor 时,指定当前活动 actor 方法的完成超时时间。如果没有正在进行的方法调用,则忽略此项。 | 60 秒 | +| `drainRebalancedActors` | 如果设置为 true,Dapr 将在 `drainOngoingCallTimeout` 时间内等待当前 actor 调用完成,然后再尝试停用 actor。 | true | +| `reentrancy` (`ActorReentrancyConfig`) | 配置 actor 的重入行为。如果未提供,则重入功能被禁用。 | 禁用,false | +| `remindersStoragePartitions` | 配置 actor 的提醒分区数量。如果未提供,所有提醒将作为 actor 状态存储中的单个记录保存。 | 0 | +| `entitiesConfig` | 使用配置数组单独配置每个 actor 类型。任何在单个实体配置中指定的实体也必须在顶级 `entities` 字段中列出。 | N/A | + +## 示例 + +{{< tabs ".NET" JavaScript Python Java Go >}} + +{{% codetab %}} +```csharp +// 在 Startup.cs 中 +public void ConfigureServices(IServiceCollection services) +{ + // 使用 DI 注册 actor 运行时 + services.AddActors(options => + { + // 注册 actor 类型并配置 actor 设置 + options.Actors.RegisterActor(); + + // 配置默认设置 + options.ActorIdleTimeout = TimeSpan.FromMinutes(60); + options.ActorScanInterval = TimeSpan.FromSeconds(30); + options.DrainOngoingCallTimeout = TimeSpan.FromSeconds(60); + options.DrainRebalancedActors = true; + options.RemindersStoragePartitions = 7; + options.ReentrancyConfig = new() { Enabled = false }; + + // 为特定 actor 类型添加配置。 + // 此 actor 类型必须在基础级别的 'entities' 字段中有匹配值。如果没有,配置将被忽略。 + // 如果有匹配的实体,这里的值将用于覆盖根配置中指定的任何值。 + // 在此示例中,`ReentrantActor` 启用了重入;然而,'MyActor' 将不启用重入。 + options.Actors.RegisterActor(typeOptions: new() + { + ReentrancyConfig = new() + { + Enabled = true, + } + }); + }); + + // 注册用于 actor 的其他服务 + services.AddSingleton(); +} +``` +[查看 .NET SDK 文档以注册 actor]({{< ref "dotnet-actors-usage.md#registring-actors" >}})。 + +{{% /codetab %}} + +{{% codetab %}} + + + +```js +import { CommunicationProtocolEnum, DaprClient, DaprServer } from "@dapr/dapr"; + +// 使用 DaprClientOptions 配置 actor 运行时。 +const clientOptions = { + actor: { + actorIdleTimeout: "1h", + actorScanInterval: "30s", + drainOngoingCallTimeout: "1m", + drainRebalancedActors: true, + reentrancy: { + enabled: true, + maxStackDepth: 32, + }, + remindersStoragePartitions: 0, + }, +}; + +// 在创建 DaprServer 和 DaprClient 时使用这些选项。 + +// 注意,DaprServer 内部创建了一个 DaprClient,需要使用 clientOptions 进行配置。 +const server = new DaprServer(serverHost, serverPort, daprHost, daprPort, clientOptions); + +const client = new DaprClient(daprHost, daprPort, CommunicationProtocolEnum.HTTP, clientOptions); +``` + +[查看使用 JavaScript SDK 编写 actor 的文档]({{< ref "js-actors.md#registering-actors" >}})。 + +{{% /codetab %}} + +{{% codetab %}} + + + +```python +from datetime import timedelta +from dapr.actor.runtime.config import ActorRuntimeConfig, ActorReentrancyConfig + +ActorRuntime.set_actor_config( + ActorRuntimeConfig( + actor_idle_timeout=timedelta(hours=1), + actor_scan_interval=timedelta(seconds=30), + drain_ongoing_call_timeout=timedelta(minutes=1), + drain_rebalanced_actors=True, + reentrancy=ActorReentrancyConfig(enabled=False), + remindersStoragePartitions=7 + ) +) +``` + +[查看使用 Python SDK 运行 actor 的文档]({{< ref "python-actor.md" >}}) + +{{% /codetab %}} + +{{% codetab %}} + + + +```java +// import io.dapr.actors.runtime.ActorRuntime; +// import java.time.Duration; + +ActorRuntime.getInstance().getConfig().setActorIdleTimeout(Duration.ofMinutes(60)); +ActorRuntime.getInstance().getConfig().setActorScanInterval(Duration.ofSeconds(30)); +ActorRuntime.getInstance().getConfig().setDrainOngoingCallTimeout(Duration.ofSeconds(60)); +ActorRuntime.getInstance().getConfig().setDrainBalancedActors(true); +ActorRuntime.getInstance().getConfig().setActorReentrancyConfig(false, null); +ActorRuntime.getInstance().getConfig().setRemindersStoragePartitions(7); +``` + +[查看使用 Java SDK 编写 actor 的文档]({{< ref "java.md#actors" >}})。 + +{{% /codetab %}} + +{{% codetab %}} + + +```go +const ( + defaultActorType = "basicType" + reentrantActorType = "reentrantType" +) + +type daprConfig struct { + Entities []string `json:"entities,omitempty"` + ActorIdleTimeout string `json:"actorIdleTimeout,omitempty"` + ActorScanInterval string `json:"actorScanInterval,omitempty"` + DrainOngoingCallTimeout string `json:"drainOngoingCallTimeout,omitempty"` + DrainRebalancedActors bool `json:"drainRebalancedActors,omitempty"` + Reentrancy config.ReentrancyConfig `json:"reentrancy,omitempty"` + EntitiesConfig []config.EntityConfig `json:"entitiesConfig,omitempty"` +} + +var daprConfigResponse = daprConfig{ + Entities: []string{defaultActorType, reentrantActorType}, + ActorIdleTimeout: actorIdleTimeout, + ActorScanInterval: actorScanInterval, + DrainOngoingCallTimeout: drainOngoingCallTimeout, + DrainRebalancedActors: drainRebalancedActors, + Reentrancy: config.ReentrancyConfig{Enabled: false}, + EntitiesConfig: []config.EntityConfig{ + { + // 为特定 actor 类型添加配置。 + // 此 actor 类型必须在基础级别的 'entities' 字段中有匹配值。如果没有,配置将被忽略。 + // 如果有匹配的实体,这里的值将用于覆盖根配置中指定的任何值。 + // 在此示例中,`reentrantActorType` 启用了重入;然而,'defaultActorType' 将不启用重入。 + Entities: []string{reentrantActorType}, + Reentrancy: config.ReentrancyConfig{ + Enabled: true, + MaxStackDepth: &maxStackDepth, + }, + }, + }, +} + +func configHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(daprConfigResponse) +} +``` + +[查看使用 Go SDK 的 actor 示例](https://github.com/dapr/go-sdk/tree/main/examples/actor)。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 + +{{< button text="启用 actor reminder 分区 >>" page="howto-actors-partitioning.md" >}} + +## 相关链接 + +- 参考 [Dapr SDK 文档和示例]({{< ref "developing-applications/sdks/#sdk-languages" >}})。 +- [actor API 参考]({{< ref actors_api.md >}}) +- [actor 概述]({{< ref actors-overview.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actors-timers-reminders.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actors-timers-reminders.md new file mode 100644 index 000000000..fa7627d16 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/actors-timers-reminders.md @@ -0,0 +1,194 @@ +--- +type: docs +title: "actor 定时器和提醒" +linkTitle: "定时器和提醒" +weight: 50 +description: "为您的 actor 设置定时器和提醒并执行错误处理" +aliases: + - "/zh-hans/developing-applications/building-blocks/actors/actors-background" +--- + +actor 可以通过注册定时器或提醒来安排周期性工作。 + +定时器和提醒的功能非常相似。主要区别在于 Dapr actor 运行时在停用后不会保留任何关于定时器的信息,而是使用 Dapr actor 状态提供程序持久化提醒的信息。 + +这种区别允许用户在轻量但无状态的定时器与更资源密集但有状态的提醒之间进行选择。 + +定时器和提醒的调度配置是相同的,概述如下: + +--- +`dueTime` 是一个可选参数,用于设置第一次调用回调的时间或时间间隔。如果省略 `dueTime`,则在定时器/提醒注册后立即调用回调。 + +支持的格式: +- RFC3339 日期格式,例如 `2020-10-02T15:00:00Z` +- time.Duration 格式,例如 `2h30m` +- [ISO 8601 持续时间](https://en.wikipedia.org/wiki/ISO_8601#Durations) 格式,例如 `PT2H30M` + +--- +`period` 是一个可选参数,用于设置两次连续回调调用之间的时间间隔。当以 `ISO 8601-1 持续时间` 格式指定时,您还可以配置重复次数以限制回调调用的总次数。 +如果省略 `period`,则回调只会被调用一次。 + +支持的格式: +- time.Duration 格式,例如 `2h30m` +- [ISO 8601 持续时间](https://en.wikipedia.org/wiki/ISO_8601#Durations) 格式,例如 `PT2H30M`, `R5/PT1M30S` + +--- +`ttl` 是一个可选参数,用于设置定时器/提醒将过期和删除的时间或时间间隔。如果省略 `ttl`,则不应用任何限制。 + +支持的格式: +* RFC3339 日期格式,例如 `2020-10-02T15:00:00Z` +* time.Duration 格式,例如 `2h30m` +* [ISO 8601 持续时间](https://en.wikipedia.org/wiki/ISO_8601#Durations) 格式。示例:`PT2H30M` + +--- +actor 运行时验证调度配置的正确性,并在输入无效时返回错误。 + +当您同时指定 `period` 中的重复次数和 `ttl` 时,定时器/提醒将在任一条件满足时停止。 + +## actor 定时器 + +您可以在 actor 上注册一个基于定时器执行的回调。 + +Dapr actor 运行时确保回调方法遵循基于轮次的并发保证。这意味着在此回调完成执行之前,不会有其他 actor 方法或定时器/提醒回调正在进行。 + +Dapr actor 运行时在回调完成时保存对 actor 状态所做的更改。如果在保存状态时发生错误,该 actor 对象将被停用,并激活一个新实例。 + +当 actor 作为垃圾回收的一部分被停用时,所有定时器都会停止。之后不会调用任何定时器回调。此外,Dapr actor 运行时不会保留关于停用前正在运行的定时器的任何信息。actor 需要在将来重新激活时注册所需的任何定时器。 + +您可以通过调用如下所示的 HTTP/gRPC 请求或通过 Dapr SDK 为 actor 创建定时器。 + +```md +POST/PUT http://localhost:3500/v1.0/actors///timers/ +``` + +### 示例 + +定时器参数在请求体中指定。 + +以下请求体配置了一个 `dueTime` 为 9 秒和 `period` 为 3 秒的定时器。这意味着它将在 9 秒后首次触发,然后每隔 3 秒触发一次。 +```json +{ + "dueTime":"0h0m9s0ms", + "period":"0h0m3s0ms" +} +``` + +以下请求体配置了一个 `period` 为 3 秒(ISO 8601 持续时间格式)的定时器。它还将调用次数限制为 10 次。这意味着它将触发 10 次:首先在注册后立即触发,然后每隔 3 秒触发一次。 +```json +{ + "period":"R10/PT3S", +} +``` + +以下请求体配置了一个 `period` 为 3 秒(ISO 8601 持续时间格式)和 `ttl` 为 20 秒的定时器。这意味着它在注册后立即触发,然后每隔 3 秒触发一次,持续 20 秒。 +```json +{ + "period":"PT3S", + "ttl":"20s" +} +``` + +以下请求体配置了一个 `dueTime` 为 10 秒、`period` 为 3 秒和 `ttl` 为 10 秒的定时器。它还将调用次数限制为 4 次。这意味着它将在 10 秒后首次触发,然后每隔 3 秒触发一次,持续 10 秒,但总共不超过 4 次。 +```json +{ + "dueTime":"10s", + "period":"R4/PT3S", + "ttl":"10s" +} +``` + +您可以通过调用以下命令删除 actor 定时器 + +```md +DELETE http://localhost:3500/v1.0/actors///timers/ +``` + +有关更多详细信息,请参阅 [api 规范]({{< ref "actors_api.md#invoke-timer" >}})。 + +## actor 提醒 + +{{% alert title="注意" color="primary" %}} +在 Dapr v1.15 中,actor 提醒默认存储在 [Scheduler 服务]({{< ref "scheduler.md#actor-reminders" >}})中。 +{{% /alert %}} + +提醒是一种在指定时间触发 actor 上*持久*回调的机制。它们的功能类似于定时器。但与定时器不同,提醒在所有情况下都会被触发,直到 actor 明确取消注册它们或 actor 被明确删除或调用次数耗尽。具体来说,提醒在 actor 停用和故障转移期间被触发,因为 Dapr actor 运行时使用 Dapr actor 状态提供程序持久化关于 actor 提醒的信息。 + +您可以通过调用如下所示的 HTTP/gRPC 请求或通过 Dapr SDK 为 actor 创建持久提醒。 + +```md +POST/PUT http://localhost:3500/v1.0/actors///reminders/ +``` + +提醒的请求结构与 actor 的相同。请参阅 [actor 定时器示例]({{< ref "#actor-timers" >}})。 + +### 检索 actor 提醒 + +您可以通过调用以下命令检索 actor 提醒 + +```md +GET http://localhost:3500/v1.0/actors///reminders/ +``` + +### 删除 actor 提醒 + +您可以通过调用以下命令删除 actor 提醒 + +```md +DELETE http://localhost:3500/v1.0/actors///reminders/ +``` + +如果 actor 提醒被触发且应用程序未向运行时返回 2** 代码(例如,由于连接问题),actor 提醒将重试最多三次,每次尝试之间的退避间隔为一秒。可能会根据任何可选应用的 [actor 弹性策略]({{< ref "policies.md#overriding-default-retries" >}})进行额外的重试。 + +有关更多详细信息,请参阅 [api 规范]({{< ref "actors_api.md#invoke-reminder" >}})。 + +## 错误处理 + +当 actor 的方法成功完成时,运行时将继续按照指定的定时器或提醒计划调用该方法。然而,如果方法抛出异常,运行时会捕获它并在 Dapr sidecar 日志中记录错误消息,而不进行重试。 + +为了允许 actor 从故障中恢复并在崩溃或重启后重试,您可以通过配置状态存储(如 Redis 或 Azure Cosmos DB)来持久化 actor 的状态。 + +如果方法的调用失败,定时器不会被移除。定时器仅在以下情况下被移除: +- sidecar 崩溃 +- 执行次数用尽 +- 您明确删除它 + +## 提醒数据序列化格式 + +actor 提醒数据默认序列化为 JSON。从 Dapr v1.13 开始,支持通过 Placement 和 Scheduler 服务为工作流的内部提醒数据使用 protobuf 序列化格式。根据吞吐量和负载大小,这可以显著提高性能,为开发人员提供更高的吞吐量和更低的延迟。 + +另一个好处是将较小的数据存储在 actor 底层数据库中,这在使用某些云数据库时可以实现成本优化。使用 protobuf 序列化的限制是提醒数据不再可查询。 + +{{% alert title="注意" color="primary" %}} +protobuf 序列化将在 Dapr 1.14 中成为默认格式 +{{% /alert %}} + +以 protobuf 格式保存的提醒数据无法在 Dapr 1.12.x 及更早版本中读取。建议在 Dapr v1.13 中测试此功能,并验证它在您的数据库中按预期工作,然后再投入生产。 + +{{% alert title="注意" color="primary" %}} +如果您在 Dapr v1.13 中使用 protobuf 序列化并需要降级到更早的 Dapr 版本,提醒数据将与 1.12.x 及更早版本不兼容。**一旦您以 protobuf 格式保存提醒数据,就无法将其移回 JSON 格式**。 +{{% /alert %}} + +### 在 Kubernetes 上启用 protobuf 序列化 + +要在 Kubernetes 上为 actor 提醒使用 protobuf 序列化,请使用以下 Helm 值: + +``` +--set dapr_placement.maxActorApiLevel=20 +``` + +### 在自托管环境中启用 protobuf 序列化 + +要在自托管环境中为 actor 提醒使用 protobuf 序列化,请使用以下 `daprd` 标志: + +``` +--max-api-level=20 +``` + +## 下一步 + +{{< button text="配置 actor 运行时行为 >>" page="actors-runtime-config.md" >}} + +## 相关链接 + +- [actor API 参考]({{< ref actors_api.md >}}) +- [actor 概述]({{< ref actors-overview.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/howto-actors-partitioning.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/howto-actors-partitioning.md new file mode 100644 index 000000000..0cd8ee813 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/howto-actors-partitioning.md @@ -0,0 +1,196 @@ +--- +type: docs +title: "如何启用actor提醒分区" +linkTitle: "如何分区提醒" +weight: 60 +description: "为您的应用程序启用actor提醒分区" +aliases: + - "/zh-hans/developing-applications/building-blocks/actors/actors-background" +--- + +[actor提醒]({{< ref "actors-timers-reminders.md#actor-reminders" >}})在sidecar重启后仍然持久化并继续触发。注册了多个提醒的应用程序可能会遇到以下问题: + +- 提醒注册和注销的吞吐量低 +- 基于state存储单个记录大小限制的提醒注册数量有限 + +为了解决这些问题,应用程序可以通过在state存储中将数据分布在多个键中来启用actor提醒分区。 + +1. 在`actors\|\|\|\|metadata`中使用一个元数据记录来存储给定actor类型的持久化配置。 +1. 多个记录存储同一actor类型的提醒子集。 + +| 键 | 值 | +| ----------- | ----------- | +| `actors\|\|\|\|metadata` | `{ "id": , "actorRemindersMetadata": { "partitionCount": } }` | +| `actors\|\|\|\|\|\|reminders\|\|1` | `[ , , ... , ]` | +| `actors\|\|\|\|\|\|reminders\|\|2` | `[ , , ... , ]` | + +如果您需要更改分区数量,Dapr的sidecar将自动重新分配提醒集。 + +## 配置actor运行时以分区actor提醒 + +与其他actor配置元素类似,actor运行时通过actor的`GET /dapr/config`端点提供适当的配置来分区actor提醒。选择您偏好的语言以获取actor运行时配置示例。 + +{{< tabs ".NET" JavaScript Python Java Go >}} + +{{% codetab %}} + + + +```csharp +// 在Startup.cs中 +public void ConfigureServices(IServiceCollection services) +{ + // 使用DI注册actor运行时 + services.AddActors(options => + { + // 注册actor类型并配置actor设置 + options.Actors.RegisterActor(); + + // 配置默认设置 + options.ActorIdleTimeout = TimeSpan.FromMinutes(60); + options.ActorScanInterval = TimeSpan.FromSeconds(30); + options.RemindersStoragePartitions = 7; + }); + + // 注册用于actor的其他服务 + services.AddSingleton(); +} +``` + +[查看.NET SDK中注册actor的文档]({{< ref "dotnet-actors-usage.md#registring-actors" >}})。 + +{{% /codetab %}} + +{{% codetab %}} + + +```js +import { CommunicationProtocolEnum, DaprClient, DaprServer } from "@dapr/dapr"; + +// 使用DaprClientOptions配置actor运行时。 +const clientOptions = { + actor: { + remindersStoragePartitions: 0, + }, +}; + +const actor = builder.build(new ActorId("my-actor")); + +// 注册一个提醒,它有一个默认回调:`receiveReminder` +await actor.registerActorReminder( + "reminder-id", // 提醒的唯一名称。 + Temporal.Duration.from({ seconds: 2 }), // DueTime + Temporal.Duration.from({ seconds: 1 }), // Period + Temporal.Duration.from({ seconds: 1 }), // TTL + 100, // 发送到提醒回调的状态。 +); + +// 删除提醒 +await actor.unregisterActorReminder("reminder-id"); +``` + +[查看使用JavaScript SDK编写actor的文档]({{< ref "js-actors.md#registering-actors" >}})。 + +{{% /codetab %}} + +{{% codetab %}} + + + +```python +from datetime import timedelta + +ActorRuntime.set_actor_config( + ActorRuntimeConfig( + actor_idle_timeout=timedelta(hours=1), + actor_scan_interval=timedelta(seconds=30), + remindersStoragePartitions=7 + ) +) +``` + +[查看使用Python SDK运行actor的文档]({{< ref "python-actor.md" >}}) + +{{% /codetab %}} + +{{% codetab %}} + + +```java +// import io.dapr.actors.runtime.ActorRuntime; +// import java.time.Duration; + +ActorRuntime.getInstance().getConfig().setActorIdleTimeout(Duration.ofMinutes(60)); +ActorRuntime.getInstance().getConfig().setActorScanInterval(Duration.ofSeconds(30)); +ActorRuntime.getInstance().getConfig().setRemindersStoragePartitions(7); +``` + +[查看使用Java SDK编写actor的文档]({{< ref "java.md#actors" >}})。 + +{{% /codetab %}} + +{{% codetab %}} + + +```go +type daprConfig struct { + Entities []string `json:"entities,omitempty"` + ActorIdleTimeout string `json:"actorIdleTimeout,omitempty"` + ActorScanInterval string `json:"actorScanInterval,omitempty"` + DrainOngoingCallTimeout string `json:"drainOngoingCallTimeout,omitempty"` + DrainRebalancedActors bool `json:"drainRebalancedActors,omitempty"` + RemindersStoragePartitions int `json:"remindersStoragePartitions,omitempty"` +} + +var daprConfigResponse = daprConfig{ + []string{defaultActorType}, + actorIdleTimeout, + actorScanInterval, + drainOngoingCallTimeout, + drainRebalancedActors, + 7, +} + +func configHandler(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(daprConfigResponse) +} +``` + +[查看使用Go SDK的actor示例](https://github.com/dapr/go-sdk/tree/main/examples/actor)。 + +{{% /codetab %}} + +{{< /tabs >}} + +以下是一个有效的提醒分区配置示例: + +```json +{ + "entities": [ "MyActorType", "AnotherActorType" ], + "remindersStoragePartitions": 7 +} +``` + +## 处理配置更改 + +为了配置actor提醒分区,Dapr将actor类型元数据持久化在actor的state存储中。这允许配置更改在全局范围内应用,而不仅仅是在单个sidecar实例中。 + +此外,**您只能增加分区数量**,不能减少。这允许Dapr在滚动重启时自动重新分配数据,其中一个或多个分区配置可能处于活动状态。 + +## 演示 + +观看[此视频以获取actor提醒分区的演示](https://youtu.be/ZwFOEUYe1WA?t=1493): + +
+ + +## 下一步 + +{{< button text="与虚拟actor交互 >>" page="howto-actors.md" >}} + +## 相关链接 + +- [actor API参考]({{< ref actors_api.md >}}) +- [actor概述]({{< ref actors-overview.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/howto-actors.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/howto-actors.md new file mode 100644 index 000000000..0fbe74cfc --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/howto-actors.md @@ -0,0 +1,43 @@ +--- +type: docs +title: "操作指南:使用脚本与虚拟actor交互" +linkTitle: "操作指南:与虚拟actor交互" +weight: 70 +description: 通过调用actor方法来管理状态 +--- + +了解如何通过HTTP/gRPC端点来使用虚拟actor。 + +## 调用actor方法 + +您可以通过调用HTTP/gRPC端点与Dapr交互,以调用actor方法。 + +```html +POST/GET/PUT/DELETE http://localhost:3500/v1.0/actors///method/ +``` + +在请求体中提供actor方法所需的数据。请求的响应,即actor方法调用返回的数据,将在响应体中。 + +有关更多详细信息,请参阅[Actors API规范]({{< ref "actors_api.md#invoke-actor-method" >}})。 + +{{% alert title="注意" color="primary" %}} +您也可以使用[Dapr SDKs来操作actors]({{< ref "developing-applications/sdks/#sdk-languages" >}})。 +{{% /alert %}} + +## 使用actors保存状态 + +您可以通过HTTP/gRPC端点与Dapr交互,利用Dapr的actor状态管理功能来可靠地保存状态。 + +要使用actors,您的状态存储必须支持多项事务。这意味着您的状态存储组件需要实现`TransactionalStore`接口。 + +[查看支持事务/actors的组件列表]({{< ref supported-state-stores.md >}})。所有actors只能使用一个状态存储组件来保存状态。 + +## 下一步 + +{{< button text="actor重入 >>" page="actor-reentrancy.md" >}} + +## 相关链接 + +- 请参阅[Dapr SDK文档和示例]({{< ref "developing-applications/sdks/#sdk-languages" >}})。 +- [Actors API参考]({{< ref actors_api.md >}}) +- [Actors概述]({{< ref actors-overview.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/namespaced-actors.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/namespaced-actors.md new file mode 100644 index 000000000..3e137f16f --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/actors/namespaced-actors.md @@ -0,0 +1,123 @@ +--- +type: docs +title: "命名空间中的actor" +linkTitle: "命名空间中的actor" +weight: 40 +description: "了解命名空间中的actor" +--- + +在Dapr中,命名空间用于提供隔离,从而支持多租户。通过为actor添加命名空间,相同的actor类型可以部署在不同的命名空间中。您可以在同一命名空间中使用这些actor的实例。 + +{{% alert title="注意" color="primary" %}} +每个命名空间中的actor部署必须使用独立的状态存储,特别是在相同的actor类型跨多个命名空间使用时。换句话说,actor记录中不包含任何命名空间信息,因此每个命名空间需要单独的状态存储。请参阅[为命名空间配置actor状态存储]({{< ref "#configuring-actor-state-stores-for-namespacing" >}})部分以获取示例。 +{{% /alert %}} + +## 创建和配置命名空间 + +您可以在自托管模式或Kubernetes上使用命名空间。 + +{{< tabs "自托管" "Kubernetes">}} + +{{% codetab %}} +在自托管模式下,您可以通过设置[`NAMESPACE`环境变量]({{< ref environment.md >}})为Dapr实例指定命名空间。 + +{{% /codetab %}} + +{{% codetab %}} +在Kubernetes上,您可以在部署actor应用程序时创建和配置命名空间。例如,使用以下`kubectl`命令开始: + +```bash +kubectl create namespace namespace-actorA +kubectl config set-context --current --namespace=namespace-actorA +``` + +然后,将您的actor应用程序部署到此命名空间中(在示例中为`namespace-actorA`)。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 为命名空间配置actor状态存储 + +每个命名空间中的actor部署**必须**使用独立的状态存储。虽然您可以为每个actor命名空间使用不同的物理数据库,但某些状态存储组件提供了一种通过表、前缀、集合等逻辑分隔数据的方法。这允许您在多个命名空间中使用相同的物理数据库,只要您在Dapr组件定义中提供逻辑分隔即可。 + +以下是一些示例。 + +### 示例1:通过etcd中的前缀 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: statestore +spec: + type: state.etcd + version: v2 + metadata: + - name: endpoints + value: localhost:2379 + - name: keyPrefixPath + value: namespace-actorA + - name: actorStateStore + value: "true" +``` + +### 示例2:通过SQLite中的表名 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: statestore +spec: + type: state.sqlite + version: v1 + metadata: + - name: connectionString + value: "data.db" + - name: tableName + value: "namespace-actorA" + - name: actorStateStore + value: "true" +``` + +### 示例3:通过Redis中的逻辑数据库编号 + +```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" + - name: redisDB + value: "1" + - name: redisPassword + secretKeyRef: + name: redis-secret + key: redis-password + - name: actorStateStore + value: "true" + - name: redisDB + value: "1" +auth: + secretStore: +``` + +查看您的[状态存储组件规格]({{< ref supported-state-stores.md >}})以了解其提供的功能。 + +{{% alert title="注意" color="primary" %}} +命名空间中的actor使用多租户Placement服务。在这个控制平面服务中,每个应用程序部署都有自己的命名空间,属于命名空间"ActorA"的应用程序的sidecar不会接收到命名空间"ActorB"的应用程序的placement信息。 +{{% /alert %}} + +## 下一步 +- [了解更多关于Dapr Placement服务的信息]({{< ref placement.md >}}) +- [Placement API参考指南]({{< ref placement_api.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/bindings/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/bindings/_index.md new file mode 100644 index 000000000..3321bd4cd --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/bindings/_index.md @@ -0,0 +1,15 @@ +--- +type: docs +title: "Bindings" +linkTitle: "Bindings" +weight: 50 +description: 与外部系统交互或被外部系统触发 +--- + +{{% alert title="更多关于 Dapr Bindings" color="primary" %}} +了解如何使用 Dapr bindings 的更多信息: +- 试试 [Bindings 快速入门]({{< ref bindings-quickstart.md >}})。 +- 使用任意支持的 [Dapr SDKs]({{< ref sdks >}}) 来探索输入和输出 bindings。 +- 查看 [Bindings API 参考文档]({{< ref bindings_api.md >}})。 +- 浏览支持的 [输入和输出 bindings 组件规格]({{< ref supported-bindings >}})。 +{{% /alert %}} diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/bindings/bindings-overview.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/bindings/bindings-overview.md new file mode 100644 index 000000000..3d72182a1 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/bindings/bindings-overview.md @@ -0,0 +1,112 @@ +--- +type: docs +title: "bindings 概述" +linkTitle: "概述" +weight: 100 +description: bindings API 模块的概述 +--- + +通过 Dapr 的 bindings API,您可以利用外部系统的事件来触发应用程序,并与外部系统交互。使用 bindings API,您可以: + +- 避免连接到消息系统并进行轮询的复杂性(如队列和消息总线)。 +- 专注于业务逻辑,而不是系统交互的实现细节。 +- 使您的代码不依赖于特定的 SDK 或库。 +- 处理重试和故障恢复。 +- 在运行时可以切换不同的 bindings。 +- 构建具有特定环境 bindings 设置的可移植应用程序,而无需更改代码。 + +例如,通过 bindings,您的应用程序可以响应传入的 Twilio/SMS 消息,而无需: + +- 添加或配置第三方 Twilio SDK +- 担心从 Twilio 轮询(或使用 WebSockets 等) + +显示 bindings 的图示 + +在上图中: +- 输入 binding 触发您应用程序上的一个方法。 +- 在组件上执行输出 binding 操作,例如 `"create"`。 + +bindings 的开发独立于 Dapr 运行时。您可以[查看并贡献 bindings](https://github.com/dapr/components-contrib/tree/master/bindings)。 + +{{% alert title="注意" color="primary" %}} +如果您正在使用 HTTP Binding,建议使用[service-invocation]({{< ref service_invocation_api.md >}}) 代替。阅读[如何:使用 HTTP 调用非 Dapr 端点]({{< ref "howto-invoke-non-dapr-endpoints.md" >}})以获取更多信息。 +{{% /alert %}} + +## 输入 bindings + +通过输入 bindings,您可以在外部资源发生事件时触发您的应用程序。请求中可以发送可选的负载和元数据。 + +[以下概述视频和演示](https://www.youtube.com/live/0y7ne6teHT4?si=wlmAi7BJBWS8KNK7&t=8261)展示了 Dapr 输入 binding 的工作原理。 + + + +要接收来自输入 binding 的事件: + +1. 定义描述 binding 类型及其元数据(如连接信息)的组件 YAML。 +1. 使用以下方式监听传入事件: + - HTTP 端点 + - gRPC proto 库获取传入事件。 + +{{% alert title="注意" color="primary" %}} +在启动时,Dapr 会向应用程序发送[一个 OPTIONS 请求]({{< ref "bindings_api.md#invoking-service-code-through-input-bindings" >}})以获取所有定义的输入 bindings。如果应用程序想要订阅 binding,Dapr 期望返回状态码为 2xx 或 405。 + +{{% /alert %}} + +阅读[使用输入 bindings 创建事件驱动应用程序指南]({{< ref howto-triggers.md >}})以开始使用输入 bindings。 + +## 输出 bindings + +通过输出 bindings,您可以调用外部资源。调用请求中可以发送可选的负载和元数据。 + +[以下概述视频和演示](https://www.youtube.com/live/0y7ne6teHT4?si=PoA4NEqL5mqNj6Il&t=7668)展示了 Dapr 输出 binding 的工作原理。 + + + +要调用输出 binding: + +1. 定义描述 binding 类型及其元数据(如连接信息)的组件 YAML。 +1. 使用 HTTP 端点或 gRPC 方法调用 binding,并附带可选负载。 +1. 指定输出操作。输出操作取决于您使用的 binding 组件,可以包括: + - `"create"` + - `"update"` + - `"delete"` + - `"exec"` + +阅读[使用输出 bindings 与外部资源交互指南]({{< ref howto-bindings.md >}})以开始使用输出 bindings。 + +## binding 方向(可选) + +您可以提供 `direction` 元数据字段以指示 binding 组件支持的方向。这可以使 Dapr sidecar 避免“等待应用程序准备就绪”状态,减少 Dapr sidecar 与应用程序之间的生命周期依赖: + +- `"input"` +- `"output"` +- `"input, output"` + +{{% alert title="注意" color="primary" %}} +强烈建议所有输入 bindings 应该包含 `direction` 属性。 +{{% /alert %}} + +[查看 bindings `direction` 元数据的完整示例。]({{< ref "bindings_api.md#binding-direction-optional" >}}) + +## 试用 bindings + +### 快速入门和教程 + +想要测试 Dapr bindings API?通过以下快速入门和教程来查看 bindings 的实际应用: + +| 快速入门/教程 | 描述 | +| ------------------- | ----------- | +| [bindings 快速入门]({{< ref bindings-quickstart.md >}}) | 使用输入 bindings 处理外部系统的事件,并使用输出 bindings 调用操作。 | +| [bindings 教程](https://github.com/dapr/quickstarts/tree/master/tutorials/bindings) | 演示如何使用 Dapr 创建到其他组件的输入和输出 bindings。使用 bindings 连接到 Kafka。 | + +### 直接在您的应用程序中开始使用 bindings + +想要跳过快速入门?没问题。您可以直接在应用程序中试用 bindings 模块,以调用输出 bindings 和触发输入 bindings。在[Dapr 安装完成后]({{< ref "getting-started/_index.md" >}}),您可以从[输入 bindings 如何指南]({{< ref howto-triggers.md >}})开始使用 bindings API。 + +## 下一步 + +- 请遵循以下指南: + - [如何:使用输入 bindings 从不同资源触发服务]({{< ref howto-triggers.md >}}) + - [如何:使用输出 bindings 与外部资源交互]({{< ref howto-bindings.md >}}) +- 尝试[bindings 教程](https://github.com/dapr/quickstarts/tree/master/tutorials/bindings/README.md)以体验绑定到 Kafka 队列。 +- 阅读[bindings API 规范]({{< ref bindings_api.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/bindings/howto-bindings.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/bindings/howto-bindings.md new file mode 100644 index 000000000..caff03d34 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/bindings/howto-bindings.md @@ -0,0 +1,314 @@ +--- +type: docs +title: "操作指南:使用输出绑定与外部资源交互" +linkTitle: "操作指南:输出绑定" +description: "通过输出绑定调用外部系统" +weight: 300 +--- + +使用输出绑定,您可以与外部资源进行交互。在调用请求中,您可以发送可选的负载和元数据。 + +示例服务的绑定图示 + +本指南以Kafka绑定为例。您可以从[绑定组件列表]({{< ref setup-bindings >}})中选择您偏好的绑定规范。在本指南中: + +1. 示例中调用了`/binding`端点,使用`checkout`作为要调用的绑定名称。 +2. 负载放在必需的`data`字段中,可以是任何JSON可序列化的值。 +3. `operation`字段指定绑定需要执行的操作。例如,[Kafka绑定支持`create`操作]({{< ref "kafka.md#binding-support" >}})。 + - 您可以查看[每个输出绑定支持的操作(特定于每个组件)]({{< ref supported-bindings >}})。 + +{{% alert title="注意" color="primary" %}} +如果您还没有尝试过,[请尝试绑定快速入门]({{< ref bindings-quickstart.md >}}),以快速了解如何使用bindings API。 + +{{% /alert %}} + +## 创建绑定 + +创建一个`binding.yaml`文件,并将其保存到应用程序目录中的`components`子文件夹中。 + +创建一个名为`checkout`的新绑定组件。在`metadata`部分中,配置以下与Kafka相关的属性: + +- 您将发布消息的主题 +- 代理 + +在创建绑定组件时,[指定绑定的支持`direction`]({{< ref "bindings_api.md#binding-direction-optional" >}})。 + +{{< tabs "Self-Hosted (CLI)" Kubernetes >}} + +{{% codetab %}} + +使用`dapr run`的`--resources-path`标志指向您的自定义资源目录。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: checkout +spec: + type: bindings.kafka + version: v1 + metadata: + # Kafka代理连接设置 + - name: brokers + value: localhost:9092 + # 消费者配置:主题和消费者组 + - name: topics + value: sample + - name: consumerGroup + value: group1 + # 发布者配置:主题 + - name: publishTopic + value: sample + - name: authRequired + value: false + - name: direction + value: output +``` + +{{% /codetab %}} + +{{% codetab %}} + +要将以下`binding.yaml`文件部署到Kubernetes集群中,运行`kubectl apply -f binding.yaml`。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: checkout +spec: + type: bindings.kafka + version: v1 + metadata: + # Kafka代理连接设置 + - name: brokers + value: localhost:9092 + # 消费者配置:主题和消费者组 + - name: topics + value: sample + - name: consumerGroup + value: group1 + # 发布者配置:主题 + - name: publishTopic + value: sample + - name: authRequired + value: false + - name: direction + value: output +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 发送事件(输出绑定) + +下面的代码示例利用Dapr SDK在运行的Dapr实例上调用输出绑定端点。 + +{{< tabs ".NET" Java Python Go JavaScript>}} + +{{% codetab %}} + +```csharp +//依赖项 +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using Dapr.Client; +using Microsoft.AspNetCore.Mvc; +using System.Threading; + +//代码 +namespace EventService +{ + class Program + { + static async Task Main(string[] args) + { + string BINDING_NAME = "checkout"; + string BINDING_OPERATION = "create"; + while(true) + { + System.Threading.Thread.Sleep(5000); + Random random = new Random(); + int orderId = random.Next(1,1000); + using var client = new DaprClientBuilder().Build(); + //使用Dapr SDK调用输出绑定 + await client.InvokeBindingAsync(BINDING_NAME, BINDING_OPERATION, orderId); + Console.WriteLine("发送消息: " + orderId); + } + } + } +} + +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +//依赖项 +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.domain.HttpExtension; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +//代码 +@SpringBootApplication +public class OrderProcessingServiceApplication { + + private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); + + public static void main(String[] args) throws InterruptedException{ + String BINDING_NAME = "checkout"; + String BINDING_OPERATION = "create"; + while(true) { + TimeUnit.MILLISECONDS.sleep(5000); + Random random = new Random(); + int orderId = random.nextInt(1000-1) + 1; + DaprClient client = new DaprClientBuilder().build(); + //使用Dapr SDK调用输出绑定 + client.invokeBinding(BINDING_NAME, BINDING_OPERATION, orderId).block(); + log.info("发送消息: " + orderId); + } + } +} + +``` + +{{% /codetab %}} + +{{% codetab %}} + +```python +#依赖项 +import random +from time import sleep +import requests +import logging +import json +from dapr.clients import DaprClient + +#代码 +logging.basicConfig(level = logging.INFO) +BINDING_NAME = 'checkout' +BINDING_OPERATION = 'create' +while True: + sleep(random.randrange(50, 5000) / 1000) + orderId = random.randint(1, 1000) + with DaprClient() as client: + #使用Dapr SDK调用输出绑定 + resp = client.invoke_binding(BINDING_NAME, BINDING_OPERATION, json.dumps(orderId)) + logging.basicConfig(level = logging.INFO) + logging.info('发送消息: ' + str(orderId)) + +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +//依赖项 +import ( + "context" + "log" + "math/rand" + "time" + "strconv" + dapr "github.com/dapr/go-sdk/client" + +) + +//代码 +func main() { + BINDING_NAME := "checkout"; + BINDING_OPERATION := "create"; + for i := 0; i < 10; i++ { + time.Sleep(5000) + orderId := rand.Intn(1000-1) + 1 + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + defer client.Close() + ctx := context.Background() + //使用Dapr SDK调用输出绑定 + in := &dapr.InvokeBindingRequest{ Name: BINDING_NAME, Operation: BINDING_OPERATION , Data: []byte(strconv.Itoa(orderId))} + err = client.InvokeOutputBinding(ctx, in) + log.Println("发送消息: " + strconv.Itoa(orderId)) + } +} + +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +//依赖项 +import { DaprClient, CommunicationProtocolEnum } from "@dapr/dapr"; + +//代码 +const daprHost = "127.0.0.1"; + +(async function () { + for (var i = 0; i < 10; i++) { + await sleep(2000); + const orderId = Math.floor(Math.random() * (1000 - 1) + 1); + try { + await sendOrder(orderId) + } catch (err) { + console.error(e); + process.exit(1); + } + } +})(); + +async function sendOrder(orderId) { + const BINDING_NAME = "checkout"; + const BINDING_OPERATION = "create"; + const client = new DaprClient({ + daprHost, + daprPort: process.env.DAPR_HTTP_PORT, + communicationProtocol: CommunicationProtocolEnum.HTTP, + }); + //使用Dapr SDK调用输出绑定 + const result = await client.binding.send(BINDING_NAME, BINDING_OPERATION, orderId); + console.log("发送消息: " + orderId); +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +您还可以使用HTTP调用输出绑定端点: + +```bash +curl -X POST -H 'Content-Type: application/json' http://localhost:3601/v1.0/bindings/checkout -d '{ "data": 100, "operation": "create" }' +``` + +观看此[视频](https://www.youtube.com/watch?v=ysklxm81MTs&feature=youtu.be&t=1960)以了解如何使用双向输出绑定。 + +
+ +
+ +## 参考资料 + +- [绑定API]({{< ref bindings_api.md >}}) +- [绑定组件]({{< ref bindings >}}) +- [绑定详细规格]({{< ref supported-bindings >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/bindings/howto-triggers.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/bindings/howto-triggers.md new file mode 100644 index 000000000..8510c37f9 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/bindings/howto-triggers.md @@ -0,0 +1,295 @@ +--- +type: docs +title: "操作指南:使用输入绑定触发应用程序" +linkTitle: "操作指南:输入绑定" +description: "使用Dapr输入绑定触发事件驱动的应用程序" +weight: 200 +--- + +当外部资源发生事件时,您可以通过输入绑定来触发您的应用程序。外部资源可以是队列、消息管道、云服务、文件系统等。请求中可以发送可选的负载和元数据。 + +输入绑定非常适合用于事件驱动的处理、数据管道或一般的事件响应和后续处理。Dapr输入绑定允许您: + +- 在不需要特定SDK或库的情况下接收事件 +- 在不更改代码的情况下替换绑定 +- 专注于业务逻辑而不是事件资源的实现 + +示例服务的绑定图示 + +本指南使用Kafka绑定作为示例。您可以从[绑定组件列表]({{< ref setup-bindings >}})中找到您偏好的绑定规范。在本指南中: + +1. 示例调用`/binding`端点,使用`checkout`作为要调用的绑定名称。 +1. 负载需要放在`data`字段中,可以是任何可序列化为JSON的值。 +1. `operation`字段指定绑定需要执行的操作。例如,[Kafka绑定支持`create`操作]({{< ref "kafka.md#binding-support" >}})。 + - 您可以查看[每个输出绑定支持的操作(特定于每个组件)]({{< ref supported-bindings >}})。 + +{{% alert title="注意" color="primary" %}} + 如果您还没有尝试过,[试试绑定快速入门]({{< ref bindings-quickstart.md >}}),快速了解如何使用绑定API。 + +{{% /alert %}} + +## 创建绑定 + +创建一个`binding.yaml`文件,并保存到应用程序目录中的`components`子文件夹中。 + +创建一个名为`checkout`的新绑定组件。在`metadata`部分中,配置以下与Kafka相关的属性: + +- 您将发布消息的主题 +- 代理 + +在创建绑定组件时,[指定绑定的支持`direction`]({{< ref "bindings_api.md#binding-direction-optional" >}})。 + +{{< tabs "Self-Hosted (CLI)" Kubernetes >}} + +{{% codetab %}} + +使用`dapr run`命令的`--resources-path`标志指向您的自定义资源目录。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: checkout +spec: + type: bindings.kafka + version: v1 + metadata: + # Kafka代理连接设置 + - name: brokers + value: localhost:9092 + # 消费者配置:主题和消费者组 + - name: topics + value: sample + - name: consumerGroup + value: group1 + # 发布者配置:主题 + - name: publishTopic + value: sample + - name: authRequired + value: false + - name: direction + value: input +``` + +{{% /codetab %}} + +{{% codetab %}} + +要部署到Kubernetes集群中,运行`kubectl apply -f binding.yaml`。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: checkout +spec: + type: bindings.kafka + version: v1 + metadata: + # Kafka代理连接设置 + - name: brokers + value: localhost:9092 + # 消费者配置:主题和消费者组 + - name: topics + value: sample + - name: consumerGroup + value: group1 + # 发布者配置:主题 + - name: publishTopic + value: sample + - name: authRequired + value: false + - name: direction + value: input +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 监听传入事件(输入绑定) + +配置您的应用程序以接收传入事件。如果您使用HTTP,您需要: +- 监听一个`POST`端点,其名称与`binding.yaml`文件中的`metadata.name`指定的绑定名称相同。 +- 确保您的应用程序允许Dapr对该端点进行`OPTIONS`请求。 + +以下是利用Dapr SDK展示输入绑定的代码示例。 + +{{< tabs ".NET" Java Python Go JavaScript>}} + +{{% codetab %}} + +```csharp +//依赖项 +using System.Collections.Generic; +using System.Threading.Tasks; +using System; +using Microsoft.AspNetCore.Mvc; + +//代码 +namespace CheckoutService.controller +{ + [ApiController] + public class CheckoutServiceController : Controller + { + [HttpPost("/checkout")] + public ActionResult getCheckout([FromBody] int orderId) + { + Console.WriteLine("Received Message: " + orderId); + return "CID" + orderId; + } + } +} + +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +//依赖项 +import org.springframework.web.bind.annotation.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +//代码 +@RestController +@RequestMapping("/") +public class CheckoutServiceController { + private static final Logger log = LoggerFactory.getLogger(CheckoutServiceController.class); + @PostMapping(path = "/checkout") + public Mono getCheckout(@RequestBody(required = false) byte[] body) { + return Mono.fromRunnable(() -> + log.info("Received Message: " + new String(body))); + } +} + +``` + +{{% /codetab %}} + +{{% codetab %}} + +```python +#依赖项 +import logging +from dapr.ext.grpc import App, BindingRequest + +#代码 +app = App() + +@app.binding('checkout') +def getCheckout(request: BindingRequest): + logging.basicConfig(level = logging.INFO) + logging.info('Received Message : ' + request.text()) + +app.run(6002) + +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +//依赖项 +import ( + "encoding/json" + "log" + "net/http" + "github.com/gorilla/mux" +) + +//代码 +func getCheckout(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + var orderId int + err := json.NewDecoder(r.Body).Decode(&orderId) + log.Println("Received Message: ", orderId) + if err != nil { + log.Printf("error parsing checkout input binding payload: %s", err) + w.WriteHeader(http.StatusOK) + return + } +} + +func main() { + r := mux.NewRouter() + r.HandleFunc("/checkout", getCheckout).Methods("POST", "OPTIONS") + http.ListenAndServe(":6002", r) +} + +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +//依赖项 +import { DaprServer, CommunicationProtocolEnum } from '@dapr/dapr'; + +//代码 +const daprHost = "127.0.0.1"; +const serverHost = "127.0.0.1"; +const serverPort = "6002"; +const daprPort = "3602"; + +start().catch((e) => { + console.error(e); + process.exit(1); +}); + +async function start() { + const server = new DaprServer({ + serverHost, + serverPort, + communicationProtocol: CommunicationProtocolEnum.HTTP, + clientOptions: { + daprHost, + daprPort, + } + }); + await server.binding.receive('checkout', async (orderId) => console.log(`Received Message: ${JSON.stringify(orderId)}`)); + await server.start(); +} + +``` + +{{% /codetab %}} + +{{< /tabs >}} + +### 确认事件 + +通过从HTTP处理程序返回`200 OK`响应,告知Dapr您已成功处理应用程序中的事件。 + +### 拒绝事件 + +通过返回`200 OK`以外的任何响应,告知Dapr事件在您的应用程序中未正确处理,并安排重新投递。例如,`500 Error`。 + +### 指定自定义路由 + +默认情况下,传入事件将被发送到与输入绑定名称对应的HTTP端点。您可以通过在`binding.yaml`中设置以下元数据属性来覆盖此设置: + +```yaml +name: mybinding +spec: + type: binding.rabbitmq + metadata: + - name: route + value: /onevent +``` + +### 事件投递保证 + +事件投递保证由绑定实现控制。根据绑定实现,事件投递可以是精确一次或至少一次。 + +## 参考资料 + +- [绑定构建块]({{< ref bindings >}}) +- [绑定API]({{< ref bindings_api.md >}}) +- [组件概念]({{< ref components-concept.md >}}) +- [支持的绑定]({{< ref supported-bindings >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/configuration/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/configuration/_index.md new file mode 100644 index 000000000..8e30482a2 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/configuration/_index.md @@ -0,0 +1,15 @@ +--- +type: docs +title: "配置" +linkTitle: "配置" +weight: 80 +description: 管理应用程序配置并接收更改通知 +--- + +{{% alert title="更多关于Dapr配置的信息" color="primary" %}} +了解如何使用Dapr配置的更多信息: +- 试试[配置快速入门]({{< ref configuration-quickstart.md >}})。 +- 使用任意支持的[Dapr SDKs]({{< ref sdks >}})来探索配置。 +- 查看[配置API参考文档]({{< ref configuration_api.md >}})。 +- 查阅支持的[配置组件规范]({{< ref supported-configuration-stores >}})。 +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/configuration/configuration-api-overview.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/configuration/configuration-api-overview.md new file mode 100644 index 000000000..878c575ff --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/configuration/configuration-api-overview.md @@ -0,0 +1,51 @@ +--- +type: docs +title: "配置概述" +linkTitle: "概述" +weight: 1000 +description: "配置API构建模块的概述" +--- + +在开发应用程序时,配置是一个常见的任务。通常,我们会使用配置存储来管理这些配置数据。配置项通常具有动态特性,并且与应用程序的需求紧密相关。 + +例如,应用程序的配置可能包括: +- 密钥名称 +- 各种标识符 +- 分区或消费者ID +- 数据库名称等 + +通常,配置项以键/值对的形式存储在状态存储或数据库中。开发人员或运维人员可以在运行时更改配置存储中的应用程序配置。一旦进行了更改,服务会被通知以加载新的配置。 + +从应用程序API的角度来看,配置数据是只读的,配置存储的更新通过运维工具进行。使用Dapr的配置API,您可以: +- 获取以只读键/值对形式返回的配置项 +- 订阅配置项的变更通知 + + + +{{% alert title="注意" color="primary" %}} +配置API不应与[Dapr sidecar和控制平面配置]({{< ref "configuration-overview" >}})混淆,后者用于在Dapr sidecar实例或已安装的Dapr控制平面上设置策略和参数。 +{{% /alert %}} + +## 试用配置 + +### 快速入门 + +想要测试Dapr配置API?通过以下快速入门来了解配置API的实际应用: + +| 快速入门 | 描述 | +| ---------- | ----------- | +| [配置快速入门]({{< ref configuration-quickstart.md >}}) | 使用配置API获取配置项或订阅配置更改。 | + +### 直接在应用中开始使用配置API + +想要跳过快速入门?没问题。您可以直接在应用程序中尝试配置构建模块以读取和管理配置数据。在[Dapr安装完成]({{< ref "getting-started/_index.md" >}})后,您可以从[配置操作指南]({{< ref howto-manage-configuration.md >}})开始使用配置API。 + +## 观看演示 + +观看[使用Dapr配置构建模块的演示](https://youtu.be/tNq-n1XQuLA?t=496) + + + +## 下一步 +请参阅以下指南: +- [操作指南:从配置存储读取应用程序配置]({{< ref howto-manage-configuration.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/configuration/howto-manage-configuration.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/configuration/howto-manage-configuration.md new file mode 100644 index 000000000..c73d517c9 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/configuration/howto-manage-configuration.md @@ -0,0 +1,684 @@ +--- +type: docs +title: "操作指南:从存储中管理配置" +linkTitle: "操作指南:从存储中管理配置" +weight: 2000 +description: "学习如何获取应用程序配置并订阅更改" +--- + +本示例使用Redis配置存储组件来演示如何检索配置项。 + +示例服务获取配置的图示 + +{{% alert title="注意" color="primary" %}} +如果您还没有试过,请尝试[配置快速入门]({{< ref configuration-quickstart.md >}}),快速了解如何使用配置API。 + +{{% /alert %}} + +## 在存储中创建配置项 + +在支持的配置存储中创建一个配置项。这可以是一个简单的键值项,使用您选择的任何键。本示例使用Redis配置存储组件。 + +### 使用Docker运行Redis + +``` +docker run --name my-redis -p 6379:6379 -d redis:6 +``` + +### 保存一个配置项 + +使用[Redis CLI](https://redis.com/blog/get-redis-cli-without-installing-redis-server/),连接到Redis实例: + +``` +redis-cli -p 6379 +``` + +保存一个配置项: + +``` +MSET orderId1 "101||1" orderId2 "102||1" +``` + +## 配置Dapr配置存储 + +将以下组件文件保存到您机器上的[默认组件文件夹]({{< ref "install-dapr-selfhost.md#step-5-verify-components-directory-has-been-initialized" >}})。您可以将其用作Dapr组件YAML: + +- 对于Kubernetes使用`kubectl`。 +- 使用Dapr CLI运行时。 + +{{% alert title="注意" color="primary" %}} +由于Redis配置组件与Redis `statestore.yaml`组件具有相同的元数据,如果您已经有Redis `statestore.yaml`,可以直接复制或修改Redis状态存储组件类型。 + +{{% /alert %}} + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: configstore +spec: + type: configuration.redis + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + value: +``` + +## 检索配置项 +### 获取配置项 + +以下示例展示了如何使用Dapr配置API获取已保存的配置项。 + +{{< tabs ".NET" Java Python Go JavaScript "HTTP API (BASH)" "HTTP API (Powershell)">}} + +{{% codetab %}} + +```csharp +//依赖项 +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Dapr.Client; + +//代码 +namespace ConfigurationApi +{ + public class Program + { + private static readonly string CONFIG_STORE_NAME = "configstore"; + + public static async Task Main(string[] args) + { + using var client = new DaprClientBuilder().Build(); + var configuration = await client.GetConfiguration(CONFIG_STORE_NAME, new List() { "orderId1", "orderId2" }); + Console.WriteLine($"Got key=\n{configuration[0].Key} -> {configuration[0].Value}\n{configuration[1].Key} -> {configuration[1].Value}"); + } + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +//依赖项 +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.DaprClient; +import io.dapr.client.domain.ConfigurationItem; +import io.dapr.client.domain.GetConfigurationRequest; +import io.dapr.client.domain.SubscribeConfigurationRequest; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +//代码 +private static final String CONFIG_STORE_NAME = "configstore"; + +public static void main(String[] args) throws Exception { + try (DaprClient client = (new DaprClientBuilder()).build()) { + List keys = new ArrayList<>(); + keys.add("orderId1"); + keys.add("orderId2"); + GetConfigurationRequest req = new GetConfigurationRequest(CONFIG_STORE_NAME, keys); + try { + Mono> items = client.getConfiguration(req); + items.block().forEach(ConfigurationClient::print); + } catch (Exception ex) { + System.out.println(ex.getMessage()); + } + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```python +#依赖项 +from dapr.clients import DaprClient +#代码 +with DaprClient() as d: + CONFIG_STORE_NAME = 'configstore' + keys = ['orderId1', 'orderId2'] + #Dapr启动时间 + d.wait(20) + configuration = d.get_configuration(store_name=CONFIG_STORE_NAME, keys=[keys], config_metadata={}) + print(f"Got key={configuration.items[0].key} value={configuration.items[0].value} version={configuration.items[0].version}") +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +package main + +import ( + "context" + "fmt" + + dapr "github.com/dapr/go-sdk/client" +) + +func main() { + ctx := context.Background() + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + items, err := client.GetConfigurationItems(ctx, "configstore", ["orderId1","orderId2"]) + if err != nil { + panic(err) + } + for key, item := range items { + fmt.Printf("get config: key = %s value = %s version = %s",key,(*item).Value, (*item).Version) + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```js +import { CommunicationProtocolEnum, DaprClient } from "@dapr/dapr"; + +// JS SDK尚不支持通过HTTP协议的配置API +const protocol = CommunicationProtocolEnum.GRPC; +const host = process.env.DAPR_HOST ?? "localhost"; +const port = process.env.DAPR_GRPC_PORT ?? 3500; + +const DAPR_CONFIGURATION_STORE = "configstore"; +const CONFIGURATION_ITEMS = ["orderId1", "orderId2"]; + +async function main() { + const client = new DaprClient(host, port, protocol); + // 从配置存储中获取配置项 + try { + const config = await client.configuration.get(DAPR_CONFIGURATION_STORE, CONFIGURATION_ITEMS); + Object.keys(config.items).forEach((key) => { + console.log("Configuration for " + key + ":", JSON.stringify(config.items[key])); + }); + } catch (error) { + console.log("Could not get config item, err:" + error); + process.exit(1); + } +} + +main().catch((e) => console.error(e)); +``` + +{{% /codetab %}} + +{{% codetab %}} + +启动一个Dapr sidecar: + +```bash +dapr run --app-id orderprocessing --dapr-http-port 3601 +``` + +在另一个终端中,获取之前保存的配置项: + +```bash +curl http://localhost:3601/v1.0/configuration/configstore?key=orderId1 +``` + +{{% /codetab %}} + +{{% codetab %}} + +启动一个Dapr sidecar: + +```bash +dapr run --app-id orderprocessing --dapr-http-port 3601 +``` + +在另一个终端中,获取之前保存的配置项: + +```powershell +Invoke-RestMethod -Uri 'http://localhost:3601/v1.0/configuration/configstore?key=orderId1' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +### 订阅配置项更新 + +以下是利用SDK订阅使用`configstore`存储组件的键`[orderId1, orderId2]`的代码示例。 + +{{< tabs ".NET" "ASP.NET Core" Java Python Go JavaScript>}} + +{{% codetab %}} + +```csharp +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Dapr.Client; + +const string DAPR_CONFIGURATION_STORE = "configstore"; +var CONFIGURATION_KEYS = new List { "orderId1", "orderId2" }; +var client = new DaprClientBuilder().Build(); + +// 订阅配置更改 +SubscribeConfigurationResponse subscribe = await client.SubscribeConfiguration(DAPR_CONFIGURATION_STORE, CONFIGURATION_ITEMS); + +// 打印配置更改 +await foreach (var items in subscribe.Source) +{ + // 应用程序订阅配置更改时的首次调用仅返回订阅ID + if (items.Keys.Count == 0) + { + Console.WriteLine("App subscribed to config changes with subscription id: " + subscribe.Id); + subscriptionId = subscribe.Id; + continue; + } + var cfg = System.Text.Json.JsonSerializer.Serialize(items); + Console.WriteLine("Configuration update " + cfg); +} +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和订阅者应用程序: + +```bash +dapr run --app-id orderprocessing -- dotnet run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```csharp +using System; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; +using Dapr.Client; +using Dapr.Extensions.Configuration; +using System.Collections.Generic; +using System.Threading; + +namespace ConfigurationApi +{ + public class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Starting application."); + CreateHostBuilder(args).Build().Run(); + Console.WriteLine("Closing application."); + } + + /// + /// 创建WebHost Builder。 + /// + /// 参数。 + /// 返回IHostbuilder。 + public static IHostBuilder CreateHostBuilder(string[] args) + { + var client = new DaprClientBuilder().Build(); + return Host.CreateDefaultBuilder(args) + .ConfigureAppConfiguration(config => + { + // 获取初始值并继续监视其更改。 + config.AddDaprConfigurationStore("configstore", new List() { "orderId1","orderId2" }, client, TimeSpan.FromSeconds(20)); + config.AddStreamingDaprConfigurationStore("configstore", new List() { "orderId1","orderId2" }, client, TimeSpan.FromSeconds(20)); + + }) + .ConfigureWebHostDefaults(webBuilder => + { + webBuilder.UseStartup(); + }); + } + } +} +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和订阅者应用程序: + +```bash +dapr run --app-id orderprocessing -- dotnet run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.DaprClient; +import io.dapr.client.domain.ConfigurationItem; +import io.dapr.client.domain.GetConfigurationRequest; +import io.dapr.client.domain.SubscribeConfigurationRequest; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +//代码 +private static final String CONFIG_STORE_NAME = "configstore"; +private static String subscriptionId = null; + +public static void main(String[] args) throws Exception { + try (DaprClient client = (new DaprClientBuilder()).build()) { + // 订阅配置更改 + List keys = new ArrayList<>(); + keys.add("orderId1"); + keys.add("orderId2"); + Flux subscription = client.subscribeConfiguration(DAPR_CONFIGURATON_STORE,keys); + + // 读取配置更改20秒 + subscription.subscribe((response) -> { + // 首次响应包含订阅ID + if (response.getItems() == null || response.getItems().isEmpty()) { + subscriptionId = response.getSubscriptionId(); + System.out.println("App subscribed to config changes with subscription id: " + subscriptionId); + } else { + response.getItems().forEach((k, v) -> { + System.out.println("Configuration update for " + k + ": {'value':'" + v.getValue() + "'}"); + }); + } + }); + Thread.sleep(20000); + } +} +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和订阅者应用程序: + +```bash +dapr run --app-id orderprocessing -- -- mvn spring-boot:run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```python +#依赖项 +from dapr.clients import DaprClient +#代码 + +def handler(id: str, resp: ConfigurationResponse): + for key in resp.items: + print(f"Subscribed item received key={key} value={resp.items[key].value} " + f"version={resp.items[key].version} " + f"metadata={resp.items[key].metadata}", flush=True) + +def executeConfiguration(): + with DaprClient() as d: + storeName = 'configurationstore' + keys = ['orderId1', 'orderId2'] + id = d.subscribe_configuration(store_name=storeName, keys=keys, + handler=handler, config_metadata={}) + print("Subscription ID is", id, flush=True) + sleep(20) + +executeConfiguration() +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和订阅者应用程序: + +```bash +dapr run --app-id orderprocessing -- python3 OrderProcessingService.py +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +package main + +import ( + "context" + "fmt" + "time" + + dapr "github.com/dapr/go-sdk/client" +) + +func main() { + ctx := context.Background() + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + subscribeID, err := client.SubscribeConfigurationItems(ctx, "configstore", []string{"orderId1", "orderId2"}, func(id string, items map[string]*dapr.ConfigurationItem) { + for k, v := range items { + fmt.Printf("get updated config key = %s, value = %s version = %s \n", k, v.Value, v.Version) + } + }) + if err != nil { + panic(err) + } + time.Sleep(20*time.Second) +} +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和订阅者应用程序: + +```bash +dapr run --app-id orderprocessing -- go run main.go +``` + +{{% /codetab %}} + +{{% codetab %}} + +```js +import { CommunicationProtocolEnum, DaprClient } from "@dapr/dapr"; + +// JS SDK尚不支持通过HTTP协议的配置API +const protocol = CommunicationProtocolEnum.GRPC; +const host = process.env.DAPR_HOST ?? "localhost"; +const port = process.env.DAPR_GRPC_PORT ?? 3500; + +const DAPR_CONFIGURATION_STORE = "configstore"; +const CONFIGURATION_ITEMS = ["orderId1", "orderId2"]; + +async function main() { + const client = new DaprClient(host, port, protocol); + // 订阅配置更新 + try { + const stream = await client.configuration.subscribeWithKeys( + DAPR_CONFIGURATION_STORE, + CONFIGURATION_ITEMS, + (config) => { + console.log("Configuration update", JSON.stringify(config.items)); + } + ); + // 取消订阅配置更新并在20秒后退出应用程序 + setTimeout(() => { + stream.stop(); + console.log("App unsubscribed to config changes"); + process.exit(0); + }, 20000); + } catch (error) { + console.log("Error subscribing to config updates, err:" + error); + process.exit(1); + } +} +main().catch((e) => console.error(e)); +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和订阅者应用程序: + +```bash +dapr run --app-id orderprocessing --app-protocol grpc --dapr-grpc-port 3500 -- node index.js +``` + +{{% /codetab %}} + +{{< /tabs >}} + +### 取消订阅配置项更新 + +在您订阅监视配置项后,您将收到所有订阅键的更新。要停止接收更新,您需要显式调用取消订阅API。 + +以下是展示如何使用取消订阅API取消订阅配置更新的代码示例。 + +{{< tabs ".NET" Java Python Go JavaScript "HTTP API (BASH)" "HTTP API (Powershell)">}} + +{{% codetab %}} +```csharp +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Dapr.Client; + +const string DAPR_CONFIGURATION_STORE = "configstore"; +var client = new DaprClientBuilder().Build(); + +// 取消订阅配置更新并退出应用程序 +async Task unsubscribe(string subscriptionId) +{ + try + { + await client.UnsubscribeConfiguration(DAPR_CONFIGURATION_STORE, subscriptionId); + Console.WriteLine("App unsubscribed from config changes"); + Environment.Exit(0); + } + catch (Exception ex) + { + Console.WriteLine("Error unsubscribing from config updates: " + ex.Message); + } +} +``` +{{% /codetab %}} + +{{% codetab %}} +```java +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.DaprClient; +import io.dapr.client.domain.ConfigurationItem; +import io.dapr.client.domain.GetConfigurationRequest; +import io.dapr.client.domain.SubscribeConfigurationRequest; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +//代码 +private static final String CONFIG_STORE_NAME = "configstore"; +private static String subscriptionId = null; + +public static void main(String[] args) throws Exception { + try (DaprClient client = (new DaprClientBuilder()).build()) { + // 取消订阅配置更改 + UnsubscribeConfigurationResponse unsubscribe = client + .unsubscribeConfiguration(subscriptionId, DAPR_CONFIGURATON_STORE).block(); + if (unsubscribe.getIsUnsubscribed()) { + System.out.println("App unsubscribed to config changes"); + } else { + System.out.println("Error unsubscribing to config updates, err:" + unsubscribe.getMessage()); + } + } catch (Exception e) { + System.out.println("Error unsubscribing to config updates," + e.getMessage()); + System.exit(1); + } +} +``` +{{% /codetab %}} + +{{% codetab %}} +```python +import asyncio +import time +import logging +from dapr.clients import DaprClient +subscriptionID = "" + +with DaprClient() as d: + isSuccess = d.unsubscribe_configuration(store_name='configstore', id=subscriptionID) + print(f"Unsubscribed successfully? {isSuccess}", flush=True) +``` +{{% /codetab %}} + +{{% codetab %}} +```go +package main + +import ( + "context" + "encoding/json" + "fmt" + "log" + "os" + "time" + + dapr "github.com/dapr/go-sdk/client" +) + +var DAPR_CONFIGURATION_STORE = "configstore" +var subscriptionID = "" + +func main() { + client, err := dapr.NewClient() + if err != nil { + log.Panic(err) + } + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + if err := client.UnsubscribeConfigurationItems(ctx, DAPR_CONFIGURATION_STORE , subscriptionID); err != nil { + panic(err) + } +} +``` +{{% /codetab %}} + +{{% codetab %}} +```js +import { CommunicationProtocolEnum, DaprClient } from "@dapr/dapr"; + +// JS SDK尚不支持通过HTTP协议的配置API +const protocol = CommunicationProtocolEnum.GRPC; +const host = process.env.DAPR_HOST ?? "localhost"; +const port = process.env.DAPR_GRPC_PORT ?? 3500; + +const DAPR_CONFIGURATION_STORE = "configstore"; +const CONFIGURATION_ITEMS = ["orderId1", "orderId2"]; + +async function main() { + const client = new DaprClient(host, port, protocol); + + try { + const stream = await client.configuration.subscribeWithKeys( + DAPR_CONFIGURATION_STORE, + CONFIGURATION_ITEMS, + (config) => { + console.log("Configuration update", JSON.stringify(config.items)); + } + ); + setTimeout(() => { + // 取消订阅配置更新 + stream.stop(); + console.log("App unsubscribed to config changes"); + process.exit(0); + }, 20000); + } catch (error) { + console.log("Error subscribing to config updates, err:" + error); + process.exit(1); + } +} + +main().catch((e) => console.error(e)); +``` +{{% /codetab %}} + +{{% codetab %}} +```bash +curl 'http://localhost:/v1.0/configuration/configstore//unsubscribe' +``` +{{% /codetab %}} + +{{% codetab %}} +```powershell +Invoke-RestMethod -Uri 'http://localhost:/v1.0/configuration/configstore//unsubscribe' +``` +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 + +* 阅读[配置API概述]({{< ref configuration-api-overview.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/conversation/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/conversation/_index.md new file mode 100644 index 000000000..380fb78be --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/conversation/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "互动" +linkTitle: "互动" +weight: 130 +description: "通过提示有效使用大型语言模型(LLMs)" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/conversation/conversation-overview.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/conversation/conversation-overview.md new file mode 100644 index 000000000..8b27c6c34 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/conversation/conversation-overview.md @@ -0,0 +1,58 @@ +--- +type: docs +title: "会话概述" +linkTitle: "概述" +weight: 1000 +description: "会话API功能概述" +--- + +{{% alert title="Alpha" color="primary" %}} +会话API目前处于[alpha]({{< ref "certification-lifecycle.md#certification-levels" >}})阶段。 +{{% /alert %}} + +Dapr的会话API简化了与大型语言模型(LLM)进行大规模、安全、可靠交互的复杂性。无论您是缺乏必要本地SDK的开发者,还是只想专注于LLM交互提示的多语言开发团队,会话API都提供了一个统一的API接口来与底层LLM提供商进行对话。 + +显示用户应用与Dapr的LLM组件通信流程的图示。 + +除了启用关键的性能和安全功能(如[提示缓存]({{< ref "#prompt-caching" >}})和[个人信息清理]({{< ref "#personally-identifiable-information-pii-obfuscation" >}})),您还可以将会话API与Dapr的其他功能结合使用,例如: +- 弹性断路器和重试机制,以应对限制和令牌错误,或 +- 中间件,用于验证与LLM之间的请求 + +Dapr通过为您的LLM交互提供指标,增强了系统的可观测性。 + +## 功能 + +以下功能适用于[所有支持的会话组件]({{< ref supported-conversation >}})。 + +### 提示缓存 + +提示缓存通过存储和重用在多个API调用中经常重复的提示来优化性能。Dapr将这些频繁使用的提示存储在本地缓存中,从而显著减少延迟和成本,使您的集群、pod或其他组件可以重用,而无需为每个新请求重新处理信息。 + +### 个人信息清理 + +个人信息清理功能能够识别并删除会话响应中的任何形式的敏感用户信息。只需在输入和输出数据上启用此功能,即可保护您的隐私,清除可能用于识别个人的敏感细节。 + +## 演示 + +观看在[Diagrid的Dapr v1.15庆祝活动](https://www.diagrid.io/videos/dapr-1-15-deep-dive)中展示的演示,了解会话API如何使用.NET SDK工作。 + + + +## 试用会话 + +### 快速入门和教程 + +想要测试Dapr会话API?通过以下快速入门和教程来查看其实际应用: + +| 快速入门/教程 | 描述 | +| ------------------- | ----------- | +| [会话快速入门](todo) | TODO | + +### 直接在您的应用中开始使用会话API + +想跳过快速入门?没问题。您可以直接在您的应用中试用会话模块。在[Dapr安装完成]({{< ref "getting-started/_index.md" >}})后,您可以从[操作指南]({{< ref howto-conversation-layer.md >}})开始使用会话API。 + +## 下一步 + +- [操作指南:使用会话API与LLM对话]({{< ref howto-conversation-layer.md >}}) +- [会话API组件]({{< ref supported-conversation >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/conversation/howto-conversation-layer.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/conversation/howto-conversation-layer.md new file mode 100644 index 000000000..eaa3e73f0 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/conversation/howto-conversation-layer.md @@ -0,0 +1,236 @@ +--- +type: docs +title: "操作指南:使用 conversation API 与 LLM 对话" +linkTitle: "操作指南:对话" +weight: 2000 +description: "学习如何简化与大型语言模型交互的复杂性" +--- + +{{% alert title="Alpha" color="primary" %}} +conversation API 目前处于 [alpha]({{< ref "certification-lifecycle.md#certification-levels" >}}) 阶段。 +{{% /alert %}} + +让我们开始使用 [conversation API]({{< ref conversation-overview.md >}})。在本指南中,您将学习如何: + +- 配置一个可用的 Dapr 组件(echo),以便与 conversation API 搭配使用。 +- 将 conversation 客户端集成到您的应用程序中。 +- 使用 `dapr run` 启动连接。 + +## 配置 conversation 组件 + +创建一个名为 `conversation.yaml` 的新配置文件,并将其保存到应用程序目录中的组件或配置子文件夹中。 + +为您的 `conversation.yaml` 文件选择 [合适的 conversation 组件规范]({{< ref supported-conversation >}})。 + +在这个场景中,我们使用一个简单的 echo 组件。 + +```yml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: echo +spec: + type: conversation.echo + version: v1 +``` + +## 集成 conversation 客户端 + +以下示例使用 HTTP 客户端向 Dapr 的 sidecar HTTP 端点发送 POST 请求。您也可以使用 [Dapr SDK 客户端]({{< ref "#related-links" >}})。 + +{{< tabs ".NET" "Go" "Rust" >}} + + +{{% codetab %}} + +```csharp +using Dapr.AI.Conversation; +using Dapr.AI.Conversation.Extensions; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddDaprConversationClient(); + +var app = builder.Build(); + +var conversationClient = app.Services.GetRequiredService(); +var response = await conversationClient.ConverseAsync("conversation", + new List + { + new DaprConversationInput( + "Please write a witty haiku about the Dapr distributed programming framework at dapr.io", + DaprConversationRole.Generic) + }); + +Console.WriteLine("Received the following from the LLM:"); +foreach (var resp in response.Outputs) +{ + Console.WriteLine($"\t{resp.Result}"); +} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```go +package main + +import ( + "context" + "fmt" + dapr "github.com/dapr/go-sdk/client" + "log" +) + +func main() { + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + + input := dapr.ConversationInput{ + Message: "Please write a witty haiku about the Dapr distributed programming framework at dapr.io", + // Role: nil, // Optional + // ScrubPII: nil, // Optional + } + + fmt.Printf("conversation input: %s\n", input.Message) + + var conversationComponent = "echo" + + request := dapr.NewConversationRequest(conversationComponent, []dapr.ConversationInput{input}) + + resp, err := client.ConverseAlpha1(context.Background(), request) + if err != nil { + log.Fatalf("err: %v", err) + } + + fmt.Printf("conversation output: %s\n", resp.Outputs[0].Result) +} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```rust +use dapr::client::{ConversationInputBuilder, ConversationRequestBuilder}; +use std::thread; +use std::time::Duration; + +type DaprClient = dapr::Client; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Sleep to allow for the server to become available + thread::sleep(Duration::from_secs(5)); + + // Set the Dapr address + let address = "https://127.0.0.1".to_string(); + + let mut client = DaprClient::connect(address).await?; + + let input = ConversationInputBuilder::new("Please write a witty haiku about the Dapr distributed programming framework at dapr.io").build(); + + let conversation_component = "echo"; + + let request = + ConversationRequestBuilder::new(conversation_component, vec![input.clone()]).build(); + + println!("conversation input: {:?}", input.message); + + let response = client.converse_alpha1(request).await?; + + println!("conversation output: {:?}", response.outputs[0].result); + Ok(()) +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 启动 conversation 连接 + +使用 `dapr run` 命令启动连接。例如,在这个场景中,我们在一个应用程序上运行 `dapr run`,其应用程序 ID 为 `conversation`,并指向 `./config` 目录中的 conversation YAML 文件。 + +{{< tabs ".NET" "Go" "Rust" >}} + + +{{% codetab %}} + +```bash +dapr run --app-id conversation --dapr-grpc-port 50001 --log-level debug --resources-path ./config -- dotnet run +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```bash +dapr run --app-id conversation --dapr-grpc-port 50001 --log-level debug --resources-path ./config -- go run ./main.go +``` + +**预期输出** + +``` + - '== APP == conversation output: Please write a witty haiku about the Dapr distributed programming framework at dapr.io' +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```bash +dapr run --app-id=conversation --resources-path ./config --dapr-grpc-port 3500 -- cargo run --example conversation +``` + +**预期输出** + +``` + - 'conversation input: hello world' + - 'conversation output: hello world' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 相关链接 + +尝试使用支持的 SDK 仓库中提供的完整示例来体验 conversation API。 + +{{< tabs ".NET" "Go" "Rust" >}} + + +{{% codetab %}} + +[Dapr conversation 示例与 .NET SDK](https://github.com/dapr/dotnet-sdk/tree/master/examples/AI/ConversationalAI) + +{{% /codetab %}} + + +{{% codetab %}} + +[Dapr conversation 示例与 Go SDK](https://github.com/dapr/go-sdk/tree/main/examples/conversation) + +{{% /codetab %}} + + +{{% codetab %}} + +[Dapr conversation 示例与 Rust SDK](https://github.com/dapr/rust-sdk/tree/main/examples/src/conversation) + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 + +- [conversation API 参考指南]({{< ref conversation_api.md >}}) +- [可用的 conversation 组件]({{< ref supported-conversation >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/cryptography/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/cryptography/_index.md new file mode 100644 index 000000000..2f8290252 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/cryptography/_index.md @@ -0,0 +1,14 @@ +type: docs +title: "加密技术" +linkTitle: "加密技术" +weight: 100 +description: "在不暴露密钥的情况下执行加密操作,确保应用程序的安全性" + +--- + +{{% alert title="更多关于Dapr加密技术" color="primary" %}} +了解如何使用Dapr加密技术: +- 尝试[加密技术快速入门]({{< ref cryptography-quickstart.md >}})。 +- 通过不同的[Dapr SDKs]({{< ref sdks >}})体验加密技术。 +- 查看支持的[加密技术组件规格]({{< ref supported-cryptography >}})。 +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/cryptography/cryptography-overview.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/cryptography/cryptography-overview.md new file mode 100644 index 000000000..93286c419 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/cryptography/cryptography-overview.md @@ -0,0 +1,88 @@ +--- +type: docs +title: 加密概述 +linkTitle: 概述 +weight: 1000 +description: "Dapr 加密概述" +--- + +使用加密构建块,您可以安全且一致地利用加密技术。Dapr 提供的 API 允许您在密钥库或 Dapr sidecar 中执行加密和解密操作,而无需将加密密钥暴露给您的应用程序。 + +## 为什么需要加密? + +加密技术在应用程序中被广泛使用,正确实施可以在数据泄露时提高安全性。在某些情况下,您可能需要使用加密技术以符合行业法规(如金融领域)或法律要求(如 GDPR 等隐私法规)。 + +然而,正确使用加密技术可能很复杂。您需要: + +- 选择合适的算法和选项 +- 学习正确的密钥管理和保护方法 +- 在希望限制对加密密钥材料的访问时,处理操作复杂性 + +安全的一个重要要求是限制对加密密钥的访问,这通常被称为“原始密钥材料”。Dapr 可以与密钥库集成,如 Azure Key Vault(未来将支持更多组件),这些密钥库将密钥存储在安全的环境中,并在库中执行加密操作,而不将密钥暴露给您的应用程序或 Dapr。 + +或者,您可以配置 Dapr 为您管理加密密钥,在 sidecar 中执行操作,同样不将原始密钥材料暴露给您的应用程序。 + +## Dapr 中的加密 + +使用 Dapr,您可以在不将加密密钥暴露给应用程序的情况下执行加密操作。 + +显示 Dapr 加密如何与您的应用程序协作的图示 + +通过使用加密构建块,您可以: + +- 更轻松地以安全的方式执行加密操作。Dapr 提供了防止使用不安全算法或不安全选项的保护措施。 +- 将密钥保存在应用程序之外。应用程序从未看到“原始密钥材料”,但可以请求库使用密钥执行操作。当使用 Dapr 的加密引擎时,操作在 Dapr sidecar 中安全地执行。 +- 实现更好的关注点分离。通过使用外部库或加密组件,只有授权团队可以访问私钥材料。 +- 更轻松地管理和轮换密钥。密钥在库中管理并在应用程序之外,它们可以在不需要开发人员参与(甚至不需要重启应用程序)的情况下轮换。 +- 启用更好的审计日志记录,以监控何时在库中使用密钥执行操作。 + +{{% alert title="注意" color="primary" %}} +虽然在 alpha 版本中同时支持 HTTP 和 gRPC,但使用支持的 Dapr SDK 的 gRPC API 是加密的推荐方法。 +{{% /alert %}} + +## 功能 + +### 加密组件 + +Dapr 加密构建块包括两种组件: + +- **允许与管理服务或库(“密钥库”)交互的组件。** + 类似于 Dapr 在各种 secret 存储或 state 存储之上的“抽象层”,这些组件允许与各种密钥库(如 Azure Key Vault)交互(未来 Dapr 版本中会有更多)。通过这些组件,对私钥的加密操作在库中执行,Dapr 从未看到您的私钥。 + +- **基于 Dapr 自身加密引擎的组件。** + 当密钥库不可用时,您可以利用基于 Dapr 自身加密引擎的组件。这些组件名称中带有 `.dapr.`,在 Dapr sidecar 中执行加密操作,密钥存储在文件、Kubernetes secret 或其他来源中。虽然 Dapr 知道私钥,但它们仍然对您的应用程序不可用。 + +这两种组件,无论是利用密钥库还是使用 Dapr 中的加密引擎,都提供相同的抽象层。这允许您的解决方案根据需要在各种库和/或加密组件之间切换。例如,您可以在开发期间使用本地存储的密钥,而在生产中使用云库。 + +### 加密 API + +加密 API 允许使用 [Dapr Crypto Scheme v1](https://github.com/dapr/kit/blob/main/schemes/enc/v1/README.md) 加密和解密数据。这是一种有见地的加密方案,旨在使用现代、安全的加密标准,并以流的方式高效处理数据(甚至是大文件)。 + +## 试用加密 + +### 快速入门和教程 + +想要测试 Dapr 加密 API 吗?通过以下快速入门和教程,看看加密如何实际运作: + +| 快速入门/教程 | 描述 | +| ------------------- | ----------- | +| [加密快速入门]({{< ref cryptography-quickstart.md >}}) | 使用加密 API 使用 RSA 和 AES 密钥加密和解密消息和大文件。 | + +### 直接在您的应用程序中开始使用加密 + +想要跳过快速入门?没问题。您可以直接在应用程序中试用加密构建块来加密和解密您的应用程序。在 [安装 Dapr]({{< ref "getting-started/_index.md" >}}) 后,您可以从 [加密操作指南]({{< ref howto-cryptography.md >}}) 开始使用加密 API。 + +## 演示 + +观看此 [Dapr 社区电话 #83 中的加密 API 演示视频](https://youtu.be/PRWYX4lb2Sg?t=1148): + + + +## 下一步 + +{{< button text="使用加密 API >>" page="howto-cryptography.md" >}} + +## 相关链接 +- [加密概述]({{< ref cryptography-overview.md >}}) +- [加密组件规范]({{< ref supported-cryptography >}}) +- [加密 API 参考文档]({{< ref cryptography_api >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/cryptography/howto-cryptography.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/cryptography/howto-cryptography.md new file mode 100644 index 000000000..6f9077178 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/cryptography/howto-cryptography.md @@ -0,0 +1,299 @@ +--- +type: docs +title: "如何:使用加密API" +linkTitle: "如何:使用加密" +weight: 2000 +description: "学习如何加密和解密文件" +--- + +在您了解了[Dapr作为加密构建块]({{< ref cryptography-overview.md >}})之后,让我们通过使用SDK来学习如何使用加密API。 + +{{% alert title="注意" color="primary" %}} +Dapr加密功能目前处于alpha测试阶段。 + +{{% /alert %}} + +## 加密 + +{{< tabs "Python" "JavaScript" ".NET" "Go" >}} + +{{% codetab %}} + + + +在您的项目中使用Dapr SDK和gRPC API,您可以加密数据流,例如文件或字符串: + +```python +# 当传递数据(缓冲区或字符串)时,`encrypt`会返回一个包含加密信息的缓冲区 +def encrypt_decrypt_string(dapr: DaprClient): + message = 'The secret is "passw0rd"' + + # 加密消息 + resp = dapr.encrypt( + data=message.encode(), + options=EncryptOptions( + # 加密组件的名称(必需) + component_name=CRYPTO_COMPONENT_NAME, + # 存储在加密组件中的密钥(必需) + key_name=RSA_KEY_NAME, + # 用于包装密钥的算法,必须由上述密钥支持。 + # 选项包括:"RSA", "AES" + key_wrap_algorithm='RSA', + ), + ) + + # 该方法返回一个可读流,我们将其完整读取到内存中 + encrypt_bytes = resp.read() + print(f'加密后的消息长度为 {len(encrypt_bytes)} 字节') +``` + +{{% /codetab %}} + +{{% codetab %}} + + + +在您的项目中使用Dapr SDK和gRPC API,您可以加密缓冲区或字符串中的数据: + +```js +// 当传递数据(缓冲区或字符串)时,`encrypt`会返回一个包含加密信息的缓冲区 +const ciphertext = await client.crypto.encrypt(plaintext, { + // Dapr组件的名称(必需) + componentName: "mycryptocomponent", + // 存储在组件中的密钥名称(必需) + keyName: "mykey", + // 用于包装密钥的算法,必须由上述密钥支持。 + // 选项包括:"RSA", "AES" + keyWrapAlgorithm: "RSA", +}); +``` + +API也可以与流一起使用,以更高效地加密来自流的数据。下面的示例使用流加密文件,并写入另一个文件: + +```js +// `encrypt`可以用作双工流 +await pipeline( + fs.createReadStream("plaintext.txt"), + await client.crypto.encrypt({ + // Dapr组件的名称(必需) + componentName: "mycryptocomponent", + // 存储在组件中的密钥名称(必需) + keyName: "mykey", + // 用于包装密钥的算法,必须由上述密钥支持。 + // 选项包括:"RSA", "AES" + keyWrapAlgorithm: "RSA", + }), + fs.createWriteStream("ciphertext.out"), +); +``` + +{{% /codetab %}} + +{{% codetab %}} + + +在您的项目中使用Dapr SDK和gRPC API,您可以加密字符串或字节数组中的数据: + +```csharp +using var client = new DaprClientBuilder().Build(); + +const string componentName = "azurekeyvault"; //更改此以匹配您的加密组件 +const string keyName = "myKey"; //更改此以匹配您加密存储中的密钥名称 + +const string plainText = "This is the value we're going to encrypt today"; + +//将字符串编码为UTF-8字节数组并加密 +var plainTextBytes = Encoding.UTF8.GetBytes(plainText); +var encryptedBytesResult = await client.EncryptAsync(componentName, plaintextBytes, keyName, new EncryptionOptions(KeyWrapAlgorithm.Rsa)); +``` + +{{% /codetab %}} + +{{% codetab %}} + + + +在您的项目中使用Dapr SDK,您可以加密数据流,例如文件。 + +```go +out, err := sdkClient.Encrypt(context.Background(), rf, dapr.EncryptOptions{ + // Dapr组件的名称(必需) + ComponentName: "mycryptocomponent", + // 存储在组件中的密钥名称(必需) + KeyName: "mykey", + // 用于包装密钥的算法,必须由上述密钥支持。 + // 选项包括:"RSA", "AES" + Algorithm: "RSA", +}) +``` + +以下示例将`Encrypt` API置于上下文中,代码读取文件,加密它,然后将结果存储在另一个文件中。 + +```go +// 输入文件,明文 +rf, err := os.Open("input") +if err != nil { + panic(err) +} +defer rf.Close() + +// 输出文件,加密 +wf, err := os.Create("output.enc") +if err != nil { + panic(err) +} +defer wf.Close() + +// 使用Dapr加密数据 +out, err := sdkClient.Encrypt(context.Background(), rf, dapr.EncryptOptions{ + // 这是3个必需参数 + ComponentName: "mycryptocomponent", + KeyName: "mykey", + Algorithm: "RSA", +}) +if err != nil { + panic(err) +} + +// 读取流并将其复制到输出文件 +n, err := io.Copy(wf, out) +if err != nil { + panic(err) +} +fmt.Println("已写入", n, "字节") +``` + +以下示例使用`Encrypt` API加密字符串。 + +```go +// 输入字符串 +rf := strings.NewReader("Amor, ch’a nullo amato amar perdona, mi prese del costui piacer sì forte, che, come vedi, ancor non m’abbandona") + +// 使用Dapr加密数据 +enc, err := sdkClient.Encrypt(context.Background(), rf, dapr.EncryptOptions{ + ComponentName: "mycryptocomponent", + KeyName: "mykey", + Algorithm: "RSA", +}) +if err != nil { + panic(err) +} + +// 将加密数据读取到字节切片中 +enc, err := io.ReadAll(enc) +if err != nil { + panic(err) +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 解密 + +{{< tabs "Python" "JavaScript" ".NET" "Go" >}} + +{{% codetab %}} + + + +要解密数据流,请使用`decrypt`。 + +```python +def encrypt_decrypt_string(dapr: DaprClient): + message = 'The secret is "passw0rd"' + + # ... + + # 解密加密数据 + resp = dapr.decrypt( + data=encrypt_bytes, + options=DecryptOptions( + # 加密组件的名称(必需) + component_name=CRYPTO_COMPONENT_NAME, + # 存储在加密组件中的密钥(必需) + key_name=RSA_KEY_NAME, + ), + ) + + # 该方法返回一个可读流,我们将其完整读取到内存中 + decrypt_bytes = resp.read() + print(f'解密后的消息长度为 {len(decrypt_bytes)} 字节') + + print(decrypt_bytes.decode()) + assert message == decrypt_bytes.decode() +``` + +{{% /codetab %}} + +{{% codetab %}} + + + +使用Dapr SDK,您可以解密缓冲区中的数据或使用流。 + +```js +// 当传递数据作为缓冲区时,`decrypt`会返回一个包含解密信息的缓冲区 +const plaintext = await client.crypto.decrypt(ciphertext, { + // 唯一必需的选项是组件名称 + componentName: "mycryptocomponent", +}); + +// `decrypt`也可以用作双工流 +await pipeline( + fs.createReadStream("ciphertext.out"), + await client.crypto.decrypt({ + // 唯一必需的选项是组件名称 + componentName: "mycryptocomponent", + }), + fs.createWriteStream("plaintext.out"), +); +``` + +{{% /codetab %}} + +{{% codetab %}} + + +要解密字符串,请在您的项目中使用'解密Async' gRPC API。 + +在以下示例中,我们将获取一个字节数组(例如上面的示例)并将其解密为UTF-8编码的字符串。 + +```csharp +public async Task DecryptBytesAsync(byte[] encryptedBytes) +{ + using var client = new DaprClientBuilder().Build(); + + const string componentName = "azurekeyvault"; //更改此以匹配您的加密组件 + const string keyName = "myKey"; //更改此以匹配您加密存储中的密钥名称 + + var decryptedBytes = await client.DecryptAsync(componentName, encryptedBytes, keyName); + var decryptedString = Encoding.UTF8.GetString(decryptedBytes.ToArray()); + return decryptedString; +} +``` + +{{% /codetab %}} + +{{% codetab %}} + + + +要解密文件,请在您的项目中使用`Decrypt` gRPC API。 + +在以下示例中,`out`是一个可以写入文件或在内存中读取的流,如上面的示例中所示。 + +```go +out, err := sdkClient.Decrypt(context.Background(), rf, dapr.EncryptOptions{ + // 唯一必需的选项是组件名称 + ComponentName: "mycryptocomponent", +}) +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 +[加密组件规范]({{< ref supported-cryptography >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/distributed-lock/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/distributed-lock/_index.md new file mode 100644 index 000000000..bb5e472f2 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/distributed-lock/_index.md @@ -0,0 +1,14 @@ +--- +type: docs +title: "分布式锁" +linkTitle: "分布式锁" +weight: 90 +description: 分布式锁为应用程序提供对共享资源的独占访问。 +--- + +{{% alert title="更多关于 Dapr 分布式锁的信息" color="primary" %}} +了解如何使用 Dapr 分布式锁的更多信息: +- 使用任意支持的 [Dapr SDKs]({{< ref sdks >}}) 来实现分布式锁。 +- 查看 [分布式锁 API 参考文档]({{< ref distributed_lock_api.md >}})。 +- 浏览支持的 [分布式锁组件规格]({{< ref supported-locks >}})。 +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/distributed-lock/distributed-lock-api-overview.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/distributed-lock/distributed-lock-api-overview.md new file mode 100644 index 000000000..a37ea0f45 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/distributed-lock/distributed-lock-api-overview.md @@ -0,0 +1,50 @@ +--- +type: docs +title: "分布式锁概述" +linkTitle: "概述" +weight: 1000 +description: "分布式锁API构建模块概述" +--- + +## 介绍 +锁用于确保资源的互斥访问。例如,您可以使用锁来: + +- 独占访问数据库的行、表或整个数据库 +- 顺序锁定从队列中读取消息 + +任何需要更新的共享资源都可以被锁定。锁通常用于改变状态的操作,而不是读取操作。 + +每个锁都有一个名称。应用程序决定锁定哪些资源。通常,同一应用程序的多个实例使用这个命名锁来独占访问资源并进行更新。 + +例如,在竞争消费者模式中,应用程序的多个实例访问一个队列。您可以选择在应用程序执行其业务逻辑时锁定队列。 + +在下图中,同一应用程序的两个实例,`App1`,使用[Redis锁组件]({{< ref redis-lock >}})来锁定共享资源。 + +- 第一个应用程序实例获取命名锁并获得独占访问权。 +- 第二个应用程序实例无法获取锁,因此在锁被释放之前不允许访问资源,释放方式可以是: + - 通过应用程序显式调用解锁API,或 + - 由于租约超时而在一段时间后自动释放。 + + + +*此API目前处于`Alpha`状态。 + +## 特性 + +### 资源的互斥访问 +在任何给定时刻,只有一个应用程序实例可以持有命名锁。锁的范围限定在Dapr应用程序ID内。 + +### 使用租约防止死锁 +Dapr分布式锁使用基于租约的锁定机制。如果应用程序获取锁后遇到异常,无法释放锁,则锁将在一段时间后通过租约自动释放。这防止了在应用程序故障时发生资源死锁。 + +## 演示 + +观看[此视频以了解分布式锁API的概述](https://youtu.be/wLYYOJLt_KQ?t=583): + +
+ + +## 下一步 + +请参阅以下指南: +- [如何在您的应用程序中使用分布式锁]({{< ref howto-use-distributed-lock.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/distributed-lock/howto-use-distributed-lock.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/distributed-lock/howto-use-distributed-lock.md new file mode 100644 index 000000000..e1523af35 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/distributed-lock/howto-use-distributed-lock.md @@ -0,0 +1,194 @@ +--- +type: docs +title: "操作指南:使用锁" +linkTitle: "操作指南:使用锁" +weight: 2000 +description: "学习如何使用分布式锁来提供对资源的独占访问" +--- + +了解了Dapr分布式锁API构建块的功能后,学习如何在服务中使用它。在本指南中,我们将通过一个示例应用程序演示如何使用Redis锁组件获取锁。有关支持的锁存储类型,请参阅[此参考页面](/reference/components-reference/supported-locks/)。 + +下图展示了相同应用程序的两个实例尝试获取锁,其中一个成功,另一个被拒绝。 + +下图显示了相同应用程序的两个实例获取锁,其中一个实例成功,另一个被拒绝 + +下图展示了相同应用程序的两个实例,其中一个实例释放锁,另一个实例随后成功获取锁。 + +图示显示了从相同应用程序的多个实例中释放锁 + +下图展示了不同应用程序的两个实例在同一资源上获取不同的锁。 + +下图显示了不同应用程序的两个实例,在同一资源上获取不同的锁 + +### 配置锁组件 + +将以下组件文件保存到您机器上的[默认组件文件夹]({{< ref "install-dapr-selfhost.md#step-5-verify-components-directory-has-been-initialized" >}})。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: lockstore +spec: + type: lock.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + value: +``` + +### 获取锁 + +{{< tabs HTTP ".NET" Go >}} + +{{% codetab %}} + +```bash +curl -X POST http://localhost:3500/v1.0-alpha1/lock/lockstore + -H 'Content-Type: application/json' + -d '{"resourceId":"my_file_name", "lockOwner":"random_id_abc123", "expiryInSeconds": 60}' +``` + +{{% /codetab %}} + +{{% codetab %}} + +```csharp +using System; +using Dapr.Client; + +namespace LockService +{ + class Program + { + [Obsolete("Distributed Lock API is in Alpha, this can be removed once it is stable.")] + static async Task Main(string[] args) + { + string DAPR_LOCK_NAME = "lockstore"; + string fileName = "my_file_name"; + var client = new DaprClientBuilder().Build(); + + await using (var fileLock = await client.Lock(DAPR_LOCK_NAME, fileName, "random_id_abc123", 60)) + { + if (fileLock.Success) + { + Console.WriteLine("Success"); + } + else + { + Console.WriteLine($"Failed to lock {fileName}."); + } + } + } + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +package main + +import ( + "fmt" + + dapr "github.com/dapr/go-sdk/client" +) + +func main() { + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + defer client.Close() + + resp, err := client.TryLockAlpha1(ctx, "lockstore", &dapr.LockRequest{ + LockOwner: "random_id_abc123", + ResourceID: "my_file_name", + ExpiryInSeconds: 60, + }) + + fmt.Println(resp.Success) +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +### 解锁现有锁 + +{{< tabs HTTP ".NET" Go >}} + +{{% codetab %}} + +```bash +curl -X POST http://localhost:3500/v1.0-alpha1/unlock/lockstore + -H 'Content-Type: application/json' + -d '{"resourceId":"my_file_name", "lockOwner":"random_id_abc123"}' +``` + +{{% /codetab %}} + +{{% codetab %}} + +```csharp +using System; +using Dapr.Client; + +namespace LockService +{ + class Program + { + static async Task Main(string[] args) + { + string DAPR_LOCK_NAME = "lockstore"; + var client = new DaprClientBuilder().Build(); + + var response = await client.Unlock(DAPR_LOCK_NAME, "my_file_name", "random_id_abc123")); + Console.WriteLine(response.status); + } + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +package main + +import ( + "fmt" + + dapr "github.com/dapr/go-sdk/client" +) + +func main() { + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + defer client.Close() + + resp, err := client.UnlockAlpha1(ctx, "lockstore", &UnlockRequest{ + LockOwner: "random_id_abc123", + ResourceID: "my_file_name", + }) + + fmt.Println(resp.Status) +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 + +阅读[分布式锁API概述]({{< ref distributed-lock-api-overview.md >}})以了解更多信息。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/jobs/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/jobs/_index.md new file mode 100644 index 000000000..416133a2e --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/jobs/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "任务" +linkTitle: "任务" +weight: 120 +description: "管理任务的调度与编排" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/jobs/howto-schedule-and-handle-triggered-jobs.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/jobs/howto-schedule-and-handle-triggered-jobs.md new file mode 100644 index 000000000..72eee7454 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/jobs/howto-schedule-and-handle-triggered-jobs.md @@ -0,0 +1,290 @@ +--- +type: docs +title: "操作指南:调度和处理触发的作业" +linkTitle: "操作指南:调度和处理触发的作业" +weight: 2000 +description: "学习如何使用作业API来调度和处理触发的作业" +--- + +现在您已经了解了[作业构建块]({{< ref jobs-overview.md >}})提供的功能,让我们来看一个如何使用API的示例。下面的代码示例描述了一个为数据库备份应用程序调度作业并在触发时处理它们的应用程序,也就是作业因到达其到期时间而被返回到应用程序的时间。 + + + +## 启动调度器服务 + +当您[在本地托管模式或Kubernetes上运行`dapr init`]({{< ref install-dapr-selfhost.md >}})时,Dapr调度器服务会启动。 + +## 设置作业API + +在您的代码中,配置并调度应用程序内的作业。 + +{{< tabs ".NET" "Go" >}} + +{{% codetab %}} + + + +以下.NET SDK代码示例调度名为`prod-db-backup`的作业。作业数据包含有关您将定期备份的数据库的信息。在本示例中,您将: +- 定义在示例其余部分中使用的类型 +- 在应用程序启动期间注册一个端点,以处理服务上的所有作业触发调用 +- 向Dapr注册作业 + +在以下示例中,您将创建记录,序列化并与作业一起注册,以便在将来作业被触发时可以使用这些信息: +- 备份任务的名称(`db-backup`) +- 备份任务的`Metadata`,包括: + - 数据库名称(`DBName`) + - 数据库位置(`BackupLocation`) + +创建一个ASP.NET Core项目,并从NuGet添加最新版本的`Dapr.Jobs`。 + +> **注意:** 虽然您的项目不严格需要使用`Microsoft.NET.Sdk.Web` SDK来创建作业,但在撰写本文档时,只有调度作业的服务会接收到其触发调用。由于这些调用期望有一个可以处理作业触发的端点,并且需要`Microsoft.NET.Sdk.Web` SDK,因此建议您为此目的使用ASP.NET Core项目。 + +首先定义类型以持久化我们的备份作业数据,并将我们自己的JSON属性名称属性应用于属性,以便它们与其他语言示例保持一致。 + +```cs +//定义我们将用来表示作业数据的类型 +internal sealed record BackupJobData([property: JsonPropertyName("task")] string Task, [property: JsonPropertyName("metadata")] BackupMetadata Metadata); +internal sealed record BackupMetadata([property: JsonPropertyName("DBName")]string DatabaseName, [property: JsonPropertyName("BackupLocation")] string BackupLocation); +``` + +接下来,作为应用程序设置的一部分,设置一个处理程序,该处理程序将在作业在您的应用程序上被触发时调用。此处理程序负责根据提供的作业名称识别应如何处理作业。 + +这通过在ASP.NET Core中注册一个处理程序来实现,路径为`/job/`,其中``是参数化的,并传递给此处理程序委托,以满足Dapr期望有一个端点可用于处理触发的命名作业。 + +在您的`Program.cs`文件中填入以下内容: + +```cs +using System.Text; +using System.Text.Json; +using Dapr.Jobs; +using Dapr.Jobs.Extensions; +using Dapr.Jobs.Models; +using Dapr.Jobs.Models.Responses; + +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddDaprJobsClient(); +var app = builder.Build(); + +//注册一个端点以接收和处理触发的作业 +var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5)); +app.MapDaprScheduledJobHandler((string jobName, DaprJobDetails jobDetails, ILogger logger, CancellationToken cancellationToken) => { + logger?.LogInformation("Received trigger invocation for job '{jobName}'", jobName); + switch (jobName) + { + case "prod-db-backup": + // 反序列化作业负载元数据 + var jobData = JsonSerializer.Deserialize(jobDetails.Payload); + + // 处理备份操作 - 我们假设这在您的代码中已实现 + await BackupDatabaseAsync(jobData, cancellationToken); + break; + } +}, cancellationTokenSource.Token); + +await app.RunAsync(); +``` + +最后,作业本身需要在Dapr中注册,以便可以在以后触发。您可以通过将`DaprJobsClient`注入到类中并作为应用程序的入站操作的一部分执行此操作,但为了本示例的目的,它将放在您上面开始的`Program.cs`文件的底部。因为您将使用依赖注入注册的`DaprJobsClient`,所以首先创建一个范围以便可以访问它。 + +```cs +//创建一个范围以便可以访问注册的DaprJobsClient +await using scope = app.Services.CreateAsyncScope(); +var daprJobsClient = scope.ServiceProvider.GetRequiredService(); + +//创建我们希望与未来作业触发一起呈现的负载 +var jobData = new BackupJobData("db-backup", new BackupMetadata("my-prod-db", "/backup-dir")); + +//将我们的负载序列化为UTF-8字节 +var serializedJobData = JsonSerializer.SerializeToUtf8Bytes(jobData); + +//调度我们的备份作业每分钟运行一次,但只重复10次 +await daprJobsClient.ScheduleJobAsync("prod-db-backup", DaprJobSchedule.FromDuration(TimeSpan.FromMinutes(1)), + serializedJobData, repeats: 10); +``` + +{{% /codetab %}} + +{{% codetab %}} + + + +以下Go SDK代码示例调度名为`prod-db-backup`的作业。作业数据存储在备份数据库(`"my-prod-db"`)中,并使用`ScheduleJobAlpha1`进行调度。这提供了`jobData`,其中包括: +- 备份`Task`名称 +- 备份任务的`Metadata`,包括: + - 数据库名称(`DBName`) + - 数据库位置(`BackupLocation`) + +```go +package main + +import ( + //... + + daprc "github.com/dapr/go-sdk/client" + "github.com/dapr/go-sdk/examples/dist-scheduler/api" + "github.com/dapr/go-sdk/service/common" + daprs "github.com/dapr/go-sdk/service/grpc" +) + +func main() { + // 初始化服务器 + server, err := daprs.NewService(":50070") + // ... + + if err = server.AddJobEventHandler("prod-db-backup", prodDBBackupHandler); err != nil { + log.Fatalf("failed to register job event handler: %v", err) + } + + log.Println("starting server") + go func() { + if err = server.Start(); err != nil { + log.Fatalf("failed to start server: %v", err) + } + }() + // ... + + // 设置备份位置 + jobData, err := json.Marshal(&api.DBBackup{ + Task: "db-backup", + Metadata: api.Metadata{ + DBName: "my-prod-db", + BackupLocation: "/backup-dir", + }, + }, + ) + // ... +} +``` + +作业是通过设置`Schedule`和所需的`Repeats`数量来调度的。这些设置决定了作业应被触发并发送回应用程序的最大次数。 + +在此示例中,在触发时间,即根据`Schedule`的`@every 1s`,此作业被触发并最多发送回应用程序`Repeats`(`10`)次。 + +```go + // ... + // 设置作业 + job := daprc.Job{ + Name: "prod-db-backup", + Schedule: "@every 1s", + Repeats: 10, + Data: &anypb.Any{ + Value: jobData, + }, + } +``` + +在触发时间,调用`prodDBBackupHandler`函数,在触发时间执行此作业的所需业务逻辑。例如: + +#### HTTP + +当您使用Dapr的作业API创建作业时,Dapr会自动假定在`/job/`有一个可用的端点。例如,如果您调度一个名为`test`的作业,Dapr期望您的应用程序在`/job/test`监听作业事件。确保您的应用程序为此端点设置了一个处理程序,以便在作业被触发时处理它。例如: + +*注意:以下示例是用Go编写的,但适用于任何编程语言。* + +```go + +func main() { + ... + http.HandleFunc("/job/", handleJob) + http.HandleFunc("/job/", specificJob) + ... +} + +func specificJob(w http.ResponseWriter, r *http.Request) { + // 处理特定触发的作业 +} + +func handleJob(w http.ResponseWriter, r *http.Request) { + // 处理触发的作业 +} +``` + +#### gRPC + +当作业到达其计划的触发时间时,触发的作业通过以下回调函数发送回应用程序: + +*注意:以下示例是用Go编写的,但适用于任何支持gRPC的编程语言。* + +```go +import rtv1 "github.com/dapr/dapr/pkg/proto/runtime/v1" +... +func (s *JobService) OnJobEventAlpha1(ctx context.Context, in *rtv1.JobEventRequest) (*rtv1.JobEventResponse, error) { + // 处理触发的作业 +} +``` + +此函数在您的gRPC服务器上下文中处理触发的作业。当您设置服务器时,确保注册回调服务器,当作业被触发时将调用此函数: + +```go +... +js := &JobService{} +rtv1.RegisterAppCallbackAlphaServer(server, js) +``` + +在此设置中,您可以完全控制如何接收和处理触发的作业,因为它们直接通过此gRPC方法路由。 + +#### SDKs + +对于SDK用户,处理触发的作业更简单。当作业被触发时,Dapr会自动将作业路由到您在服务器初始化期间设置的事件处理程序。例如,在Go中,您可以这样注册事件处理程序: + +```go +... +if err = server.AddJobEventHandler("prod-db-backup", prodDBBackupHandler); err != nil { + log.Fatalf("failed to register job event handler: %v", err) +} +``` + +Dapr负责底层路由。当作业被触发时,您的`prodDBBackupHandler`函数将被调用,并带有触发的作业数据。以下是处理触发作业的示例: + +```go +// ... + +// 在作业触发时调用此函数 +func prodDBBackupHandler(ctx context.Context, job *common.JobEvent) error { + var jobData common.Job + if err := json.Unmarshal(job.Data, &jobData); err != nil { + // ... + } + + var jobPayload api.DBBackup + if err := json.Unmarshal(job.Data, &jobPayload); err != nil { + // ... + } + fmt.Printf("job %d received:\n type: %v \n typeurl: %v\n value: %v\n extracted payload: %v\n", jobCount, job.JobType, jobData.TypeURL, jobData.Value, jobPayload) + jobCount++ + return nil +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 运行Dapr sidecar + +一旦您在应用程序中设置了作业API,在终端窗口中使用以下命令运行Dapr sidecar。 + +{{< tabs "Go" >}} + +{{% codetab %}} + +```bash +dapr run --app-id=distributed-scheduler \ + --metrics-port=9091 \ + --dapr-grpc-port 50001 \ + --app-port 50070 \ + --app-protocol grpc \ + --log-level debug \ + go run ./main.go +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 + +- [了解更多关于调度器控制平面服务的信息]({{< ref "concepts/dapr-services/scheduler.md" >}}) +- [作业API参考]({{< ref jobs_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/jobs/jobs-overview.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/jobs/jobs-overview.md new file mode 100644 index 000000000..1c2fcc590 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/jobs/jobs-overview.md @@ -0,0 +1,70 @@ +--- +type: docs +title: "作业概述" +linkTitle: "概述" +weight: 1000 +description: "作业API构建模块概述" +--- + +许多应用程序需要作业调度,或者需要在未来执行某些操作。作业API是一个用于管理和安排这些未来作业的工具,可以在特定时间或间隔执行。 + +作业API不仅帮助您安排作业,Dapr内部还利用调度服务来安排actor提醒。 + +在Dapr中,作业包括: +- [作业API构建模块]({{< ref jobs_api.md >}}) +- [调度器控制平面服务]({{< ref "concepts/dapr-services/scheduler.md" >}}) + +[查看示例场景。]({{< ref "#scenarios" >}}) + +显示调度器控制平面服务和作业API的图示 + +## 工作原理 + +作业API是一个作业调度器,而不是作业的执行者。设计上保证作业至少执行一次,注重可靠性和可扩展性,而非精确性。这意味着: +- **保证:** 作业不会在计划时间之前被调用。 +- **不保证:** 作业在到期时间之后被调用的具体时间。 + +所有计划作业的详细信息和用户相关数据都存储在调度器服务的Etcd数据库中。 +您可以使用作业来: + +- **延迟您的[pubsub消息传递]({{< ref pubsub-overview.md >}})。** 您可以在未来的特定时间发布消息(例如:一周后,或特定的UTC日期/时间)。 +- **调度应用程序之间的[服务调用]({{< ref service-invocation-overview.md >}})方法。** + +## 场景 + +作业调度在以下场景中可能会有所帮助: + +- **自动化数据库备份:** + 确保数据库每天备份以防止数据丢失。安排一个备份脚本在每晚2点运行,创建数据库备份并将其存储在安全位置。 + +- **定期数据处理和ETL(提取、转换、加载):** + 处理和转换来自各种来源的原始数据并将其加载到数据仓库中。安排ETL作业在特定时间运行(例如:每小时、每天)以获取新数据、处理并更新数据仓库中的信息。 + +- **电子邮件通知和报告:** + 通过电子邮件接收每日销售报告和每周性能摘要。安排一个作业生成所需的报告并在每天早上6点通过电子邮件发送每日报告,每周一早上8点发送每周摘要。 + +- **维护任务和系统更新:** + 执行定期维护任务,如清理临时文件、更新软件和检查系统健康状况。安排各种维护脚本在非高峰时段运行,如周末或深夜,以尽量减少对用户的干扰。 + +- **金融交易的批处理:** + 处理需要在每个工作日结束时批处理和结算的大量交易。安排批处理作业在每个工作日下午5点运行,汇总当天的交易并执行必要的结算和对账。 + +Dapr的作业API确保这些场景中表示的任务在没有人工干预的情况下始终如一地执行,提高效率并减少错误风险。 + +## 特性 + +作业API提供了多种特性,使您可以轻松调度作业。 + +### 在多个副本之间调度作业 + +调度器服务支持在多个副本之间扩展作业调度,同时保证作业仅由一个调度器服务实例触发。 + +## 试用作业API + +您可以在应用程序中试用作业API。在[Dapr安装完成后]({{< ref install-dapr-cli.md >}}),您可以开始使用作业API,从[如何:调度作业指南]({{< ref howto-schedule-and-handle-triggered-jobs.md >}})开始。 + +## 下一步 + +- [了解如何使用作业API]({{< ref howto-schedule-and-handle-triggered-jobs.md >}}) +- [了解更多关于调度器控制平面服务的信息]({{< ref "concepts/dapr-services/scheduler.md" >}}) +- [作业API参考]({{< ref jobs_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/_index.md new file mode 100644 index 000000000..41a4138f6 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/_index.md @@ -0,0 +1,15 @@ +--- +type: docs +title: "消息发布与订阅" +linkTitle: "发布/订阅" +weight: 20 +description: 服务之间安全且可扩展的消息传递 +--- + +{{% alert title="Dapr 发布/订阅的更多信息" color="primary" %}} +了解如何使用 Dapr 进行发布/订阅: +- 试试 [发布/订阅快速入门]({{< ref pubsub-quickstart.md >}})。 +- 通过支持的 [Dapr SDKs]({{< ref sdks >}}) 探索发布/订阅功能。 +- 查看 [发布/订阅 API 参考文档]({{< ref pubsub_api.md >}})。 +- 浏览支持的 [发布/订阅组件说明]({{< ref supported-pubsub >}})。 +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/howto-namespace.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/howto-namespace.md new file mode 100644 index 000000000..4a4da66b1 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/howto-namespace.md @@ -0,0 +1,74 @@ +--- +type: docs +title: "如何:设置 pub/sub 命名空间消费者组" +linkTitle: "如何:命名空间消费者组" +weight: 5000 +description: "了解如何在组件中使用基于元数据的命名空间消费者组" +--- + +您已经配置了 [Dapr 的 pub/sub API 构建块]({{< ref pubsub-overview >}}),并且您的应用程序正在使用集中式消息代理顺利地发布和订阅主题。如果您想为应用程序执行简单的 A/B 测试、蓝/绿部署,甚至金丝雀部署,该怎么办?即使使用 Dapr,这也可能很困难。 + +Dapr 通过其 pub/sub 命名空间消费者组机制解决了大规模的多租户问题。 + +## 没有命名空间消费者组 + +假设您有一个 Kubernetes 集群,其中两个应用程序(App1 和 App2)部署在同一个命名空间(namespace-a)中。App2 发布到一个名为 `order` 的主题,而 App1 订阅名为 `order` 的主题。这将创建两个以您的应用程序命名的消费者组(App1 和 App2)。 + +显示基本 pubsub 过程的图示。 + +为了在使用集中式消息代理时进行简单的测试和部署,您创建了另一个命名空间,其中包含两个具有相同 `app-id` 的应用程序,App1 和 App2。 + +Dapr 使用单个应用程序的 `app-id` 创建消费者组,因此消费者组名称将保持为 App1 和 App2。 + +显示没有 Dapr 命名空间消费者组的多租户复杂性的图示。 + +为了避免这种情况,您需要在代码中“潜入”一些东西来更改 `app-id`,具体取决于您运行的命名空间。这种方法既麻烦又容易出错。 + +## 使用命名空间消费者组 + +Dapr 不仅允许您使用 UUID 和 pod 名称的 consumerID 更改消费者组的行为,还提供了一个存在于 pub/sub 组件元数据中的 **命名空间机制**。例如,使用 Redis 作为您的消息代理: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: pubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + value: "" + - name: consumerID + value: "{namespace}" +``` + +通过将 `consumerID` 配置为 `{namespace}` 值,您可以在不同的命名空间中使用相同的 `app-id` 和相同的主题。 + +显示命名空间消费者组如何帮助多租户的图示。 + +在上图中,您有两个命名空间,每个命名空间都有相同 `app-id` 的应用程序,发布和订阅相同的集中式消息代理 `orders`。然而这次,Dapr 创建了以它们运行的命名空间为前缀的消费者组名称。 + +无需更改您的代码或 `app-id`,命名空间消费者组允许您: +- 添加更多命名空间 +- 保持相同的主题 +- 在命名空间之间保持相同的 `app-id` +- 保持整个部署管道完整 + +只需在您的组件元数据中包含 `"{namespace}"` 消费者组机制。您无需在元数据中手动编码命名空间。Dapr 会自动识别其运行的命名空间并为您填充命名空间值,就像由运行时注入的动态元数据值一样。 + +{{% alert title="注意" color="primary" %}} +如果您之后将命名空间消费者组添加到元数据中,Dapr 会为您更新所有内容。这意味着您可以将命名空间元数据值添加到现有的 pub/sub 部署中。 +{{% /alert %}} + +## 演示 + +观看 [此视频以了解 pub/sub 多租户的概述](https://youtu.be/eK463jugo0c?t=1188): + + + +## 下一步 + +- 了解更多关于使用多个命名空间配置 Pub/Sub 组件的信息 [pub/sub 命名空间]({{< ref pubsub-namespaces >}})。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/howto-publish-subscribe.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/howto-publish-subscribe.md new file mode 100644 index 000000000..b657496b8 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/howto-publish-subscribe.md @@ -0,0 +1,679 @@ +--- +type: docs +title: "如何:发布消息并订阅主题" +linkTitle: "如何:发布 & 订阅主题" +weight: 2000 +description: "学习如何使用一个服务向主题发送消息,并在另一个服务中订阅该主题" +--- + +既然您已经了解了Dapr pubsub构建块的功能,接下来我们来看看如何在您的服务中应用它。下面的代码示例描述了一个使用两个服务处理订单的应用程序,每个服务都有Dapr sidecar: + +- 一个结账服务,使用Dapr订阅消息队列中的主题。 +- 一个订单处理服务,使用Dapr向RabbitMQ发布消息。 + +示例服务的状态管理图 + +Dapr会自动将用户的负载封装在符合CloudEvents v1.0的格式中,并使用`Content-Type`头的值作为`datacontenttype`属性。[了解更多关于CloudEvents的消息。]({{< ref pubsub-cloudevents.md >}}) + +以下示例展示了如何在您的应用程序中发布和订阅名为`orders`的主题。 + +{{% alert title="注意" color="primary" %}} +如果您还没有,请[尝试pubsub快速入门]({{< ref pubsub-quickstart.md >}}),快速了解如何使用pubsub。 + +{{% /alert %}} + +## 设置Pub/Sub组件 + +第一步是设置pubsub组件: + +{{< tabs "Self-Hosted (CLI)" Kubernetes >}} + +{{% codetab %}} +当您运行`dapr init`时,Dapr会创建一个默认的Redis `pubsub.yaml`并在您的本地机器上运行一个Redis容器,位置如下: + +- 在Windows上,位于`%UserProfile%\.dapr\components\pubsub.yaml` +- 在Linux/MacOS上,位于`~/.dapr/components/pubsub.yaml` + +使用`pubsub.yaml`组件,您可以轻松地更换底层组件而无需更改应用程序代码。在此示例中,使用RabbitMQ。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: order-pub-sub +spec: + type: pubsub.rabbitmq + version: v1 + metadata: + - name: host + value: "amqp://localhost:5672" + - name: durable + value: "false" + - name: deletedWhenUnused + value: "false" + - name: autoAck + value: "false" + - name: reconnectWait + value: "0" + - name: concurrency + value: parallel +scopes: + - orderprocessing + - checkout +``` + +您可以通过创建一个包含该文件的组件目录(在此示例中为`myComponents`)并使用`dapr run` CLI命令的`--resources-path`标志来覆盖此文件。 + +{{< tabs ".NET" Java Python Go JavaScript >}} + +{{% codetab %}} + +```bash +dapr run --app-id myapp --resources-path ./myComponents -- dotnet run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +dapr run --app-id myapp --resources-path ./myComponents -- mvn spring-boot:run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +dapr run --app-id myapp --resources-path ./myComponents -- python3 app.py +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +dapr run --app-id myapp --resources-path ./myComponents -- go run app.go +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +dapr run --app-id myapp --resources-path ./myComponents -- npm start +``` +{{% /codetab %}} + +{{< /tabs >}} + +{{% /codetab %}} + +{{% codetab %}} +要将其部署到Kubernetes集群中,请填写以下YAML中的[pub/sub组件]({{< ref setup-pubsub >}})的`metadata`连接详细信息,保存为`pubsub.yaml`,然后运行`kubectl apply -f pubsub.yaml`。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: order-pub-sub +spec: + type: pubsub.rabbitmq + version: v1 + metadata: + - name: connectionString + value: "amqp://localhost:5672" + - name: protocol + value: amqp + - name: hostname + value: localhost + - name: username + value: username + - name: password + value: password + - name: durable + value: "false" + - name: deletedWhenUnused + value: "false" + - name: autoAck + value: "false" + - name: reconnectWait + value: "0" + - name: concurrency + value: parallel +scopes: + - orderprocessing + - checkout +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 订阅主题 + +Dapr提供了三种方法来订阅主题: + +- **声明式**,在外部文件中定义订阅。 +- **流式**,在用户代码中定义订阅。 +- **编程式**,在用户代码中定义订阅。 + +在[声明式、流式和编程式订阅文档]({{< ref subscription-methods.md >}})中了解更多信息。此示例演示了**声明式**订阅。 + +创建一个名为`subscription.yaml`的文件并粘贴以下内容: + +```yaml +apiVersion: dapr.io/v2alpha1 +kind: Subscription +metadata: + name: order-pub-sub +spec: + topic: orders + routes: + default: /checkout + pubsubname: order-pub-sub +scopes: +- orderprocessing +- checkout +``` + +上面的示例显示了对主题`orders`的事件订阅,针对pubsub组件`order-pub-sub`。 + +- `route`字段指示Dapr将所有主题消息发送到应用程序中的`/checkout`端点。 +- `scopes`字段指定此订阅适用于ID为`orderprocessing`和`checkout`的应用程序。 + +将`subscription.yaml`放在与您的`pubsub.yaml`组件相同的目录中。当Dapr启动时,它会加载订阅和组件。 + +{{% alert title="注意" color="primary" %}} +此功能目前处于预览阶段。 +Dapr可以实现“热重载”声明式订阅,从而在不需要重启的情况下自动拾取更新。 +这通过[`HotReload`功能门]({{< ref "support-preview-features.md" >}})启用。 +为了防止重新处理或丢失未处理的消息,在Dapr和您的应用程序之间的飞行消息在热重载事件期间不受影响。 +{{% /alert %}} + +以下是利用Dapr SDK订阅您在`subscription.yaml`中定义的主题的代码示例。 + +{{< tabs ".NET" Java Python Go JavaScript>}} + +{{% codetab %}} + +```csharp +//依赖项 +using System.Collections.Generic; +using System.Threading.Tasks; +using System; +using Microsoft.AspNetCore.Mvc; +using Dapr; +using Dapr.Client; + +//代码 +namespace CheckoutService.controller +{ + [ApiController] + public class CheckoutServiceController : Controller + { + //订阅一个主题 + [Topic("order-pub-sub", "orders")] + [HttpPost("checkout")] + public void getCheckout([FromBody] int orderId) + { + Console.WriteLine("订阅者接收到 : " + orderId); + } + } +} +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和订阅者应用程序: + +```bash +dapr run --app-id checkout --app-port 6002 --dapr-http-port 3602 --dapr-grpc-port 60002 --app-protocol https dotnet run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +//依赖项 +import io.dapr.Topic; +import io.dapr.client.domain.CloudEvent; +import org.springframework.web.bind.annotation.*; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +//代码 +@RestController +public class CheckoutServiceController { + + private static final Logger log = LoggerFactory.getLogger(CheckoutServiceController.class); + //订阅一个主题 + @Topic(name = "orders", pubsubName = "order-pub-sub") + @PostMapping(path = "/checkout") + public Mono getCheckout(@RequestBody(required = false) CloudEvent cloudEvent) { + return Mono.fromRunnable(() -> { + try { + log.info("订阅者接收到: " + cloudEvent.getData()); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + } +} +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和订阅者应用程序: + +```bash +dapr run --app-id checkout --app-port 6002 --dapr-http-port 3602 --dapr-grpc-port 60002 mvn spring-boot:run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```python +#依赖项 +from cloudevents.sdk.event import v1 +from dapr.ext.grpc import App +import logging +import json + +#代码 +app = App() +logging.basicConfig(level = logging.INFO) +#订阅一个主题 +@app.subscribe(pubsub_name='order-pub-sub', topic='orders') +def mytopic(event: v1.Event) -> None: + data = json.loads(event.Data()) + logging.info('订阅者接收到: ' + str(data)) + +app.run(6002) +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和订阅者应用程序: + +```bash +dapr run --app-id checkout --app-port 6002 --dapr-http-port 3602 --app-protocol grpc -- python3 CheckoutService.py +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +//依赖项 +import ( + "log" + "net/http" + "context" + + "github.com/dapr/go-sdk/service/common" + daprd "github.com/dapr/go-sdk/service/http" +) + +//代码 +var sub = &common.Subscription{ + PubsubName: "order-pub-sub", + Topic: "orders", + Route: "/checkout", +} + +func main() { + s := daprd.NewService(":6002") + //订阅一个主题 + if err := s.AddTopicEventHandler(sub, eventHandler); err != nil { + log.Fatalf("添加主题订阅时出错: %v", err) + } + if err := s.Start(); err != nil && err != http.ErrServerClosed { + log.Fatalf("监听时出错: %v", err) + } +} + +func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool, err error) { + log.Printf("订阅者接收到: %s", e.Data) + return false, nil +} +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和订阅者应用程序: + +```bash +dapr run --app-id checkout --app-port 6002 --dapr-http-port 3602 --dapr-grpc-port 60002 go run CheckoutService.go +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +//依赖项 +import { DaprServer, CommunicationProtocolEnum } from '@dapr/dapr'; + +//代码 +const daprHost = "127.0.0.1"; +const serverHost = "127.0.0.1"; +const serverPort = "6002"; + +start().catch((e) => { + console.error(e); + process.exit(1); +}); + +async function start(orderId) { + const server = new DaprServer({ + serverHost, + serverPort, + communicationProtocol: CommunicationProtocolEnum.HTTP, + clientOptions: { + daprHost, + daprPort: process.env.DAPR_HTTP_PORT, + }, + }); + //订阅一个主题 + await server.pubsub.subscribe("order-pub-sub", "orders", async (orderId) => { + console.log(`订阅者接收到: ${JSON.stringify(orderId)}`) + }); + await server.start(); +} +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和订阅者应用程序: + +```bash +dapr run --app-id checkout --app-port 6002 --dapr-http-port 3602 --dapr-grpc-port 60002 npm start +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 发布消息 + +启动一个名为`orderprocessing`的Dapr实例: + +```bash +dapr run --app-id orderprocessing --dapr-http-port 3601 +``` + +然后向`orders`主题发布消息: + +{{< tabs "Dapr CLI" "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + +```bash +dapr publish --publish-app-id orderprocessing --pubsub order-pub-sub --topic orders --data '{"orderId": "100"}' +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +curl -X POST http://localhost:3601/v1.0/publish/order-pub-sub/orders -H "Content-Type: application/json" -d '{"orderId": "100"}' +``` + +{{% /codetab %}} + +{{% codetab %}} + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"orderId": "100"}' -Uri 'http://localhost:3601/v1.0/publish/order-pub-sub/orders' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +以下是利用Dapr SDK发布主题的代码示例。 + +{{< tabs ".NET" Java Python Go JavaScript>}} + +{{% codetab %}} + +```csharp +//依赖项 +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using Dapr.Client; +using Microsoft.AspNetCore.Mvc; +using System.Threading; + +//代码 +namespace EventService +{ + class Program + { + static async Task Main(string[] args) + { + string PUBSUB_NAME = "order-pub-sub"; + string TOPIC_NAME = "orders"; + while(true) { + System.Threading.Thread.Sleep(5000); + Random random = new Random(); + int orderId = random.Next(1,1000); + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken cancellationToken = source.Token; + using var client = new DaprClientBuilder().Build(); + //使用Dapr SDK发布主题 + await client.PublishEventAsync(PUBSUB_NAME, TOPIC_NAME, orderId, cancellationToken); + Console.WriteLine("发布的数据: " + orderId); + } + } + } +} +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和发布者应用程序: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 --app-protocol https dotnet run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +//依赖项 +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.domain.Metadata; +import static java.util.Collections.singletonMap; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +//代码 +@SpringBootApplication +public class OrderProcessingServiceApplication { + + private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); + + public static void main(String[] args) throws InterruptedException{ + String MESSAGE_TTL_IN_SECONDS = "1000"; + String TOPIC_NAME = "orders"; + String PUBSUB_NAME = "order-pub-sub"; + + while(true) { + TimeUnit.MILLISECONDS.sleep(5000); + Random random = new Random(); + int orderId = random.nextInt(1000-1) + 1; + DaprClient client = new DaprClientBuilder().build(); + //使用Dapr SDK发布主题 + client.publishEvent( + PUBSUB_NAME, + TOPIC_NAME, + orderId, + singletonMap(Metadata.TTL_IN_SECONDS, MESSAGE_TTL_IN_SECONDS)).block(); + log.info("发布的数据:" + orderId); + } + } +} +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和发布者应用程序: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```python +#依赖项 +import random +from time import sleep +import requests +import logging +import json +from dapr.clients import DaprClient + +#代码 +logging.basicConfig(level = logging.INFO) +while True: + sleep(random.randrange(50, 5000) / 1000) + orderId = random.randint(1, 1000) + PUBSUB_NAME = 'order-pub-sub' + TOPIC_NAME = 'orders' + with DaprClient() as client: + #使用Dapr SDK发布主题 + result = client.publish_event( + pubsub_name=PUBSUB_NAME, + topic_name=TOPIC_NAME, + data=json.dumps(orderId), + data_content_type='application/json', + ) + logging.info('发布的数据: ' + str(orderId)) +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和发布者应用程序: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --app-protocol grpc python3 OrderProcessingService.py +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +//依赖项 +import ( + "context" + "log" + "math/rand" + "time" + "strconv" + dapr "github.com/dapr/go-sdk/client" +) + +//代码 +var ( + PUBSUB_NAME = "order-pub-sub" + TOPIC_NAME = "orders" +) + +func main() { + for i := 0; i < 10; i++ { + time.Sleep(5000) + orderId := rand.Intn(1000-1) + 1 + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + defer client.Close() + ctx := context.Background() + //使用Dapr SDK发布主题 + if err := client.PublishEvent(ctx, PUBSUB_NAME, TOPIC_NAME, []byte(strconv.Itoa(orderId))); + err != nil { + panic(err) + } + + log.Println("发布的数据: " + strconv.Itoa(orderId)) + } +} +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和发布者应用程序: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 go run OrderProcessingService.go +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +//依赖项 +import { DaprServer, DaprClient, CommunicationProtocolEnum } from '@dapr/dapr'; + +const daprHost = "127.0.0.1"; + +var main = function() { + for(var i=0;i<10;i++) { + sleep(5000); + var orderId = Math.floor(Math.random() * (1000 - 1) + 1); + start(orderId).catch((e) => { + console.error(e); + process.exit(1); + }); + } +} + +async function start(orderId) { + const PUBSUB_NAME = "order-pub-sub" + const TOPIC_NAME = "orders" + const client = new DaprClient({ + daprHost, + daprPort: process.env.DAPR_HTTP_PORT, + communicationProtocol: CommunicationProtocolEnum.HTTP + }); + console.log("发布的数据:" + orderId) + //使用Dapr SDK发布主题 + await client.pubsub.publish(PUBSUB_NAME, TOPIC_NAME, orderId); +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +main(); +``` + +导航到包含上述代码的目录,然后运行以下命令以启动Dapr sidecar和发布者应用程序: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 消息确认和重试 + +为了告诉Dapr消息已成功处理,返回`200 OK`响应。如果Dapr收到的返回状态码不是`200`,或者您的应用程序崩溃,Dapr将尝试根据至少一次语义重新传递消息。 + +## 演示视频 + +观看[此演示视频](https://youtu.be/1dqe1k-FXJQ?si=s3gvWxRxeOsmXuE1)以了解更多关于Dapr的pubsub消息传递。 + + + +## 下一步 + +- 尝试[pubsub教程](https://github.com/dapr/quickstarts/tree/master/tutorials/pub-sub)。 +- 了解[使用CloudEvents进行消息传递]({{< ref pubsub-cloudevents.md >}})以及何时可能需要[发送不带CloudEvents的消息]({{< ref pubsub-raw.md >}})。 +- 查看[pubsub组件]({{< ref setup-pubsub >}})列表。 +- 阅读[API参考]({{< ref pubsub_api.md >}})。 diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/howto-route-messages.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/howto-route-messages.md new file mode 100644 index 000000000..81b63b721 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/howto-route-messages.md @@ -0,0 +1,457 @@ +--- +type: docs +title: "操作指南:将消息路由到不同的事件处理程序" +linkTitle: "操作指南:路由事件" +weight: 2300 +description: "学习如何根据 CloudEvent 字段将主题中的消息路由到不同的事件处理程序" +--- + +pubsub 路由实现了[基于内容的路由](https://www.enterpriseintegrationpatterns.com/ContentBasedRouter.html),这是一种使用 DSL 而不是命令式应用程序代码的消息模式。通过 pubsub 路由,您可以根据 [CloudEvents](https://cloudevents.io) 的内容,将消息路由到应用程序中的不同 URI/路径和事件处理程序。如果没有匹配的路由,则可以使用可选的默认路由。随着您的应用程序扩展以支持多个事件版本或特殊情况,这种方法将非常有用。 + +虽然可以通过代码实现路由,但将路由规则与应用程序分离可以提高可移植性。 + +此功能适用于[声明式和编程式订阅方法]({{< ref subscription-methods.md >}}),但不适用于流式订阅。 + +## 声明式订阅 + +对于声明式订阅,使用 `dapr.io/v2alpha1` 作为 `apiVersion`。以下是使用路由的 `subscriptions.yaml` 示例: + +```yaml +apiVersion: dapr.io/v2alpha1 +kind: Subscription +metadata: + name: myevent-subscription +spec: + pubsubname: pubsub + topic: inventory + routes: + rules: + - match: event.type == "widget" + path: /widgets + - match: event.type == "gadget" + path: /gadgets + default: /products +scopes: + - app1 + - app2 +``` + +## 编程式订阅 + +在编程方法中,返回的是 `routes` 结构而不是 `route`。JSON 结构与声明式 YAML 匹配: + +{{< tabs Python JavaScript ".NET" Go PHP>}} + +{{% codetab %}} +```python +import flask +from flask import request, jsonify +from flask_cors import CORS +import json +import sys + +app = flask.Flask(__name__) +CORS(app) + +@app.route('/dapr/subscribe', methods=['GET']) +def subscribe(): + subscriptions = [ + { + 'pubsubname': 'pubsub', + 'topic': 'inventory', + 'routes': { + 'rules': [ + { + 'match': 'event.type == "widget"', + 'path': '/widgets' + }, + { + 'match': 'event.type == "gadget"', + 'path': '/gadgets' + }, + ], + 'default': '/products' + } + }] + return jsonify(subscriptions) + +@app.route('/products', methods=['POST']) +def ds_subscriber(): + print(request.json, flush=True) + return json.dumps({'success':True}), 200, {'ContentType':'application/json'} +app.run() +``` + +{{% /codetab %}} + +{{% codetab %}} +```javascript +const express = require('express') +const bodyParser = require('body-parser') +const app = express() +app.use(bodyParser.json({ type: 'application/*+json' })); + +const port = 3000 + +app.get('/dapr/subscribe', (req, res) => { + res.json([ + { + pubsubname: "pubsub", + topic: "inventory", + routes: { + rules: [ + { + match: 'event.type == "widget"', + path: '/widgets' + }, + { + match: 'event.type == "gadget"', + path: '/gadgets' + }, + ], + default: '/products' + } + } + ]); +}) + +app.post('/products', (req, res) => { + console.log(req.body); + res.sendStatus(200); +}); + +app.listen(port, () => console.log(`consumer app listening on port ${port}!`)) +``` +{{% /codetab %}} + +{{% codetab %}} +```csharp + [Topic("pubsub", "inventory", "event.type ==\"widget\"", 1)] + [HttpPost("widgets")] + public async Task> HandleWidget(Widget widget, [FromServices] DaprClient daprClient) + { + // Logic + return stock; + } + + [Topic("pubsub", "inventory", "event.type ==\"gadget\"", 2)] + [HttpPost("gadgets")] + public async Task> HandleGadget(Gadget gadget, [FromServices] DaprClient daprClient) + { + // Logic + return stock; + } + + [Topic("pubsub", "inventory")] + [HttpPost("products")] + public async Task> HandleProduct(Product product, [FromServices] DaprClient daprClient) + { + // Logic + return stock; + } +``` +{{% /codetab %}} + +{{% codetab %}} +```golang +package main + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + + "github.com/gorilla/mux" +) + +const appPort = 3000 + +type subscription struct { + PubsubName string `json:"pubsubname"` + Topic string `json:"topic"` + Metadata map[string]string `json:"metadata,omitempty"` + Routes routes `json:"routes"` +} + +type routes struct { + Rules []rule `json:"rules,omitempty"` + Default string `json:"default,omitempty"` +} + +type rule struct { + Match string `json:"match"` + Path string `json:"path"` +} + +// This handles /dapr/subscribe +func configureSubscribeHandler(w http.ResponseWriter, _ *http.Request) { + t := []subscription{ + { + PubsubName: "pubsub", + Topic: "inventory", + Routes: routes{ + Rules: []rule{ + { + Match: `event.type == "widget"`, + Path: "/widgets", + }, + { + Match: `event.type == "gadget"`, + Path: "/gadgets", + }, + }, + Default: "/products", + }, + }, + } + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(t) +} + +func main() { + router := mux.NewRouter().StrictSlash(true) + router.HandleFunc("/dapr/subscribe", configureSubscribeHandler).Methods("GET") + log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", appPort), router)) +} +``` +{{% /codetab %}} + +{{% codetab %}} +```php + $builder->addDefinitions(['dapr.subscriptions' => [ + new \Dapr\PubSub\Subscription(pubsubname: 'pubsub', topic: 'inventory', routes: ( + rules: => [ + ('match': 'event.type == "widget"', path: '/widgets'), + ('match': 'event.type == "gadget"', path: '/gadgets'), + ] + default: '/products')), +]])); +$app->post('/products', function( + #[\Dapr\Attributes\FromBody] + \Dapr\PubSub\CloudEvent $cloudEvent, + \Psr\Log\LoggerInterface $logger + ) { + $logger->alert('Received event: {event}', ['event' => $cloudEvent]); + return ['status' => 'SUCCESS']; + } +); +$app->start(); +``` +{{% /codetab %}} + +{{< /tabs >}} + +## 通用表达式语言 (CEL) + +在这些示例中,根据 `event.type`,应用程序将被调用于: + +- `/widgets` +- `/gadgets` +- `/products` + +表达式是用[通用表达式语言 (CEL)](https://github.com/google/cel-spec)编写的,其中 `event` 代表云事件。表达式中可以引用 [CloudEvents 核心规范](https://github.com/cloudevents/spec/blob/v1.0.1/spec.md#required-attributes)中的任何属性。 + +### 示例表达式 + +匹配“重要”消息: + +```javascript +has(event.data.important) && event.data.important == true +``` + +匹配大于 $10,000 的存款: + +```javascript +event.type == "deposit" && int(event.data.amount) > 10000 +``` +{{% alert title="注意" color="primary" %}} +默认情况下,数值以双精度浮点数书写。数值没有自动算术转换。在这种情况下,如果 `event.data.amount` 未被转换为整数,则不进行匹配。有关更多信息,请参阅 [CEL 文档](https://github.com/google/cel-spec/blob/master/doc/langdef.md)。 +{{% /alert %}} + +匹配消息的多个版本: + +```javascript +event.type == "mymessage.v1" +``` + +```javascript +event.type == "mymessage.v2" +``` + +## CloudEvent 属性 + +作为参考,以下属性来自 CloudEvents 规范。 + +### 事件数据 + +#### data + +根据术语 **data** 的定义,CloudEvents _可能_ 包含有关事件发生的领域特定信息。当存在时,此信息将被封装在 `data` 中。 + +- **描述:** 事件负载。此规范对信息类型没有限制。它被编码为一种媒体格式,由 `datacontenttype` 属性指定(例如 application/json),并在这些相应属性存在时遵循 `dataschema` 格式。 +- **约束:** + - 可选 + +{{% alert title="限制" color="warning" %}} +目前,您只能访问嵌套 JSON 值中的数据属性,而不能访问字符串中 JSON 转义的属性。 +{{% /alert %}} + +### 必需属性 + +以下属性在所有 CloudEvents 中是**必需**的: + +#### id + +- **类型:** `String` +- **描述:** 标识事件。生产者 _必须_ 确保 `source` + `id` 对于每个不同的事件都是唯一的。如果由于网络错误而重新发送重复事件,则它可能具有相同的 `id`。消费者可以假设具有相同 `source` 和 `id` 的事件是重复的。 +- **约束:** + - 必需 + - 必须是非空字符串 + - 必须在生产者范围内唯一 +- **示例:** + - 由生产者维护的事件计数器 + - UUID + +#### source + +- **类型:** `URI-reference` +- **描述:** 标识事件发生的上下文。通常包括以下信息: + - 事件源的类型 + - 发布事件的组织 + - 产生事件的过程 + + URI 中编码的数据的确切语法和语义由事件生产者定义。 + + 生产者 _必须_ 确保 `source` + `id` 对于每个不同的事件都是唯一的。 + + 应用程序可以: + - 为每个不同的生产者分配一个唯一的 `source`,以便更容易生成唯一的 ID,并防止其他生产者具有相同的 `source`。 + - 使用 UUID、URN、DNS 权威或应用程序特定方案创建唯一的 `source` 标识符。 + + 一个 source 可能包含多个生产者。在这种情况下,生产者 _必须_ 合作以确保 `source` + `id` 对于每个不同的事件都是唯一的。 + +- **约束:** + - 必需 + - 必须是非空 URI-reference + - 推荐使用绝对 URI +- **示例:** + - 具有 DNS 权威的互联网范围唯一 URI: + - https://github.com/cloudevents + - mailto:cncf-wg-serverless@lists.cncf.io + - 具有 UUID 的全球唯一 URN: + - urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66 + - 应用程序特定标识符: + - /cloudevents/spec/pull/123 + - /sensors/tn-1234567/alerts + - 1-555-123-4567 + +#### specversion + +- **类型:** `String` +- **描述:** 事件使用的 CloudEvents 规范版本。这使得上下文的解释成为可能。合规的事件生产者 _必须_ 在引用此版本的规范时使用 `1.0` 值。 + + 目前,此属性仅包含“主要”和“次要”版本号。这允许在不更改此属性值的情况下对规范进行补丁更改。 + + 注意:对于“候选发布”版本,可能会使用后缀进行测试。 + +- **约束:** + - 必需 + - 必须是非空字符串 + +#### type + +- **类型:** `String` +- **描述:** 包含描述与原始事件相关的事件类型的值。通常,此属性用于路由、可观察性、策略执行等。格式由生产者定义,可能包括 `type` 的版本信息。有关更多信息,请参阅[CloudEvents 的版本控制](https://github.com/cloudevents/spec/blob/v1.0.1/primer.md#versioning-of-cloudevents)。 +- **约束:** + - 必需 + - 必须是非空字符串 + - 应该以反向 DNS 名称为前缀。前缀域决定了定义此事件类型语义的组织。 +- **示例:** + - com.github.pull_request.opened + - com.example.object.deleted.v2 + +### 可选属性 + +以下属性在 CloudEvents 中是**可选**的。有关可选定义的更多信息,请参阅[符号约定](https://github.com/cloudevents/spec/blob/v1.0.1/spec.md#notational-conventions)部分。 + +#### datacontenttype + +- **类型:** `String` 根据 [RFC 2046](https://tools.ietf.org/html/rfc2046) +- **描述:** `data` 值的内容类型。此属性使 `data` 能够携带任何类型的内容,其中格式和编码可能与所选事件格式不同。 + + 例如,使用 [JSON 信封](https://github.com/cloudevents/spec/blob/v1.0.1/json-format.md#3-envelope)格式呈现的事件可能在 `data` 中携带 XML 负载。此属性被设置为 `"application/xml"`,通知消费者。 + + 不同 `datacontenttype` 值的数据内容呈现规则在事件格式规范中定义。例如,JSON 事件格式在[第 3.1 节](https://github.com/cloudevents/spec/blob/v1.0.1/json-format.md#31-handling-of-data)中定义了关系。 + + 对于某些二进制模式协议绑定,此字段直接映射到相应协议的内容类型元数据属性。您可以在相应协议中找到二进制模式和内容类型元数据映射的规范规则。 + + 在某些事件格式中,您可以省略 `datacontenttype` 属性。例如,如果 JSON 格式事件没有 `datacontenttype` 属性,则意味着 `data` 是符合 `"application/json"` 媒体类型的 JSON 值。换句话说:没有 `datacontenttype` 的 JSON 格式事件与 `datacontenttype="application/json"` 的事件完全等效。 + + 当将没有 `datacontenttype` 属性的事件消息转换为不同格式或协议绑定时,目标 `datacontenttype` 应明确设置为源的隐含 `datacontenttype`。 + +- **约束:** + - 可选 + - 如果存在,必须符合 [RFC 2046](https://tools.ietf.org/html/rfc2046) 中指定的格式 +- 有关媒体类型示例,请参阅 [IANA 媒体类型](http://www.iana.org/assignments/media-types/media-types.xhtml) + +#### dataschema + +- **类型:** `URI` +- **描述:** 标识 `data` 遵循的模式。与模式不兼容的更改应通过不同的 URI 反映。有关更多信息,请参阅[CloudEvents 的版本控制](https://github.com/cloudevents/spec/blob/v1.0.1/primer.md#versioning-of-cloudevents)。 +- **约束:** + - 可选 + - 如果存在,必须是非空 URI + +#### subject + +- **类型:** `String` +- **描述:** 这描述了事件生产者(由 `source` 标识)上下文中的事件主题。在发布-订阅场景中,订阅者通常会订阅由 `source` 发出的事件。如果 `source` 上下文具有内部子结构,则仅 `source` 标识符可能不足以作为任何特定事件的限定符。 + + 在上下文元数据中(而不是仅在 `data` 负载中)识别事件的主题在通用订阅过滤场景中很有帮助,其中中间件无法解释 `data` 内容。在上述示例中,订阅者可能只对名称以 '.jpg' 或 '.jpeg' 结尾的 blob 感兴趣。使用 `subject` 属性,您可以为该事件子集构建简单而高效的字符串后缀过滤器。 + +- **约束:** + - 可选 + - 如果存在,必须是非空字符串 +- **示例:** + 订阅者可能会注册对在 blob 存储容器中创建新 blob 时的兴趣。在这种情况下: + - 事件 `source` 标识订阅范围(存储容器) + - 事件 `type` 标识“blob 创建”事件 + - 事件 `id` 唯一标识事件实例,以区分同名 blob 的单独创建事件。 + + 新创建的 blob 的名称在 `subject` 中传递: + - `source`: https://example.com/storage/tenant/container + - `subject`: mynewfile.jpg + +#### time + +- **类型:** `Timestamp` +- **描述:** 事件发生的时间戳。如果无法确定事件发生的时间,则此属性可以由 CloudEvents 生产者设置为其他时间(例如当前时间)。然而,所有相同 `source` 的生产者 _必须_ 在这方面保持一致。换句话说,要么他们都使用事件发生的实际时间,要么他们都使用相同的算法来确定使用的值。 +- **约束:** + - 可选 + - 如果存在,必须符合 [RFC 3339](https://tools.ietf.org/html/rfc3339) 中指定的格式 + +{{% alert title="限制" color="warning" %}} +目前,不支持与时间的比较(例如在“现在”之前或之后)。 +{{% /alert %}} + +## 社区电话演示 + +观看[此视频](https://www.youtube.com/watch?v=QqJgRmbH82I&t=1063s)以了解如何使用 pubsub 进行消息路由: + +

+ +

+ +## 下一步 + +- 尝试 [pubsub 路由示例](https://github.com/dapr/samples/tree/master/pub-sub-routing)。 +- 了解 [主题范围]({{< ref pubsub-scopes.md >}}) 和 [消息生存时间]({{< ref pubsub-message-ttl.md >}})。 +- [配置具有多个命名空间的 pubsub 组件]({{< ref pubsub-namespaces.md >}})。 +- 查看 [pubsub 组件列表]({{< ref setup-pubsub >}})。 +- 阅读 [API 参考]({{< ref pubsub_api.md >}})。 diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/howto-subscribe-statefulset.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/howto-subscribe-statefulset.md new file mode 100644 index 000000000..c8bb41896 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/howto-subscribe-statefulset.md @@ -0,0 +1,94 @@ +--- +type: docs +title: "如何:使用StatefulSets水平扩展订阅者" +linkTitle: "如何:使用StatefulSets水平扩展订阅者" +weight: 6000 +description: "学习如何使用StatefulSet进行订阅,并通过一致的消费者ID水平扩展" +--- + +与在Deployments中Pod是临时的不同,[StatefulSets](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/)通过为每个Pod保持固定的身份,使得在Kubernetes上可以部署有状态应用程序。 + +以下是一个使用Dapr的StatefulSet示例: +```yaml +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: python-subscriber +spec: + selector: + matchLabels: + app: python-subscriber # 必须匹配.spec.template.metadata.labels + serviceName: "python-subscriber" + replicas: 3 + template: + metadata: + labels: + app: python-subscriber # 必须匹配.spec.selector.matchLabels + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "python-subscriber" + dapr.io/app-port: "5001" + spec: + containers: + - name: python-subscriber + image: ghcr.io/dapr/samples/pubsub-python-subscriber:latest + ports: + - containerPort: 5001 + imagePullPolicy: Always +``` + +在通过Dapr订阅pubsub主题时,应用程序可以定义一个`consumerID`,这个ID决定了订阅者在队列或主题中的位置。利用StatefulSets中Pod的固定身份,您可以为每个Pod分配一个唯一的`consumerID`,从而实现订阅者应用程序的水平扩展。Dapr会跟踪每个Pod的名称,并可以在组件中使用`{podName}`标记来声明。 + +当扩展某个主题的订阅者数量时,每个Dapr组件都有特定的设置来决定其行为。通常,对于多个消费者有两种选择: + +- 广播:发布到主题的每条消息将被所有订阅者接收。 +- 共享:一条消息仅由一个订阅者接收(而不是所有订阅者)。 + +Kafka通过`consumerID`为每个订阅者分配独立的位置。当实例重新启动时,它会使用相同的`consumerID`继续从上次的位置处理消息,而不会遗漏任何消息。以下组件示例展示了如何让多个Pod使用Kafka组件: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: pubsub +spec: + type: pubsub.kafka + version: v1 + metadata: + - name: brokers + value: my-cluster-kafka-bootstrap.kafka.svc.cluster.local:9092 + - name: consumerID + value: "{podName}" + - name: authRequired + value: "false" +``` + +MQTT3协议支持共享主题,允许多个订阅者“竞争”处理来自主题的消息,这意味着每条消息仅由其中一个订阅者处理。例如: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: mqtt-pubsub +spec: + type: pubsub.mqtt3 + version: v1 + metadata: + - name: consumerID + value: "{podName}" + - name: cleanSession + value: "true" + - name: url + value: "tcp://admin:public@localhost:1883" + - name: qos + value: 1 + - name: retain + value: "false" +``` + +## 下一步 + +- 尝试[pubsub教程](https://github.com/dapr/quickstarts/tree/master/tutorials/pub-sub)。 +- 了解[使用CloudEvents进行消息传递]({{< ref pubsub-cloudevents.md >}})以及何时可能需要[发送不带CloudEvents的消息]({{< ref pubsub-raw.md >}})。 +- 查看[pubsub组件列表]({{< ref setup-pubsub >}})。 +- 阅读[API参考]({{< ref pubsub_api.md >}})。 diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-bulk.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-bulk.md new file mode 100644 index 000000000..401d49263 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-bulk.md @@ -0,0 +1,553 @@ +--- +type: docs +title: "批量发布和订阅消息" +linkTitle: "批量发布和订阅消息" +weight: 7100 +description: "了解如何在Dapr中使用批量发布和订阅API。" +--- + +{{% alert title="alpha" color="warning" %}} +批量发布和订阅API目前处于**alpha**阶段。 +{{% /alert %}} + +通过批量发布和订阅API,您可以在单个请求中发布和订阅多个消息。在开发需要发送或接收大量消息的应用程序时,使用批量操作可以通过减少Dapr sidecar、应用程序和底层pubsub代理之间的请求总数来提高吞吐量。 + +## 批量发布消息 + +### 批量发布消息时的限制 + +批量发布API允许您通过单个请求将多个消息发布到一个主题。它是*非事务性*的,这意味着在一个批量请求中,某些消息可能会成功发布,而某些可能会失败。如果有消息发布失败,批量发布操作将返回失败消息的列表。 + +批量发布操作不保证消息的顺序。 + +### 示例 + +{{< tabs Java JavaScript ".NET" Python Go "HTTP API (Bash)" "HTTP API (PowerShell)" >}} + +{{% codetab %}} + +```java +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.DaprPreviewClient; +import io.dapr.client.domain.BulkPublishResponse; +import io.dapr.client.domain.BulkPublishResponseFailedEntry; +import java.util.ArrayList; +import java.util.List; + +class BulkPublisher { + private static final String PUBSUB_NAME = "my-pubsub-name"; + private static final String TOPIC_NAME = "topic-a"; + + public void publishMessages() { + try (DaprPreviewClient client = (new DaprClientBuilder()).buildPreviewClient()) { + // 创建要发布的消息列表 + List messages = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + String message = String.format("这是消息 #%d", i); + messages.add(message); + } + + // 使用批量发布API发布消息列表 + BulkPublishResponse res = client.publishEvents(PUBSUB_NAME, TOPIC_NAME, "text/plain", messages).block(); + } + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```typescript + +import { DaprClient } from "@dapr/dapr"; + +const pubSubName = "my-pubsub-name"; +const topic = "topic-a"; + +async function start() { + const client = new DaprClient(); + + // 向主题发布多个消息。 + await client.pubsub.publishBulk(pubSubName, topic, ["message 1", "message 2", "message 3"]); + + // 使用显式批量发布消息向主题发布多个消息。 + const bulkPublishMessages = [ + { + entryID: "entry-1", + contentType: "application/json", + event: { hello: "foo message 1" }, + }, + { + entryID: "entry-2", + contentType: "application/cloudevents+json", + event: { + specversion: "1.0", + source: "/some/source", + type: "example", + id: "1234", + data: "foo message 2", + datacontenttype: "text/plain" + }, + }, + { + entryID: "entry-3", + contentType: "text/plain", + event: "foo message 3", + }, + ]; + await client.pubsub.publishBulk(pubSubName, topic, bulkPublishMessages); +} + +start().catch((e) => { + console.error(e); + process.exit(1); +}); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```csharp +using System; +using System.Collections.Generic; +using Dapr.Client; + +const string PubsubName = "my-pubsub-name"; +const string TopicName = "topic-a"; +IReadOnlyList BulkPublishData = new List() { + new { Id = "17", Amount = 10m }, + new { Id = "18", Amount = 20m }, + new { Id = "19", Amount = 30m } +}; + +using var client = new DaprClientBuilder().Build(); + +var res = await client.BulkPublishEventAsync(PubsubName, TopicName, BulkPublishData); +if (res == null) { + throw new Exception("从dapr返回的响应为空"); +} +if (res.FailedEntries.Count > 0) +{ + Console.WriteLine("某些事件发布失败!"); + foreach (var failedEntry in res.FailedEntries) + { + Console.WriteLine("EntryId: " + failedEntry.Entry.EntryId + " 错误信息: " + + failedEntry.ErrorMessage); + } +} +else +{ + Console.WriteLine("所有事件已发布!"); +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```python +import requests +import json + +base_url = "http://localhost:3500/v1.0-alpha1/publish/bulk/{}/{}" +pubsub_name = "my-pubsub-name" +topic_name = "topic-a" +payload = [ + { + "entryId": "ae6bf7c6-4af2-11ed-b878-0242ac120002", + "event": "first text message", + "contentType": "text/plain" + }, + { + "entryId": "b1f40bd6-4af2-11ed-b878-0242ac120002", + "event": { + "message": "second JSON message" + }, + "contentType": "application/json" + } +] + +response = requests.post(base_url.format(pubsub_name, topic_name), json=payload) +print(response.status_code) +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +package main + +import ( + "fmt" + "strings" + "net/http" + "io/ioutil" +) + +const ( + pubsubName = "my-pubsub-name" + topicName = "topic-a" + baseUrl = "http://localhost:3500/v1.0-alpha1/publish/bulk/%s/%s" +) + +func main() { + url := fmt.Sprintf(baseUrl, pubsubName, topicName) + method := "POST" + payload := strings.NewReader(`[ + { + "entryId": "ae6bf7c6-4af2-11ed-b878-0242ac120002", + "event": "first text message", + "contentType": "text/plain" + }, + { + "entryId": "b1f40bd6-4af2-11ed-b878-0242ac120002", + "event": { + "message": "second JSON message" + }, + "contentType": "application/json" + } +]`) + + client := &http.Client {} + req, _ := http.NewRequest(method, url, payload) + + req.Header.Add("Content-Type", "application/json") + res, err := client.Do(req) + // ... +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +curl -X POST http://localhost:3500/v1.0-alpha1/publish/bulk/my-pubsub-name/topic-a \ + -H 'Content-Type: application/json' \ + -d '[ + { + "entryId": "ae6bf7c6-4af2-11ed-b878-0242ac120002", + "event": "first text message", + "contentType": "text/plain" + }, + { + "entryId": "b1f40bd6-4af2-11ed-b878-0242ac120002", + "event": { + "message": "second JSON message" + }, + "contentType": "application/json" + }, + ]' +``` + +{{% /codetab %}} + +{{% codetab %}} + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Uri 'http://localhost:3500/v1.0-alpha1/publish/bulk/my-pubsub-name/topic-a' ` +-Body '[ + { + "entryId": "ae6bf7c6-4af2-11ed-b878-0242ac120002", + "event": "first text message", + "contentType": "text/plain" + }, + { + "entryId": "b1f40bd6-4af2-11ed-b878-0242ac120002", + "event": { + "message": "second JSON message" + }, + "contentType": "application/json" + }, + ]' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 批量订阅消息 + +批量订阅API允许您在单个请求中从一个主题订阅多个消息。正如我们从[如何:发布和订阅主题]({{< ref howto-publish-subscribe.md >}})中所知,有三种方式可以订阅主题: + +- **声明式** - 订阅在外部文件中定义。 +- **编程式** - 订阅在代码中定义。 +- **流式** - *不支持*批量订阅,因为消息被发送到处理程序代码。 + +要批量订阅主题,我们只需使用`bulkSubscribe`规范属性,如下所示: + +```yaml +apiVersion: dapr.io/v2alpha1 +kind: Subscription +metadata: + name: order-pub-sub +spec: + topic: orders + routes: + default: /checkout + pubsubname: order-pub-sub + bulkSubscribe: + enabled: true + maxMessagesCount: 100 + maxAwaitDurationMs: 40 +scopes: +- orderprocessing +- checkout +``` + +在上面的示例中,`bulkSubscribe`是_可选的_。如果您使用`bulkSubscribe`,那么: +- `enabled`是必需的,用于启用或禁用此主题的批量订阅。 +- 您可以选择配置批量消息中传递的最大消息数(`maxMessagesCount`)。 +对于不支持批量订阅的组件,`maxMessagesCount`的默认值为100,即应用程序和Dapr之间的默认批量事件。请参阅[组件如何处理发布和订阅批量消息]({{< ref pubsub-bulk >}})。 +如果组件支持批量订阅,则该参数的默认值可以在该组件文档中找到。 +- 您可以选择提供在批量消息发送到应用程序之前的最大等待时间(`maxAwaitDurationMs`)。 +对于不支持批量订阅的组件,`maxAwaitDurationMs`的默认值为1000,即应用程序和Dapr之间的默认批量事件。请参阅[组件如何处理发布和订阅批量消息]({{< ref pubsub-bulk >}})。 +如果组件支持批量订阅,则该参数的默认值可以在该组件文档中找到。 + +应用程序接收与批量消息中的每个条目(单个消息)关联的`EntryId`。应用程序必须使用此`EntryId`来传达该特定条目的状态。如果应用程序未能通知`EntryId`状态,则被视为`RETRY`。 + +需要发送一个带有每个条目处理状态的JSON编码的有效负载体: + +```json +{ + "statuses": + [ + { + "entryId": "", + "status": "" + }, + { + "entryId": "", + "status": "" + } + ] +} +``` + +可能的状态值: + +状态 | 描述 +--------- | ----------- +`SUCCESS` | 消息处理成功 +`RETRY` | 消息由Dapr重试 +`DROP` | 记录警告并丢弃消息 + +请参阅[批量订阅的预期HTTP响应]({{< ref pubsub_api.md >}})以获取更多见解。 + +### 示例 + +以下代码示例演示如何使用批量订阅。 + +{{< tabs "Java" "JavaScript" ".NET" "Python" >}} +{{% codetab %}} + +```java +import io.dapr.Topic; +import io.dapr.client.domain.BulkSubscribeAppResponse; +import io.dapr.client.domain.BulkSubscribeAppResponseEntry; +import io.dapr.client.domain.BulkSubscribeAppResponseStatus; +import io.dapr.client.domain.BulkSubscribeMessage; +import io.dapr.client.domain.BulkSubscribeMessageEntry; +import io.dapr.client.domain.CloudEvent; +import io.dapr.springboot.annotations.BulkSubscribe; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import reactor.core.publisher.Mono; + +class BulkSubscriber { + @BulkSubscribe() + // @BulkSubscribe(maxMessagesCount = 100, maxAwaitDurationMs = 40) + @Topic(name = "topicbulk", pubsubName = "orderPubSub") + @PostMapping(path = "/topicbulk") + public Mono handleBulkMessage( + @RequestBody(required = false) BulkSubscribeMessage> bulkMessage) { + return Mono.fromCallable(() -> { + List entries = new ArrayList(); + for (BulkSubscribeMessageEntry entry : bulkMessage.getEntries()) { + try { + CloudEvent cloudEvent = (CloudEvent) entry.getEvent(); + System.out.printf("批量订阅者收到: %s\n", cloudEvent.getData()); + entries.add(new BulkSubscribeAppResponseEntry(entry.getEntryId(), BulkSubscribeAppResponseStatus.SUCCESS)); + } catch (Exception e) { + e.printStackTrace(); + entries.add(new BulkSubscribeAppResponseEntry(entry.getEntryId(), BulkSubscribeAppResponseStatus.RETRY)); + } + } + return new BulkSubscribeAppResponse(entries); + }); + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```typescript + +import { DaprServer } from "@dapr/dapr"; + +const pubSubName = "orderPubSub"; +const topic = "topicbulk"; + +const daprHost = process.env.DAPR_HOST || "127.0.0.1"; +const daprPort = process.env.DAPR_HTTP_PORT || "3502"; +const serverHost = process.env.SERVER_HOST || "127.0.0.1"; +const serverPort = process.env.APP_PORT || 5001; + +async function start() { + const server = new DaprServer({ + serverHost, + serverPort, + clientOptions: { + daprHost, + daprPort, + }, + }); + + // 使用默认配置向主题发布多个消息。 + await client.pubsub.bulkSubscribeWithDefaultConfig(pubSubName, topic, (data) => console.log("订阅者收到: " + JSON.stringify(data))); + + // 使用特定的maxMessagesCount和maxAwaitDurationMs向主题发布多个消息。 + await client.pubsub.bulkSubscribeWithConfig(pubSubName, topic, (data) => console.log("订阅者收到: " + JSON.stringify(data)), 100, 40); +} + +``` + +{{% /codetab %}} + +{{% codetab %}} + +```csharp +using Microsoft.AspNetCore.Mvc; +using Dapr.AspNetCore; +using Dapr; + +namespace DemoApp.Controllers; + +[ApiController] +[Route("[controller]")] +public class BulkMessageController : ControllerBase +{ + private readonly ILogger logger; + + public BulkMessageController(ILogger logger) + { + this.logger = logger; + } + + [BulkSubscribe("messages", 10, 10)] + [Topic("pubsub", "messages")] + public ActionResult HandleBulkMessages([FromBody] BulkSubscribeMessage> bulkMessages) + { + List responseEntries = new List(); + logger.LogInformation($"收到 {bulkMessages.Entries.Count()} 条消息"); + foreach (var message in bulkMessages.Entries) + { + try + { + logger.LogInformation($"收到一条数据为 '{message.Event.Data.MessageData}' 的消息"); + responseEntries.Add(new BulkSubscribeAppResponseEntry(message.EntryId, BulkSubscribeAppResponseStatus.SUCCESS)); + } + catch (Exception e) + { + logger.LogError(e.Message); + responseEntries.Add(new BulkSubscribeAppResponseEntry(message.EntryId, BulkSubscribeAppResponseStatus.RETRY)); + } + } + return new BulkSubscribeAppResponse(responseEntries); + } + public class BulkMessageModel + { + public string MessageData { get; set; } + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} +目前,您只能使用HTTP客户端在Python中进行批量订阅。 + +```python +import json +from flask import Flask, request, jsonify + +app = Flask(__name__) + +@app.route('/dapr/subscribe', methods=['GET']) +def subscribe(): + # 定义批量订阅配置 + subscriptions = [{ + "pubsubname": "pubsub", + "topic": "TOPIC_A", + "route": "/checkout", + "bulkSubscribe": { + "enabled": True, + "maxMessagesCount": 3, + "maxAwaitDurationMs": 40 + } + }] + print('Dapr pub/sub已订阅: ' + json.dumps(subscriptions)) + return jsonify(subscriptions) + + +# 定义处理传入消息的端点 +@app.route('/checkout', methods=['POST']) +def checkout(): + messages = request.json + print(messages) + for message in messages: + print(f"收到消息: {message}") + return json.dumps({'success': True}), 200, {'ContentType': 'application/json'} + +if __name__ == '__main__': + app.run(port=5000) + +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 组件如何处理发布和订阅批量消息 + +对于事件发布/订阅,涉及两种网络传输。 +1. 从/到*应用程序*到/从*Dapr*。 +1. 从/到*Dapr*到/从*pubsub代理*。 + +这些是可以进行优化的机会。当优化时,进行批量请求,从而减少总体调用次数,从而提高吞吐量并提供更好的延迟。 + +启用批量发布和/或批量订阅时,应用程序和Dapr sidecar之间的通信(上面第1点)针对**所有组件**进行了优化。 + +从Dapr sidecar到pubsub代理的优化取决于许多因素,例如: +- 代理必须本质上支持批量pubsub +- Dapr组件必须更新以支持代理提供的批量API的使用 + +目前,以下组件已更新以支持此级别的优化: + +| 组件 | 批量发布 | 批量订阅 | +|:--------------------:|:--------:|--------| +| Kafka | 是 | 是 | +| Azure Servicebus | 是 | 是 | +| Azure Eventhubs | 是 | 是 | + +## 演示 + +观看以下关于批量pubsub的演示和演讲。 + +### [KubeCon Europe 2023 演讲](https://youtu.be/WMBAo-UNg6o) + + + +### [Dapr社区电话#77 演讲](https://youtu.be/BxiKpEmchgQ?t=1170) + + + +## 相关链接 + +- [支持的pubsub组件列表]({{< ref supported-pubsub >}}) +- 阅读[API参考]({{< ref pubsub_api.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-cloudevents.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-cloudevents.md new file mode 100644 index 000000000..1d6525cfa --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-cloudevents.md @@ -0,0 +1,228 @@ +--- +type: docs +title: "使用 CloudEvents 进行消息传递" +linkTitle: "CloudEvents 消息传递" +weight: 2100 +description: "了解 Dapr 使用 CloudEvents 的原因,它们在 Dapr 发布订阅中的工作原理,以及如何创建 CloudEvents。" +--- + +为了实现消息路由并为每条消息提供额外的上下文,Dapr 采用 [CloudEvents 1.0 规范](https://github.com/cloudevents/spec/tree/v1.0) 作为其消息格式。通过 Dapr 发送到主题的任何消息都会自动被包装在 CloudEvents 信封中,使用 [`Content-Type` 头部值]({{< ref "pubsub-overview.md#content-types" >}}) 作为 `datacontenttype` 属性。 + +Dapr 使用 CloudEvents 为事件负载提供额外的上下文,从而实现以下功能: + +- 跟踪 +- 事件数据的正确反序列化的内容类型 +- 发送应用程序的验证 + +您可以选择以下三种方法之一通过发布订阅发布 CloudEvent: + +1. 发送一个发布订阅事件,然后由 Dapr 包装在 CloudEvent 信封中。 +2. 通过覆盖标准 CloudEvent 属性来替换 Dapr 提供的特定 CloudEvents 属性。 +3. 将您自己的 CloudEvent 信封作为发布订阅事件的一部分编写。 + +## Dapr 生成的 CloudEvents 示例 + +向 Dapr 发送发布操作会自动将其包装在一个包含以下字段的 CloudEvent 信封中: + +- `id` +- `source` +- `specversion` +- `type` +- `traceparent` +- `traceid` +- `tracestate` +- `topic` +- `pubsubname` +- `time` +- `datacontenttype` (可选) + +以下示例演示了 Dapr 为发布到 `orders` 主题的操作生成的 CloudEvent,其中包括: +- 一个 W3C `traceid`,唯一标识消息 +- `data` 和 CloudEvent 的字段,其中数据内容被序列化为 JSON + +```json +{ + "topic": "orders", + "pubsubname": "order_pub_sub", + "traceid": "00-113ad9c4e42b27583ae98ba698d54255-e3743e35ff56f219-01", + "tracestate": "", + "data": { + "orderId": 1 + }, + "id": "5929aaac-a5e2-4ca1-859c-edfe73f11565", + "specversion": "1.0", + "datacontenttype": "application/json; charset=utf-8", + "source": "checkout", + "type": "com.dapr.event.sent", + "time": "2020-09-23T06:23:21Z", + "traceparent": "00-113ad9c4e42b27583ae98ba698d54255-e3743e35ff56f219-01" +} +``` + +作为另一个 v1.0 CloudEvent 的示例,以下显示了在 CloudEvent 消息中以 JSON 序列化的 XML 内容的数据: + +```json +{ + "topic": "orders", + "pubsubname": "order_pub_sub", + "traceid": "00-113ad9c4e42b27583ae98ba698d54255-e3743e35ff56f219-01", + "tracestate": "", + "data" : "user2Order", + "id" : "id-1234-5678-9101", + "specversion" : "1.0", + "datacontenttype" : "text/xml", + "subject" : "Test XML Message", + "source" : "https://example.com/message", + "type" : "xml.message", + "time" : "2020-09-23T06:23:21Z" +} +``` + +## 替换 Dapr 生成的 CloudEvents 值 + +Dapr 自动生成多个 CloudEvent 属性。您可以通过提供以下可选元数据键/值来替换这些生成的 CloudEvent 属性: + +- `cloudevent.id`: 覆盖 `id` +- `cloudevent.source`: 覆盖 `source` +- `cloudevent.type`: 覆盖 `type` +- `cloudevent.traceid`: 覆盖 `traceid` +- `cloudevent.tracestate`: 覆盖 `tracestate` +- `cloudevent.traceparent`: 覆盖 `traceparent` + +使用这些元数据属性替换 CloudEvents 属性的能力适用于所有发布订阅组件。 + +### 示例 + +例如,要替换代码中[上述 CloudEvent 示例]({{< ref "#cloudevents-example" >}})中的 `source` 和 `id` 值: + +{{< tabs "Python" ".NET" >}} + +{{% codetab %}} + +```python +with DaprClient() as client: + order = {'orderId': i} + # 使用 Dapr 发布订阅发布事件/消息 + result = client.publish_event( + pubsub_name='order_pub_sub', + topic_name='orders', + publish_metadata={'cloudevent.id': 'd99b228f-6c73-4e78-8c4d-3f80a043d317', 'cloudevent.source': 'payment'} + ) +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```csharp +var order = new Order(i); +using var client = new DaprClientBuilder().Build(); + +// 覆盖 cloudevent 元数据 +var metadata = new Dictionary() { + { "cloudevent.source", "payment" }, + { "cloudevent.id", "d99b228f-6c73-4e78-8c4d-3f80a043d317" } +} + +// 使用 Dapr 发布订阅发布事件/消息 +await client.PublishEventAsync("order_pub_sub", "orders", order, metadata); +Console.WriteLine("Published data: " + order); + +await Task.Delay(TimeSpan.FromSeconds(1)); +``` + +{{% /codetab %}} + +{{< /tabs >}} + +然后 JSON 负载反映新的 `source` 和 `id` 值: + +```json +{ + "topic": "orders", + "pubsubname": "order_pub_sub", + "traceid": "00-113ad9c4e42b27583ae98ba698d54255-e3743e35ff56f219-01", + "tracestate": "", + "data": { + "orderId": 1 + }, + "id": "d99b228f-6c73-4e78-8c4d-3f80a043d317", + "specversion": "1.0", + "datacontenttype": "application/json; charset=utf-8", + "source": "payment", + "type": "com.dapr.event.sent", + "time": "2020-09-23T06:23:21Z", + "traceparent": "00-113ad9c4e42b27583ae98ba698d54255-e3743e35ff56f219-01" +} +``` + +{{% alert title="重要" color="warning" %}} +虽然您可以替换 `traceid`/`traceparent` 和 `tracestate`,但这样做可能会干扰事件跟踪并在跟踪工具中报告不一致的结果。建议使用 Open Telemetry 进行分布式跟踪。[了解更多关于分布式跟踪的信息。]({{< ref tracing-overview.md >}}) + +{{% /alert %}} + +## 发布您自己的 CloudEvent + +如果您想使用自己的 CloudEvent,请确保将 [`datacontenttype`]({{< ref "pubsub-overview.md#setting-message-content-types" >}}) 指定为 `application/cloudevents+json`。 + +如果应用程序编写的 CloudEvent 不包含 CloudEvent 规范中[最低要求的字段](https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md#required-attributes),则消息将被拒绝。如果缺少,Dapr 会将以下字段添加到 CloudEvent 中: + +- `time` +- `traceid` +- `traceparent` +- `tracestate` +- `topic` +- `pubsubname` +- `source` +- `type` +- `specversion` + +您可以向自定义 CloudEvent 添加不属于官方 CloudEvent 规范的其他字段。Dapr 将按原样传递这些字段。 + +### 示例 + +{{< tabs "Dapr CLI" "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + +发布一个 CloudEvent 到 `orders` 主题: + +```bash +dapr publish --publish-app-id orderprocessing --pubsub order-pub-sub --topic orders --data '{\"orderId\": \"100\"}' +``` + +{{% /codetab %}} + +{{% codetab %}} + +发布一个 CloudEvent 到 `orders` 主题: + +```bash +curl -X POST http://localhost:3601/v1.0/publish/order-pub-sub/orders -H "Content-Type: application/cloudevents+json" -d '{"specversion" : "1.0", "type" : "com.dapr.cloudevent.sent", "source" : "testcloudeventspubsub", "subject" : "Cloud Events Test", "id" : "someCloudEventId", "time" : "2021-08-02T09:00:00Z", "datacontenttype" : "application/cloudevents+json", "data" : {"orderId": "100"}}' +``` + +{{% /codetab %}} + +{{% codetab %}} + +发布一个 CloudEvent 到 `orders` 主题: + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/cloudevents+json' -Body '{"specversion" : "1.0", "type" : "com.dapr.cloudevent.sent", "source" : "testcloudeventspubsub", "subject" : "Cloud Events Test", "id" : "someCloudEventId", "time" : "2021-08-02T09:00:00Z", "datacontenttype" : "application/cloudevents+json", "data" : {"orderId": "100"}}' -Uri 'http://localhost:3601/v1.0/publish/order-pub-sub/orders' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 事件去重 + +使用 Dapr 创建的 CloudEvents 时,信封中包含一个 `id` 字段,应用程序可以使用该字段执行消息去重。Dapr 不会自动进行去重处理。Dapr 支持使用本身具备消息去重功能的消息代理。 + +## 下一步 + +- 了解为什么您可能[不想使用 CloudEvents]({{< ref pubsub-raw.md >}}) +- 试用 [发布订阅快速入门]({{< ref pubsub-quickstart.md >}}) +- [发布订阅组件列表]({{< ref setup-pubsub >}}) +- 阅读 [API 参考]({{< ref pubsub_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-deadletter.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-deadletter.md new file mode 100644 index 000000000..6a706348d --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-deadletter.md @@ -0,0 +1,125 @@ +--- +type: docs +title: "死信主题" +linkTitle: "死信主题" +weight: 4000 +description: "通过订阅死信主题来处理无法投递的消息" +--- + +## 介绍 + +在某些情况下,应用程序可能由于各种原因无法处理消息。例如,可能会出现获取处理消息所需数据的临时问题,或者应用程序的业务逻辑失败并返回错误。死信主题用于处理这些无法投递的消息,并将其转发到订阅应用程序。这可以减轻应用程序处理失败消息的负担,使开发人员可以编写代码从死信主题中读取消息,修复后重新发送,或者选择放弃这些消息。 + +死信主题通常与重试策略和处理死信主题消息的订阅一起使用。 + +当配置了死信主题时,任何无法投递到应用程序的消息都会被放置在死信主题中,以便转发到处理这些消息的订阅。这可以是同一个应用程序或完全不同的应用程序。 + +即使底层系统不支持,Dapr 也为其所有的 pubsub 组件启用了死信主题。例如,[AWS SNS 组件]({{< ref "setup-aws-snssqs" >}})有一个死信队列,[RabbitMQ]({{< ref "setup-rabbitmq" >}})有死信主题。您需要确保正确配置这些组件。 + +下图展示了死信主题的工作原理。首先,消息从 `orders` 主题的发布者发送。Dapr 代表订阅者应用程序接收消息,但 `orders` 主题的消息未能投递到应用程序的 `/checkout` 端点,即使经过重试也是如此。由于投递失败,消息被转发到 `poisonMessages` 主题,该主题将其投递到 `/failedMessages` 端点进行处理,在这种情况下是在同一个应用程序上。`failedMessages` 处理代码可以选择丢弃消息或重新发送新消息。 + + + +## 使用声明式订阅配置死信主题 + +以下 YAML 显示了如何为从 `orders` 主题消费的消息配置名为 `poisonMessages` 的死信主题。此订阅的范围限定为具有 `checkout` ID 的应用程序。 + +```yaml +apiVersion: dapr.io/v2alpha1 +kind: Subscription +metadata: + name: order +spec: + topic: orders + routes: + default: /checkout + pubsubname: pubsub + deadLetterTopic: poisonMessages +scopes: +- checkout +``` + +## 使用流式订阅配置死信主题 + +```go + var deadLetterTopic = "poisonMessages" + sub, err := cl.Subscribe(context.Background(), client.SubscriptionOptions{ + PubsubName: "pubsub", + Topic: "orders", + DeadLetterTopic: &deadLetterTopic, + }) +``` + +## 使用编程订阅配置死信主题 + +从 `/subscribe` 端点返回的 JSON 显示了如何为从 `orders` 主题消费的消息配置名为 `poisonMessages` 的死信主题。 + +```javascript +app.get('/dapr/subscribe', (_req, res) => { + res.json([ + { + pubsubname: "pubsub", + topic: "orders", + route: "/checkout", + deadLetterTopic: "poisonMessages" + } + ]); +}); +``` + +## 重试和死信主题 + +默认情况下,当设置了死信主题时,任何失败的消息会立即进入死信主题。因此,建议在订阅中使用死信主题时始终设置重试策略。 +要在将消息发送到死信主题之前启用消息重试,请对 pubsub 组件应用 [重试策略]({{< ref "policies.md#retries" >}})。 + +此示例显示了如何为 `pubsub` pubsub 组件设置名为 `pubsubRetry` 的常量重试策略,每 5 秒应用一次,最多尝试投递 10 次。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Resiliency +metadata: + name: myresiliency +spec: + policies: + retries: + pubsubRetry: + policy: constant + duration: 5s + maxRetries: 10 + targets: + components: + pubsub: + inbound: + retry: pubsubRetry +``` + +## 配置处理死信主题的订阅 + +请记得配置一个订阅来处理死信主题。例如,您可以创建另一个声明式订阅,在同一个或不同的应用程序上接收这些消息。下面的示例显示了 checkout 应用程序通过另一个订阅订阅 `poisonMessages` 主题,并将这些消息发送到 `/failedmessages` 端点进行处理。 + +```yaml +apiVersion: dapr.io/v2alpha1 +kind: Subscription +metadata: + name: deadlettertopics +spec: + topic: poisonMessages + routes: + rules: + - match: + path: /failedMessages + pubsubname: pubsub +scopes: +- checkout +``` + +## 演示 + +观看[此视频以了解死信主题的概述](https://youtu.be/wLYYOJLt_KQ?t=69): + + + +## 下一步 + +- 有关弹性策略的更多信息,请阅读[弹性概述]({{< ref resiliency-overview.md >}})。 +- 有关主题订阅的更多信息,请阅读[声明式、流式和编程订阅方法]({{< ref "pubsub-overview.md#message-subscription" >}})。 diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-message-ttl.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-message-ttl.md new file mode 100644 index 000000000..a1bd7d137 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-message-ttl.md @@ -0,0 +1,95 @@ +--- +type: docs +title: "消息生存时间 (TTL)" +linkTitle: "消息 TTL" +weight: 7000 +description: "在发布/订阅消息中使用生存时间。" +--- + +## 介绍 + +Dapr 支持为每条消息设置生存时间 (TTL)。这意味着应用程序可以为每条消息指定生存时间,过期后订阅者将不会收到这些消息。 + +所有 Dapr [发布/订阅组件]({{< ref supported-pubsub >}}) 都兼容消息 TTL,因为 Dapr 在运行时内处理 TTL 逻辑。只需在发布消息时设置 `ttlInSeconds` 元数据即可。 + +在某些组件中,例如 Kafka,可以通过 `retention.ms` 在主题中配置生存时间,详见[文档](https://kafka.apache.org/documentation/#topicconfigs_retention.ms)。使用 Dapr 的消息 TTL,使用 Kafka 的应用程序现在可以为每条消息设置生存时间,而不仅限于每个主题。 + +## 原生消息 TTL 支持 + +当发布/订阅组件原生支持消息生存时间时,Dapr 仅转发生存时间配置而不添加额外逻辑,保持行为的可预测性。这在组件以不同方式处理过期消息时非常有用。例如,在 Azure Service Bus 中,过期消息会被存储在死信队列中,而不是简单地删除。 + +{{% alert title="注意" color="primary" %}} +您还可以在创建时为给定的消息代理设置消息 TTL。查看您正在使用的组件的特定特性,以确定这是否合适。 + +{{% /alert %}} + +### 支持的组件 + +#### Azure Service Bus + +Azure Service Bus 支持[实体级别的生存时间](https://docs.microsoft.com/azure/service-bus-messaging/message-expiration)。这意味着消息有默认的生存时间,但也可以在发布时设置为更短的时间跨度。Dapr 传播消息的生存时间元数据,并让 Azure Service Bus 直接处理过期。 + +## 非 Dapr 订阅者 + +如果消息由不使用 Dapr 的订阅者消费,过期消息不会自动丢弃,因为过期是由 Dapr 运行时在 Dapr sidecar 接收到消息时处理的。然而,订阅者可以通过在云事件中添加逻辑来处理 `expiration` 属性,以编程方式丢弃过期消息,该属性遵循 [RFC3339](https://tools.ietf.org/html/rfc3339) 格式。 + +当非 Dapr 订阅者使用诸如 Azure Service Bus 等原生处理消息 TTL 的组件时,他们不会收到过期消息。在这种情况下,不需要额外的逻辑。 + +## 示例 + +消息 TTL 可以在发布请求的元数据中设置: + +{{< tabs curl "Python SDK" "PHP SDK">}} + +{{% codetab %}} +```bash +curl -X "POST" http://localhost:3500/v1.0/publish/pubsub/TOPIC_A?metadata.ttlInSeconds=120 -H "Content-Type: application/json" -d '{"order-number": "345"}' +``` +{{% /codetab %}} + +{{% codetab %}} +```python +from dapr.clients import DaprClient + +with DaprClient() as d: + req_data = { + 'order-number': '345' + } + # 创建一个带有内容类型和主体的类型化消息 + resp = d.publish_event( + pubsub_name='pubsub', + topic='TOPIC_A', + data=json.dumps(req_data), + publish_metadata={'ttlInSeconds': '120'} + ) + # 打印请求 + print(req_data, flush=True) +``` +{{% /codetab %}} + +{{% codetab %}} + +```php +run(function(\DI\FactoryInterface $factory) { + $publisher = $factory->make(\Dapr\PubSub\Publish::class, ['pubsub' => 'pubsub']); + $publisher->topic('TOPIC_A')->publish('data', ['ttlInSeconds' => '120']); +}); +``` + +{{% /codetab %}} + +{{< /tabs >}} + +请参阅[本指南]({{< ref pubsub_api.md >}})以获取发布/订阅 API 的参考。 + +## 下一步 + +- 了解[主题范围]({{< ref pubsub-scopes.md >}}) +- 学习[如何配置具有多个命名空间的发布/订阅组件]({{< ref pubsub-namespaces.md >}}) +- [发布/订阅组件]({{< ref supported-pubsub >}})列表 +- 阅读[API 参考]({{< ref pubsub_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-overview.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-overview.md new file mode 100644 index 000000000..cd3561b29 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-overview.md @@ -0,0 +1,177 @@ +--- +type: docs +title: "发布-订阅模式概述" +linkTitle: "概述" +weight: 1000 +description: "pubsub API 的基本构建块概述" +--- + +发布-订阅模式(pubsub)使微服务能够通过消息进行事件驱动的架构通信。 + +- 生产者或**发布者**将消息写入输入通道并发送到主题,而不关心哪个应用程序会接收它们。 +- 消费者或**订阅者**订阅主题并从输出通道接收消息,而不关心哪个服务生成了这些消息。 + +消息代理会将每条消息从发布者的输入通道复制到所有对该消息感兴趣的订阅者的输出通道。这种模式在需要将微服务解耦时特别有用。 + + + +

+ +## pubsub API + +在 Dapr 中,pubsub API: +- 提供一个平台无关的 API 来发送和接收消息。 +- 确保消息至少被传递一次。 +- 与多种消息代理和队列系统集成。 + +您可以在运行时配置 Dapr pubsub 组件来使用特定的消息代理,这种可插拔性使您的服务更具可移植性和灵活性。 + +在 Dapr 中使用 pubsub 时: + +1. 您的服务通过网络调用 Dapr pubsub 构建块 API。 +2. pubsub 构建块调用封装特定消息代理的 Dapr pubsub 组件。 +3. 为了接收主题上的消息,Dapr 代表您的服务订阅 pubsub 组件,并在消息到达时将其传递到您的服务的端点。 + +[以下概述视频和演示](https://www.youtube.com/live/0y7ne6teHT4?si=FMg2Y7bRuljKism-&t=5384)展示了 Dapr pubsub 的工作原理。 + + + +在下图中,“shipping”服务和“email”服务都已订阅由“cart”服务发布的主题。每个服务加载指向相同 pubsub 消息代理组件的 pubsub 组件配置文件;例如:Redis Streams、NATS Streaming、Azure Service Bus 或 GCP pubsub。 + + + +在下图中,Dapr API 将“cart”服务的“order”主题发布到“shipping”和“email”订阅服务的“order”端点。 + + + +[查看 Dapr 支持的 pubsub 组件的完整列表]({{< ref supported-pubsub >}})。 + +## 特性 + +pubsub API 构建块为您的应用程序带来了多个特性。 + +### 使用 Cloud Events 发送消息 + +为了启用消息路由并为服务之间的每条消息提供额外的上下文,Dapr 使用 [CloudEvents 1.0 规范](https://github.com/cloudevents/spec/tree/v1.0) 作为其消息格式。任何应用程序通过 Dapr 发送到主题的消息都会自动包装在 Cloud Events 信封中,使用 [`Content-Type` 头值]({{< ref "pubsub-overview.md#content-types" >}}) 作为 `datacontenttype` 属性。 + +有关更多信息,请阅读 [使用 CloudEvents 进行消息传递]({{< ref pubsub-cloudevents.md >}}),或 [发送不带 CloudEvents 的原始消息]({{< ref pubsub-raw.md >}})。 + +### 与不使用 Dapr 和 CloudEvents 的应用程序通信 + +如果您的一个应用程序使用 Dapr 而另一个不使用,您可以为发布者或订阅者禁用 CloudEvent 包装。这允许在无法一次性采用 Dapr 的应用程序中部分采用 Dapr pubsub。 + +有关更多信息,请阅读 [如何在没有 CloudEvents 的情况下使用 pubsub]({{< ref pubsub-raw.md >}})。 + +### 设置消息内容类型 + +发布消息时,指定发送数据的内容类型很重要。除非指定,否则 Dapr 将假定为 `text/plain`。 + +- HTTP 客户端:可以在 `Content-Type` 头中设置内容类型 +- gRPC 客户端和 SDK:有一个专用的内容类型参数 + +### 消息传递 + +原则上,Dapr 认为消息一旦被订阅者处理并以非错误响应进行响应,就已成功传递。为了更细粒度的控制,Dapr 的 pubsub API 还提供了明确的状态,定义在响应负载中,订阅者可以用这些状态向 Dapr 指示特定的处理指令(例如,`RETRY` 或 `DROP`)。 + +### 使用主题订阅接收消息 + +Dapr 应用程序可以通过支持相同功能的三种订阅类型订阅已发布的主题:声明式、流式和编程式。 + +| 订阅类型 | 描述 | +| ------------------- | ----------- | +| **声明式** | 订阅在**外部文件**中定义。声明式方法消除了代码中的 Dapr 依赖性,并允许现有应用程序订阅主题,而无需更改代码。 | +| **流式** | 订阅在**用户代码**中定义。流式订阅是动态的,意味着它们允许在运行时添加或删除订阅。它们不需要应用程序中的订阅端点(这是编程式和声明式订阅所需的),使其易于在代码中配置。流式订阅也不需要应用程序配置 sidecar 来接收消息。由于消息被发送到消息处理程序代码,因此流式订阅中没有路由或批量订阅的概念。 | +| **编程式** | 订阅在**用户代码**中定义。编程式方法实现了静态订阅,并需要在代码中有一个端点。| + +有关更多信息,请阅读 [关于订阅类型的订阅]({{< ref subscription-methods.md >}})。 + +### 重新加载主题订阅 + +要重新加载以编程方式或声明式定义的主题订阅,需要重新启动 Dapr sidecar。 +通过启用 [`HotReload` 功能门]({{< ref "support-preview-features.md" >}}),可以使 Dapr sidecar 动态重新加载更改的声明式主题订阅,而无需重新启动。 +主题订阅的热重载目前是一个预览功能。 +重新加载订阅时,正在传输的消息不受影响。 + +### 消息路由 + +Dapr 提供 [基于内容的路由](https://www.enterpriseintegrationpatterns.com/ContentBasedRouter.html) 模式。[Pubsub 路由]({{< ref howto-route-messages.md >}}) 是此模式的实现,允许开发人员使用表达式根据其内容将 [CloudEvents](https://cloudevents.io) 路由到应用程序中的不同 URI/路径和事件处理程序。如果没有路由匹配,则使用可选的默认路由。随着您的应用程序扩展以支持多个事件版本或特殊情况,这很有用。 + +此功能适用于声明式和编程式订阅方法。 + +有关消息路由的更多信息,请阅读 [Dapr pubsub API 参考]({{< ref "pubsub_api.md#provide-routes-for-dapr-to-deliver-topic-events" >}}) + +### 使用死信主题处理失败的消息 + +有时,由于各种可能的问题,例如生产者或消费者应用程序中的错误条件或导致应用程序代码出现问题的意外状态更改,消息无法被处理。Dapr 允许开发人员设置死信主题来处理无法传递到应用程序的消息。此功能适用于所有 pubsub 组件,并防止消费者应用程序无休止地重试失败的消息。有关更多信息,请阅读 [死信主题]({{< ref "pubsub-deadletter.md">}}) + +### 启用外发模式 + +Dapr 使开发人员能够使用外发模式在事务性状态存储和任何消息代理之间实现单一事务。有关更多信息,请阅读 [如何启用事务性外发消息]({{< ref howto-outbox.md >}}) + +### 命名空间消费者组 + +Dapr 通过 [命名空间消费者组]({{< ref howto-namespace >}}) 解决大规模多租户问题。只需在组件元数据中包含 `"{namespace}"` 值,即可允许具有相同 `app-id` 的多个命名空间的应用程序发布和订阅相同的消息代理。 + +### 至少一次保证 + +Dapr 保证消息传递的至少一次语义。当应用程序使用 pubsub API 向主题发布消息时,Dapr 确保消息至少一次传递给每个订阅者。 + +即使消息传递失败,或者您的应用程序崩溃,Dapr 也会尝试重新传递消息,直到成功传递。 + +所有 Dapr pubsub 组件都支持至少一次保证。 + +### 消费者组和竞争消费者模式 + +Dapr 处理消费者组和竞争消费者模式的负担。在竞争消费者模式中,使用单个消费者组的多个应用程序实例竞争消息。当副本使用相同的 `app-id` 而没有显式消费者组覆盖时,Dapr 强制执行竞争消费者模式。 + +当同一应用程序的多个实例(具有相同的 `app-id`)订阅一个主题时,Dapr 将每条消息仅传递给*该应用程序的一个实例*。此概念在下图中进行了说明。 + + +

+ +同样,如果两个不同的应用程序(具有不同的 `app-id`)订阅同一主题,Dapr 将每条消息仅传递给*每个应用程序的一个实例*。 + +并非所有 Dapr pubsub 组件都支持竞争消费者模式。目前,以下(非详尽)pubsub 组件支持此功能: + +- [Apache Kafka]({{< ref setup-apache-kafka >}}) +- [Azure Service Bus Queues]({{< ref setup-azure-servicebus-queues >}}) +- [RabbitMQ]({{< ref setup-rabbitmq >}}) +- [Redis Streams]({{< ref setup-redis-pubsub >}}) + +### 为增强安全性设置主题范围 + +默认情况下,与 pubsub 组件实例关联的所有主题消息对配置了该组件的每个应用程序都是可用的。您可以使用 Dapr 主题范围限制哪个应用程序可以发布或订阅主题。有关更多信息,请阅读:[pubsub 主题范围]({{< ref pubsub-scopes.md >}})。 + +### 消息生存时间(TTL) + +Dapr 可以在每条消息的基础上设置超时消息,这意味着如果消息未从 pubsub 组件中读取,则消息将被丢弃。此超时消息可防止未读消息的积累。如果消息在队列中的时间超过配置的 TTL,则标记为死信。有关更多信息,请阅读 [pubsub 消息 TTL]({{< ref pubsub-message-ttl.md >}})。 + +### 发布和订阅批量消息 + +Dapr 支持在单个请求中发送和接收多条消息。当编写需要发送或接收大量消息的应用程序时,使用批量操作可以通过减少请求总数来实现高吞吐量。有关更多信息,请阅读 [pubsub 批量消息]({{< ref pubsub-bulk.md >}})。 + +### 使用 StatefulSets 扩展订阅者 + +在 Kubernetes 上运行时,使用 StatefulSets 结合 `{podName}` 标记,订阅者可以为每个实例拥有一个粘性 `consumerID`。请参阅 [如何使用 StatefulSets 水平扩展订阅者]({{< ref "howto-subscribe-statefulset.md" >}})。 + +## 试用 pubsub + +### 快速入门和教程 + +想要测试 Dapr pubsub API 吗?通过以下快速入门和教程来查看 pubsub 的实际应用: + +| 快速入门/教程 | 描述 | +| ------------------- | ----------- | +| [Pubsub 快速入门]({{< ref pubsub-quickstart.md >}}) | 使用发布和订阅 API 发送和接收消息。 | +| [Pubsub 教程](https://github.com/dapr/quickstarts/tree/master/tutorials/pub-sub) | 演示如何使用 Dapr 启用 pubsub 应用程序。使用 Redis 作为 pubsub 组件。| + +### 直接在您的应用中开始使用 pubsub + +想要跳过快速入门?没问题。您可以直接在应用程序中试用 pubsub 构建块来发布消息并订阅主题。在 [安装 Dapr]({{< ref "getting-started/_index.md" >}}) 后,您可以从 [pubsub 如何指南]({{< ref howto-publish-subscribe.md >}}) 开始使用 pubsub API。 + +## 下一步 + +- 了解 [使用 CloudEvents 进行消息传递]({{< ref pubsub-cloudevents.md >}}) 以及何时可能需要 [发送不带 CloudEvents 的消息]({{< ref pubsub-raw.md >}})。 +- 遵循 [如何:配置具有多个命名空间的 pubsub 组件]({{< ref pubsub-namespaces.md >}})。 +- 查看 [pubsub 组件]({{< ref setup-pubsub >}}) 列表。 +- 阅读 [API 参考]({{< ref pubsub_api.md >}})。 diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-raw.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-raw.md new file mode 100644 index 000000000..51c03f5ef --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-raw.md @@ -0,0 +1,164 @@ +--- +type: docs +title: "发布和订阅非CloudEvents消息" +linkTitle: "非CloudEvents消息" +weight: 2200 +description: "了解何时可能不使用CloudEvents以及如何禁用它们。" +--- + +在将Dapr集成到您的应用程序时,由于兼容性原因或某些应用程序不使用Dapr,某些服务可能仍需要通过不封装在CloudEvents中的pub/sub消息进行通信。这些消息被称为“原始”pub/sub消息。Dapr允许应用程序[发布和订阅原始事件]({{< ref "pubsub-cloudevents.md#publishing-raw-messages" >}}),这些事件未封装在CloudEvent中以实现兼容性。 + +## 发布原始消息 + +Dapr应用程序可以将原始事件发布到pub/sub主题中,而不需要CloudEvent封装,以便与非Dapr应用程序兼容。 + +显示当订阅者不使用Dapr或CloudEvent时如何使用Dapr发布的图示 + +{{% alert title="警告" color="warning" %}} +不使用CloudEvents会禁用对跟踪、每个messageId的事件去重、内容类型元数据以及任何其他基于CloudEvent架构构建的功能的支持。 +{{% /alert %}} + +要禁用CloudEvent封装,请在发布请求中将`rawPayload`元数据设置为`true`。这样,订阅者可以接收这些消息而无需解析CloudEvent架构。 + +{{< tabs curl "Python SDK" "PHP SDK">}} + +{{% codetab %}} +```bash +curl -X "POST" http://localhost:3500/v1.0/publish/pubsub/TOPIC_A?metadata.rawPayload=true -H "Content-Type: application/json" -d '{"order-number": "345"}' +``` +{{% /codetab %}} + +{{% codetab %}} +```python +from dapr.clients import DaprClient + +with DaprClient() as d: + req_data = { + 'order-number': '345' + } + # 创建一个带有内容类型和主体的类型化消息 + resp = d.publish_event( + pubsub_name='pubsub', + topic_name='TOPIC_A', + data=json.dumps(req_data), + publish_metadata={'rawPayload': 'true'} + ) + # 打印请求 + print(req_data, flush=True) +``` +{{% /codetab %}} + +{{% codetab %}} + +```php +run(function(\DI\FactoryInterface $factory) { + $publisher = $factory->make(\Dapr\PubSub\Publish::class, ['pubsub' => 'pubsub']); + $publisher->topic('TOPIC_A')->publish('data', ['rawPayload' => 'true']); +}); +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 订阅原始消息 + +Dapr应用程序还可以订阅来自不使用CloudEvent封装的现有pub/sub主题的原始事件。 + +显示当发布者不使用Dapr或CloudEvent时如何使用Dapr订阅的图示 + +### 以编程方式订阅原始事件 + +在以编程方式订阅时,添加`rawPayload`的额外元数据条目,以便Dapr sidecar自动将负载封装到与当前Dapr SDK兼容的CloudEvent中。 + +{{< tabs "Python" "PHP SDK" >}} + +{{% codetab %}} + +```python +import flask +from flask import request, jsonify +from flask_cors import CORS +import json +import sys + +app = flask.Flask(__name__) +CORS(app) + +@app.route('/dapr/subscribe', methods=['GET']) +def subscribe(): + subscriptions = [{'pubsubname': 'pubsub', + 'topic': 'deathStarStatus', + 'route': 'dsstatus', + 'metadata': { + 'rawPayload': 'true', + } }] + return jsonify(subscriptions) + +@app.route('/dsstatus', methods=['POST']) +def ds_subscriber(): + print(request.json, flush=True) + return json.dumps({'success':True}), 200, {'ContentType':'application/json'} + +app.run() +``` + +{{% /codetab %}} +{{% codetab %}} + +```php + $builder->addDefinitions(['dapr.subscriptions' => [ + new \Dapr\PubSub\Subscription(pubsubname: 'pubsub', topic: 'deathStarStatus', route: '/dsstatus', metadata: [ 'rawPayload' => 'true'] ), +]])); + +$app->post('/dsstatus', function( + #[\Dapr\Attributes\FromBody] + \Dapr\PubSub\CloudEvent $cloudEvent, + \Psr\Log\LoggerInterface $logger + ) { + $logger->alert('Received event: {event}', ['event' => $cloudEvent]); + return ['status' => 'SUCCESS']; + } +); + +$app->start(); +``` +{{% /codetab %}} + +{{< /tabs >}} + +## 声明式订阅原始事件 + +同样,您可以通过在订阅规范中添加`rawPayload`元数据条目来声明式地订阅原始事件。 + +```yaml +apiVersion: dapr.io/v2alpha1 +kind: Subscription +metadata: + name: myevent-subscription +spec: + topic: deathStarStatus + routes: + default: /dsstatus + pubsubname: pubsub + metadata: + rawPayload: "true" +scopes: +- app1 +- app2 +``` + +## 下一步 + +- 了解更多关于[发布和订阅消息]({{< ref pubsub-overview.md >}}) +- [pub/sub组件]({{< ref supported-pubsub >}})列表 +- 阅读[API参考]({{< ref pubsub_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-scopes.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-scopes.md new file mode 100644 index 000000000..2feb982fa --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/pubsub-scopes.md @@ -0,0 +1,214 @@ +--- +type: docs +title: "限制 Pub/sub 主题访问" +linkTitle: "限制主题访问" +weight: 6000 +description: "通过范围控制将 pub/sub 主题限制为特定应用程序" +--- + +## 介绍 + +[命名空间或组件范围]({{< ref component-scopes.md >}})可以用来限制组件的访问权限,使其仅对特定应用程序可用。这些应用程序范围的设置确保只有具有特定 ID 的应用程序才能使用该组件。 + +除了这种通用的组件范围外,还可以对 pub/sub 组件进行以下限制: +- 哪些主题可以被使用(发布或订阅) +- 哪些应用程序被允许发布到特定主题 +- 哪些应用程序被允许订阅特定主题 + +这被称为 **pub/sub 主题范围控制**。 + +为每个 pub/sub 组件定义 pub/sub 范围。您可能有一个名为 `pubsub` 的 pub/sub 组件,它有一组范围,另一个 `pubsub2` 则有不同的范围。 + +要使用此主题范围,可以为 pub/sub 组件设置三个元数据属性: +- `spec.metadata.publishingScopes` + - 一个以分号分隔的应用程序列表和以逗号分隔的主题列表,允许该应用程序发布到该主题列表 + - 如果在 `publishingScopes` 中未指定任何内容(默认行为),则所有应用程序都可以发布到所有主题 + - 要拒绝应用程序发布到任何主题的能力,请将主题列表留空(`app1=;app2=topic2`) + - 例如,`app1=topic1;app2=topic2,topic3;app3=` 将允许 app1 仅发布到 topic1,app2 仅发布到 topic2 和 topic3,app3 则不能发布到任何主题。 +- `spec.metadata.subscriptionScopes` + - 一个以分号分隔的应用程序列表和以逗号分隔的主题列表,允许该应用程序订阅该主题列表 + - 如果在 `subscriptionScopes` 中未指定任何内容(默认行为),则所有应用程序都可以订阅所有主题 + - 例如,`app1=topic1;app2=topic2,topic3` 将允许 app1 仅订阅 topic1,app2 仅订阅 topic2 和 topic3 +- `spec.metadata.allowedTopics` + - 一个为所有应用程序允许的主题的逗号分隔列表。 + - 如果未设置 `allowedTopics`(默认行为),则所有主题都是有效的。如果存在,`subscriptionScopes` 和 `publishingScopes` 仍然生效。 + - `publishingScopes` 或 `subscriptionScopes` 可以与 `allowedTopics` 结合使用以添加细粒度限制 +- `spec.metadata.protectedTopics` + - 一个为所有应用程序保护的主题的逗号分隔列表。 + - 如果一个主题被标记为保护,则必须通过 `publishingScopes` 或 `subscriptionScopes` 明确授予应用程序发布或订阅权限才能发布/订阅该主题。 + +这些元数据属性可用于所有 pub/sub 组件。以下示例使用 Redis 作为 pub/sub 组件。 + +## 示例 1:限制主题访问 + +在某些情况下,限制哪些应用程序可以发布/订阅主题是有用的,例如当您有包含敏感信息的主题时,只有一部分应用程序被允许发布或订阅这些主题。 + +它也可以用于所有主题,以始终拥有一个“真实来源”,以了解哪些应用程序作为发布者/订阅者使用哪些主题。 + +以下是三个应用程序和三个主题的示例: +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: pubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: "localhost:6379" + - name: redisPassword + value: "" + - name: publishingScopes + value: "app1=topic1;app2=topic2,topic3;app3=" + - name: subscriptionScopes + value: "app2=;app3=topic1" +``` + +下表显示了哪些应用程序被允许发布到主题: + +| | topic1 | topic2 | topic3 | +|------|--------|--------|--------| +| app1 | ✅ | | | +| app2 | | ✅ | ✅ | +| app3 | | | | + +下表显示了哪些应用程序被允许订阅主题: + +| | topic1 | topic2 | topic3 | +|------|--------|--------|--------| +| app1 | ✅ | ✅ | ✅ | +| app2 | | | | +| app3 | ✅ | | | + +> 注意:如果应用程序未列出(例如 subscriptionScopes 中的 app1),则允许其订阅所有主题。因为未使用 `allowedTopics`,且 app1 没有任何订阅范围,它也可以使用上面未列出的其他主题。 + +## 示例 2:限制允许的主题 + +如果 Dapr 应用程序向其发送消息,则会创建一个主题。在某些情况下,这种主题创建应该受到管理。例如: +- Dapr 应用程序在生成主题名称时的错误可能导致创建无限数量的主题 +- 精简主题名称和总数,防止主题无限增长 + +在这些情况下可以使用 `allowedTopics`。 + +以下是三个允许的主题的示例: +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: pubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: "localhost:6379" + - name: redisPassword + value: "" + - name: allowedTopics + value: "topic1,topic2,topic3" +``` + +所有应用程序都可以使用这些主题,但仅限于这些主题,不允许其他主题。 + +## 示例 3:结合 `allowedTopics` 和范围 + +有时您希望结合两者范围,从而仅拥有一组固定的允许主题,并指定对某些应用程序的范围。 + +以下是三个应用程序和两个主题的示例: +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: pubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: "localhost:6379" + - name: redisPassword + value: "" + - name: allowedTopics + value: "A,B" + - name: publishingScopes + value: "app1=A" + - name: subscriptionScopes + value: "app1=;app2=A" +``` + +> 注意:第三个应用程序未列出,因为如果应用程序未在范围内指定,则允许其使用所有主题。 + +下表显示了哪个应用程序被允许发布到主题: + +| | A | B | C | +|------|---|---|---| +| app1 | ✅ | | | +| app2 | ✅ | ✅ | | +| app3 | ✅ | ✅ | | + +下表显示了哪个应用程序被允许订阅主题: + +| | A | B | C | +|------|---|---|---| +| app1 | | | | +| app2 | ✅ | | | +| app3 | ✅ | ✅ | | + +## 示例 4:将主题标记为保护 + +如果您的主题涉及敏感数据,则每个新应用程序必须在 `publishingScopes` 和 `subscriptionScopes` 中明确列出,以确保其无法读取或写入该主题。或者,您可以将主题指定为“保护”(使用 `protectedTopics`),并仅授予真正需要的特定应用程序访问权限。 + +以下是三个应用程序和三个主题的示例,其中两个主题是保护的: +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: pubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: "localhost:6379" + - name: redisPassword + value: "" + - name: protectedTopics + value: "A,B" + - name: publishingScopes + value: "app1=A,B;app2=B" + - name: subscriptionScopes + value: "app1=A,B;app2=B" +``` + +在上面的示例中,主题 A 和 B 被标记为保护。因此,即使 `app3` 未列在 `publishingScopes` 或 `subscriptionScopes` 中,它也无法与这些主题交互。 + +下表显示了哪个应用程序被允许发布到主题: + +| | A | B | C | +|------|---|---|---| +| app1 | ✅ | ✅ | | +| app2 | | ✅ | | +| app3 | | | ✅ | + +下表显示了哪个应用程序被允许订阅主题: + +| | A | B | C | +|------|---|---|---| +| app1 | ✅ | ✅ | | +| app2 | | ✅ | | +| app3 | | | ✅ | + + +## 演示 + +
+ +
+ +## 下一步 + +- 学习[如何配置具有多个命名空间的 pub/sub 组件]({{< ref pubsub-namespaces.md >}}) +- 了解[消息生存时间]({{< ref pubsub-message-ttl.md >}}) +- [pub/sub 组件列表]({{< ref supported-pubsub >}}) +- 阅读 [API 参考]({{< ref pubsub_api.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/subscription-methods.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/subscription-methods.md new file mode 100644 index 000000000..b05aeca09 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/pubsub/subscription-methods.md @@ -0,0 +1,624 @@ +--- +type: docs +title: "声明式、流式和编程式订阅类型" +linkTitle: "订阅类型" +weight: 3000 +description: "了解更多关于允许您订阅消息主题的订阅类型。" +--- + +## 发布/订阅 API 订阅类型 + +Dapr 应用程序可以通过三种订阅类型来订阅已发布的主题,这三种类型支持相同的功能:声明式、流式和编程式。 + +| 订阅类型 | 描述 | +| ------------------- | ----------- | +| [**声明式**]({{< ref "subscription-methods.md#declarative-subscriptions" >}}) | 订阅在**外部文件**中定义。声明式方法将 Dapr 的依赖从代码中移除,允许现有应用程序无需更改代码即可订阅主题。 | +| [**流式**]({{< ref "subscription-methods.md#streaming-subscriptions" >}}) | 订阅在**应用程序代码**中定义。流式订阅是动态的,允许在运行时添加或删除订阅。它们不需要在应用程序中设置订阅端点(这是编程式和声明式订阅所需的),使其在代码中易于配置。流式订阅也不需要应用程序配置 sidecar 来接收消息。 | +| [**编程式**]({{< ref "subscription-methods.md#programmatic-subscriptions" >}}) | 订阅在**应用程序代码**中定义。编程式方法实现了静态订阅,并需要在代码中设置一个端点。 | + +下面的示例演示了通过 `orders` 主题在 `checkout` 应用程序和 `orderprocessing` 应用程序之间的发布/订阅消息。示例首先以声明式,然后以编程式演示了相同的 Dapr 发布/订阅组件。 + +### 声明式订阅 + +{{% alert title="注意" color="primary" %}} +此功能目前处于预览状态。 +Dapr 可以实现“热重载”声明式订阅,从而在不需要重启的情况下自动获取更新。 +这通过 [`HotReload` 功能门控]({{< ref "support-preview-features.md" >}})启用。 +为了防止重新处理或丢失未处理的消息,在 Dapr 和您的应用程序之间的飞行消息在热重载事件期间不受影响。 +{{% /alert %}} + +您可以使用外部组件文件声明性地订阅一个主题。此示例使用名为 `subscription.yaml` 的 YAML 组件文件: + +```yaml +apiVersion: dapr.io/v2alpha1 +kind: Subscription +metadata: + name: order +spec: + topic: orders + routes: + default: /orders + pubsubname: pubsub +scopes: +- orderprocessing +``` + +这里的订阅名为 `order`: +- 使用名为 `pubsub` 的发布/订阅组件订阅名为 `orders` 的主题。 +- 设置 `route` 字段以将所有主题消息发送到应用程序中的 `/orders` 端点。 +- 设置 `scopes` 字段以将此订阅的访问范围仅限于 ID 为 `orderprocessing` 的应用程序。 + +运行 Dapr 时,设置 YAML 组件文件路径以指向 Dapr 的组件。 + +{{< tabs ".NET" Java Python JavaScript Go Kubernetes>}} + +{{% codetab %}} + +```bash +dapr run --app-id myapp --resources-path ./myComponents -- dotnet run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +dapr run --app-id myapp --resources-path ./myComponents -- mvn spring-boot:run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +dapr run --app-id myapp --resources-path ./myComponents -- python3 app.py +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +dapr run --app-id myapp --resources-path ./myComponents -- npm start +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +dapr run --app-id myapp --resources-path ./myComponents -- go run app.go +``` + +{{% /codetab %}} + +{{% codetab %}} + +在 Kubernetes 中,将组件应用到集群: + +```bash +kubectl apply -f subscription.yaml +``` + +{{% /codetab %}} + +{{< /tabs >}} + +在您的应用程序代码中,订阅 Dapr 发布/订阅组件中指定的主题。 + +{{< tabs ".NET" Java Python JavaScript Go >}} + +{{% codetab %}} + +```csharp + //订阅一个主题 +[HttpPost("orders")] +public void getCheckout([FromBody] int orderId) +{ + Console.WriteLine("Subscriber received : " + orderId); +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +import io.dapr.client.domain.CloudEvent; + + //订阅一个主题 +@PostMapping(path = "/orders") +public Mono getCheckout(@RequestBody(required = false) CloudEvent cloudEvent) { + return Mono.fromRunnable(() -> { + try { + log.info("Subscriber received: " + cloudEvent.getData()); + } + }); +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```python +from cloudevents.sdk.event import v1 + +#订阅一个主题 +@app.route('/orders', methods=['POST']) +def checkout(event: v1.Event) -> None: + data = json.loads(event.Data()) + logging.info('Subscriber received: ' + str(data)) +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +const express = require('express') +const bodyParser = require('body-parser') +const app = express() +app.use(bodyParser.json({ type: 'application/*+json' })); + +// 监听声明式路由 +app.post('/orders', (req, res) => { + console.log(req.body); + res.sendStatus(200); +}); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +//订阅一个主题 +var sub = &common.Subscription{ + PubsubName: "pubsub", + Topic: "orders", + Route: "/orders", +} + +func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool, err error) { + log.Printf("Subscriber received: %s", e.Data) + return false, nil +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +`/orders` 端点与订阅中定义的 `route` 匹配,这是 Dapr 发送所有主题消息的地方。 + +### 流式订阅 + +流式订阅是在应用程序代码中定义的订阅,可以在运行时动态停止和启动。 +消息由应用程序从 Dapr 拉取。这意味着不需要端点来订阅主题,并且可以在没有任何应用程序配置在 sidecar 上的情况下进行订阅。 +可以同时订阅任意数量的发布/订阅和主题。 +由于消息被发送到给定的消息处理代码,因此没有路由或批量订阅的概念。 + +> **注意:** 每个应用程序一次只能订阅一个发布/订阅/主题对。 + +下面的示例展示了不同的流式订阅主题的方法。 + +{{< tabs Python Go >}} + +{{% codetab %}} + +您可以使用 `subscribe` 方法,该方法返回一个 `Subscription` 对象,并允许您通过调用 `next_message` 方法从流中拉取消息。这在主线程中运行,并可能在等待消息时阻塞主线程。 + +```python +import time + +from dapr.clients import DaprClient +from dapr.clients.grpc.subscription import StreamInactiveError + +counter = 0 + + +def process_message(message): + global counter + counter += 1 + # 在此处处理消息 + print(f'Processing message: {message.data()} from {message.topic()}...') + return 'success' + + +def main(): + with DaprClient() as client: + global counter + + subscription = client.subscribe( + pubsub_name='pubsub', topic='orders', dead_letter_topic='orders_dead' + ) + + try: + while counter < 5: + try: + message = subscription.next_message() + + except StreamInactiveError as e: + print('Stream is inactive. Retrying...') + time.sleep(1) + continue + if message is None: + print('No message received within timeout period.') + continue + + # 处理消息 + response_status = process_message(message) + + if response_status == 'success': + subscription.respond_success(message) + elif response_status == 'retry': + subscription.respond_retry(message) + elif response_status == 'drop': + subscription.respond_drop(message) + + finally: + print("Closing subscription...") + subscription.close() + + +if __name__ == '__main__': + main() + +``` + +您还可以使用 `subscribe_with_handler` 方法,该方法接受一个回调函数,该函数为从流中接收到的每条消息执行。此方法在单独的线程中运行,因此不会阻塞主线程。 + +```python +import time + +from dapr.clients import DaprClient +from dapr.clients.grpc._response import TopicEventResponse + +counter = 0 + + +def process_message(message): + # 在此处处理消息 + global counter + counter += 1 + print(f'Processing message: {message.data()} from {message.topic()}...') + return TopicEventResponse('success') + + +def main(): + with (DaprClient() as client): + # 这将启动一个新线程,该线程将监听消息 + # 并在 `process_message` 函数中处理它们 + close_fn = client.subscribe_with_handler( + pubsub_name='pubsub', topic='orders', handler_fn=process_message, + dead_letter_topic='orders_dead' + ) + + while counter < 5: + time.sleep(1) + + print("Closing subscription...") + close_fn() + + +if __name__ == '__main__': + main() +``` + +[了解更多关于使用 Python SDK 客户端的流式订阅。]({{< ref "python-client.md#streaming-message-subscription" >}}) + +{{% /codetab %}} + +{{% codetab %}} + +```go +package main + +import ( + "context" + "log" + + "github.com/dapr/go-sdk/client" +) + +func main() { + cl, err := client.NewClient() + if err != nil { + log.Fatal(err) + } + + sub, err := cl.Subscribe(context.Background(), client.SubscriptionOptions{ + PubsubName: "pubsub", + Topic: "orders", + }) + if err != nil { + panic(err) + } + // 必须始终调用 Close。 + defer sub.Close() + + for { + msg, err := sub.Receive() + if err != nil { + panic(err) + } + + // 处理事件 + + // 我们 _必须_ 始终表示消息处理的结果,否则 + // 消息将不会被视为已处理,并将被重新传递或 + // 死信。 + // msg.Retry() + // msg.Drop() + if err := msg.Success(); err != nil { + panic(err) + } + } +} +``` + +或 + +```go +package main + +import ( + "context" + "log" + + "github.com/dapr/go-sdk/client" + "github.com/dapr/go-sdk/service/common" +) + +func main() { + cl, err := client.NewClient() + if err != nil { + log.Fatal(err) + } + + stop, err := cl.SubscribeWithHandler(context.Background(), + client.SubscriptionOptions{ + PubsubName: "pubsub", + Topic: "orders", + }, + eventHandler, + ) + if err != nil { + panic(err) + } + + // 必须始终调用 Stop。 + defer stop() + + <-make(chan struct{}) +} + +func eventHandler(e *common.TopicEvent) common.SubscriptionResponseStatus { + // 在此处处理消息 + // common.SubscriptionResponseStatusRetry + // common.SubscriptionResponseStatusDrop + common.SubscriptionResponseStatusDrop, status) + } + + return common.SubscriptionResponseStatusSuccess +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 演示 + +观看 [此视频以了解流式订阅的概述](https://youtu.be/57l-QDwgI-Y?t=841): + + + +### 编程式订阅 + +动态编程式方法在代码中返回 `routes` JSON 结构,与声明式方法的 `route` YAML 结构不同。 + +> **注意:** 编程式订阅仅在应用程序启动时读取一次。您不能 _动态_ 添加新的编程式订阅,只能在编译时添加新的。 + +在下面的示例中,您在应用程序代码中定义了在上面的[声明式 YAML 订阅](#declarative-subscriptions)中找到的值。 + +{{< tabs ".NET" Java Python JavaScript Go>}} + +{{% codetab %}} + +```csharp +[Topic("pubsub", "orders")] +[HttpPost("/orders")] +public async Task>Checkout(Order order, [FromServices] DaprClient daprClient) +{ + // 逻辑 + return order; +} +``` + +或 + +```csharp +// Dapr 订阅在 [Topic] 中将 orders 主题路由到此路由 +app.MapPost("/orders", [Topic("pubsub", "orders")] (Order order) => { + Console.WriteLine("Subscriber received : " + order); + return Results.Ok(order); +}); +``` + +上面定义的两个处理程序还需要映射以配置 `dapr/subscribe` 端点。这是在定义端点时在应用程序启动代码中完成的。 + +```csharp +app.UseEndpoints(endpoints => +{ + endpoints.MapSubscribeHandler(); +}); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + +@Topic(name = "orders", pubsubName = "pubsub") +@PostMapping(path = "/orders") +public Mono handleMessage(@RequestBody(required = false) CloudEvent cloudEvent) { + return Mono.fromRunnable(() -> { + try { + System.out.println("Subscriber received: " + cloudEvent.getData()); + System.out.println("Subscriber received: " + OBJECT_MAPPER.writeValueAsString(cloudEvent)); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```python +@app.route('/dapr/subscribe', methods=['GET']) +def subscribe(): + subscriptions = [ + { + 'pubsubname': 'pubsub', + 'topic': 'orders', + 'routes': { + 'rules': [ + { + 'match': 'event.type == "order"', + 'path': '/orders' + }, + ], + 'default': '/orders' + } + }] + return jsonify(subscriptions) + +@app.route('/orders', methods=['POST']) +def ds_subscriber(): + print(request.json, flush=True) + return json.dumps({'success':True}), 200, {'ContentType':'application/json'} +app.run() +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +const express = require('express') +const bodyParser = require('body-parser') +const app = express() +app.use(bodyParser.json({ type: 'application/*+json' })); + +const port = 3000 + +app.get('/dapr/subscribe', (req, res) => { + res.json([ + { + pubsubname: "pubsub", + topic: "orders", + routes: { + rules: [ + { + match: 'event.type == "order"', + path: '/orders' + }, + ], + default: '/products' + } + } + ]); +}) + +app.post('/orders', (req, res) => { + console.log(req.body); + res.sendStatus(200); +}); + +app.listen(port, () => console.log(`consumer app listening on port ${port}!`)) +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +package main + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + + "github.com/gorilla/mux" +) + +const appPort = 3000 + +type subscription struct { + PubsubName string `json:"pubsubname"` + Topic string `json:"topic"` + Metadata map[string]string `json:"metadata,omitempty"` + Routes routes `json:"routes"` +} + +type routes struct { + Rules []rule `json:"rules,omitempty"` + Default string `json:"default,omitempty"` +} + +type rule struct { + Match string `json:"match"` + Path string `json:"path"` +} + +// 处理 /dapr/subscribe +func configureSubscribeHandler(w http.ResponseWriter, _ *http.Request) { + t := []subscription{ + { + PubsubName: "pubsub", + Topic: "orders", + Routes: routes{ + Rules: []rule{ + { + Match: `event.type == "order"`, + Path: "/orders", + }, + }, + Default: "/orders", + }, + }, + } + + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(t) +} + +func main() { + router := mux.NewRouter().StrictSlash(true) + router.HandleFunc("/dapr/subscribe", configureSubscribeHandler).Methods("GET") + log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", appPort), router)) +} +``` +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 + +* 试用 [发布/订阅快速入门]({{< ref pubsub-quickstart.md >}}) +* 关注:[如何:配置具有多个命名空间的发布/订阅组件]({{< ref pubsub-namespaces.md >}}) +* 了解更多关于[声明式和编程式订阅方法]({{< ref subscription-methods >}})。 +* 了解[主题范围]({{< ref pubsub-scopes.md >}}) +* 了解[消息 TTL]({{< ref pubsub-message-ttl.md >}}) +* 了解更多关于[带有和不带有 CloudEvent 的发布/订阅]({{< ref pubsub-cloudevents.md >}}) +* [发布/订阅组件列表]({{< ref supported-pubsub.md >}}) +* 阅读 [发布/订阅 API 参考]({{< ref pubsub_api.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/secrets/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/secrets/_index.md new file mode 100644 index 000000000..2bbedfcd1 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/secrets/_index.md @@ -0,0 +1,15 @@ +--- +type: docs +title: "Secret 管理" +linkTitle: "Secret 管理" +weight: 70 +description: 安全地从应用程序访问 Secret +--- + +{{% alert title="更多关于DaprSecret" color="primary" %}} +了解如何使用DaprSecret的更多信息: +- 尝试[Secret快速入门]({{< ref secrets-quickstart.md >}})。 +- 通过任何支持的[Dapr SDKs]({{< ref sdks >}})探索Secret。 +- 查看[SecretAPI参考文档]({{< ref secrets_api.md >}})。 +- 浏览支持的[Secret组件规格]({{< ref supported-secret-stores >}})。 +{{% /alert %}} diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/secrets/howto-secrets.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/secrets/howto-secrets.md new file mode 100644 index 000000000..84915aace --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/secrets/howto-secrets.md @@ -0,0 +1,245 @@ +--- +type: docs +title: "如何检索 Secret" +linkTitle: "如何检索 Secret" +weight: 2000 +description: "使用 Secret 存储构建块安全地检索 Secret" +--- + +在了解了[Dapr Secret 构建块的功能]({{< ref secrets-overview >}})后,接下来学习如何在服务中使用它。本指南将演示如何调用 Secret API,并从配置的 Secret 存储中将 Secret 检索到应用程序代码中。 + +示例服务的 Secret 管理示意图。 + +{{% alert title="提示" color="primary" %}} +如果您还没有尝试过,[请先查看 Secret 管理快速入门]({{< ref secrets-quickstart.md >}}),以快速了解如何使用 Secret API。 +{{% /alert %}} + +## 配置 Secret 存储 + +在应用程序代码中检索 Secret 之前,您需要先配置一个 Secret 存储组件。此示例配置了一个使用本地 JSON 文件存储 Secret 的 Secret 存储。 + +{{% alert title="警告" color="warning" %}} +在生产环境中,不建议使用本地 Secret 存储。[请查看其他安全管理 Secret 的方案]({{< ref supported-secret-stores >}})。 +{{% /alert %}} + +在项目目录中,创建一个名为 `secrets.json` 的文件,内容如下: + +```json +{ + "secret": "Order Processing pass key" +} +``` + +创建一个名为 `components` 的新目录。进入该目录并创建一个名为 `local-secret-store.yaml` 的组件文件,内容如下: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: localsecretstore +spec: + type: secretstores.local.file + version: v1 + metadata: + - name: secretsFile + value: secrets.json # Secret 文件的路径 + - name: nestedSeparator + value: ":" +``` + +{{% alert title="注意" color="warning" %}} +Secret 存储 JSON 的路径是相对于您执行 `dapr run` 命令的位置。 +{{% /alert %}} + +更多信息: + +- 查看如何[配置不同类型的 Secret 存储]({{< ref setup-secret-store >}})。 +- 查看[支持的 Secret 存储]({{< ref supported-secret-stores >}})以了解不同 Secret 存储解决方案的具体细节。 + +## 获取 Secret + +通过调用 Dapr sidecar 的 Secret API 来获取 Secret: + +```bash +curl http://localhost:3601/v1.0/secrets/localsecretstore/secret +``` + +查看[完整的 API 参考]({{< ref secrets_api.md >}})。 + +## 从代码中调用 Secret API + +现在您已经设置了本地 Secret 存储,可以通过 Dapr 从应用程序代码中获取 Secret。以下是利用 Dapr SDK 检索 Secret 的代码示例。 + +{{< tabs ".NET" Java Python Go JavaScript>}} + +{{% codetab %}} + +```csharp +// 依赖项 +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using Dapr.Client; +using Microsoft.AspNetCore.Mvc; +using System.Threading; +using System.Text.Json; + +// 代码 +namespace EventService +{ + class Program + { + static async Task Main(string[] args) + { + string SECRET_STORE_NAME = "localsecretstore"; + using var client = new DaprClientBuilder().Build(); + // 使用 Dapr SDK 获取 Secret + var secret = await client.GetSecretAsync(SECRET_STORE_NAME, "secret"); + Console.WriteLine($"Result: {string.Join(", ", secret)}"); + } + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +// 依赖项 +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.Map; + +// 代码 +@SpringBootApplication +public class OrderProcessingServiceApplication { + + private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); + private static final ObjectMapper JSON_SERIALIZER = new ObjectMapper(); + + private static final String SECRET_STORE_NAME = "localsecretstore"; + + public static void main(String[] args) throws InterruptedException, JsonProcessingException { + DaprClient client = new DaprClientBuilder().build(); + // 使用 Dapr SDK 获取 Secret + Map secret = client.getSecret(SECRET_STORE_NAME, "secret").block(); + log.info("Result: " + JSON_SERIALIZER.writeValueAsString(secret)); + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```python +# 依赖项 +import random +from time import sleep +import requests +import logging +from dapr.clients import DaprClient +from dapr.clients.grpc._state import StateItem +from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType + +# 代码 +logging.basicConfig(level = logging.INFO) +DAPR_STORE_NAME = "localsecretstore" +key = 'secret' + +with DaprClient() as client: + # 使用 Dapr SDK 获取 Secret + secret = client.get_secret(store_name=DAPR_STORE_NAME, key=key) + logging.info('Result: ') + logging.info(secret.secret) + # 使用 Dapr SDK 获取批量 Secret + secret = client.get_bulk_secret(store_name=DAPR_STORE_NAME) + logging.info('Result for bulk secret: ') + logging.info(sorted(secret.secrets.items())) +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +// 依赖项 +import ( + "context" + "log" + + dapr "github.com/dapr/go-sdk/client" +) + +// 代码 +func main() { + client, err := dapr.NewClient() + SECRET_STORE_NAME := "localsecretstore" + if err != nil { + panic(err) + } + defer client.Close() + ctx := context.Background() + // 使用 Dapr SDK 获取 Secret + secret, err := client.GetSecret(ctx, SECRET_STORE_NAME, "secret", nil) + if secret != nil { + log.Println("Result : ") + log.Println(secret) + } + // 使用 Dapr SDK 获取批量 Secret + secretBulk, err := client.GetBulkSecret(ctx, SECRET_STORE_NAME, nil) + + if secret != nil { + log.Println("Result for bulk: ") + log.Println(secretBulk) + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +// 依赖项 +import { DaprClient, HttpMethod, CommunicationProtocolEnum } from '@dapr/dapr'; + +// 代码 +const daprHost = "127.0.0.1"; + +async function main() { + const client = new DaprClient({ + daprHost, + daprPort: process.env.DAPR_HTTP_PORT, + communicationProtocol: CommunicationProtocolEnum.HTTP, + }); + const SECRET_STORE_NAME = "localsecretstore"; + // 使用 Dapr SDK 获取 Secret + var secret = await client.secret.get(SECRET_STORE_NAME, "secret"); + console.log("Result: " + secret); + // 使用 Dapr SDK 获取批量 Secret + secret = await client.secret.getBulk(SECRET_STORE_NAME); + console.log("Result for bulk: " + secret); +} + +main(); +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 相关链接 + +- 查看[Dapr Secret API 功能]({{< ref secrets-overview >}})。 +- 学习如何[使用 Secret 范围]({{< ref secrets-scopes >}}) +- 阅读[Secret API 参考]({{< ref secrets_api >}})并查看[支持的 Secret]({{< ref supported-secret-stores >}})。 +- 学习如何[设置不同的 Secret 存储组件]({{< ref setup-secret-store >}})以及如何[在组件中引用 Secret]({{< ref component-secrets >}})。 diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/secrets/secrets-overview.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/secrets/secrets-overview.md new file mode 100644 index 000000000..488290388 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/secrets/secrets-overview.md @@ -0,0 +1,89 @@ +--- +type: docs +title: "Secrets 管理概述" +linkTitle: "概述" +weight: 1000 +description: "Secrets 管理 API 构建块概述" +--- + +应用程序通常使用专用的 secret 存储来保存敏感信息。例如,您可以使用存储在 secret 存储中的连接字符串、密钥、令牌和其他应用程序级别的 secret 来对数据库、服务和外部系统进行身份验证,例如 [AWS Secrets Manager, Azure Key Vault, Hashicorp Vault 等]({{< ref supported-secret-stores >}})。 + +为了访问这些 secret 存储,应用程序需要导入 secret 存储的 SDK。在多云场景中,这种情况更具挑战性,因为可能会使用不同供应商特定的 secret 存储。 + +## Secrets 管理 API + +Dapr 的专用 secrets 构建块 API 使开发人员更容易从 secret 存储中使用应用程序 secret。要使用 Dapr 的 secret 存储构建块,您需要: + +1. 为特定的 secret 存储解决方案设置一个组件。 +1. 在应用程序代码中使用 Dapr secrets API 检索 secret。 +1. 可选地,在 Dapr 组件文件中引用 secret。 + +[以下概述视频和演示](https://www.youtube.com/live/0y7ne6teHT4?si=3bmNSSyIEIVSF-Ej&t=9931)展示了 Dapr secrets 管理的工作原理。 + + + +## 功能 + +Secrets 管理 API 构建块为您的应用程序带来了多种功能。 + +### 在不更改应用程序代码的情况下配置 secret + +您可以在应用程序代码中调用 secrets API,从 Dapr 支持的 secret 存储中检索和使用 secret。观看[此视频](https://www.youtube.com/watch?v=OtbYCBt9C34&t=1818)以了解如何在应用程序中使用 secrets 管理 API 的示例。 + + + +例如,下图显示了一个应用程序从配置的云 secret 存储中请求名为 "mysecret" 的 secret,该 secret 存储名为 "vault"。 + + + +应用程序还可以使用 secrets API 从 Kubernetes secret 存储中访问 secret。默认情况下,Dapr 在 Kubernetes 模式下启用了内置的 [Kubernetes secret 存储]({{< ref "kubernetes-secret-store.md" >}}),可以通过以下方式部署: + +- 使用 Helm 的默认设置,或 +- 运行 `dapr init -k` + +如果您使用其他 secret 存储,可以通过在 deployment.yaml 文件中添加注释 `dapr.io/disable-builtin-k8s-secret-store: "true"` 来禁用(不配置)Dapr Kubernetes secret 存储。默认值为 `false`。 + +在下面的示例中,应用程序从 Kubernetes secret 存储中检索相同的 secret "mysecret"。 + + + +在 Azure 中,您可以配置 Dapr 使用托管身份通过 Azure Key Vault 检索 secret。在下面的示例中: + +1. 配置了一个 [Azure Kubernetes Service (AKS) 集群](https://docs.microsoft.com/azure/aks) 以使用托管身份。 +1. Dapr 使用 [pod 身份](https://docs.microsoft.com/azure/aks/operator-best-practices-identity#use-pod-identities) 代表应用程序从 Azure Key Vault 检索 secret。 + + + +在上述示例中,应用程序代码无需更改即可获取相同的 secret。Dapr 通过 secrets 管理构建块 API 使用 secret 管理组件。 + +[尝试使用 secrets API]({{< ref "#try-out-secrets-management" >}}) 通过我们的快速入门或教程之一。 + +### 在 Dapr 组件中引用 secret 存储 + +在配置 Dapr 组件(如 state 存储)时,通常需要在组件文件中包含凭据。或者,您可以将凭据放在 Dapr 支持的 secret 存储中,并在 Dapr 组件中引用该 secret。这是首选方法和推荐的最佳实践,尤其是在生产环境中。 + +有关更多信息,请阅读[在组件中引用 secret 存储]({{< ref component-secrets.md >}})。 + +### 限制对 secret 的访问 + +为了对 secret 的访问提供更细粒度的控制,Dapr 提供了定义范围和限制访问权限的能力。了解更多关于[使用 secret 范围]({{< ref secrets-scopes >}})的信息。 + +## 尝试 secrets 管理 + +### 快速入门和教程 + +想要测试 Dapr secrets 管理 API 吗?通过以下快速入门和教程来查看 Dapr secrets 的实际应用: + +| 快速入门/教程 | 描述 | +| ------------------- | ----------- | +| [Secrets 管理快速入门]({{< ref secrets-quickstart.md >}}) | 使用 secrets 管理 API 从配置的 secret 存储中在应用程序代码中检索 secret。 | +| [Secret Store 教程](https://github.com/dapr/quickstarts/tree/master/tutorials/secretstore) | 演示如何使用 Dapr Secrets API 访问 secret 存储。 | + +### 直接在您的应用中开始管理 secret + +想要跳过快速入门?没问题。您可以直接在应用程序中尝试使用 secret 管理构建块来检索和管理 secret。在[安装 Dapr]({{< ref "getting-started/_index.md" >}})后,您可以从[secrets 使用指南]({{< ref howto-secrets.md >}})开始使用 secrets 管理 API。 + +## 下一步 + +- 了解[如何使用 secret 范围]({{< ref secrets-scopes.md >}})。 +- 阅读 [secrets API 参考文档]({{< ref secrets_api.md >}})。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/secrets/secrets-scopes.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/secrets/secrets-scopes.md new file mode 100644 index 000000000..3b68dc1fd --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/secrets/secrets-scopes.md @@ -0,0 +1,109 @@ +--- +type: docs +title: "如何使用:配置 secret 访问范围" +linkTitle: "如何使用:配置 secret 访问范围" +weight: 3000 +description: "通过设置访问范围限制应用程序从 secret 存储中读取的 secret" +--- + +当您[为应用程序配置了 secret 存储]({{< ref setup-secret-store >}})后,Dapr 应用程序默认可以访问该存储中定义的*所有* secret。 + +您可以通过在[应用程序配置]({{< ref configuration-concept.md >}})中定义 secret 访问范围策略,来限制 Dapr 应用程序对特定 secret 的访问权限。 + +secret 访问范围策略适用于任何[secret 存储]({{< ref supported-secret-stores.md >}}),包括: + +- 本地 secret 存储 +- Kubernetes secret 存储 +- 公有云 secret 存储 + +有关如何设置[secret 存储]({{< ref setup-secret-store.md >}})的详细信息,请阅读[如何:检索 secret]({{< ref howto-secrets.md >}})。 + +观看[此视频](https://youtu.be/j99RN_nxExA?start=2272)以了解如何在应用程序中使用 secret 访问范围的演示。 + +
+ +
+ +## 场景 1:拒绝访问 secret 存储中的所有 secret + +在此示例中,所有 secret 访问都被拒绝给运行在 Kubernetes 集群上的应用程序,该集群配置了名为 `mycustomsecretstore` 的[Kubernetes secret 存储]({{< ref kubernetes-secret-store >}})。除了用户定义的自定义存储外,示例还配置了 Kubernetes 默认存储(名为 `kubernetes`),以确保所有 secret 都被拒绝访问。[了解有关 Kubernetes 默认 secret 存储的更多信息]({{< ref "kubernetes-secret-store.md#default-kubernetes-secret-store-component" >}})。 + +定义以下 `appconfig.yaml` 配置,并使用命令 `kubectl apply -f appconfig.yaml` 将其应用于 Kubernetes 集群。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: appconfig +spec: + secrets: + scopes: + - storeName: kubernetes + defaultAccess: deny + - storeName: mycustomsecreststore + defaultAccess: deny +``` + +对于需要拒绝访问 Kubernetes secret 存储的应用程序,请按照[这些说明]({{< ref kubernetes-overview.md >}}),并将以下注释添加到应用程序 pod: + +```yaml +dapr.io/config: appconfig +``` + +配置完成后,应用程序将无法访问 Kubernetes secret 存储中的任何 secret。 + +## 场景 2:仅允许访问 secret 存储中的某些 secret + +此示例使用名为 `vault` 的 secret 存储。这可以是设置在应用程序上的 Hashicorp secret 存储组件。要允许 Dapr 应用程序仅访问 `vault` secret 存储中的 `secret1` 和 `secret2`,请定义以下 `appconfig.yaml`: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: appconfig +spec: + secrets: + scopes: + - storeName: vault + defaultAccess: deny + allowedSecrets: ["secret1", "secret2"] +``` + +对 `vault` secret 存储的默认访问是 `deny`,但应用程序可以根据 `allowedSecrets` 列表访问特定的 secret。[了解如何将配置应用于 sidecar]({{< ref configuration-concept.md >}})。 + +## 场景 3:拒绝访问 secret 存储中的某些敏感 secret + +定义以下 `config.yaml`: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: appconfig +spec: + secrets: + scopes: + - storeName: vault + defaultAccess: allow # 这是默认值,可以省略 + deniedSecrets: ["secret1", "secret2"] +``` + +此示例配置明确拒绝访问名为 `vault` 的 secret 存储中的 `secret1` 和 `secret2`,同时允许访问所有其他 secret。[了解如何将配置应用于 sidecar]({{< ref configuration-concept.md >}})。 + +## 权限优先级 + +`allowedSecrets` 和 `deniedSecrets` 列表的设置优先于 `defaultAccess` 策略。 + +场景 | defaultAccess | allowedSecrets | deniedSecrets | 权限 +---- | ------- | -----------| ----------| ------------ +1 - 仅默认访问 | deny/allow | 空 | 空 | deny/allow +2 - 默认拒绝并允许列表 | deny | ["s1"] | 空 | 仅 "s1" 可访问 +3 - 默认允许并拒绝列表 | allow | 空 | ["s1"] | 仅 "s1" 不可访问 +4 - 默认允许并允许列表 | allow | ["s1"] | 空 | 仅 "s1" 可访问 +5 - 默认拒绝并拒绝列表 | deny | 空 | ["s1"] | deny +6 - 默认拒绝/允许并同时有列表 | deny/allow | ["s1"] | ["s2"] | 仅 "s1" 可访问 + +## 相关链接 + +- [secret 存储]({{< ref supported-secret-stores.md >}})列表 +- [secret 存储]({{< ref setup-secret-store.md >}})概述 diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/_index.md new file mode 100644 index 000000000..2d8a36519 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/_index.md @@ -0,0 +1,15 @@ +--- +type: docs +title: "服务调用" +linkTitle: "服务调用" +weight: 10 +description: 实现直接且安全的服务间方法调用 + +--- + +{{% alert title="更多关于 Dapr 服务调用" color="primary" %}} +了解更多关于 Dapr 服务调用的使用方法: +- 试试 [服务调用快速入门]({{< ref serviceinvocation-quickstart.md >}})。 +- 使用任意可用的 [Dapr SDKs]({{< ref sdks >}}) 来探索服务调用。 +- 查看 [服务调用 API 参考文档]({{< ref service_invocation_api.md >}})。 +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md new file mode 100644 index 000000000..aec0bb39e --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/howto-invoke-discover-services.md @@ -0,0 +1,442 @@ +--- +type: docs +title: "操作指南:使用HTTP调用服务" +linkTitle: "操作指南:使用HTTP调用" +description: "通过服务调用实现服务之间的通信" +weight: 20 +--- + +本文演示了如何部署服务,每个服务都有一个唯一的应用程序ID,以便其他服务可以通过HTTP进行服务调用来发现并调用它们的端点。 + +示例服务的服务调用图示 + +{{% alert title="注意" color="primary" %}} +如果您还没有尝试过,[请先查看服务调用快速入门]({{< ref serviceinvocation-quickstart.md >}}),以快速了解如何使用服务调用API。 + +{{% /alert %}} + +## 为服务选择一个ID + +Dapr允许您为应用程序分配一个全局唯一的ID。无论应用程序有多少实例,该ID都代表应用程序的状态。 + +{{< tabs Python JavaScript ".NET" Java Go Kubernetes >}} + +{{% codetab %}} + +```bash +dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- python3 checkout/app.py + +dapr run --app-id order-processor --app-port 8001 --app-protocol http --dapr-http-port 3501 -- python3 order-processor/app.py +``` + +如果您的应用程序使用TLS,您可以通过设置`--app-protocol https`来告诉Dapr通过TLS连接调用您的应用程序: + +```bash +dapr run --app-id checkout --app-protocol https --dapr-http-port 3500 -- python3 checkout/app.py + +dapr run --app-id order-processor --app-port 8001 --app-protocol https --dapr-http-port 3501 -- python3 order-processor/app.py +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- npm start + +dapr run --app-id order-processor --app-port 5001 --app-protocol http --dapr-http-port 3501 -- npm start +``` + +如果您的应用程序使用TLS,您可以通过设置`--app-protocol https`来告诉Dapr通过TLS连接调用您的应用程序: + +```bash +dapr run --app-id checkout --dapr-http-port 3500 --app-protocol https -- npm start + +dapr run --app-id order-processor --app-port 5001 --dapr-http-port 3501 --app-protocol https -- npm start +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- dotnet run + +dapr run --app-id order-processor --app-port 7001 --app-protocol http --dapr-http-port 3501 -- dotnet run +``` + +如果您的应用程序使用TLS,您可以通过设置`--app-protocol https`来告诉Dapr通过TLS连接调用您的应用程序: + +```bash +dapr run --app-id checkout --dapr-http-port 3500 --app-protocol https -- dotnet run + +dapr run --app-id order-processor --app-port 7001 --dapr-http-port 3501 --app-protocol https -- dotnet run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- java -jar target/CheckoutService-0.0.1-SNAPSHOT.jar + +dapr run --app-id order-processor --app-port 9001 --app-protocol http --dapr-http-port 3501 -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar +``` + +如果您的应用程序使用TLS,您可以通过设置`--app-protocol https`来告诉Dapr通过TLS连接调用您的应用程序: + +```bash +dapr run --app-id checkout --dapr-http-port 3500 --app-protocol https -- java -jar target/CheckoutService-0.0.1-SNAPSHOT.jar + +dapr run --app-id order-processor --app-port 9001 --dapr-http-port 3501 --app-protocol https -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +dapr run --app-id checkout --dapr-http-port 3500 -- go run . + +dapr run --app-id order-processor --app-port 6006 --app-protocol http --dapr-http-port 3501 -- go run . +``` + +如果您的应用程序使用TLS,您可以通过设置`--app-protocol https`来告诉Dapr通过TLS连接调用您的应用程序: + +```bash +dapr run --app-id checkout --dapr-http-port 3500 --app-protocol https -- go run . + +dapr run --app-id order-processor --app-port 6006 --dapr-http-port 3501 --app-protocol https -- go run . +``` + +{{% /codetab %}} + +{{% codetab %}} + +### 在Kubernetes中部署时设置app-id + +在Kubernetes中,在您的pod上设置`dapr.io/app-id`注解: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: -app + namespace: default + labels: + app: -app +spec: + replicas: 1 + selector: + matchLabels: + app: -app + template: + metadata: + labels: + app: -app + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "order-processor" + dapr.io/app-port: "6001" +... +``` + +如果您的应用程序使用TLS连接,您可以通过`app-protocol: "https"`注解告诉Dapr通过TLS调用您的应用程序(完整列表[在此]({{< ref arguments-annotations-overview.md >}}))。请注意,Dapr不会验证应用程序提供的TLS证书。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 调用服务 + +要使用Dapr调用应用程序,您可以在任何Dapr实例上使用`invoke` API。sidecar编程模型鼓励每个应用程序与其自己的Dapr实例交互。Dapr的sidecar会自动发现并相互通信。 + +以下是利用Dapr SDK进行服务调用的代码示例。 + +{{< tabs Python JavaScript ".NET" Java Go >}} + +{{% codetab %}} + +```python +# 依赖 +import random +from time import sleep +import logging +import requests + +# 代码 +logging.basicConfig(level = logging.INFO) +while True: + sleep(random.randrange(50, 5000) / 1000) + orderId = random.randint(1, 1000) + # 调用服务 + result = requests.post( + url='%s/orders' % (base_url), + data=json.dumps(order), + headers=headers + ) + logging.info('Order requested: ' + str(orderId)) + logging.info('Result: ' + str(result)) +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +// 依赖 +import axios from "axios"; + +// 代码 +const daprHost = "127.0.0.1"; + +var main = function() { + for(var i=0;i<10;i++) { + sleep(5000); + var orderId = Math.floor(Math.random() * (1000 - 1) + 1); + start(orderId).catch((e) => { + console.error(e); + process.exit(1); + }); + } +} + +// 调用服务 +const result = await axios.post('order-processor' , "orders/" + orderId , axiosConfig); +console.log("Order requested: " + orderId); +console.log("Result: " + result.config.data); + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +main(); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```csharp +// 依赖 +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using System.Threading; + +// 代码 +namespace EventService +{ + class Program + { + static async Task Main(string[] args) + { + while(true) { + await Task.Delay(5000); + var random = new Random(); + var orderId = random.Next(1,1000); + + // 使用Dapr SDK调用方法 + var order = new Order(orderId.ToString()); + + var httpClient = DaprClient.CreateInvokeHttpClient(); + var response = await httpClient.PostAsJsonAsync("http://order-processor/orders", order); + var result = await response.Content.ReadAsStringAsync(); + + Console.WriteLine("Order requested: " + orderId); + Console.WriteLine("Result: " + result); + } + } + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +// 依赖 +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +// 代码 +@SpringBootApplication +public class CheckoutServiceApplication { + private static final HttpClient httpClient = HttpClient.newBuilder() + .version(HttpClient.Version.HTTP_2) + .connectTimeout(Duration.ofSeconds(10)) + .build(); + + public static void main(String[] args) throws InterruptedException, IOException { + while (true) { + TimeUnit.MILLISECONDS.sleep(5000); + Random random = new Random(); + int orderId = random.nextInt(1000 - 1) + 1; + + // 创建一个Map来表示请求体 + Map requestBody = new HashMap<>(); + requestBody.put("orderId", orderId); + // 根据需要向requestBody Map添加其他字段 + + HttpRequest request = HttpRequest.newBuilder() + .POST(HttpRequest.BodyPublishers.ofString(new JSONObject(requestBody).toString())) + .uri(URI.create(dapr_url)) + .header("Content-Type", "application/json") + .header("dapr-app-id", "order-processor") + .build(); + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + System.out.println("Order passed: " + orderId); + TimeUnit.MILLISECONDS.sleep(1000); + + log.info("Order requested: " + orderId); + log.info("Result: " + response.body()); + } + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +package main + +import ( + "fmt" + "io" + "log" + "math/rand" + "net/http" + "os" + "time" +) + +func main() { + daprHttpPort := os.Getenv("DAPR_HTTP_PORT") + if daprHttpPort == "" { + daprHttpPort = "3500" + } + + client := &http.Client{ + Timeout: 15 * time.Second, + } + + for i := 0; i < 10; i++ { + time.Sleep(5000) + orderId := rand.Intn(1000-1) + 1 + + url := fmt.Sprintf("http://localhost:%s/checkout/%v", daprHttpPort, orderId) + req, err := http.NewRequest(http.MethodGet, url, nil) + if err != nil { + panic(err) + } + + // 将目标应用程序ID添加为头的一部分 + req.Header.Add("dapr-app-id", "order-processor") + + // 调用服务 + resp, err := client.Do(req) + if err != nil { + log.Fatal(err.Error()) + } + + b, err := io.ReadAll(resp.Body) + if err != nil { + panic(err) + } + + fmt.Println(string(b)) + } +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +### 其他URL格式 + +要调用'GET'端点: + +```bash +curl http://localhost:3602/v1.0/invoke/checkout/method/checkout/100 +``` + +为了尽量减少URL路径的更改,Dapr提供了以下方式来调用服务API: + +1. 将URL中的地址更改为`localhost:`。 +2. 添加一个`dapr-app-id`头来指定目标服务的ID,或者通过HTTP基本认证传递ID:`http://dapr-app-id:@localhost:3602/path`。 + +例如,以下命令: + +```bash +curl http://localhost:3602/v1.0/invoke/checkout/method/checkout/100 +``` + +等同于: + +```bash +curl -H 'dapr-app-id: checkout' 'http://localhost:3602/checkout/100' -X POST +``` + +或: + +```bash +curl 'http://dapr-app-id:checkout@localhost:3602/checkout/100' -X POST +``` + +使用CLI: + +```bash +dapr invoke --app-id checkout --method checkout/100 +``` + +#### 在URL中包含查询字符串 + +您还可以在URL末尾附加查询字符串或片段,Dapr将其原样传递。这意味着如果您需要在服务调用中传递一些不属于有效负载或路径的附加参数,可以通过在URL末尾附加一个`?`,然后是用`=`号分隔的键/值对,并用`&`分隔。例如: + +```bash +curl 'http://dapr-app-id:checkout@localhost:3602/checkout/100?basket=1234&key=abc' -X POST +``` + +### 命名空间 + +在[支持命名空间的平台]({{< ref "service_invocation_api.md#namespace-supported-platforms" >}})上运行时,您可以在应用程序ID中包含目标应用程序的命名空间。例如,按照`.`格式,使用`checkout.production`。 + +在此示例中,使用命名空间调用服务将如下所示: + +```bash +curl http://localhost:3602/v1.0/invoke/checkout.production/method/checkout/100 -X POST +``` + +有关命名空间的更多信息,请参阅[跨命名空间API规范]({{< ref "service_invocation_api.md#cross-namespace-invocation" >}})。 + +## 查看跟踪和日志 + +我们上面的示例向您展示了如何直接调用本地或Kubernetes中运行的不同服务。Dapr: + +- 输出指标、跟踪和日志信息, +- 允许您可视化服务之间的调用图并记录错误, +- 可选地,记录有效负载体。 + +有关跟踪和日志的更多信息,请参阅[可观察性]({{< ref observability-concept.md >}})文章。 + +## 相关链接 + +- [服务调用概述]({{< ref service-invocation-overview.md >}}) +- [服务调用API规范]({{< ref service_invocation_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/howto-invoke-non-dapr-endpoints.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/howto-invoke-non-dapr-endpoints.md new file mode 100644 index 000000000..bf43f356e --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/howto-invoke-non-dapr-endpoints.md @@ -0,0 +1,136 @@ +--- +type: docs +title: "如何:使用HTTP调用非Dapr端点" +linkTitle: "如何:调用非Dapr端点" +description: "从Dapr应用程序中通过服务调用访问非Dapr端点" +weight: 40 +--- + +本文介绍如何通过Dapr使用HTTP调用非Dapr端点。 + +通过Dapr的服务调用API,您可以与使用或不使用Dapr的端点进行通信。使用Dapr调用非Dapr端点不仅提供了一致的API,还带来了以下[Dapr服务调用]({{< ref service-invocation-overview.md >}})的优势: + +- 应用弹性策略 +- 通过跟踪和指标实现调用的可观测性 +- 通过访问控制实现安全性 +- 利用中间件管道组件 +- 服务发现 +- 使用请求头进行身份验证 + +## 通过HTTP调用外部服务或非Dapr端点 +有时您可能需要调用非Dapr的HTTP端点,例如: +- 您可能只在应用程序的一部分中使用Dapr,尤其是在涉及旧系统时 +- 您可能无法访问代码以将现有应用程序迁移到Dapr +- 您需要调用外部的HTTP服务 + +通过定义`HTTPEndpoint`资源,您可以声明性地配置与非Dapr端点的交互方式。然后,您可以使用服务调用URL来访问非Dapr端点。或者,您可以直接在服务调用URL中使用非Dapr的完全限定域名(FQDN)端点URL。 + +### HttpEndpoint、FQDN URL和appId的优先级 +在进行服务调用时,Dapr运行时遵循以下优先级顺序: + +1. 是否为命名的`HTTPEndpoint`资源? +2. 是否为带有`http://`或`https://`前缀的FQDN URL? +3. 是否为`appID`? + +## 服务调用与非Dapr HTTP端点 +下图概述了Dapr在调用非Dapr端点时的工作流程。 + +显示服务调用到非Dapr端点步骤的图示 + +1. 服务A发起一个HTTP调用,目标是服务B(一个非Dapr端点)。调用被发送到本地的Dapr sidecar。 +2. Dapr通过`HTTPEndpoint`或FQDN URL定位服务B的位置,然后将消息转发给服务B。 +3. 服务B向服务A的Dapr sidecar发送响应。 +4. 服务A接收响应。 + +## 使用HTTPEndpoint资源或FQDN URL调用非Dapr端点 +在与Dapr应用程序或非Dapr应用程序通信时,有两种方法可以调用非Dapr端点。Dapr应用程序可以通过以下方式之一调用非Dapr端点: + +- 使用命名的`HTTPEndpoint`资源,定义一个`HTTPEndpoint`资源类型。请参阅[HTTPEndpoint参考]({{< ref httpendpoints-schema.md >}})中的示例。 + + ```sh + localhost:3500/v1.0/invoke//method/ + ``` + + 例如,使用名为"palpatine"的`HTTPEndpoint`资源和名为"Order66"的方法: + ```sh + curl http://localhost:3500/v1.0/invoke/palpatine/method/order66 + ``` + +- 使用指向非Dapr端点的FQDN URL。 + + ```sh + localhost:3500/v1.0/invoke//method/ + ``` + + 例如,使用名为`https://darthsidious.starwars`的FQDN资源: + ```sh + curl http://localhost:3500/v1.0/invoke/https://darthsidious.starwars/method/order66 + ``` + +### 使用appId调用启用Dapr的应用程序 +AppID用于通过`appID`和`my-method`调用Dapr应用程序。阅读[如何:使用HTTP调用服务]({{< ref howto-invoke-discover-services.md >}})指南以获取更多信息。例如: + +```sh +localhost:3500/v1.0/invoke//method/ +``` +```sh +curl http://localhost:3602/v1.0/invoke/orderprocessor/method/checkout +``` + +## TLS认证 + +使用[HTTPEndpoint资源]({{< ref httpendpoints-schema.md >}})允许您根据远程端点的认证要求使用根证书、客户端证书和私钥的任意组合。 + +### 使用根证书的示例 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: HTTPEndpoint +metadata: + name: "external-http-endpoint-tls" +spec: + baseUrl: https://service-invocation-external:443 + headers: + - name: "Accept-Language" + value: "en-US" + clientTLS: + rootCA: + secretKeyRef: + name: dapr-tls-client + key: ca.crt +``` + +### 使用客户端证书和私钥的示例 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: HTTPEndpoint +metadata: + name: "external-http-endpoint-tls" +spec: + baseUrl: https://service-invocation-external:443 + headers: + - name: "Accept-Language" + value: "en-US" + clientTLS: + certificate: + secretKeyRef: + name: dapr-tls-client + key: tls.crt + privateKey: + secretKeyRef: + name: dapr-tls-key + key: tls.key +``` + +## 相关链接 + +- [HTTPEndpoint参考]({{< ref httpendpoints-schema.md >}}) +- [服务调用概述]({{< ref service-invocation-overview.md >}}) +- [服务调用API规范]({{< ref service_invocation_api.md >}}) + +## 社区电话演示 +观看此[视频](https://youtu.be/BEXJgLsO4hA?t=364)以了解如何使用服务调用来调用非Dapr端点。 +
+ +
\ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/howto-invoke-services-grpc.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/howto-invoke-services-grpc.md new file mode 100644 index 000000000..6cdcb4da6 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/howto-invoke-services-grpc.md @@ -0,0 +1,331 @@ +--- +type: docs +title: "如何使用 gRPC 调用服务" +linkTitle: "使用 gRPC 调用" +description: "通过服务调用在服务之间进行通信" +weight: 30 +--- + +本文介绍如何通过 Dapr 使用 gRPC 进行服务间通信。 + +通过 Dapr 的 gRPC 代理功能,您可以使用现有的基于 proto 的 gRPC 服务,并让流量通过 Dapr sidecar。这为开发人员带来了以下 [Dapr 服务调用]({{< ref service-invocation-overview.md >}}) 的优势: + +1. 双向认证 +2. 跟踪 +3. 指标 +4. 访问控制列表 +5. 网络级别的弹性 +6. 基于 API 令牌的认证 + +Dapr 支持代理所有类型的 gRPC 调用,包括一元和[流式调用](#proxying-of-streaming-rpcs)。 + +## 第一步:运行 gRPC 服务器 + +以下示例来自 ["hello world" grpc-go 示例](https://github.com/grpc/grpc-go/tree/master/examples/helloworld)。虽然此示例使用 Go 语言,但相同的概念适用于所有支持 gRPC 的编程语言。 + +```go +package main + +import ( + "context" + "log" + "net" + + "google.golang.org/grpc" + pb "google.golang.org/grpc/examples/helloworld/helloworld" +) + +const ( + port = ":50051" +) + +// server 用于实现 helloworld.GreeterServer。 +type server struct { + pb.UnimplementedGreeterServer +} + +// SayHello 实现 helloworld.GreeterServer +func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { + log.Printf("Received: %v", in.GetName()) + return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil +} + +func main() { + lis, err := net.Listen("tcp", port) + if err != nil { + log.Fatalf("failed to listen: %v", err) + } + s := grpc.NewServer() + pb.RegisterGreeterServer(s, &server{}) + log.Printf("server listening at %v", lis.Addr()) + if err := s.Serve(lis); err != nil { + log.Fatalf("failed to serve: %v", err) + } +} +``` + +这个 Go 应用实现了 Greeter proto 服务并提供了一个 `SayHello` 方法。 + +### 使用 Dapr CLI 运行 gRPC 服务器 + +```bash +dapr run --app-id server --app-port 50051 -- go run main.go +``` + +使用 Dapr CLI,我们为应用分配了一个唯一的 ID,`server`,通过 `--app-id` 标志指定。 + +## 第二步:调用服务 + +以下示例展示了如何使用 Dapr 从 gRPC 客户端发现 Greeter 服务。 +注意,客户端不是直接通过端口 `50051` 调用目标服务,而是通过端口 `50007` 调用其本地 Dapr sidecar,这样就提供了所有的服务调用功能,包括服务发现、跟踪、mTLS 和重试。 + +```go +package main + +import ( + "context" + "log" + "time" + + "google.golang.org/grpc" + pb "google.golang.org/grpc/examples/helloworld/helloworld" + "google.golang.org/grpc/metadata" +) + +const ( + address = "localhost:50007" +) + +func main() { + // 设置与服务器的连接。 + conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock()) + if err != nil { + log.Fatalf("did not connect: %v", err) + } + defer conn.Close() + c := pb.NewGreeterClient(conn) + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) + defer cancel() + + ctx = metadata.AppendToOutgoingContext(ctx, "dapr-app-id", "server") + r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "Darth Tyrannus"}) + if err != nil { + log.Fatalf("could not greet: %v", err) + } + + log.Printf("Greeting: %s", r.GetMessage()) +} +``` + +以下行告诉 Dapr 发现并调用名为 `server` 的应用: + +```go +ctx = metadata.AppendToOutgoingContext(ctx, "dapr-app-id", "server") +``` + +所有 gRPC 支持的语言都允许添加元数据。以下是一些示例: + +{{< tabs Java ".NET" Python JavaScript Ruby "C++">}} + +{{% codetab %}} +```java +Metadata headers = new Metadata(); +Metadata.Key jwtKey = Metadata.Key.of("dapr-app-id", "server"); + +GreeterService.ServiceBlockingStub stub = GreeterService.newBlockingStub(channel); +stub = MetadataUtils.attachHeaders(stub, header); +stub.SayHello(new HelloRequest() { Name = "Darth Malak" }); +``` +{{% /codetab %}} + +{{% codetab %}} +```csharp +var metadata = new Metadata +{ + { "dapr-app-id", "server" } +}; + +var call = client.SayHello(new HelloRequest { Name = "Darth Nihilus" }, metadata); +``` +{{% /codetab %}} + +{{% codetab %}} +```python +metadata = (('dapr-app-id', 'server'),) +response = stub.SayHello(request={ name: 'Darth Revan' }, metadata=metadata) +``` +{{% /codetab %}} + +{{% codetab %}} +```javascript +const metadata = new grpc.Metadata(); +metadata.add('dapr-app-id', 'server'); + +client.sayHello({ name: "Darth Malgus" }, metadata) +``` +{{% /codetab %}} + +{{% codetab %}} +```ruby +metadata = { 'dapr-app-id' : 'server' } +response = service.sayHello({ 'name': 'Darth Bane' }, metadata) +``` +{{% /codetab %}} + +{{% codetab %}} +```c++ +grpc::ClientContext context; +context.AddMetadata("dapr-app-id", "server"); +``` +{{% /codetab %}} + +{{< /tabs >}} + +### 使用 Dapr CLI 运行客户端 + +```bash +dapr run --app-id client --dapr-grpc-port 50007 -- go run main.go +``` + +### 查看遥测 + +如果您在本地运行 Dapr 并安装了 Zipkin,请在浏览器中打开 `http://localhost:9411` 并查看客户端和服务器之间的跟踪。 + +### 部署到 Kubernetes + +在您的部署上设置以下 Dapr 注解: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: grpc-app + namespace: default + labels: + app: grpc-app +spec: + replicas: 1 + selector: + matchLabels: + app: grpc-app + template: + metadata: + labels: + app: grpc-app + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "server" + dapr.io/app-protocol: "grpc" + dapr.io/app-port: "50051" +... +``` + +`dapr.io/app-protocol: "grpc"` 注解告诉 Dapr 使用 gRPC 调用应用。 + +如果您的应用使用 TLS 连接,您可以通过 `app-protocol: "grpcs"` 注解告诉 Dapr 通过 TLS 调用您的应用(完整列表[在此]({{< ref arguments-annotations-overview.md >}}))。注意,Dapr 不会验证应用提供的 TLS 证书。 + +### 命名空间 + +在[支持命名空间的平台]({{< ref "service_invocation_api.md#namespace-supported-platforms" >}})上运行时,您可以在应用 ID 中包含目标应用的命名空间:`myApp.production` + +例如,在不同命名空间中调用 gRPC 服务器: + +```go +ctx = metadata.AppendToOutgoingContext(ctx, "dapr-app-id", "server.production") +``` + +有关命名空间的更多信息,请参阅[跨命名空间 API 规范]({{< ref "service_invocation_api.md#cross-namespace-invocation" >}})。 + +## 第三步:查看跟踪和日志 + +上面的示例展示了如何直接调用本地或 Kubernetes 中运行的不同服务。Dapr 输出指标、跟踪和日志信息,允许您可视化服务之间的调用图、记录错误并可选地记录负载体。 + +有关跟踪和日志的更多信息,请参阅[可观测性]({{< ref observability-concept.md >}})文章。 + +## 流式 RPC 的代理 + +使用 Dapr 代理 gRPC 的流式 RPC 调用时,您必须设置一个额外的元数据选项 `dapr-stream`,值为 `true`。 + +例如: + +{{< tabs Go Java ".NET" Python JavaScript Ruby "C++">}} + +{{% codetab %}} +```go +ctx = metadata.AppendToOutgoingContext(ctx, "dapr-app-id", "server") +ctx = metadata.AppendToOutgoingContext(ctx, "dapr-stream", "true") +``` +{{% /codetab %}} + +{{% codetab %}} +```java +Metadata headers = new Metadata(); +Metadata.Key jwtKey = Metadata.Key.of("dapr-app-id", "server"); +Metadata.Key jwtKey = Metadata.Key.of("dapr-stream", "true"); +``` +{{% /codetab %}} + +{{% codetab %}} +```csharp +var metadata = new Metadata +{ + { "dapr-app-id", "server" }, + { "dapr-stream", "true" } +}; +``` +{{% /codetab %}} + +{{% codetab %}} +```python +metadata = (('dapr-app-id', 'server'), ('dapr-stream', 'true'),) +``` +{{% /codetab %}} + +{{% codetab %}} +```javascript +const metadata = new grpc.Metadata(); +metadata.add('dapr-app-id', 'server'); +metadata.add('dapr-stream', 'true'); +``` +{{% /codetab %}} + +{{% codetab %}} +```ruby +metadata = { 'dapr-app-id' : 'server' } +metadata = { 'dapr-stream' : 'true' } +``` +{{% /codetab %}} + +{{% codetab %}} +```c++ +grpc::ClientContext context; +context.AddMetadata("dapr-app-id", "server"); +context.AddMetadata("dapr-stream", "true"); +``` +{{% /codetab %}} + +{{< /tabs >}} + +### 流式 gRPC 和弹性 + +在代理流式 gRPC 时,由于其长时间存在的特性,[弹性]({{< ref "resiliency-overview.md" >}})策略仅应用于“初始握手”。因此: + +- 如果流在初始握手后中断,Dapr 不会自动重新建立。您的应用将被通知流已结束,并需要重新创建它。 +- 重试策略仅影响初始连接“握手”。如果您的弹性策略包括重试,Dapr 将检测到建立与目标应用的初始连接失败,并将重试直到成功(或直到策略中定义的重试次数耗尽)。 +- 同样,弹性策略中定义的超时仅适用于初始“握手”。连接建立后,超时不再影响流。 + +## 相关链接 + +* [服务调用概述]({{< ref service-invocation-overview.md >}}) +* [服务调用 API 规范]({{< ref service_invocation_api.md >}}) +* [gRPC 代理社区通话视频](https://youtu.be/B_vkXqptpXY?t=70) + +## 社区通话演示 + +观看此[视频](https://youtu.be/B_vkXqptpXY?t=69)了解如何使用 Dapr 的 gRPC 代理功能: + +
+ + +
diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/service-invocation-namespaces.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/service-invocation-namespaces.md new file mode 100644 index 000000000..e3d7f8fe9 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/service-invocation-namespaces.md @@ -0,0 +1,49 @@ +--- +type: docs +title: "指南:跨命名空间进行服务调用" +linkTitle: "指南:服务调用命名空间" +weight: 50 +description: "在不同命名空间之间进行服务调用" +--- + +在本文中,您将学习如何在不同命名空间之间进行服务调用。默认情况下,service-invocation支持通过简单引用应用程序ID(如`nodeapp`)来调用*同一*命名空间内的服务: + +```sh +localhost:3500/v1.0/invoke/nodeapp/method/neworder +``` + +service-invocation也支持跨命名空间的调用。在所有支持的平台上,Dapr应用程序ID遵循包含目标命名空间的有效FQDN格式。您可以同时指定: + +- 应用程序ID(如`nodeapp`),以及 +- 应用程序所在的命名空间(如`production`)。 + +**示例 1** + +调用位于`production`命名空间中`nodeapp`的`neworder`方法: + +```sh +localhost:3500/v1.0/invoke/nodeapp.production/method/neworder +``` + +在使用service-invocation调用不同命名空间中的应用程序时,您需要使用命名空间来限定它。这在Kubernetes集群中的跨命名空间调用中非常有用。 + +**示例 2** + +调用位于`production`命名空间中`myapp`的`ping`方法: + +```bash +https://localhost:3500/v1.0/invoke/myapp.production/method/ping +``` + +**示例 3** + +使用curl命令从外部DNS地址(例如`api.demo.dapr.team`)调用与示例2相同的`ping`方法,并提供Dapr API令牌进行身份验证: + +MacOS/Linux: + +``` +curl -i -d '{ "message": "hello" }' \ + -H "Content-type: application/json" \ + -H "dapr-api-token: ${API_TOKEN}" \ + https://api.demo.dapr.team/v1.0/invoke/myapp.production/method/ping +``` diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/service-invocation-overview.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/service-invocation-overview.md new file mode 100644 index 000000000..a902d60fb --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/service-invocation/service-invocation-overview.md @@ -0,0 +1,159 @@ +--- +type: docs +title: "服务调用概述" +linkTitle: "概述" +weight: 10 +description: "服务调用API模块的概述" +--- + +通过服务调用,您的应用程序可以使用标准的[gRPC](https://grpc.io)或[HTTP](https://www.w3.org/Protocols/)协议可靠且安全地与其他应用程序进行通信。 + +在许多基于微服务的应用程序中,多个服务需要能够相互通信。这种服务间通信要求应用程序开发人员处理以下问题: + +- **服务发现。** 如何找到我的不同服务? +- **标准化服务间的API调用。** 如何在服务之间调用方法? +- **安全的服务间通信。** 如何通过加密安全地调用其他服务并对方法应用访问控制? +- **缓解请求超时或失败。** 如何处理重试和瞬态错误? +- **实现可观测性和追踪。** 如何使用追踪查看带有指标的调用图以诊断生产中的问题? + +## 服务调用API + +Dapr通过提供一个类似反向代理的服务调用API来解决这些挑战,该API内置了服务发现,并利用了分布式追踪、指标、错误处理、加密等功能。 + +Dapr采用sidecar架构。要使用Dapr调用应用程序: +- 您在Dapr实例上使用`invoke` API。 +- 每个应用程序与其自己的Dapr实例通信。 +- Dapr实例相互发现并通信。 + +[以下概述视频和演示](https://www.youtube.com/live/0y7ne6teHT4?si=mtLMrajE5wVXJYz8&t=3598)展示了Dapr服务调用的工作原理。 + + + +下图概述了Dapr的服务调用在两个集成Dapr的应用程序之间的工作原理。 + +显示服务调用步骤的图示 + +1. 服务A发起一个HTTP或gRPC调用,目标是服务B。调用发送到本地Dapr sidecar。 +2. Dapr使用正在运行的[名称解析组件]({{< ref supported-name-resolution >}})在给定的[托管平台]({{< ref "hosting" >}})上发现服务B的位置。 +3. Dapr将消息转发到服务B的Dapr sidecar + - **注意**:所有Dapr sidecar之间的调用都通过gRPC进行以提高性能。只有服务与Dapr sidecar之间的调用可以是HTTP或gRPC。 +4. 服务B的Dapr sidecar将请求转发到服务B上的指定端点(或方法)。服务B然后运行其业务逻辑代码。 +5. 服务B向服务A发送响应。响应发送到服务B的sidecar。 +6. Dapr将响应转发到服务A的Dapr sidecar。 +7. 服务A接收响应。 + +您还可以使用服务调用API调用非Dapr HTTP端点。例如,您可能只在整个应用程序的一部分中使用Dapr,可能无法访问代码以迁移现有应用程序以使用Dapr,或者只是需要调用外部HTTP服务。阅读["如何:使用HTTP调用非Dapr端点"]({{< ref howto-invoke-non-dapr-endpoints.md >}})以获取更多信息。 + +## 功能 +服务调用提供了多种功能,使您可以轻松地在应用程序之间调用方法或调用外部HTTP端点。 + +### HTTP和gRPC服务调用 +- **HTTP**:如果您已经在应用程序中使用HTTP协议,使用Dapr HTTP头可能是最简单的入门方式。您无需更改现有的端点URL;只需添加`dapr-app-id`头即可开始。有关更多信息,请参阅[使用HTTP调用服务]({{< ref howto-invoke-discover-services.md >}})。 +- **gRPC**:Dapr允许用户保留自己的proto服务并以gRPC的方式工作。这意味着您可以使用服务调用来调用现有的gRPC应用程序,而无需包含任何Dapr SDK或自定义gRPC服务。有关更多信息,请参阅[Dapr和gRPC的操作教程]({{< ref howto-invoke-services-grpc.md >}})。 + +### 服务到服务的安全性 + +通过Dapr Sentry服务,所有Dapr应用程序之间的调用都可以通过托管平台上的相互(mTLS)认证来实现安全,包括自动证书轮换。 + +有关更多信息,请阅读[服务到服务的安全性]({{< ref "security-concept.md#sidecar-to-sidecar-communication" >}})文章。 + +### 包括重试的弹性 + +在调用失败和瞬态错误的情况下,服务调用提供了一种弹性功能,可以在回退时间段内自动重试。要了解更多信息,请参阅[弹性文章]({{< ref resiliency-overview.md >}})。 + +### 具有可观测性的追踪和指标 + +默认情况下,所有应用程序之间的调用都会被追踪,并收集指标以提供应用程序的洞察和诊断。这在生产场景中特别重要,提供了服务之间调用的调用图和指标。有关更多信息,请阅读[可观测性]({{< ref observability-concept.md >}})。 + +### 访问控制 + +通过访问策略,应用程序可以控制: + +- 哪些应用程序被允许调用它们。 +- 应用程序被授权做什么。 + +例如,您可以限制包含人员信息的敏感应用程序不被未授权的应用程序访问。结合服务到服务的安全通信,您可以提供软多租户部署。 + +有关更多信息,请阅读[服务调用的访问控制允许列表]({{< ref invoke-allowlist.md >}})文章。 + +### 命名空间范围 + +您可以将应用程序限定到命名空间以进行部署和安全,并在部署到不同命名空间的服务之间进行调用。有关更多信息,请阅读[跨命名空间的服务调用]({{< ref "service-invocation-namespaces.md" >}})文章。 + +### 使用mDNS的轮询负载均衡 + +Dapr通过mDNS协议提供服务调用请求的轮询负载均衡,例如在单台机器或多台联网的物理机器上。 + +下图显示了其工作原理的示例。如果您有一个应用程序实例,应用程序ID为`FrontEnd`,以及三个应用程序实例,应用程序ID为`Cart`,并且您从`FrontEnd`应用程序调用`Cart`应用程序,Dapr在三个实例之间进行轮询。这些实例可以在同一台机器上或不同的机器上。 + +显示服务调用步骤的图示 + +**注意**:应用程序ID在_应用程序_中是唯一的,而不是应用程序实例。无论该应用程序存在多少个实例(由于扩展),它们都将共享相同的应用程序ID。 + +### 可交换的服务发现 + +Dapr可以在多种[托管平台]({{< ref hosting >}})上运行。为了启用可交换的服务发现,Dapr使用[名称解析组件]({{< ref supported-name-resolution >}})。例如,Kubernetes名称解析组件使用Kubernetes DNS服务来解析在集群中运行的其他应用程序的位置。 + +自托管机器可以使用mDNS名称解析组件。作为替代方案,您可以使用SQLite名称解析组件在单节点环境中运行Dapr,并用于本地开发场景。属于集群的Dapr sidecar将其信息存储在本地机器上的SQLite数据库中。 + +Consul名称解析组件特别适合多机部署,并且可以在任何托管环境中使用,包括Kubernetes、多台虚拟机或自托管。 + +### HTTP服务调用的流式处理 + +您可以在HTTP服务调用中将数据作为流处理。这可以在使用Dapr通过HTTP调用另一个服务时提供性能和内存利用率的改进,尤其是在请求或响应体较大的情况下。 + +下图演示了数据流的六个步骤。 + +显示表中描述的服务调用步骤的图示 + +1. 请求:"应用程序A"到"Dapr sidecar A" +2. 请求:"Dapr sidecar A"到"Dapr sidecar B" +3. 请求:"Dapr sidecar B"到"应用程序B" +4. 响应:"应用程序B"到"Dapr sidecar B" +5. 响应:"Dapr sidecar B"到"Dapr sidecar A" +6. 响应:"Dapr sidecar A"到"应用程序A" + +## 示例架构 + +按照上述调用顺序,假设您有如[Hello World教程](https://github.com/dapr/quickstarts/blob/master/tutorials/hello-world/README.md)中描述的应用程序,其中一个Python应用程序调用一个Node.js应用程序。在这种情况下,Python应用程序将是"服务A",Node.js应用程序将是"服务B"。 + +下图再次显示了本地机器上的1-7序列,显示了API调用: + + + +1. Node.js应用程序的Dapr应用程序ID为`nodeapp`。Python应用程序通过POST `http://localhost:3500/v1.0/invoke/nodeapp/method/neworder`调用Node.js应用程序的`neworder`方法,该请求首先发送到Python应用程序的本地Dapr sidecar。 +2. Dapr使用名称解析组件(在这种情况下是自托管时的mDNS)发现Node.js应用程序的位置,该组件在您的本地机器上运行。 +3. Dapr使用刚刚接收到的位置将请求转发到Node.js应用程序的sidecar。 +4. Node.js应用程序的sidecar将请求转发到Node.js应用程序。Node.js应用程序执行其业务逻辑,记录传入消息,然后将订单ID持久化到Redis(图中未显示)。 +5. Node.js应用程序通过Node.js sidecar向Python应用程序发送响应。 +6. Dapr将响应转发到Python Dapr sidecar。 +7. Python应用程序接收响应。 + +## 试用服务调用 +### 快速入门和教程 +Dapr文档包含多个利用服务调用构建模块的快速入门,适用于不同的示例架构。为了直观地理解服务调用API及其功能,我们建议从我们的快速入门开始: + +| 快速入门/教程 | 描述 | +| ------------------- | ----------- | +| [服务调用快速入门]({{< ref serviceinvocation-quickstart.md >}}) | 这个快速入门让您直接与服务调用构建模块进行交互。 | +| [Hello World教程](https://github.com/dapr/quickstarts/blob/master/tutorials/hello-world/README.md) | 本教程展示了如何在本地机器上运行服务调用和状态管理构建模块。 | +| [Hello World Kubernetes教程](https://github.com/dapr/quickstarts/blob/master/tutorials/hello-kubernetes/README.md) | 本教程演示了如何在Kubernetes中使用Dapr,并涵盖了服务调用和状态管理构建模块。 | + +### 直接在您的应用程序中开始使用服务调用 +想跳过快速入门?没问题。您可以直接在应用程序中试用服务调用构建模块,以安全地与其他服务通信。在[Dapr安装完成](https://docs.dapr.io/getting-started)后,您可以通过以下方式开始使用服务调用API。 + +使用以下方式调用服务: +- **HTTP和gRPC服务调用**(推荐的设置方法) + - *HTTP* - 只需添加`dapr-app-id`头即可开始。有关更多信息,请阅读[使用HTTP调用服务]({{< ref howto-invoke-discover-services.md >}})。 + - *gRPC* - 对于基于gRPC的应用程序,服务调用API也可用。运行gRPC服务器,然后使用Dapr CLI调用服务。有关更多信息,请阅读[配置Dapr以使用gRPC]({{< ref grpc >}})和[使用gRPC调用服务]({{< ref howto-invoke-services-grpc.md >}})。 +- **直接调用API** - 除了代理,还有一个选项可以直接调用服务调用API以调用GET端点。只需将您的地址URL更新为`localhost:`,您就可以直接调用API。您还可以在上面链接的HTTP代理文档中阅读更多关于此的信息。 +- **SDKs** - 如果您正在使用Dapr SDK,您可以直接通过SDK使用服务调用。选择您需要的SDK,并使用Dapr客户端调用服务。有关更多信息,请阅读[Dapr SDKs]({{< ref sdks.md >}})。 + +为了快速测试,尝试使用Dapr CLI进行服务调用: +- **Dapr CLI命令** - 一旦设置了Dapr CLI,使用`dapr invoke --method `命令以及方法标志和感兴趣的方法。有关更多信息,请阅读[Dapr CLI]({{< ref dapr-invoke.md >}})。 + +## 下一步 +- 阅读[服务调用API规范]({{< ref service_invocation_api.md >}})。此服务调用参考指南描述了如何调用其他服务上的方法。 +- 了解[服务调用性能数据]({{< ref perf-service-invocation.md >}})。 +- 查看[可观测性]({{< ref observability >}})。在这里,您可以深入了解Dapr的监控工具,如追踪、指标和日志记录。 +- 阅读我们的[安全实践]({{< ref security-concept.md >}}),了解mTLS加密、令牌认证和端点授权。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/_index.md new file mode 100644 index 000000000..b635b2bc2 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/_index.md @@ -0,0 +1,15 @@ +--- +type: docs +title: "状态管理" +linkTitle: "状态管理" +weight: 40 +description: 创建持久运行的有状态服务 +--- + +{{% alert title="更多关于 Dapr 状态管理的内容" color="primary" %}} +了解如何使用 Dapr 进行状态管理: +- 试试 [状态管理快速入门]({{< ref statemanagement-quickstart.md >}})。 +- 使用任意 [Dapr SDKs]({{< ref sdks >}}) 探索状态管理。 +- 查看 [状态管理 API 参考文档]({{< ref state_api.md >}})。 +- 浏览支持的 [状态管理组件规格]({{< ref supported-state-stores >}})。 +{{% /alert %}} diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-encrypt-state.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-encrypt-state.md new file mode 100644 index 000000000..7cb28e83d --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-encrypt-state.md @@ -0,0 +1,98 @@ +--- +type: docs +title: "操作指南:加密应用程序状态" +linkTitle: "操作指南:加密状态" +weight: 450 +description: "自动加密应用程序状态并管理密钥轮换" + +--- + +对静态应用程序状态进行加密,以在企业工作负载或受监管环境中提供更强的安全性。Dapr 提供基于 [AES](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) 的自动客户端加密,采用 [Galois/Counter Mode (GCM)](https://en.wikipedia.org/wiki/Galois/Counter_Mode),支持 128、192 和 256 位的密钥。 + +除了自动加密,Dapr 还支持主加密密钥和次加密密钥,使开发人员和运维团队更容易启用密钥轮换策略。此功能由所有 Dapr 状态存储支持。 + +加密密钥始终从 secret 中获取,不能在 `metadata` 部分中以明文形式提供。 + +## 启用自动加密 + +将以下 `metadata` 部分添加到任何 Dapr 支持的状态存储中: + +```yaml +metadata: +- name: primaryEncryptionKey + secretKeyRef: + name: mysecret + key: mykey # key 是可选的。 +``` + +例如,这是一个 Redis 加密状态存储的完整 YAML: + +```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: primaryEncryptionKey + secretKeyRef: + name: mysecret + key: mykey +``` + +现在,您已配置了一个 Dapr 状态存储,以从名为 `mysecret` 的 secret 中获取加密密钥,其中包含名为 `mykey` 的实际加密密钥。 + +实际的加密密钥*必须*是有效的、十六进制编码的加密密钥。虽然支持 192 位和 256 位密钥,但建议使用 128 位加密密钥。如果加密密钥无效,Dapr 会报错并退出。 + +例如,您可以使用以下命令生成一个随机的、十六进制编码的 128 位(16 字节)密钥: + +```sh +openssl rand 16 | hexdump -v -e '/1 "%02x"' +# 结果将类似于 "cb321007ad11a9d23f963bff600d58e0" +``` + +*注意,secret 存储不必支持密钥。* + +## 密钥轮换 + +为了支持密钥轮换,Dapr 提供了一种指定次加密密钥的方法: + +```yaml +metadata: +- name: primaryEncryptionKey + secretKeyRef: + name: mysecret + key: mykey +- name: secondaryEncryptionKey + secretKeyRef: + name: mysecret2 + key: mykey2 +``` + +当 Dapr 启动时,它会获取 `metadata` 部分中列出的包含加密密钥的 secrets。Dapr 自动识别哪个状态项是用哪个密钥加密的,因为它会将 `secretKeyRef.name` 字段附加到实际状态密钥的末尾。 + +要轮换密钥, + +1. 更改 `primaryEncryptionKey` 以指向包含新密钥的 secret。 +2. 将旧的主加密密钥移至 `secondaryEncryptionKey`。 + +新数据将使用新密钥加密,任何检索到的旧数据将使用次密钥解密。 + +使用旧密钥加密的数据项的任何更新都将使用新密钥重新加密。 + +{{% alert title="注意" color="primary" %}} +当您轮换密钥时,除非您的应用程序再次写入,否则不会自动重新加密使用旧密钥加密的数据。如果您删除了轮换的密钥(即现在的次加密密钥),您将无法访问使用该密钥加密的数据。 + +{{% /alert %}} + +## 相关链接 + +- [安全概述]({{< ref "security-concept.md" >}}) +- [状态存储查询 API 实现指南](https://github.com/dapr/components-contrib/blob/master/state/README.md#implementing-state-query-api) +- [状态存储组件]({{< ref "supported-state-stores.md" >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-get-save-state.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-get-save-state.md new file mode 100644 index 000000000..daa95ea31 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-get-save-state.md @@ -0,0 +1,1112 @@ +--- +type: docs +title: "操作指南:保存和获取状态" +linkTitle: "操作指南:保存和获取状态" +weight: 200 +description: "使用键值对持久化状态" +--- + +状态管理是新应用程序、遗留应用程序、单体应用程序或微服务应用程序的常见需求之一。处理和测试不同的数据库库,以及处理重试和故障,可能既困难又耗时。 + +在本指南中,您将学习如何使用键/值状态API来保存、获取和删除应用程序的状态。 + +下面的代码示例描述了一个处理订单的应用程序,该应用程序使用Dapr sidecar。订单处理服务通过Dapr将状态存储在Redis状态存储中。 + +示例服务的状态管理图示 + +## 设置状态存储 + +状态存储组件是Dapr用于与数据库通信的资源。 + +在本指南中,我们将使用Redis状态存储,但您也可以选择[支持列表]({{< ref supported-state-stores >}})中的其他状态存储。 + +{{< tabs "Self-Hosted (CLI)" Kubernetes>}} + +{{% codetab %}} + +当您在selfhost模式下运行`dapr init`时,Dapr会在您的本地机器上创建一个默认的Redis `statestore.yaml`并运行一个Redis状态存储,位置如下: + +- 在Windows上,位于`%UserProfile%\.dapr\components\statestore.yaml` +- 在Linux/MacOS上,位于`~/.dapr/components/statestore.yaml` + +通过使用`statestore.yaml`组件,您可以在不更改应用程序代码的情况下轻松更换底层组件。 + +{{% /codetab %}} + +{{% codetab %}} + +要将其部署到Kubernetes集群中,请在下面的YAML中填写您的[状态存储组件]({{< ref supported-state-stores >}})的`metadata`连接详细信息,保存为`statestore.yaml`,然后运行`kubectl apply -f statestore.yaml`。 + +```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: "" +``` + +请参阅[如何在Kubernetes上设置不同的状态存储]({{< ref "setup-state-store" >}})以获取更多信息。 + +{{% /codetab %}} + +{{< /tabs >}} + +{{% alert title="重要" color="warning" %}} +请务必设置一个`app-id`,因为状态键会以此值为前缀。如果您不设置`app-id`,系统会在运行时为您生成一个。下次运行命令时,会生成一个新的`app-id`,您将无法再访问之前保存的状态。 +{{% /alert %}} + +## 保存和检索单个状态 + +以下示例展示了如何使用Dapr状态管理API保存和检索单个键/值对。 + +{{< tabs ".NET" Java Python Go JavaScript "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + +```csharp + +// 依赖项 +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using Dapr.Client; +using Microsoft.AspNetCore.Mvc; +using System.Threading; +using System.Text.Json; + +// 代码 +namespace EventService +{ + class Program + { + static async Task Main(string[] args) + { + string DAPR_STORE_NAME = "statestore"; + while(true) { + System.Threading.Thread.Sleep(5000); + using var client = new DaprClientBuilder().Build(); + Random random = new Random(); + int orderId = random.Next(1,1000); + // 使用Dapr SDK保存和获取状态 + await client.SaveStateAsync(DAPR_STORE_NAME, "order_1", orderId.ToString()); + await client.SaveStateAsync(DAPR_STORE_NAME, "order_2", orderId.ToString()); + var result = await client.GetStateAsync(DAPR_STORE_NAME, "order_1"); + Console.WriteLine("获取后的结果: " + result); + } + } + } +} +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +// 依赖项 +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.domain.State; +import io.dapr.client.domain.TransactionalStateOperation; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +// 代码 +@SpringBootApplication +public class OrderProcessingServiceApplication { + + private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); + + private static final String STATE_STORE_NAME = "statestore"; + + public static void main(String[] args) throws InterruptedException{ + while(true) { + TimeUnit.MILLISECONDS.sleep(5000); + Random random = new Random(); + int orderId = random.nextInt(1000-1) + 1; + DaprClient client = new DaprClientBuilder().build(); + // 使用Dapr SDK保存和获取状态 + client.saveState(STATE_STORE_NAME, "order_1", Integer.toString(orderId)).block(); + client.saveState(STATE_STORE_NAME, "order_2", Integer.toString(orderId)).block(); + Mono> result = client.getState(STATE_STORE_NAME, "order_1", String.class); + log.info("获取后的结果" + result); + } + } + +} +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```python +# 依赖项 +import random +from time import sleep +import requests +import logging +from dapr.clients import DaprClient +from dapr.clients.grpc._state import StateItem +from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType + +# 代码 +logging.basicConfig(level = logging.INFO) +DAPR_STORE_NAME = "statestore" +while True: + sleep(random.randrange(50, 5000) / 1000) + orderId = random.randint(1, 1000) + with DaprClient() as client: + # 使用Dapr SDK保存和获取状态 + client.save_state(DAPR_STORE_NAME, "order_1", str(orderId)) + result = client.get_state(DAPR_STORE_NAME, "order_1") + logging.info('获取后的结果: ' + result.data.decode('utf-8')) +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +// 依赖项 +import ( + "context" + "log" + "math/rand" + "strconv" + "time" + + dapr "github.com/dapr/go-sdk/client" +) + +// 代码 +func main() { + const STATE_STORE_NAME = "statestore" + rand.Seed(time.Now().UnixMicro()) + for i := 0; i < 10; i++ { + orderId := rand.Intn(1000-1) + 1 + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + defer client.Close() + ctx := context.Background() + err = client.SaveState(ctx, STATE_STORE_NAME, "order_1", []byte(strconv.Itoa(orderId)), nil) + if err != nil { + panic(err) + } + result, err := client.GetState(ctx, STATE_STORE_NAME, "order_1", nil) + if err != nil { + panic(err) + } + log.Println("获取后的结果:", string(result.Value)) + time.Sleep(2 * time.Second) + } +} +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 go run OrderProcessingService.go +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +// 依赖项 +import { DaprClient, HttpMethod, CommunicationProtocolEnum } from '@dapr/dapr'; + +// 代码 +const daprHost = "127.0.0.1"; +var main = function() { + for(var i=0;i<10;i++) { + sleep(5000); + var orderId = Math.floor(Math.random() * (1000 - 1) + 1); + start(orderId).catch((e) => { + console.error(e); + process.exit(1); + }); + } +} + +async function start(orderId) { + const client = new DaprClient({ + daprHost, + daprPort: process.env.DAPR_HTTP_PORT, + communicationProtocol: CommunicationProtocolEnum.HTTP, + }); + const STATE_STORE_NAME = "statestore"; + // 使用Dapr SDK保存和获取状态 + await client.state.save(STATE_STORE_NAME, [ + { + key: "order_1", + value: orderId.toString() + }, + { + key: "order_2", + value: orderId.toString() + } + ]); + var result = await client.state.get(STATE_STORE_NAME, "order_1"); + console.log("获取后的结果: " + result); +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +main(); +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start +``` + +{{% /codetab %}} + +{{% codetab %}} + +启动一个Dapr sidecar: + +```bash +dapr run --app-id orderprocessing --dapr-http-port 3601 +``` + +在一个单独的终端中,将一个键/值对保存到您的状态存储中: + +```bash +curl -X POST -H "Content-Type: application/json" -d '[{ "key": "order_1", "value": "250"}]' http://localhost:3601/v1.0/state/statestore +``` + +现在获取您刚刚保存的状态: + +```bash +curl http://localhost:3601/v1.0/state/statestore/order_1 +``` + +重新启动您的sidecar并尝试再次检索状态,以观察状态与应用程序分开持久化。 + +{{% /codetab %}} + +{{% codetab %}} + +启动一个Dapr sidecar: + +```bash +dapr --app-id orderprocessing --dapr-http-port 3601 run +``` + +在一个单独的终端中,将一个键/值对保存到您的状态存储中: + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{"key": "order_1", "value": "250"}]' -Uri 'http://localhost:3601/v1.0/state/statestore' +``` + +现在获取您刚刚保存的状态: + +```powershell +Invoke-RestMethod -Uri 'http://localhost:3601/v1.0/state/statestore/order_1' +``` + +重新启动您的sidecar并尝试再次检索状态,以观察状态与应用程序分开持久化。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 删除状态 + +以下是利用Dapr SDK删除状态的代码示例。 + +{{< tabs ".NET" Java Python Go JavaScript "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + +```csharp +// 依赖项 +using Dapr.Client; + +// 代码 +namespace EventService +{ + class Program + { + static async Task Main(string[] args) + { + string DAPR_STORE_NAME = "statestore"; + // 使用Dapr SDK删除状态 + using var client = new DaprClientBuilder().Build(); + await client.DeleteStateAsync(DAPR_STORE_NAME, "order_1", cancellationToken: cancellationToken); + } + } +} +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +// 依赖项 +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +// 代码 +@SpringBootApplication +public class OrderProcessingServiceApplication { + public static void main(String[] args) throws InterruptedException{ + String STATE_STORE_NAME = "statestore"; + + // 使用Dapr SDK删除状态 + DaprClient client = new DaprClientBuilder().build(); + String storedEtag = client.getState(STATE_STORE_NAME, "order_1", String.class).block().getEtag(); + client.deleteState(STATE_STORE_NAME, "order_1", storedEtag, null).block(); + } +} +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```python +# 依赖项 +from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType + +# 代码 +logging.basicConfig(level = logging.INFO) +DAPR_STORE_NAME = "statestore" + +# 使用Dapr SDK删除状态 +with DaprClient() as client: + client.delete_state(store_name=DAPR_STORE_NAME, key="order_1") +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +// 依赖项 +import ( + "context" + dapr "github.com/dapr/go-sdk/client" + +) + +// 代码 +func main() { + STATE_STORE_NAME := "statestore" + // 使用Dapr SDK删除状态 + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + defer client.Close() + ctx := context.Background() + + if err := client.DeleteState(ctx, STATE_STORE_NAME, "order_1"); err != nil { + panic(err) + } +} +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 go run OrderProcessingService.go +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +// 依赖项 +import { DaprClient, HttpMethod, CommunicationProtocolEnum } from '@dapr/dapr'; + +// 代码 +const daprHost = "127.0.0.1"; +var main = function() { + const STATE_STORE_NAME = "statestore"; + // 使用Dapr SDK保存和获取状态 + const client = new DaprClient({ + daprHost, + daprPort: process.env.DAPR_HTTP_PORT, + communicationProtocol: CommunicationProtocolEnum.HTTP, + }); + + await client.state.delete(STATE_STORE_NAME, "order_1"); +} + +main(); +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start +``` + +{{% /codetab %}} + +{{% codetab %}} + +使用上面相同的Dapr实例运行: + +```bash +curl -X DELETE 'http://localhost:3601/v1.0/state/statestore/order_1' +``` + +尝试再次获取状态。注意没有返回值。 + +{{% /codetab %}} + +{{% codetab %}} + +使用上面相同的Dapr实例运行: + +```powershell +Invoke-RestMethod -Method Delete -Uri 'http://localhost:3601/v1.0/state/statestore/order_1' +``` + +尝试再次获取状态。注意没有返回值。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 保存和检索多个状态 + +以下是利用Dapr SDK保存和检索多个状态的代码示例。 + +{{< tabs ".NET" Java Python Go JavaScript "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + +```csharp +// 依赖项 +using Dapr.Client; +// 代码 +namespace EventService +{ + class Program + { + static async Task Main(string[] args) + { + string DAPR_STORE_NAME = "statestore"; + // 使用Dapr SDK检索多个状态 + using var client = new DaprClientBuilder().Build(); + IReadOnlyList multipleStateResult = await client.GetBulkStateAsync(DAPR_STORE_NAME, new List { "order_1", "order_2" }, parallelism: 1); + } + } +} +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run +``` + +上述示例返回一个`BulkStateItem`,其中包含您保存到状态的值的序列化格式。如果您希望SDK在每个批量响应项中反序列化值,您可以使用以下代码: + +```csharp +// 依赖项 +using Dapr.Client; +// 代码 +namespace EventService +{ + class Program + { + static async Task Main(string[] args) + { + string DAPR_STORE_NAME = "statestore"; + // 使用Dapr SDK检索多个状态 + using var client = new DaprClientBuilder().Build(); + IReadOnlyList> mulitpleStateResult = await client.GetBulkStateAsync(DAPR_STORE_NAME, new List { "widget_1", "widget_2" }, parallelism: 1); + } + } + + class Widget + { + string Size { get; set; } + string Color { get; set; } + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +// 依赖项 +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.domain.State; +import java.util.Arrays; + +// 代码 +@SpringBootApplication +public class OrderProcessingServiceApplication { + + private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); + + public static void main(String[] args) throws InterruptedException{ + String STATE_STORE_NAME = "statestore"; + // 使用Dapr SDK检索多个状态 + DaprClient client = new DaprClientBuilder().build(); + Mono>> resultBulk = client.getBulkState(STATE_STORE_NAME, + Arrays.asList("order_1", "order_2"), String.class); + } +} +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```python +# 依赖项 +from dapr.clients import DaprClient +from dapr.clients.grpc._state import StateItem + +# 代码 +logging.basicConfig(level = logging.INFO) +DAPR_STORE_NAME = "statestore" +orderId = 100 +# 使用Dapr SDK保存和检索多个状态 +with DaprClient() as client: + client.save_bulk_state(store_name=DAPR_STORE_NAME, states=[StateItem(key="order_2", value=str(orderId))]) + result = client.get_bulk_state(store_name=DAPR_STORE_NAME, keys=["order_1", "order_2"], states_metadata={"metakey": "metavalue"}).items + logging.info('批量获取后的结果: ' + str(result)) +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +// 依赖项 +import ( + "context" + "log" + "math/rand" + "strconv" + "time" + + dapr "github.com/dapr/go-sdk/client" +) + +// 代码 +func main() { + const STATE_STORE_NAME = "statestore" + rand.Seed(time.Now().UnixMicro()) + for i := 0; i < 10; i++ { + orderId := rand.Intn(1000-1) + 1 + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + defer client.Close() + ctx := context.Background() + err = client.SaveState(ctx, STATE_STORE_NAME, "order_1", []byte(strconv.Itoa(orderId)), nil) + if err != nil { + panic(err) + } + keys := []string{"key1", "key2", "key3"} + items, err := client.GetBulkState(ctx, STATE_STORE_NAME, keys, nil, 100) + if err != nil { + panic(err) + } + for _, item := range items { + log.Println("从GetBulkState获取的项:", string(item.Value)) + } + } +} +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 go run OrderProcessingService.go +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +// 依赖项 +import { DaprClient, HttpMethod, CommunicationProtocolEnum } from '@dapr/dapr'; + +// 代码 +const daprHost = "127.0.0.1"; +var main = function() { + const STATE_STORE_NAME = "statestore"; + var orderId = 100; + // 使用Dapr SDK保存和检索多个状态 + const client = new DaprClient({ + daprHost, + daprPort: process.env.DAPR_HTTP_PORT, + communicationProtocol: CommunicationProtocolEnum.HTTP, + }); + + await client.state.save(STATE_STORE_NAME, [ + { + key: "order_1", + value: orderId.toString() + }, + { + key: "order_2", + value: orderId.toString() + } + ]); + result = await client.state.getBulk(STATE_STORE_NAME, ["order_1", "order_2"]); +} + +main(); +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start +``` + +{{% /codetab %}} + +{{% codetab %}} + +使用上面相同的Dapr实例,将两个键/值对保存到您的状态存储中: + +```bash +curl -X POST -H "Content-Type: application/json" -d '[{ "key": "order_1", "value": "250"}, { "key": "order_2", "value": "550"}]' http://localhost:3601/v1.0/state/statestore +``` + +现在获取您刚刚保存的状态: + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"keys":["order_1", "order_2"]}' http://localhost:3601/v1.0/state/statestore/bulk +``` + +{{% /codetab %}} + +{{% codetab %}} + +使用上面相同的Dapr实例,将两个键/值对保存到您的状态存储中: + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{ "key": "order_1", "value": "250"}, { "key": "order_2", "value": "550"}]' -Uri 'http://localhost:3601/v1.0/state/statestore' +``` + +现在获取您刚刚保存的状态: + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"keys":["order_1", "order_2"]}' -Uri 'http://localhost:3601/v1.0/state/statestore/bulk' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 执行状态事务 + +{{% alert title="注意" color="primary" %}} +状态事务需要支持多项事务的状态存储。请参阅[支持的状态存储页面]({{< ref supported-state-stores >}})以获取完整列表。 +{{% /alert %}} + +以下是利用Dapr SDK执行状态事务的代码示例。 + +{{< tabs ".NET" Java Python Go JavaScript "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + +```csharp +// 依赖项 +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using Dapr.Client; +using Microsoft.AspNetCore.Mvc; +using System.Threading; +using System.Text.Json; + +// 代码 +namespace EventService +{ + class Program + { + static async Task Main(string[] args) + { + string DAPR_STORE_NAME = "statestore"; + while(true) { + System.Threading.Thread.Sleep(5000); + Random random = new Random(); + int orderId = random.Next(1,1000); + using var client = new DaprClientBuilder().Build(); + var requests = new List() + { + new StateTransactionRequest("order_3", JsonSerializer.SerializeToUtf8Bytes(orderId.ToString()), StateOperationType.Upsert), + new StateTransactionRequest("order_2", null, StateOperationType.Delete) + }; + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken cancellationToken = source.Token; + // 使用Dapr SDK执行状态事务 + await client.ExecuteStateTransactionAsync(DAPR_STORE_NAME, requests, cancellationToken: cancellationToken); + Console.WriteLine("订单请求: " + orderId); + Console.WriteLine("结果: " + result); + } + } + } +} +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +// 依赖项 +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import io.dapr.client.domain.State; +import io.dapr.client.domain.TransactionalStateOperation; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.TimeUnit; + +// 代码 +@SpringBootApplication +public class OrderProcessingServiceApplication { + + private static final Logger log = LoggerFactory.getLogger(OrderProcessingServiceApplication.class); + + private static final String STATE_STORE_NAME = "statestore"; + + public static void main(String[] args) throws InterruptedException{ + while(true) { + TimeUnit.MILLISECONDS.sleep(5000); + Random random = new Random(); + int orderId = random.nextInt(1000-1) + 1; + DaprClient client = new DaprClientBuilder().build(); + List> operationList = new ArrayList<>(); + operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.UPSERT, + new State<>("order_3", Integer.toString(orderId), ""))); + operationList.add(new TransactionalStateOperation<>(TransactionalStateOperation.OperationType.DELETE, + new State<>("order_2"))); + // 使用Dapr SDK执行状态事务 + client.executeStateTransaction(STATE_STORE_NAME, operationList).block(); + log.info("订单请求: " + orderId); + } + } + +} +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 mvn spring-boot:run +``` + +{{% /codetab %}} +{{% codetab %}} +```python +# 依赖项 +import random +from time import sleep +import requests +import logging +from dapr.clients import DaprClient +from dapr.clients.grpc._state import StateItem +from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType + +# 代码 +logging.basicConfig(level = logging.INFO) +DAPR_STORE_NAME = "statestore" +while True: + sleep(random.randrange(50, 5000) / 1000) + orderId = random.randint(1, 1000) + with DaprClient() as client: + # 使用Dapr SDK执行状态事务 + client.execute_state_transaction(store_name=DAPR_STORE_NAME, operations=[ + TransactionalStateOperation( + operation_type=TransactionOperationType.upsert, + key="order_3", + data=str(orderId)), + TransactionalStateOperation(key="order_3", data=str(orderId)), + TransactionalStateOperation( + operation_type=TransactionOperationType.delete, + key="order_2", + data=str(orderId)), + TransactionalStateOperation(key="order_2", data=str(orderId)) + ]) + + client.delete_state(store_name=DAPR_STORE_NAME, key="order_1") + logging.basicConfig(level = logging.INFO) + logging.info('订单请求: ' + str(orderId)) + logging.info('结果: ' + str(result)) +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +// 依赖项 +package main + +import ( + "context" + "log" + "math/rand" + "strconv" + "time" + + dapr "github.com/dapr/go-sdk/client" +) + +// 代码 +func main() { + const STATE_STORE_NAME = "statestore" + rand.Seed(time.Now().UnixMicro()) + for i := 0; i < 10; i++ { + orderId := rand.Intn(1000-1) + 1 + client, err := dapr.NewClient() + if err != nil { + panic(err) + } + defer client.Close() + ctx := context.Background() + err = client.SaveState(ctx, STATE_STORE_NAME, "order_1", []byte(strconv.Itoa(orderId)), nil) + if err != nil { + panic(err) + } + result, err := client.GetState(ctx, STATE_STORE_NAME, "order_1", nil) + if err != nil { + panic(err) + } + + ops := make([]*dapr.StateOperation, 0) + data1 := "data1" + data2 := "data2" + + op1 := &dapr.StateOperation{ + Type: dapr.StateOperationTypeUpsert, + Item: &dapr.SetStateItem{ + Key: "key1", + Value: []byte(data1), + }, + } + op2 := &dapr.StateOperation{ + Type: dapr.StateOperationTypeDelete, + Item: &dapr.SetStateItem{ + Key: "key2", + Value: []byte(data2), + }, + } + ops = append(ops, op1, op2) + meta := map[string]string{} + err = client.ExecuteStateTransaction(ctx, STATE_STORE_NAME, meta, ops) + + log.Println("获取后的结果:", string(result.Value)) + time.Sleep(2 * time.Second) + } +} +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 go run OrderProcessingService.go +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +// 依赖项 +import { DaprClient, HttpMethod, CommunicationProtocolEnum } from '@dapr/dapr'; + +// 代码 +const daprHost = "127.0.0.1"; +var main = function() { + for(var i=0;i<10;i++) { + sleep(5000); + var orderId = Math.floor(Math.random() * (1000 - 1) + 1); + start(orderId).catch((e) => { + console.error(e); + process.exit(1); + }); + } +} + +async function start(orderId) { + const client = new DaprClient({ + daprHost, + daprPort: process.env.DAPR_HTTP_PORT, + communicationProtocol: CommunicationProtocolEnum.HTTP, + }); + + const STATE_STORE_NAME = "statestore"; + // 使用Dapr SDK保存和检索多个状态 + await client.state.transaction(STATE_STORE_NAME, [ + { + operation: "upsert", + request: { + key: "order_3", + value: orderId.toString() + } + }, + { + operation: "delete", + request: { + key: "order_2" + } + } + ]); +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +main(); +``` + +要为上述示例应用程序启动一个Dapr sidecar,运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 npm start +``` + +{{% /codetab %}} + +{{% codetab %}} + +使用上面相同的Dapr实例,执行两个状态事务: + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"operations": [{"operation":"upsert", "request": {"key": "order_1", "value": "250"}}, {"operation":"delete", "request": {"key": "order_2"}}]}' http://localhost:3601/v1.0/state/statestore/transaction +``` + +现在查看您的状态事务的结果: + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"keys":["order_1", "order_2"]}' http://localhost:3601/v1.0/state/statestore/bulk +``` + +{{% /codetab %}} + +{{% codetab %}} + +使用上面相同的Dapr实例,将两个键/值对保存到您的状态存储中: + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"operations": [{"operation":"upsert", "request": {"key": "order_1", "value": "250"}}, {"operation":"delete", "request": {"key": "order_2"}}]}' -Uri 'http://localhost:3601/v1.0/state/statestore/transaction' +``` + +现在查看您的状态事务的结果: + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '{"keys":["order_1", "order_2"]}' -Uri 'http://localhost:3601/v1.0/state/statestore/bulk' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 + +- 阅读完整的[状态API参考]({{< ref state_api.md >}}) +- 尝试使用[Dapr SDK]({{< ref sdks >}}) +- 构建一个[有状态服务]({{< ref howto-stateful-service.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-outbox.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-outbox.md new file mode 100644 index 000000000..0e300cb60 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-outbox.md @@ -0,0 +1,682 @@ +--- +type: docs +title: "操作指南:启用事务性 Outbox 模式" +linkTitle: "操作指南:启用事务性 Outbox 模式" +weight: 400 +description: "在状态存储和发布/订阅消息代理之间提交单个事务" +--- + +事务性 Outbox 模式是一种广为人知的设计模式,用于发送应用程序状态变化的通知。它通过一个跨越数据库和消息代理的单一事务来传递通知。 + +开发人员在尝试自行实现此模式时会遇到许多技术难题,通常需要编写复杂且容易出错的中央协调管理器,这些管理器最多支持一种或两种数据库和消息代理的组合。 + +例如,您可以使用 Outbox 模式来: +1. 向账户数据库写入新的用户记录。 +2. 发送账户成功创建的通知消息。 + +通过 Dapr 的 Outbox 支持,您可以在调用 Dapr 的[事务 API]({{< ref "state_api.md#state-transactions" >}})时通知订阅者应用程序的状态何时被创建或更新。 + +下图概述了 Outbox 功能的工作原理: + +1) 服务 A 使用事务将状态保存/更新到状态存储。 +2) 在同一事务下将消息写入消息代理。当消息成功传递到消息代理时,事务完成,确保状态和消息一起被事务化。 +3) 消息代理将消息主题传递给任何订阅者 - 在此情况下为服务 B。 + +显示 Outbox 模式步骤的图示 + +## 要求 + +Outbox 功能可以与 Dapr 支持的任何[事务性状态存储]({{< ref supported-state-stores >}})一起使用。所有[发布/订阅代理]({{< ref supported-pubsub >}})都支持 Outbox 功能。 + +[了解更多关于您可以使用的事务方法。]({{< ref "howto-get-save-state.md#perform-state-transactions" >}}) + +{{% alert title="注意" color="primary" %}} +建议与竞争消费者模式(例如,[Apache Kafka]({{< ref setup-apache-kafka>}}))一起使用的消息代理减少重复事件的可能性。 +{{% /alert %}} + +## 启用 Outbox 模式 + +要启用 Outbox 功能,请在状态存储组件上添加以下必需和可选字段: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: mysql-outbox +spec: + type: state.mysql + version: v1 + metadata: + - name: connectionString + value: "" + - name: outboxPublishPubsub # 必需 + value: "mypubsub" + - name: outboxPublishTopic # 必需 + value: "newOrder" + - name: outboxPubsub # 可选 + value: "myOutboxPubsub" + - name: outboxDiscardWhenMissingState # 可选,默认为 false + value: false +``` + +### 元数据字段 + +| 名称 | 必需 | 默认值 | 描述 | +| --------------------|-------------|---------------|------------------------------------------------------- | +| outboxPublishPubsub | 是 | N/A | 设置发布状态更改时传递通知的发布/订阅组件的名称 +| outboxPublishTopic | 是 | N/A | 设置接收在配置了 `outboxPublishPubsub` 的发布/订阅上的状态更改的主题。消息体将是 `insert` 或 `update` 操作的状态事务项 +| outboxPubsub | 否 | `outboxPublishPubsub` | 设置 Dapr 用于协调状态和发布/订阅事务的发布/订阅组件。如果未设置,则使用配置了 `outboxPublishPubsub` 的发布/订阅组件。如果您希望将用于发送通知状态更改的发布/订阅组件与用于协调事务的组件分开,这将很有用 +| outboxDiscardWhenMissingState | 否 | `false` | 通过将 `outboxDiscardWhenMissingState` 设置为 `true`,如果 Dapr 无法在数据库中找到状态且不重试,则 Dapr 将丢弃事务。如果在 Dapr 能够传递消息之前,状态存储数据因任何原因被删除,并且您希望 Dapr 从发布/订阅中删除项目并停止重试获取状态,此设置可能会很有用 + +## 其他配置 + +### 在同一状态存储上组合 Outbox 和非 Outbox 消息 + +如果您希望使用相同的状态存储来发送 Outbox 和非 Outbox 消息,只需定义两个连接到相同状态存储的状态存储组件,其中一个具有 Outbox 功能,另一个没有。 + +#### 没有 Outbox 的 MySQL 状态存储 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: mysql +spec: + type: state.mysql + version: v1 + metadata: + - name: connectionString + value: "" +``` + +#### 具有 Outbox 的 MySQL 状态存储 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: mysql-outbox +spec: + type: state.mysql + version: v1 + metadata: + - name: connectionString + value: "" + - name: outboxPublishPubsub # 必需 + value: "mypubsub" + - name: outboxPublishTopic # 必需 + value: "newOrder" +``` + +### 形状 Outbox 模式消息 + +您可以通过设置另一个不保存到数据库并明确提及为投影的事务来覆盖发布到发布/订阅代理的 Outbox 模式消息。此事务添加了一个名为 `outbox.projection` 的元数据键,值设置为 `true`。当添加到事务中保存的状态数组时,此负载在写入状态时被忽略,数据用作发送到上游订阅者的负载。 + +要正确使用,`key` 值必须在状态存储上的操作和消息投影之间匹配。如果键不匹配,则整个事务失败。 + +如果您为同一键启用了两个或多个 `outbox.projection` 状态项,则使用第一个定义的项,其他项将被忽略。 + +[了解更多关于默认和自定义 CloudEvent 消息。]({{< ref pubsub-cloudevents.md >}}) + +{{< tabs Python JavaScript ".NET" Java Go HTTP >}} + +{{% codetab %}} + + + +在以下 Python SDK 的状态事务示例中,值 `"2"` 被保存到数据库,但值 `"3"` 被发布到最终用户主题。 + +```python +DAPR_STORE_NAME = "statestore" + +async def main(): + client = DaprClient() + + # 定义第一个状态操作以保存值 "2" + op1 = StateItem( + key="key1", + value=b"2" + ) + + # 定义第二个状态操作以带有元数据发布值 "3" + op2 = StateItem( + key="key1", + value=b"3", + options=StateOptions( + metadata={ + "outbox.projection": "true" + } + ) + ) + + # 创建状态操作列表 + ops = [op1, op2] + + # 执行状态事务 + await client.state.transaction(DAPR_STORE_NAME, operations=ops) + print("状态事务已执行。") +``` + +通过将元数据项 `"outbox.projection"` 设置为 `"true"` 并确保 `key` 值匹配(`key1`): +- 第一个操作被写入状态存储,消息未写入消息代理。 +- 第二个操作值被发布到配置的发布/订阅主题。 + +{{% /codetab %}} + +{{% codetab %}} + + + +在以下 JavaScript SDK 的状态事务示例中,值 `"2"` 被保存到数据库,但值 `"3"` 被发布到最终用户主题。 + +```javascript +const { DaprClient, StateOperationType } = require('@dapr/dapr'); + +const DAPR_STORE_NAME = "statestore"; + +async function main() { + const client = new DaprClient(); + + // 定义第一个状态操作以保存值 "2" + const op1 = { + operation: StateOperationType.UPSERT, + request: { + key: "key1", + value: "2" + } + }; + + // 定义第二个状态操作以带有元数据发布值 "3" + const op2 = { + operation: StateOperationType.UPSERT, + request: { + key: "key1", + value: "3", + metadata: { + "outbox.projection": "true" + } + } + }; + + // 创建状态操作列表 + const ops = [op1, op2]; + + // 执行状态事务 + await client.state.transaction(DAPR_STORE_NAME, ops); + console.log("状态事务已执行。"); +} + +main().catch(err => { + console.error(err); +}); +``` + +通过将元数据项 `"outbox.projection"` 设置为 `"true"` 并确保 `key` 值匹配(`key1`): +- 第一个操作被写入状态存储,消息未写入消息代理。 +- 第二个操作值被发布到配置的发布/订阅主题。 + +{{% /codetab %}} + +{{% codetab %}} + + + +在以下 .NET SDK 的状态事务示例中,值 `"2"` 被保存到数据库,但值 `"3"` 被发布到最终用户主题。 + +```csharp +public class Program +{ + private const string DAPR_STORE_NAME = "statestore"; + + public static async Task Main(string[] args) + { + var client = new DaprClientBuilder().Build(); + + // 定义第一个状态操作以保存值 "2" + var op1 = new StateTransactionRequest( + key: "key1", + value: Encoding.UTF8.GetBytes("2"), + operationType: StateOperationType.Upsert + ); + + // 定义第二个状态操作以带有元数据发布值 "3" + var metadata = new Dictionary + { + { "outbox.projection", "true" } + }; + var op2 = new StateTransactionRequest( + key: "key1", + value: Encoding.UTF8.GetBytes("3"), + operationType: StateOperationType.Upsert, + metadata: metadata + ); + + // 创建状态操作列表 + var ops = new List { op1, op2 }; + + // 执行状态事务 + await client.ExecuteStateTransactionAsync(DAPR_STORE_NAME, ops); + Console.WriteLine("状态事务已执行。"); + } +} +``` + +通过将元数据项 `"outbox.projection"` 设置为 `"true"` 并确保 `key` 值匹配(`key1`): +- 第一个操作被写入状态存储,消息未写入消息代理。 +- 第二个操作值被发布到配置的发布/订阅主题。 + +{{% /codetab %}} + +{{% codetab %}} + + + +在以下 Java SDK 的状态事务示例中,值 `"2"` 被保存到数据库,但值 `"3"` 被发布到最终用户主题。 + +```java +public class Main { + private static final String DAPR_STORE_NAME = "statestore"; + + public static void main(String[] args) { + try (DaprClient client = new DaprClientBuilder().build()) { + // 定义第一个状态操作以保存值 "2" + StateOperation op1 = new StateOperation<>( + StateOperationType.UPSERT, + "key1", + "2" + ); + + // 定义第二个状态操作以带有元数据发布值 "3" + Map metadata = new HashMap<>(); + metadata.put("outbox.projection", "true"); + + StateOperation op2 = new StateOperation<>( + StateOperationType.UPSERT, + "key1", + "3", + metadata + ); + + // 创建状态操作列表 + List> ops = new ArrayList<>(); + ops.add(op1); + ops.add(op2); + + // 执行状态事务 + client.executeStateTransaction(DAPR_STORE_NAME, ops).block(); + System.out.println("状态事务已执行。"); + } catch (Exception e) { + e.printStackTrace(); + } + } +} +``` + +通过将元数据项 `"outbox.projection"` 设置为 `"true"` 并确保 `key` 值匹配(`key1`): +- 第一个操作被写入状态存储,消息未写入消息代理。 +- 第二个操作值被发布到配置的发布/订阅主题。 + +{{% /codetab %}} + +{{% codetab %}} + + + +在以下 Go SDK 的状态事务示例中,值 `"2"` 被保存到数据库,但值 `"3"` 被发布到最终用户主题。 + +```go +ops := make([]*dapr.StateOperation, 0) + +op1 := &dapr.StateOperation{ + Type: dapr.StateOperationTypeUpsert, + Item: &dapr.SetStateItem{ + Key: "key1", + Value: []byte("2"), + }, +} +op2 := &dapr.StateOperation{ + Type: dapr.StateOperationTypeUpsert, + Item: &dapr.SetStateItem{ + Key: "key1", + Value: []byte("3"), + // 覆盖保存到数据库的数据负载 + Metadata: map[string]string{ + "outbox.projection": "true", + }, + }, +} +ops = append(ops, op1, op2) +meta := map[string]string{} +err := testClient.ExecuteStateTransaction(ctx, store, meta, ops) +``` + +通过将元数据项 `"outbox.projection"` 设置为 `"true"` 并确保 `key` 值匹配(`key1`): +- 第一个操作被写入状态存储,消息未写入消息代理。 +- 第二个操作值被发布到配置的发布/订阅主题。 + +{{% /codetab %}} + +{{% codetab %}} + + + +您可以使用以下 HTTP 请求传递消息覆盖: + +```bash +curl -X POST http://localhost:3500/v1.0/state/starwars/transaction \ + -H "Content-Type: application/json" \ + -d '{ + "operations": [ + { + "operation": "upsert", + "request": { + "key": "order1", + "value": { + "orderId": "7hf8374s", + "type": "book", + "name": "The name of the wind" + } + } + }, + { + "operation": "upsert", + "request": { + "key": "order1", + "value": { + "orderId": "7hf8374s" + }, + "metadata": { + "outbox.projection": "true" + }, + "contentType": "application/json" + } + } + ] +}' +``` + +通过将元数据项 `"outbox.projection"` 设置为 `"true"` 并确保 `key` 值匹配(`key1`): +- 第一个操作被写入状态存储,消息未写入消息代理。 +- 第二个操作值被发布到配置的发布/订阅主题。 + +{{% /codetab %}} + +{{< /tabs >}} + +### 覆盖 Dapr 生成的 CloudEvent 字段 + +您可以使用自定义 CloudEvent 元数据覆盖发布的 Outbox 事件上的[Dapr 生成的 CloudEvent 字段]({{< ref "pubsub-cloudevents.md#dapr-generated-cloudevents-example" >}})。 + +{{< tabs Python JavaScript ".NET" Java Go HTTP >}} + +{{% codetab %}} + + + +```python +async def execute_state_transaction(): + async with DaprClient() as client: + # 定义状态操作 + ops = [] + + op1 = { + 'operation': 'upsert', + 'request': { + 'key': 'key1', + 'value': b'2', # 将字符串转换为字节数组 + 'metadata': { + 'cloudevent.id': 'unique-business-process-id', + 'cloudevent.source': 'CustomersApp', + 'cloudevent.type': 'CustomerCreated', + 'cloudevent.subject': '123', + 'my-custom-ce-field': 'abc' + } + } + } + + ops.append(op1) + + # 执行状态事务 + store_name = 'your-state-store-name' + try: + await client.execute_state_transaction(store_name, ops) + print('状态事务已执行。') + except Exception as e: + print('执行状态事务时出错:', e) + +# 运行异步函数 +if __name__ == "__main__": + asyncio.run(execute_state_transaction()) +``` +{{% /codetab %}} + +{{% codetab %}} + + + +```javascript +const { DaprClient } = require('dapr-client'); + +async function executeStateTransaction() { + // 初始化 Dapr 客户端 + const daprClient = new DaprClient(); + + // 定义状态操作 + const ops = []; + + const op1 = { + operationType: 'upsert', + request: { + key: 'key1', + value: Buffer.from('2'), + metadata: { + 'id': 'unique-business-process-id', + 'source': 'CustomersApp', + 'type': 'CustomerCreated', + 'subject': '123', + 'my-custom-ce-field': 'abc' + } + } + }; + + ops.push(op1); + + // 执行状态事务 + const storeName = 'your-state-store-name'; + const metadata = {}; +} + +executeStateTransaction(); +``` +{{% /codetab %}} + +{{% codetab %}} + + + +```csharp +public class StateOperationExample +{ + public async Task ExecuteStateTransactionAsync() + { + var daprClient = new DaprClientBuilder().Build(); + + // 将值 "2" 定义为字符串并序列化为字节数组 + var value = "2"; + var valueBytes = JsonSerializer.SerializeToUtf8Bytes(value); + + // 定义第一个状态操作以保存值 "2" 并带有元数据 + // 覆盖 Cloudevent 元数据 + var metadata = new Dictionary + { + { "cloudevent.id", "unique-business-process-id" }, + { "cloudevent.source", "CustomersApp" }, + { "cloudevent.type", "CustomerCreated" }, + { "cloudevent.subject", "123" }, + { "my-custom-ce-field", "abc" } + }; + + var op1 = new StateTransactionRequest( + key: "key1", + value: valueBytes, + operationType: StateOperationType.Upsert, + metadata: metadata + ); + + // 创建状态操作列表 + var ops = new List { op1 }; + + // 执行状态事务 + var storeName = "your-state-store-name"; + await daprClient.ExecuteStateTransactionAsync(storeName, ops); + Console.WriteLine("状态事务已执行。"); + } + + public static async Task Main(string[] args) + { + var example = new StateOperationExample(); + await example.ExecuteStateTransactionAsync(); + } +} +``` +{{% /codetab %}} + +{{% codetab %}} + + + +```java +public class StateOperationExample { + + public static void main(String[] args) { + executeStateTransaction(); + } + + public static void executeStateTransaction() { + // 构建 Dapr 客户端 + try (DaprClient daprClient = new DaprClientBuilder().build()) { + + // 定义值 "2" + String value = "2"; + + // 覆盖 CloudEvent 元数据 + Map metadata = new HashMap<>(); + metadata.put("cloudevent.id", "unique-business-process-id"); + metadata.put("cloudevent.source", "CustomersApp"); + metadata.put("cloudevent.type", "CustomerCreated"); + metadata.put("cloudevent.subject", "123"); + metadata.put("my-custom-ce-field", "abc"); + + // 定义状态操作 + List> ops = new ArrayList<>(); + StateOperation op1 = new StateOperation<>( + StateOperationType.UPSERT, + "key1", + value, + metadata + ); + ops.add(op1); + + // 执行状态事务 + String storeName = "your-state-store-name"; + daprClient.executeStateTransaction(storeName, ops).block(); + System.out.println("状态事务已执行。"); + } catch (Exception e) { + e.printStackTrace(); + } + } +} +``` +{{% /codetab %}} + +{{% codetab %}} + + + +```go +func main() { + // 创建 Dapr 客户端 + client, err := dapr.NewClient() + if err != nil { + log.Fatalf("创建 Dapr 客户端失败: %v", err) + } + defer client.Close() + + ctx := context.Background() + store := "your-state-store-name" + + // 定义状态操作 + ops := make([]*dapr.StateOperation, 0) + op1 := &dapr.StateOperation{ + Type: dapr.StateOperationTypeUpsert, + Item: &dapr.SetStateItem{ + Key: "key1", + Value: []byte("2"), + // 覆盖 Cloudevent 元数据 + Metadata: map[string]string{ + "cloudevent.id": "unique-business-process-id", + "cloudevent.source": "CustomersApp", + "cloudevent.type": "CustomerCreated", + "cloudevent.subject": "123", + "my-custom-ce-field": "abc", + }, + }, + } + ops = append(ops, op1) + + // 事务的元数据(如果有) + meta := map[string]string{} + + // 执行状态事务 + err = client.ExecuteStateTransaction(ctx, store, meta, ops) + if err != nil { + log.Fatalf("执行状态事务失败: %v", err) + } + + log.Println("状态事务已执行。") +} +``` +{{% /codetab %}} + +{{% codetab %}} + + + +```bash +curl -X POST http://localhost:3500/v1.0/state/starwars/transaction \ + -H "Content-Type: application/json" \ + -d '{ + "operations": [ + { + "operation": "upsert", + "request": { + "key": "key1", + "value": "2" + } + }, + ], + "metadata": { + "id": "unique-business-process-id", + "source": "CustomersApp", + "type": "CustomerCreated", + "subject": "123", + "my-custom-ce-field": "abc", + } + }' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +{{% alert title="注意" color="primary" %}} +`data` CloudEvent 字段仅供 Dapr 使用,且不可自定义。 + +{{% /alert %}} + +## 演示 + +观看[此视频以了解 Outbox 模式的概述](https://youtu.be/rTovKpG0rhY?t=1338): + +
+ diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-share-state.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-share-state.md new file mode 100644 index 000000000..8aed86510 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-share-state.md @@ -0,0 +1,115 @@ +--- +type: docs +title: "操作指南:在应用程序之间共享状态" +linkTitle: "操作指南:在应用程序之间共享状态" +weight: 400 +description: "了解在不同应用程序之间共享状态的策略" +--- + +Dapr 提供了多种在应用程序之间共享状态的方法。 + +不同的架构在共享状态时可能有不同的需求。在某些情况下,您可能会希望: + +- 在特定应用程序中封装所有状态 +- 让 Dapr 为您管理状态访问 + +在其他情况下,您可能需要两个应用程序在同一状态上进行操作,以便获取和保存相同的键。 + +为了实现状态共享,Dapr 支持以下键前缀策略: + +| 键前缀 | 描述 | +| ------------ | ----------- | +| `appid` | 默认策略,允许您仅通过指定 `appid` 的应用程序管理状态。所有状态键将以 `appid` 为前缀,并限定于该应用程序。 | +| `name` | 使用状态存储组件的名称作为前缀。多个应用程序可以共享同一状态存储中的相同状态。 | +| `namespace` | 如果设置了命名空间,此策略会将 `appid` 键前缀替换为配置的命名空间,生成一个限定于该命名空间的键。这允许在不同命名空间中具有相同 `appid` 的应用程序重用相同的状态存储。如果未配置命名空间,则会回退到 `appid` 策略。有关 Dapr 中命名空间的更多信息,请参见 [操作指南:将组件限定到一个或多个应用程序]({{< ref component-scopes.md >}}) | +| `none` | 不使用任何前缀。多个应用程序可以在不同的状态存储中共享状态,而不受特定前缀的限制。 | + +## 指定状态前缀策略 + +要指定前缀策略,请在状态组件上添加名为 `keyPrefix` 的元数据键: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: statestore + namespace: production +spec: + type: state.redis + version: v1 + metadata: + - name: keyPrefix + value: +``` + +## 示例 + +以下示例演示了使用每种支持的前缀策略进行状态检索的情况。 + +### `appid`(默认) + +在下面的示例中,具有应用程序 ID `myApp` 的 Dapr 应用程序正在将状态保存到名为 `redis` 的状态存储中: + +```shell +curl -X POST http://localhost:3500/v1.0/state/redis \ + -H "Content-Type: application/json" + -d '[ + { + "key": "darth", + "value": "nihilus" + } + ]' +``` + +键将被保存为 `myApp||darth`。 + +### `namespace` + +在命名空间 `production` 中运行的具有应用程序 ID `myApp` 的 Dapr 应用程序正在将状态保存到名为 `redis` 的状态存储中: + +```shell +curl -X POST http://localhost:3500/v1.0/state/redis \ + -H "Content-Type: application/json" + -d '[ + { + "key": "darth", + "value": "nihilus" + } + ]' +``` + +键将被保存为 `production.myApp||darth`。 + +### `name` + +在下面的示例中,具有应用程序 ID `myApp` 的 Dapr 应用程序正在将状态保存到名为 `redis` 的状态存储中: + +```shell +curl -X POST http://localhost:3500/v1.0/state/redis \ + -H "Content-Type: application/json" + -d '[ + { + "key": "darth", + "value": "nihilus" + } + ]' +``` + +键将被保存为 `redis||darth`。 + +### `none` + +在下面的示例中,具有应用程序 ID `myApp` 的 Dapr 应用程序正在将状态保存到名为 `redis` 的状态存储中: + +```shell +curl -X POST http://localhost:3500/v1.0/state/redis \ + -H "Content-Type: application/json" + -d '[ + { + "key": "darth", + "value": "nihilus" + } + ]' +``` + +键将被保存为 `darth`。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-state-query-api.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-state-query-api.md new file mode 100644 index 000000000..00ed9dbff --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-state-query-api.md @@ -0,0 +1,519 @@ +--- +type: docs +title: "操作指南:查询状态" +linkTitle: "操作指南:查询状态" +weight: 250 +description: "使用查询API查询状态存储" +--- + +{{% alert title="alpha" color="warning" %}} +状态查询API目前处于**alpha**阶段。 +{{% /alert %}} + +通过状态查询API,您可以从状态存储组件中检索、过滤和排序键/值数据。查询API并不是完整查询语言的替代品。 + +尽管状态存储是键/值存储,`value`可能是一个包含自身层次结构、键和值的JSON文档。查询API允许您使用这些键/值来检索相应的文档。 + +## 查询状态 + +您可以通过HTTP POST/PUT或gRPC提交查询请求。请求的主体是一个包含以下三个部分的JSON对象: + +- `filter` +- `sort` +- `page` + +### `filter` + +`filter`用于指定查询条件,结构类似于树形,每个节点表示一个操作,可能是单一或多个操作数。 + +支持以下操作: + +| 操作符 | 操作数 | 描述 | +|--------|------------|--------------------------------------------------------------| +| `EQ` | key:value | key 等于 value | +| `NEQ` | key:value | key 不等于 value | +| `GT` | key:value | key 大于 value | +| `GTE` | key:value | key 大于等于 value | +| `LT` | key:value | key 小于 value | +| `LTE` | key:value | key 小于等于 value | +| `IN` | key:[]value| key 等于 value[0] 或 value[1] 或 ... 或 value[n] | +| `AND` | []operation| operation[0] 且 operation[1] 且 ... 且 operation[n] | +| `OR` | []operation| operation[0] 或 operation[1] 或 ... 或 operation[n] | + +操作数中的`key`类似于JSONPath表示法。键中的每个点表示嵌套的JSON结构。例如,考虑以下结构: + +```json +{ + "shape": { + "name": "rectangle", + "dimensions": { + "height": 24, + "width": 10 + }, + "color": { + "name": "red", + "code": "#FF0000" + } + } +} +``` + +要比较颜色代码的值,键将是`shape.color.code`。 + +如果省略`filter`部分,查询将返回所有条目。 + +### `sort` + +`sort`是一个有序的`key:order`对数组,其中: + +- `key`是状态存储中的一个键 +- `order`是一个可选字符串,指示排序顺序: + - `"ASC"`表示升序 + - `"DESC"`表示降序 + 如果省略`order`,默认是升序。 + +### `page` + +`page`包含`limit`和`token`参数。 + +- `limit`设置每页返回的记录数。 +- `token`是组件返回的分页令牌,用于获取后续查询的结果。 + +在后台,此查询请求被转换为本地查询语言并由状态存储组件执行。 + +## 示例数据和查询 + +让我们来看一些从简单到复杂的真实示例。 + +作为数据集,考虑一个包含员工ID、组织、州和城市的[员工记录集合](../query-api-examples/dataset.json)。注意,这个数据集是一个键/值对数组,其中: + +- `key`是唯一ID +- `value`是包含员工记录的JSON对象。 + +为了更好地说明功能,组织名称(org)和员工ID(id)是一个嵌套的JSON person对象。 + +首先创建一个MongoDB实例,作为您的状态存储。 + +```bash +docker run -d --rm -p 27017:27017 --name mongodb mongo:5 +``` + +接下来,启动一个Dapr应用程序。参考[组件配置文件](../query-api-examples/components/mongodb/mongodb.yml),该文件指示Dapr使用MongoDB作为其状态存储。 + +```bash +dapr run --app-id demo --dapr-http-port 3500 --resources-path query-api-examples/components/mongodb +``` + +用员工数据集填充状态存储,以便您可以稍后查询它。 + +```bash +curl -X POST -H "Content-Type: application/json" -d @query-api-examples/dataset.json http://localhost:3500/v1.0/state/statestore +``` + +填充后,您可以检查状态存储中的数据。下图中,MongoDB UI的一部分显示了员工记录。 + +示例数据集 + +每个条目都有一个`_id`成员作为连接的对象键,以及一个包含JSON记录的`value`成员。 + +查询API允许您从这个JSON结构中选择记录。 + +现在您可以运行示例查询。 + +### 示例1 + +首先,查找加利福尼亚州的所有员工,并按其员工ID降序排序。 + +这是[查询](../query-api-examples/query1.json): +```json +{ + "filter": { + "EQ": { "state": "CA" } + }, + "sort": [ + { + "key": "person.id", + "order": "DESC" + } + ] +} +``` + +此查询在SQL中的等价形式是: + +```sql +SELECT * FROM c WHERE + state = "CA" +ORDER BY + person.id DESC +``` + +使用以下命令执行查询: + +{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)" >}} + +{{% codetab %}} + +```bash +curl -s -X POST -H "Content-Type: application/json" -d @query-api-examples/query1.json http://localhost:3500/v1.0-alpha1/state/statestore/query | jq . +``` + +{{% /codetab %}} + +{{% codetab %}} + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -InFile query-api-examples/query1.json -Uri 'http://localhost:3500/v1.0-alpha1/state/statestore/query' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +查询结果是一个按请求顺序排列的匹配键/值对数组: + +```json +{ + "results": [ + { + "key": "3", + "data": { + "person": { + "org": "Finance", + "id": 1071 + }, + "city": "Sacramento", + "state": "CA" + }, + "etag": "44723d41-deb1-4c23-940e-3e6896c3b6f7" + }, + { + "key": "7", + "data": { + "city": "San Francisco", + "state": "CA", + "person": { + "id": 1015, + "org": "Dev Ops" + } + }, + "etag": "0e69e69f-3dbc-423a-9db8-26767fcd2220" + }, + { + "key": "5", + "data": { + "state": "CA", + "person": { + "org": "Hardware", + "id": 1007 + }, + "city": "Los Angeles" + }, + "etag": "f87478fa-e5c5-4be0-afa5-f9f9d75713d8" + }, + { + "key": "9", + "data": { + "person": { + "org": "Finance", + "id": 1002 + }, + "city": "San Diego", + "state": "CA" + }, + "etag": "f5cf05cd-fb43-4154-a2ec-445c66d5f2f8" + } + ] +} +``` + +### 示例2 + +现在,查找来自"Dev Ops"和"Hardware"组织的所有员工。 + +这是[查询](../query-api-examples/query2.json): + +```json +{ + "filter": { + "IN": { "person.org": [ "Dev Ops", "Hardware" ] } + } +} +``` + +此查询在SQL中的等价形式是: + +```sql +SELECT * FROM c WHERE + person.org IN ("Dev Ops", "Hardware") +``` + +使用以下命令执行查询: + +{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)" >}} + +{{% codetab %}} + +```bash +curl -s -X POST -H "Content-Type: application/json" -d @query-api-examples/query2.json http://localhost:3500/v1.0-alpha1/state/statestore/query | jq . +``` + +{{% /codetab %}} + +{{% codetab %}} + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -InFile query-api-examples/query2.json -Uri 'http://localhost:3500/v1.0-alpha1/state/statestore/query' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +与前一个示例类似,结果是一个匹配键/值对的数组。 + +### 示例3 + +在此示例中,查找: + +- 来自"Dev Ops"部门的所有员工。 +- 来自"Finance"部门并居住在华盛顿州和加利福尼亚州的员工。 + +此外,首先按州按字母降序排序,然后按员工ID升序排序。让我们一次处理最多3条记录。 + +这是[查询](../query-api-examples/query3.json): + +```json +{ + "filter": { + "OR": [ + { + "EQ": { "person.org": "Dev Ops" } + }, + { + "AND": [ + { + "EQ": { "person.org": "Finance" } + }, + { + "IN": { "state": [ "CA", "WA" ] } + } + ] + } + ] + }, + "sort": [ + { + "key": "state", + "order": "DESC" + }, + { + "key": "person.id" + } + ], + "page": { + "limit": 3 + } +} +``` + +此查询在SQL中的等价形式是: + +```sql +SELECT * FROM c WHERE + person.org = "Dev Ops" OR + (person.org = "Finance" AND state IN ("CA", "WA")) +ORDER BY + state DESC, + person.id ASC +LIMIT 3 +``` + +使用以下命令执行查询: + +{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)" >}} + +{{% codetab %}} + +```bash +curl -s -X POST -H "Content-Type: application/json" -d @query-api-examples/query3.json http://localhost:3500/v1.0-alpha1/state/statestore/query | jq . +``` + +{{% /codetab %}} + +{{% codetab %}} + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -InFile query-api-examples/query3.json -Uri 'http://localhost:3500/v1.0-alpha1/state/statestore/query' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +成功执行后,状态存储返回一个包含匹配记录列表和分页令牌的JSON对象: + +```json +{ + "results": [ + { + "key": "1", + "data": { + "person": { + "org": "Dev Ops", + "id": 1036 + }, + "city": "Seattle", + "state": "WA" + }, + "etag": "6f54ad94-dfb9-46f0-a371-e42d550adb7d" + }, + { + "key": "4", + "data": { + "person": { + "org": "Dev Ops", + "id": 1042 + }, + "city": "Spokane", + "state": "WA" + }, + "etag": "7415707b-82ce-44d0-bf15-6dc6305af3b1" + }, + { + "key": "10", + "data": { + "person": { + "org": "Dev Ops", + "id": 1054 + }, + "city": "New York", + "state": "NY" + }, + "etag": "26bbba88-9461-48d1-8a35-db07c374e5aa" + } + ], + "token": "3" +} +``` + +分页令牌在[后续查询](../query-api-examples/query3-token.json)中“按原样”使用,以获取下一批记录: + +```json +{ + "filter": { + "OR": [ + { + "EQ": { "person.org": "Dev Ops" } + }, + { + "AND": [ + { + "EQ": { "person.org": "Finance" } + }, + { + "IN": { "state": [ "CA", "WA" ] } + } + ] + } + ] + }, + "sort": [ + { + "key": "state", + "order": "DESC" + }, + { + "key": "person.id" + } + ], + "page": { + "limit": 3, + "token": "3" + } +} +``` + +{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)" >}} + +{{% codetab %}} + +```bash +curl -s -X POST -H "Content-Type: application/json" -d @query-api-examples/query3-token.json http://localhost:3500/v1.0-alpha1/state/statestore/query | jq . +``` + +{{% /codetab %}} + +{{% codetab %}} + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -InFile query-api-examples/query3-token.json -Uri 'http://localhost:3500/v1.0-alpha1/state/statestore/query' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +此查询的结果是: + +```json +{ + "results": [ + { + "key": "9", + "data": { + "person": { + "org": "Finance", + "id": 1002 + }, + "city": "San Diego", + "state": "CA" + }, + "etag": "f5cf05cd-fb43-4154-a2ec-445c66d5f2f8" + }, + { + "key": "7", + "data": { + "city": "San Francisco", + "state": "CA", + "person": { + "id": 1015, + "org": "Dev Ops" + } + }, + "etag": "0e69e69f-3dbc-423a-9db8-26767fcd2220" + }, + { + "key": "3", + "data": { + "person": { + "org": "Finance", + "id": 1071 + }, + "city": "Sacramento", + "state": "CA" + }, + "etag": "44723d41-deb1-4c23-940e-3e6896c3b6f7" + } + ], + "token": "6" +} +``` + +这样,您可以在查询中更新分页令牌,并迭代结果,直到不再返回记录。 + +## 限制 + +状态查询API有以下限制: + +- 要查询存储在状态存储中的actor状态,您需要使用特定数据库的查询API。请参阅[查询actor状态]({{< ref "state-management-overview.md#querying-actor-state" >}})。 +- 该API不适用于Dapr[加密状态存储]({{< ref howto-encrypt-state >}})功能。由于加密是由Dapr运行时完成并存储为加密数据,因此这实际上阻止了服务器端查询。 + +您可以在[相关链接]({{< ref "#related-links" >}})部分找到更多信息。 + +## 相关链接 + +- 请参阅[查询API参考]({{< ref "state_api.md#state-query" >}})。 +- 查看[实现查询支持的状态存储组件]({{< ref supported-state-stores.md >}})。 +- 查看[状态存储查询API实现指南](https://github.com/dapr/components-contrib/blob/master/state/README.md#implementing-state-query-api)。 +- 查看如何[查询Redis状态存储]({{< ref "setup-redis.md#querying-json-objects" >}})。 diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-stateful-service.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-stateful-service.md new file mode 100644 index 000000000..fcdcb0062 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/howto-stateful-service.md @@ -0,0 +1,148 @@ +--- +type: docs +title: "操作指南:构建有状态服务" +linkTitle: "操作指南:构建有状态服务" +weight: 300 +description: "通过状态管理构建可扩展、可复制的服务" +--- + +在本文中,您将学习如何创建一个可以水平扩展的有状态服务,选择性使用并发和一致性模型。状态管理API可以帮助开发者简化状态协调、冲突解决和故障处理的复杂性。 + +## 设置状态存储 + +状态存储组件是Dapr用来与数据库通信的资源。在本指南中,我们将使用默认的Redis状态存储。 + +### 使用Dapr CLI + +当您在本地模式下运行`dapr init`时,Dapr会创建一个默认的Redis `statestore.yaml`并在您的本地机器上运行一个Redis状态存储,位置如下: + +- 在Windows上,位于`%UserProfile%\.dapr\components\statestore.yaml` +- 在Linux/MacOS上,位于`~/.dapr/components/statestore.yaml` + +通过`statestore.yaml`组件,您可以轻松替换底层组件而无需更改应用程序代码。 + +查看[支持的状态存储列表]({{< ref supported-state-stores >}})。 + +### Kubernetes + +查看[如何在Kubernetes上设置不同的状态存储]({{}})。 + +## 强一致性和最终一致性 + +在强一致性模式下,Dapr确保底层状态存储: + +- 在数据写入所有副本后才返回响应。 +- 在写入或删除状态之前从法定人数接收确认。 + +对于读取请求,Dapr确保在副本之间一致地返回最新的数据。默认情况下是最终一致性,除非在请求状态API时另有指定。 + +以下示例展示了如何使用强一致性保存、获取和删除状态。示例用Python编写,但适用于任何编程语言。 + +### 保存状态 + +```python +import requests +import json + +store_name = "redis-store" # 在状态存储组件yaml文件中指定的状态存储名称 +dapr_state_url = "http://localhost:3500/v1.0/state/{}".format(store_name) +stateReq = '[{ "key": "k1", "value": "Some Data", "options": { "consistency": "strong" }}]' +response = requests.post(dapr_state_url, json=stateReq) +``` + +### 获取状态 + +```python +import requests +import json + +store_name = "redis-store" # 在状态存储组件yaml文件中指定的状态存储名称 +dapr_state_url = "http://localhost:3500/v1.0/state/{}".format(store_name) +response = requests.get(dapr_state_url + "/key1", headers={"consistency":"strong"}) +print(response.headers['ETag']) +``` + +### 删除状态 + +```python +import requests +import json + +store_name = "redis-store" # 在状态存储组件yaml文件中指定的状态存储名称 +dapr_state_url = "http://localhost:3500/v1.0/state/{}".format(store_name) +response = requests.delete(dapr_state_url + "/key1", headers={"consistency":"strong"}) +``` + +如果没有指定`concurrency`选项,默认是后写胜出并发模式。 + +## 先写胜出和后写胜出 + +Dapr允许开发者在使用数据存储时选择两种常见的并发模式: + +- **先写胜出**:在应用程序的多个实例同时写入同一个键的情况下很有用。 +- **后写胜出**:Dapr的默认模式。 + +Dapr使用版本号来确定特定键是否已更新。您可以: + +1. 在读取键的数据时保留版本号。 +2. 在更新(如写入和删除)时使用版本号。 + +如果自从检索版本号以来版本信息已更改,将抛出错误,要求您执行另一次读取以获取最新的版本信息和状态。 + +Dapr利用ETags来确定状态的版本号。ETags从状态请求中以`ETag`头返回。使用ETags,您的应用程序知道自上次检查以来资源已更新,因为在ETag不匹配时会出错。 + +以下示例展示了如何: + +- 获取ETag。 +- 使用ETag保存状态。 +- 删除状态。 + +以下示例用Python编写,但适用于任何编程语言。 + +```python +import requests +import json + +store_name = "redis-store" # 在状态存储组件yaml文件中指定的状态存储名称 +dapr_state_url = "http://localhost:3500/v1.0/state/{}".format(store_name) +response = requests.get(dapr_state_url + "/key1", headers={"concurrency":"first-write"}) +etag = response.headers['ETag'] +newState = '[{ "key": "k1", "value": "New Data", "etag": {}, "options": { "concurrency": "first-write" }}]'.format(etag) + +requests.post(dapr_state_url, json=newState) +response = requests.delete(dapr_state_url + "/key1", headers={"If-Match": "{}".format(etag)}) +``` + +### 处理版本不匹配失败 + +在以下示例中,您将看到如何在版本已更改时重试保存状态操作: + +```python +import requests +import json + +# 此方法保存状态,如果保存状态失败则返回false +def save_state(data): + try: + store_name = "redis-store" # 在状态存储组件yaml文件中指定的状态存储名称 + dapr_state_url = "http://localhost:3500/v1.0/state/{}".format(store_name) + response = requests.post(dapr_state_url, json=data) + if response.status_code == 200: + return True + except: + return False + return False + +# 此方法获取状态并返回响应,ETag在头中 --> +def get_state(key): + response = requests.get("http://localhost:3500/v1.0/state//{}".format(key), headers={"concurrency":"first-write"}) + return response + +# 当保存状态成功时退出。如果存在ETag不匹配,success将为False --> +success = False +while success != True: + response = get_state("key1") + etag = response.headers['ETag'] + newState = '[{ "key": "key1", "value": "New Data", "etag": {}, "options": { "concurrency": "first-write" }}]'.format(etag) + + success = save_state(newState) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/components/mongodb/mongodb.yml b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/components/mongodb/mongodb.yml new file mode 100644 index 000000000..82c96d187 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/components/mongodb/mongodb.yml @@ -0,0 +1,10 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: statestore +spec: + type: state.mongodb + version: v1 + metadata: + - name: host + value: localhost:27017 diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/components/redis/redis.yml b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/components/redis/redis.yml new file mode 100644 index 000000000..8f3130709 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/components/redis/redis.yml @@ -0,0 +1,38 @@ +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: querystatestore +spec: + type: state.redis + version: v1 + initTimeout: 1m + metadata: + - name: redisHost + value: "localhost:6379" + - name: redisPassword + value: "" + - name: queryIndexes + value: | + [ + { + "name": "orgIndx", + "indexes": [ + { + "key": "person.org", + "type": "TEXT" + }, + { + "key": "person.id", + "type": "NUMERIC" + }, + { + "key": "state", + "type": "TEXT" + }, + { + "key": "city", + "type": "TEXT" + } + ] + } + ] diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/dataset.json b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/dataset.json new file mode 100644 index 000000000..69935f9bd --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/dataset.json @@ -0,0 +1,112 @@ +[ + { + "key": "1", + "value": { + "person": { + "org": "Dev Ops", + "id": 1036 + }, + "city": "Seattle", + "state": "WA" + } + }, + { + "key": "2", + "value": { + "person": { + "org": "Hardware", + "id": 1028 + }, + "city": "Portland", + "state": "OR" + } + }, + { + "key": "3", + "value": { + "person": { + "org": "Finance", + "id": 1071 + }, + "city": "Sacramento", + "state": "CA" + } + }, + { + "key": "4", + "value": { + "person": { + "org": "Dev Ops", + "id": 1042 + }, + "city": "Spokane", + "state": "WA" + } + }, + { + "key": "5", + "value": { + "person": { + "org": "Hardware", + "id": 1007 + }, + "city": "Los Angeles", + "state": "CA" + } + }, + { + "key": "6", + "value": { + "person": { + "org": "Finance", + "id": 1094 + }, + "city": "Eugene", + "state": "OR" + } + }, + { + "key": "7", + "value": { + "person": { + "org": "Dev Ops", + "id": 1015 + }, + "city": "San Francisco", + "state": "CA" + } + }, + { + "key": "8", + "value": { + "person": { + "org": "Hardware", + "id": 1077 + }, + "city": "Redmond", + "state": "WA" + } + }, + { + "key": "9", + "value": { + "person": { + "org": "Finance", + "id": 1002 + }, + "city": "San Diego", + "state": "CA" + } + }, + { + "key": "10", + "value": { + "person": { + "org": "Dev Ops", + "id": 1054 + }, + "city": "New York", + "state": "NY" + } + } +] diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/query1.json b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/query1.json new file mode 100644 index 000000000..34c558aae --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/query1.json @@ -0,0 +1,11 @@ +{ + "filter": { + "EQ": { "state": "CA" } + }, + "sort": [ + { + "key": "person.id", + "order": "DESC" + } + ] +} diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/query2.json b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/query2.json new file mode 100644 index 000000000..0f8e1e9ad --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/query2.json @@ -0,0 +1,5 @@ +{ + "filter": { + "IN": { "person.org": [ "Dev Ops", "Hardware" ] } + } +} diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/query3-token.json b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/query3-token.json new file mode 100644 index 000000000..61c21c3de --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/query3-token.json @@ -0,0 +1,32 @@ +{ + "filter": { + "OR": [ + { + "EQ": { "person.org": "Dev Ops" } + }, + { + "AND": [ + { + "EQ": { "person.org": "Finance" } + }, + { + "IN": { "state": [ "CA", "WA" ] } + } + ] + } + ] + }, + "sort": [ + { + "key": "state", + "order": "DESC" + }, + { + "key": "person.id" + } + ], + "page": { + "limit": 3, + "token": "3" + } +} diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/query3.json b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/query3.json new file mode 100644 index 000000000..e93f5bfdd --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-api-examples/query3.json @@ -0,0 +1,31 @@ +{ + "filter": { + "OR": [ + { + "EQ": { "person.org": "Dev Ops" } + }, + { + "AND": [ + { + "EQ": { "person.org": "Finance" } + }, + { + "IN": { "state": [ "CA", "WA" ] } + } + ] + } + ] + }, + "sort": [ + { + "key": "state", + "order": "DESC" + }, + { + "key": "person.id" + } + ], + "page": { + "limit": 3 + } +} diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-state-store/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-state-store/_index.md new file mode 100644 index 000000000..2d59be128 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-state-store/_index.md @@ -0,0 +1,9 @@ +--- +type: docs +title: "与后端状态存储交互" +linkTitle: "后端状态存储" +weight: 500 +description: "指导如何与特定的后端状态存储进行交互" +--- + +请查看**操作**部分,了解[支持的状态存储]({{< ref supported-state-stores.md >}})列表,并学习如何配置[状态存储组件]({{< ref setup-state-store.md >}})。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-state-store/query-cosmosdb-store.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-state-store/query-cosmosdb-store.md new file mode 100644 index 000000000..38c046fd4 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-state-store/query-cosmosdb-store.md @@ -0,0 +1,73 @@ +--- +type: docs +title: "Azure Cosmos DB" +linkTitle: "Azure Cosmos DB" +weight: 1000 +description: "使用 Azure Cosmos DB 作为状态存储" +--- + +Dapr 在保存和检索状态时不对状态值进行转换。Dapr 要求所有状态存储实现遵循特定的键格式规范(参见[状态管理规范]({{< ref state_api.md >}}))。您可以直接与底层存储交互以操作状态数据,例如: + +- 查询状态。 +- 创建聚合视图。 +- 进行备份。 + +{{% alert title="注意" color="primary" %}} +Azure Cosmos DB 是一个支持多种 API 的多模式数据库。默认的 Dapr Cosmos DB 状态存储实现使用 [Azure Cosmos DB SQL API](https://docs.microsoft.com/azure/cosmos-db/sql-query-getting-started)。 + +{{% /alert %}} + +## 连接到 Azure Cosmos DB + +要连接到您的 Cosmos DB 实例,您可以: + +- 使用 [Azure 管理门户](https://portal.azure.com)上的数据资源管理器。 +- 使用[各种 SDK 和工具](https://docs.microsoft.com/azure/cosmos-db/mongodb-introduction)。 + +{{% alert title="注意" color="primary" %}} +当您为 Dapr 配置 Azure Cosmos DB 时,请指定要使用的具体数据库和集合。以下 Cosmos DB [SQL API](https://docs.microsoft.com/azure/cosmos-db/sql-query-getting-started) 示例假设您已连接到正确的数据库和名为 "states" 的集合。 + +{{% /alert %}} + +## 按应用程序 ID 列出键 + +要获取与应用程序 "myapp" 关联的所有状态键,请使用查询: + +```sql +SELECT * FROM states WHERE CONTAINS(states.id, 'myapp||') +``` + +上述查询返回所有 id 包含 "myapp||" 的文档,这是状态键的前缀。 + +## 获取特定状态数据 + +要通过键 "balance" 获取应用程序 "myapp" 的状态数据,请使用查询: + +```sql +SELECT * FROM states WHERE states.id = 'myapp||balance' +``` + +读取返回文档的 **value** 字段。要获取状态版本/ETag,请使用命令: + +```sql +SELECT states._etag FROM states WHERE states.id = 'myapp||balance' +``` + +## 读取 actor 状态 + +要获取与实例 ID 为 "leroy" 的 actor 类型 "cat" 关联的所有状态键,该 actor 属于 ID 为 "mypets" 的应用程序,请使用命令: + +```sql +SELECT * FROM states WHERE CONTAINS(states.id, 'mypets||cat||leroy||') +``` + +要获取特定的 actor 状态,例如 "food",请使用命令: + +```sql +SELECT * FROM states WHERE states.id = 'mypets||cat||leroy||food' +``` + +{{% alert title="警告" color="warning" %}} +您不应手动更新或删除存储中的状态。所有写入和删除操作应通过 Dapr 运行时完成。**唯一的例外:** 通常需要在状态存储中删除 actor 记录,_一旦您知道这些记录不再使用_,以防止未使用的 actor 实例积累,这些实例可能永远不会再次加载。 + +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-state-store/query-redis-store.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-state-store/query-redis-store.md new file mode 100644 index 000000000..643a5ee4c --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-state-store/query-redis-store.md @@ -0,0 +1,76 @@ +--- +type: docs +title: "Redis" +linkTitle: "Redis" +weight: 2000 +description: "使用 Redis 作为状态存储" +--- + +Dapr 在保存和检索状态时不对状态值进行转换。Dapr 要求所有状态存储实现遵循特定的键格式规范(参见[状态管理规范]({{< ref state_api.md >}}))。您可以直接与底层存储交互以操作状态数据,例如: + +- 查询状态。 +- 创建聚合视图。 +- 进行备份。 + +{{% alert title="注意" color="primary" %}} +以下示例使用 Redis CLI 针对使用默认 Dapr 状态存储实现的 Redis 存储。 + +{{% /alert %}} + +## 连接到 Redis + +您可以使用官方的 [redis-cli](https://redis.io/topics/rediscli) 或任何其他兼容 Redis 的工具连接到 Redis 状态存储以直接查询 Dapr 状态。如果您在容器中运行 Redis,最简单的使用 redis-cli 的方法是通过容器: + +```bash +docker run --rm -it --link redis redis-cli -h +``` + +## 按应用 ID 列出键 + +要获取与应用程序 "myapp" 关联的所有状态键,请使用命令: + +```bash +KEYS myapp* +``` + +上述命令返回现有键的列表,例如: + +```bash +1) "myapp||balance" +2) "myapp||amount" +``` + +## 获取特定状态数据 + +Dapr 将状态值保存为哈希值。每个哈希值包含一个 "data" 字段,其中存储状态数据,以及一个 "version" 字段,作为 ETag,表示不断递增的版本。 + +例如,要通过键 "balance" 获取应用程序 "myapp" 的状态数据,请使用命令: + +```bash +HGET myapp||balance data +``` + +要获取状态版本/ETag,请使用命令: + +```bash +HGET myapp||balance version +``` + +## 读取 actor 状态 + +要获取与应用程序 ID 为 "mypets" 的 actor 类型 "cat" 的实例 ID 为 "leroy" 关联的所有状态键,请使用命令: + +```bash +KEYS mypets||cat||leroy* +``` + +要获取特定的 actor 状态,例如 "food",请使用命令: + +```bash +HGET mypets||cat||leroy||food value +``` + +{{% alert title="警告" color="warning" %}} +您不应手动更新或删除存储中的状态。所有写入和删除操作应通过 Dapr 运行时完成。**唯一的例外:**通常需要在状态存储中删除 actor 记录,_一旦您知道这些记录不再使用_,以防止未使用的 actor 实例积累,这些实例可能永远不会再次加载。 + +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-state-store/query-sqlserver-store.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-state-store/query-sqlserver-store.md new file mode 100644 index 000000000..d343143a2 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/query-state-store/query-sqlserver-store.md @@ -0,0 +1,76 @@ +--- +type: docs +title: "SQL server" +linkTitle: "SQL server" +weight: 3000 +description: "使用 SQL server 作为后端状态存储" +--- + +Dapr 在保存和检索状态时不对状态值进行转换。Dapr 要求所有状态存储实现遵循特定的键格式(参见[状态管理规范]({{< ref state_api.md >}}))。您可以直接与底层存储交互来操作状态数据,例如: + +- 查询状态。 +- 创建聚合视图。 +- 进行备份。 + +## 连接到 SQL Server + +连接到 SQL Server 实例的最简单方法是使用: + +- [Azure Data Studio](https://docs.microsoft.com/sql/azure-data-studio/download-azure-data-studio)(Windows、macOS、Linux) +- [SQL Server Management Studio](https://docs.microsoft.com/sql/ssms/download-sql-server-management-studio-ssms)(Windows) + +{{% alert title="注意" color="primary" %}} +当您为 Dapr 配置 Azure SQL 数据库时,您需要指定具体的表名。以下 Azure SQL 示例假设您已经连接到具有名为 "states" 的表的正确数据库。 + +{{% /alert %}} + +## 按应用程序 ID 列出键 + +要获取与应用程序 "myapp" 关联的所有状态键,请使用以下查询: + +```sql +SELECT * FROM states WHERE [Key] LIKE 'myapp||%' +``` + +上述查询返回所有 ID 包含 "myapp||" 的行,这是状态键的前缀。 + +## 获取特定状态数据 + +要通过键 "balance" 获取应用程序 "myapp" 的状态数据,请使用以下查询: + +```sql +SELECT * FROM states WHERE [Key] = 'myapp||balance' +``` + +读取返回行的 **Data** 字段。要获取状态版本/ETag,请使用以下命令: + +```sql +SELECT [RowVersion] FROM states WHERE [Key] = 'myapp||balance' +``` + +## 获取过滤的状态数据 + +要获取 JSON 数据中值 "color" 等于 "blue" 的所有状态数据,请使用以下查询: + +```sql +SELECT * FROM states WHERE JSON_VALUE([Data], '$.color') = 'blue' +``` + +## 读取 actor 状态 + +要获取与 actor 类型 "cat" 的实例 ID "leroy" 关联的所有状态键,该 actor 属于 ID 为 "mypets" 的应用程序,请使用以下命令: + +```sql +SELECT * FROM states WHERE [Key] LIKE 'mypets||cat||leroy||%' +``` + +要获取特定的 actor 状态,例如 "food",请使用以下命令: + +```sql +SELECT * FROM states WHERE [Key] = 'mypets||cat||leroy||food' +``` + +{{% alert title="警告" color="warning" %}} +您不应手动更新或删除存储中的状态。所有写入和删除操作应通过 Dapr 运行时完成。**唯一的例外:** 当您确定这些 actor 记录不再使用时,通常需要在状态存储中删除它们,以防止未使用的 actor 实例积累,这些实例可能永远不会再次加载。 + +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/state-management-overview.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/state-management-overview.md new file mode 100644 index 000000000..b94fe3304 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/state-management-overview.md @@ -0,0 +1,192 @@ +--- +type: docs +title: "状态管理概述" +linkTitle: "概述" +weight: 100 +description: "状态管理API模块概述" +--- + +您的应用程序可以利用Dapr的状态管理API在[支持的状态存储]({{< ref supported-state-stores.md >}})中保存、读取和查询键/值对。通过状态存储组件,您可以构建有状态且长时间运行的应用程序,例如购物车或游戏的会话状态。如下图所示: + +- 使用**HTTP POST**来保存或查询键/值对。 +- 使用**HTTP GET**来读取特定键并返回其值。 + + + +[以下视频和演示](https://www.youtube.com/live/0y7ne6teHT4?si=2_xX6mkU3UCy2Plr&t=6607)概述了Dapr状态管理的工作原理。 + + + +## 功能 + +通过状态管理API模块,您的应用程序可以利用一些通常复杂且容易出错的功能,包括: + +- 设置并发控制和数据一致性的选项。 +- 执行批量更新操作[CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete),包括多个事务操作。 +- 查询和过滤键/值数据。 + +以下是状态管理API的一些功能: + +### 可插拔的状态存储 + +Dapr的数据存储被设计为组件,可以在不更改服务代码的情况下进行替换。查看[支持的状态存储]({{< ref supported-state-stores >}})以获取更多信息。 + +### 可配置的状态存储行为 + +使用Dapr,您可以在状态操作请求中附加元数据,描述您期望请求如何被处理。您可以附加: + +- 并发性要求 +- 一致性要求 + +默认情况下,您的应用程序应假设数据存储是**最终一致的**,并使用**最后写入胜出并发模式**。 + +[并非所有存储都是平等的]({{< ref supported-state-stores.md >}})。为了确保您的应用程序的可移植性,您可以查询存储的元数据能力,并使您的代码适应不同的存储能力。 + +#### 并发 + +Dapr支持使用ETags的乐观并发控制(OCC)。当请求状态值时,Dapr总是将ETag属性附加到返回的状态中。当用户代码: + +- **更新状态**时,期望通过请求体附加ETag。 +- **删除状态**时,期望通过`If-Match`头附加ETag。 + +当提供的ETag与状态存储中的ETag匹配时,`写入`操作成功。 + +##### 为什么Dapr选择乐观并发控制(OCC) + +在许多应用程序中,数据更新冲突很少见,因为客户端通常根据业务上下文分区以操作不同的数据。然而,如果您的应用程序选择使用ETags,不匹配的ETags可能导致请求被拒绝。建议您在代码中使用重试策略,以在使用ETags时补偿冲突。 + +如果您的应用程序在写入请求中省略ETags,Dapr在处理请求时会跳过ETag检查。这使得**最后写入胜出**模式成为可能,与使用ETags的**首次写入胜出**模式相比。 + +{{% alert title="关于ETags的注意事项" color="primary" %}} +对于不原生支持ETags的存储,相应的Dapr状态存储实现应模拟ETags,并在处理状态时遵循Dapr状态管理API规范。由于Dapr状态存储实现技术上是底层数据存储的客户端,模拟应该是直接的,使用存储提供的并发控制机制。 +{{% /alert %}} + +阅读[API参考]({{< ref state_api.md >}})以了解如何设置并发选项。 + +#### 一致性 + +Dapr支持**强一致性**和**最终一致性**,最终一致性是默认行为。 + +- **强一致性**:Dapr在确认写入请求之前等待所有副本(或指定的法定人数)确认。 +- **最终一致性**:Dapr在底层数据存储接受写入请求后立即返回,即使这只是一个副本。 + +阅读[API参考]({{< ref state_api.md >}})以了解如何设置一致性选项。 + +### 设置内容类型 + +状态存储组件可能会根据内容类型不同地维护和操作数据。Dapr支持在[状态管理API](#state-management-api)中作为请求元数据的一部分传递内容类型。 + +设置内容类型是_可选的_,组件决定是否使用它。Dapr仅提供将此信息传递给组件的手段。 + +- **使用HTTP API**:通过URL查询参数`metadata.contentType`设置内容类型。例如,`http://localhost:3500/v1.0/state/store?metadata.contentType=application/json`。 +- **使用gRPC API**:通过在请求元数据中添加键/值对`"contentType" : `来设置内容类型。 + +### 多重操作 + +Dapr支持两种类型的多读或多写操作:**批量**或**事务性**。阅读[API参考]({{< ref state_api.md >}})以了解如何使用批量和多选项。 + +#### 批量读取操作 + +您可以将多个读取请求分组为批量(或批次)操作。在批量操作中,Dapr将读取请求作为单独的请求提交到底层数据存储,并将它们作为单个结果返回。 + +#### 事务性操作 + +您可以将写入、更新和删除操作分组为一个请求,然后作为一个原子事务处理。请求将作为一组事务性操作成功或失败。 + +### actor状态 + +事务性状态存储可用于存储actor状态。要指定用于actor的状态存储,请在状态存储组件的元数据部分中将属性`actorStateStore`的值指定为`true`。actor状态以特定方案存储在事务性状态存储中,允许进行一致的查询。所有actor只能使用一个状态存储组件作为状态存储。阅读[state API参考]({{< ref state_api.md >}})和[actors API参考]({{< ref actors_api.md >}})以了解有关actor状态存储的更多信息。 + +#### actor状态的生存时间(TTL) + +在保存actor状态时,您应始终设置TTL元数据字段(`ttlInSeconds`)或在您选择的SDK中使用等效的API调用,以确保状态最终被移除。阅读[actors概述]({{< ref actors-overview.md >}})以获取更多信息。 + +### 状态加密 + +Dapr支持应用程序状态的自动客户端加密,并支持密钥轮换。这在所有Dapr状态存储上都支持。有关更多信息,请阅读[如何:加密应用程序状态]({{< ref howto-encrypt-state.md >}})主题。 + +### 应用程序之间的共享状态 + +不同应用程序在共享状态时的需求各不相同。在一种情况下,您可能希望将所有状态封装在给定应用程序中,并让Dapr为您管理访问。在另一种情况下,您可能希望两个应用程序在同一状态上工作,以获取和保存相同的键。 + +Dapr使状态能够: + +- 隔离到一个应用程序。 +- 在应用程序之间的状态存储中共享。 +- 在不同状态存储之间的多个应用程序之间共享。 + +有关更多详细信息,请阅读[如何:在应用程序之间共享状态]({{< ref howto-share-state.md >}})。 + +### 启用外发模式 + +Dapr使开发人员能够使用外发模式在事务性状态存储和任何消息代理之间实现单一事务。有关更多信息,请阅读[如何启用事务性外发消息]({{< ref howto-outbox.md >}})。 + +### 查询状态 + +有两种方法可以查询状态: + +- 使用Dapr运行时提供的状态管理查询API。 +- 使用存储的原生SDK直接查询状态存储。 + +#### 查询API + +使用_可选的_状态管理[查询API]({{< ref "reference/api/state_api.md#query-state" >}}),您可以查询状态存储中保存的键/值数据,无论底层数据库或存储技术如何。使用状态管理查询API,您可以过滤、排序和分页键/值数据。有关更多详细信息,请阅读[如何:查询状态]({{< ref howto-state-query-api.md >}})。 + +#### 直接查询状态存储 + +Dapr在不进行任何转换的情况下保存和检索状态值。您可以直接从[底层状态存储]({{< ref query-state-store >}})查询和聚合状态。例如,要获取与应用程序ID "myApp" 相关的所有状态键,请在Redis中使用: + +```bash +KEYS "myApp*" +``` + +{{% alert title="关于直接查询的注意事项" color="primary" %}} +由于您不是通过Dapr运行时调用,直接查询状态存储不受Dapr并发控制的约束。您看到的是可接受的已提交数据的快照,用于跨多个actor的只读查询。写入应通过Dapr状态管理或actors API进行。 +{{% /alert %}} + +##### 查询actor状态 + +如果数据存储支持SQL查询,您可以使用SQL查询actor的状态。例如: + +```sql +SELECT * FROM StateTable WHERE Id='||||||' +``` + +您还可以通过对actor实例执行聚合查询来避免actor框架的常见轮次并发限制。例如,要计算所有温度计actor的平均温度,请使用: + +```sql +SELECT AVG(value) FROM StateTable WHERE Id LIKE '||||*||temperature' +``` + +### 状态生存时间(TTL) + +Dapr支持[每个状态设置请求的生存时间(TTL)]({{< ref state-store-ttl.md >}})。这意味着应用程序可以为每个存储的状态设置生存时间,这些状态在过期后无法检索。 + +### 状态管理API + +状态管理API可以在[状态管理API参考]({{< ref state_api.md >}})中找到,该参考描述了如何通过提供键来检索、保存、删除和查询状态值。 + +## 试用状态管理 + +### 快速入门和教程 + +想要测试Dapr状态管理API吗?通过以下快速入门和教程,看看状态管理的实际应用: + +| 快速入门/教程 | 描述 | +| ------------------- | ----------- | +| [状态管理快速入门]({{< ref statemanagement-quickstart.md >}}) | 使用状态管理API创建有状态的应用程序。 | +| [Hello World](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-world) | _推荐_
演示如何在本地运行Dapr。突出显示服务调用和状态管理。 | +| [Hello World Kubernetes](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-kubernetes) | _推荐_
演示如何在Kubernetes中运行Dapr。突出显示服务调用和_状态管理_。 | + +### 直接在您的应用中开始使用状态管理 + +想要跳过快速入门?没问题。您可以直接在您的应用程序中试用状态管理模块。在[Dapr安装]({{< ref "getting-started/_index.md" >}})后,您可以从[状态管理如何指南]({{< ref howto-get-save-state.md >}})开始使用状态管理API。 + +## 下一步 + +- 开始通过状态管理如何指南进行工作,从以下开始: + - [如何:保存和获取状态]({{< ref howto-get-save-state.md >}}) + - [如何:构建有状态服务]({{< ref howto-stateful-service.md >}}) +- 查看[状态存储组件]({{< ref supported-state-stores.md >}})列表 +- 阅读[状态管理API参考]({{< ref state_api.md >}}) +- 阅读[actors API参考]({{< ref actors_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/state-store-ttl.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/state-store-ttl.md new file mode 100644 index 000000000..166454655 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/state-management/state-store-ttl.md @@ -0,0 +1,143 @@ +--- +type: docs +title: "状态生存时间 (TTL)" +linkTitle: "状态 TTL" +weight: 500 +description: "管理具有 TTL 的状态。" +--- + +Dapr 允许为每个状态设置生存时间 (TTL)。这意味着应用程序可以为存储的每个状态指定一个生存时间,过期后将无法检索这些状态。 + +对于[支持的状态存储]({{< ref supported-state-stores >}}),只需在发布消息时设置 `ttlInSeconds` 元数据。其他状态存储将忽略此值。对于某些状态存储,您可以为每个表或容器指定默认的过期时间。 + +## 原生状态 TTL 支持 + +当状态存储组件原生支持状态 TTL 时,Dapr 会直接传递 TTL 配置,而不添加额外的逻辑,从而保持行为的一致性。这在组件以不同方式处理过期状态时尤为有用。 + +如果未指定 TTL,将保留状态存储的默认行为。 + +## 显式持久化绕过全局定义的 TTL + +对于允许为所有数据指定默认 TTL 的状态存储,持久化状态的方式包括: +- 通过 Dapr 组件设置全局 TTL 值,或 +- 在 Dapr 之外创建状态存储并设置全局 TTL 值。 + +如果未指定特定的 TTL,数据将在全局 TTL 时间段后过期,这不是由 Dapr 直接控制的。 + +此外,所有状态存储还支持显式持久化数据的选项。这意味着您可以忽略默认的数据库策略(可能是在 Dapr 之外或通过 Dapr 组件设置的),以无限期保留特定的数据库记录。您可以通过将 `ttlInSeconds` 设置为 `-1` 来实现,这表示忽略任何设置的 TTL 值。 + +## 支持的组件 + +请参阅[状态存储组件指南]({{< ref supported-state-stores >}})中的 TTL 列。 + +## 示例 + +您可以在状态存储请求的元数据中设置状态 TTL: + +{{< tabs Python ".NET" Go "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + + + +```python +# 依赖 + +from dapr.clients import DaprClient + +# 代码 + +DAPR_STORE_NAME = "statestore" + +with DaprClient() as client: + client.save_state(DAPR_STORE_NAME, "order_1", str(orderId), state_metadata={ + 'ttlInSeconds': '120' + }) + +``` + +要启动 Dapr sidecar 并运行上述示例应用程序,您可以运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 -- python3 OrderProcessingService.py +``` + +{{% /codetab %}} + +{{% codetab %}} + + + +```csharp +// 依赖 + +using Dapr.Client; + +// 代码 + +await client.SaveStateAsync(storeName, stateKeyName, state, metadata: new Dictionary() { + { + "ttlInSeconds", "120" + } +}); +``` + +要启动 Dapr sidecar 并运行上述示例应用程序,您可以运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 dotnet run +``` + +{{% /codetab %}} + +{{% codetab %}} + + + +```go +// 依赖 + +import ( + dapr "github.com/dapr/go-sdk/client" +) + +// 代码 + +md := map[string]string{"ttlInSeconds": "120"} +if err := client.SaveState(ctx, store, "key1", []byte("hello world"), md); err != nil { + panic(err) +} +``` + +要启动 Dapr sidecar 并运行上述示例应用程序,您可以运行类似以下的命令: + +```bash +dapr run --app-id orderprocessing --app-port 6001 --dapr-http-port 3601 --dapr-grpc-port 60001 go run . +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +curl -X POST -H "Content-Type: application/json" -d '[{ "key": "order_1", "value": "250", "metadata": { "ttlInSeconds": "120" } }]' http://localhost:3601/v1.0/state/statestore +``` + +{{% /codetab %}} + +{{% codetab %}} + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{"key": "order_1", "value": "250", "metadata": {"ttlInSeconds": "120"}}]' -Uri 'http://localhost:3601/v1.0/state/statestore' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 相关链接 + +- 查看[状态 API 参考指南]({{< ref state_api.md >}})。 +- 学习[如何使用键值对持久化状态]({{< ref howto-get-save-state.md >}})。 +- [状态存储组件]({{< ref supported-state-stores >}})列表。 +- 阅读[API 参考]({{< ref state_api.md >}})。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/_index.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/_index.md new file mode 100644 index 000000000..a3e9683ae --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/_index.md @@ -0,0 +1,14 @@ +--- +type: docs +title: "工作流" +linkTitle: "工作流" +weight: 30 +description: "在各种微服务中进行逻辑编排" +--- + +{{% alert title="更多关于Dapr工作流的内容" color="primary" %}} +了解如何使用Dapr工作流的更多信息: +- 试试[工作流快速入门]({{< ref workflow-quickstart.md >}})。 +- 使用任意[Dapr SDKs]({{< ref sdks >}})来探索工作流。 +- 查看[工作流API参考文档]({{< ref workflow_api.md >}})。 +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/howto-author-workflow.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/howto-author-workflow.md new file mode 100644 index 000000000..a4ef25688 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/howto-author-workflow.md @@ -0,0 +1,1100 @@ +--- +type: docs +title: "如何:编写一个工作流" +linkTitle: "如何:编写工作流" +weight: 5000 +description: "学习如何使用Dapr工作流引擎开发和编写工作流" +--- + +本文提供了如何编写由Dapr工作流引擎执行的工作流的高级概述。 + +{{% alert title="注意" color="primary" %}} +如果您还没有尝试过,[请尝试工作流快速入门]({{< ref workflow-quickstart.md >}}),以快速了解如何使用工作流。 + +{{% /alert %}} + +## 以代码形式编写工作流 + +Dapr工作流逻辑是通过通用编程语言实现的,这使您可以: + +- 使用您喜欢的编程语言(无需学习新的DSL或YAML模式)。 +- 访问语言的标准库。 +- 构建您自己的库和抽象。 +- 使用调试器并检查本地变量。 +- 为您的工作流编写单元测试,就像应用程序逻辑的其他部分一样。 + +Dapr sidecar不加载任何工作流定义。相反,sidecar仅负责驱动工作流的执行,而所有具体的工作流任务则由应用程序的一部分来处理。 + +## 编写工作流任务 + +[工作流任务]({{< ref "workflow-features-concepts.md#workflow-activites" >}})是工作流中的基本工作单元,是在业务流程中被编排的任务。 + +{{< tabs Python JavaScript ".NET" Java Go >}} + +{{% codetab %}} + + + +定义您希望工作流执行的工作流任务。任务是一个函数定义,可以接受输入并返回输出。以下示例创建了一个名为`hello_act`的任务,用于打印当前计数器的值。`hello_act`是一个从`WorkflowActivityContext`类派生的函数。 + +```python +def hello_act(ctx: WorkflowActivityContext, input): + global counter + counter += input + print(f'New counter value is: {counter}!', flush=True) +``` + +[查看上下文中的`hello_act`工作流任务。](https://github.com/dapr/python-sdk/blob/master/examples/demo_workflow/app.py#LL40C1-L43C59) + +{{% /codetab %}} + +{{% codetab %}} + + + +定义您希望工作流执行的工作流任务。任务被封装在实现工作流任务的`WorkflowActivityContext`类中。 + +```javascript +export default class WorkflowActivityContext { + private readonly _innerContext: ActivityContext; + constructor(innerContext: ActivityContext) { + if (!innerContext) { + throw new Error("ActivityContext cannot be undefined"); + } + this._innerContext = innerContext; + } + + public getWorkflowInstanceId(): string { + return this._innerContext.orchestrationId; + } + + public getWorkflowActivityId(): number { + return this._innerContext.taskId; + } +} +``` + +[查看上下文中的工作流任务。](https://github.com/dapr/js-sdk/blob/main/src/workflow/runtime/WorkflowActivityContext.ts) + +{{% /codetab %}} + +{{% codetab %}} + + + +定义您希望工作流执行的工作流任务。任务是一个类定义,可以接受输入并返回输出。任务还可以通过依赖注入与Dapr客户端进行交互。 + +以下示例中调用的任务是: +- `NotifyActivity`:接收新订单的通知。 +- `ReserveInventoryActivity`:检查是否有足够的库存来满足新订单。 +- `ProcessPaymentActivity`:处理订单的付款。包括`NotifyActivity`以发送成功订单的通知。 + +### NotifyActivity + +```csharp +public class NotifyActivity : WorkflowActivity +{ + //... + + public NotifyActivity(ILoggerFactory loggerFactory) + { + this.logger = loggerFactory.CreateLogger(); + } + + //... +} +``` + +[查看完整的`NotifyActivity.cs`工作流任务示例。](https://github.com/dapr/dotnet-sdk/blob/master/examples/Workflow/WorkflowConsoleApp/Activities/NotifyActivity.cs) + +### ReserveInventoryActivity + +```csharp +public class ReserveInventoryActivity : WorkflowActivity +{ + //... + + public ReserveInventoryActivity(ILoggerFactory loggerFactory, DaprClient client) + { + this.logger = loggerFactory.CreateLogger(); + this.client = client; + } + + //... + +} +``` +[查看完整的`ReserveInventoryActivity.cs`工作流任务示例。](https://github.com/dapr/dotnet-sdk/blob/master/examples/Workflow/WorkflowConsoleApp/Activities/ReserveInventoryActivity.cs) + +### ProcessPaymentActivity + +```csharp +public class ProcessPaymentActivity : WorkflowActivity +{ + //... + public ProcessPaymentActivity(ILoggerFactory loggerFactory) + { + this.logger = loggerFactory.CreateLogger(); + } + + //... + +} +``` + +[查看完整的`ProcessPaymentActivity.cs`工作流任务示例。](https://github.com/dapr/dotnet-sdk/blob/master/examples/Workflow/WorkflowConsoleApp/Activities/ProcessPaymentActivity.cs) + +{{% /codetab %}} + +{{% codetab %}} + + + +定义您希望工作流执行的工作流任务。任务被封装在实现工作流任务的公共`DemoWorkflowActivity`类中。 + +```java +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +public class DemoWorkflowActivity implements WorkflowActivity { + + @Override + public DemoActivityOutput run(WorkflowActivityContext ctx) { + Logger logger = LoggerFactory.getLogger(DemoWorkflowActivity.class); + logger.info("Starting Activity: " + ctx.getName()); + + var message = ctx.getInput(DemoActivityInput.class).getMessage(); + var newMessage = message + " World!, from Activity"; + logger.info("Message Received from input: " + message); + logger.info("Sending message to output: " + newMessage); + + logger.info("Sleeping for 5 seconds to simulate long running operation..."); + + try { + TimeUnit.SECONDS.sleep(5); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + logger.info("Activity finished"); + + var output = new DemoActivityOutput(message, newMessage); + logger.info("Activity returned: " + output); + + return output; + } +} +``` + +[查看上下文中的Java SDK工作流任务示例。](https://github.com/dapr/java-sdk/blob/master/examples/src/main/java/io/dapr/examples/workflows/DemoWorkflowActivity.java) + +{{% /codetab %}} + +{{% codetab %}} + + + +定义您希望工作流执行的每个工作流任务。任务输入可以通过`ctx.GetInput`从上下文中解组。任务应定义为接受`ctx workflow.ActivityContext`参数并返回接口和错误。 + +```go +func TestActivity(ctx workflow.ActivityContext) (any, error) { + var input int + if err := ctx.GetInput(&input); err != nil { + return "", err + } + + // Do something here + return "result", nil +} +``` + +[查看上下文中的Go SDK工作流任务示例。](https://github.com/dapr/go-sdk/tree/main/examples/workflow/README.md) + +{{% /codetab %}} + +{{< /tabs >}} + +## 编写工作流 + +接下来,在工作流中注册并调用任务。 + +{{< tabs Python JavaScript ".NET" Java Go >}} + +{{% codetab %}} + + + +`hello_world_wf`函数是从一个名为`DaprWorkflowContext`的类派生的,具有输入和输出参数类型。它还包括一个`yield`语句,该语句完成工作流的繁重工作并调用工作流任务。 + +```python +def hello_world_wf(ctx: DaprWorkflowContext, input): + print(f'{input}') + yield ctx.call_activity(hello_act, input=1) + yield ctx.call_activity(hello_act, input=10) + yield ctx.wait_for_external_event("event1") + yield ctx.call_activity(hello_act, input=100) + yield ctx.call_activity(hello_act, input=1000) +``` + +[查看上下文中的`hello_world_wf`工作流。](https://github.com/dapr/python-sdk/blob/master/examples/demo_workflow/app.py#LL32C1-L38C51) + +{{% /codetab %}} + +{{% codetab %}} + + + +接下来,使用`WorkflowRuntime`类注册工作流并启动工作流运行时。 + +```javascript +export default class WorkflowRuntime { + + //.. + // Register workflow implementation for handling orchestrations + public registerWorkflow(workflow: TWorkflow): WorkflowRuntime { + const name = getFunctionName(workflow); + const workflowWrapper = (ctx: OrchestrationContext, input: any): any => { + const workflowContext = new WorkflowContext(ctx); + return workflow(workflowContext, input); + }; + this.worker.addNamedOrchestrator(name, workflowWrapper); + return this; + } + + // Register workflow activities + public registerActivity(fn: TWorkflowActivity): WorkflowRuntime { + const name = getFunctionName(fn); + const activityWrapper = (ctx: ActivityContext, intput: TInput): TOutput => { + const wfActivityContext = new WorkflowActivityContext(ctx); + return fn(wfActivityContext, intput); + }; + this.worker.addNamedActivity(name, activityWrapper); + return this; + } + + // Start the workflow runtime processing items and block. + public async start() { + await this.worker.start(); + } + +} +``` + +[查看上下文中的`WorkflowRuntime`。](https://github.com/dapr/js-sdk/blob/main/src/workflow/runtime/WorkflowRuntime.ts) + +{{% /codetab %}} + +{{% codetab %}} + + + +`OrderProcessingWorkflow`类是从一个名为`Workflow`的基类派生的,具有输入和输出参数类型。它还包括一个`RunAsync`方法,该方法完成工作流的繁重工作并调用工作流任务。 + +```csharp + class OrderProcessingWorkflow : Workflow + { + public override async Task RunAsync(WorkflowContext context, OrderPayload order) + { + //... + + await context.CallActivityAsync( + nameof(NotifyActivity), + new Notification($"Received order {orderId} for {order.Name} at {order.TotalCost:c}")); + + //... + + InventoryResult result = await context.CallActivityAsync( + nameof(ReserveInventoryActivity), + new InventoryRequest(RequestId: orderId, order.Name, order.Quantity)); + //... + + await context.CallActivityAsync( + nameof(ProcessPaymentActivity), + new PaymentRequest(RequestId: orderId, order.TotalCost, "USD")); + + await context.CallActivityAsync( + nameof(NotifyActivity), + new Notification($"Order {orderId} processed successfully!")); + + // End the workflow with a success result + return new OrderResult(Processed: true); + } + } +``` + +[查看`OrderProcessingWorkflow.cs`中的完整工作流示例。](https://github.com/dapr/dotnet-sdk/blob/master/examples/Workflow/WorkflowConsoleApp/Workflows/OrderProcessingWorkflow.cs) + +{{% /codetab %}} + +{{% codetab %}} + + + +接下来,使用`WorkflowRuntimeBuilder`注册工作流并启动工作流运行时。 + +```java +public class DemoWorkflowWorker { + + public static void main(String[] args) throws Exception { + + // Register the Workflow with the builder. + WorkflowRuntimeBuilder builder = new WorkflowRuntimeBuilder().registerWorkflow(DemoWorkflow.class); + builder.registerActivity(DemoWorkflowActivity.class); + + // Build and then start the workflow runtime pulling and executing tasks + try (WorkflowRuntime runtime = builder.build()) { + System.out.println("Start workflow runtime"); + runtime.start(); + } + + System.exit(0); + } +} +``` + +[查看上下文中的Java SDK工作流。](https://github.com/dapr/java-sdk/blob/master/examples/src/main/java/io/dapr/examples/workflows/DemoWorkflowWorker.java) + +{{% /codetab %}} + +{{% codetab %}} + + + +定义您的工作流函数,参数为`ctx *workflow.WorkflowContext`,返回任何和错误。从您的工作流中调用您定义的任务。 + +```go +func TestWorkflow(ctx *workflow.WorkflowContext) (any, error) { + var input int + if err := ctx.GetInput(&input); err != nil { + return nil, err + } + var output string + if err := ctx.CallActivity(TestActivity, workflow.ActivityInput(input)).Await(&output); err != nil { + return nil, err + } + if err := ctx.WaitForExternalEvent("testEvent", time.Second*60).Await(&output); err != nil { + return nil, err + } + + if err := ctx.CreateTimer(time.Second).Await(nil); err != nil { + return nil, nil + } + return output, nil +} +``` + +[查看上下文中的Go SDK工作流。](https://github.com/dapr/go-sdk/tree/main/examples/workflow/README.md) + +{{% /codetab %}} + +{{< /tabs >}} + +## 编写应用程序 + +最后,使用工作流编写应用程序。 + +{{< tabs Python JavaScript ".NET" Java Go >}} + +{{% codetab %}} + + + +[在以下示例中](https://github.com/dapr/python-sdk/blob/master/examples/demo_workflow/app.py),对于使用Python SDK的基本Python hello world应用程序,您的项目代码将包括: + +- 一个名为`DaprClient`的Python包,用于接收Python SDK功能。 +- 一个带有扩展的构建器,称为: + - `WorkflowRuntime`:允许您注册工作流和工作流任务 + - `DaprWorkflowContext`:允许您[创建工作流]({{< ref "#write-the-workflow" >}}) + - `WorkflowActivityContext`:允许您[创建工作流任务]({{< ref "#write-the-workflow-activities" >}}) +- API调用。在下面的示例中,这些调用启动、暂停、恢复、清除和终止工作流。 + +```python +from dapr.ext.workflow import WorkflowRuntime, DaprWorkflowContext, WorkflowActivityContext +from dapr.clients import DaprClient + +# ... + +def main(): + with DaprClient() as d: + host = settings.DAPR_RUNTIME_HOST + port = settings.DAPR_GRPC_PORT + workflowRuntime = WorkflowRuntime(host, port) + workflowRuntime = WorkflowRuntime() + workflowRuntime.register_workflow(hello_world_wf) + workflowRuntime.register_activity(hello_act) + workflowRuntime.start() + + # Start workflow + print("==========Start Counter Increase as per Input:==========") + start_resp = d.start_workflow(instance_id=instanceId, workflow_component=workflowComponent, + workflow_name=workflowName, input=inputData, workflow_options=workflowOptions) + print(f"start_resp {start_resp.instance_id}") + + # ... + + # Pause workflow + d.pause_workflow(instance_id=instanceId, workflow_component=workflowComponent) + getResponse = d.get_workflow(instance_id=instanceId, workflow_component=workflowComponent) + print(f"Get response from {workflowName} after pause call: {getResponse.runtime_status}") + + # Resume workflow + d.resume_workflow(instance_id=instanceId, workflow_component=workflowComponent) + getResponse = d.get_workflow(instance_id=instanceId, workflow_component=workflowComponent) + print(f"Get response from {workflowName} after resume call: {getResponse.runtime_status}") + + sleep(1) + # Raise workflow + d.raise_workflow_event(instance_id=instanceId, workflow_component=workflowComponent, + event_name=eventName, event_data=eventData) + + sleep(5) + # Purge workflow + d.purge_workflow(instance_id=instanceId, workflow_component=workflowComponent) + try: + getResponse = d.get_workflow(instance_id=instanceId, workflow_component=workflowComponent) + except DaprInternalError as err: + if nonExistentIDError in err._message: + print("Instance Successfully Purged") + + # Kick off another workflow for termination purposes + start_resp = d.start_workflow(instance_id=instanceId, workflow_component=workflowComponent, + workflow_name=workflowName, input=inputData, workflow_options=workflowOptions) + print(f"start_resp {start_resp.instance_id}") + + # Terminate workflow + d.terminate_workflow(instance_id=instanceId, workflow_component=workflowComponent) + sleep(1) + getResponse = d.get_workflow(instance_id=instanceId, workflow_component=workflowComponent) + print(f"Get response from {workflowName} after terminate call: {getResponse.runtime_status}") + + # Purge workflow + d.purge_workflow(instance_id=instanceId, workflow_component=workflowComponent) + try: + getResponse = d.get_workflow(instance_id=instanceId, workflow_component=workflowComponent) + except DaprInternalError as err: + if nonExistentIDError in err._message: + print("Instance Successfully Purged") + + workflowRuntime.shutdown() + +if __name__ == '__main__': + main() +``` + +{{% /codetab %}} + +{{% codetab %}} + + + +[以下示例](https://github.com/dapr/js-sdk/blob/main/src/workflow/client/DaprWorkflowClient.ts)是一个使用JavaScript SDK的基本JavaScript应用程序。在此示例中,您的项目代码将包括: + +- 一个带有扩展的构建器,称为: + - `WorkflowRuntime`:允许您注册工作流和工作流任务 + - `DaprWorkflowContext`:允许您[创建工作流]({{< ref "#write-the-workflow" >}}) + - `WorkflowActivityContext`:允许您[创建工作流任务]({{< ref "#write-the-workflow-activities" >}}) +- API调用。在下面的示例中,这些调用启动、终止、获取状态、暂停、恢复、引发事件和清除工作流。 + +```javascript +import { TaskHubGrpcClient } from "@microsoft/durabletask-js"; +import { WorkflowState } from "./WorkflowState"; +import { generateApiTokenClientInterceptors, generateEndpoint, getDaprApiToken } from "../internal/index"; +import { TWorkflow } from "../../types/workflow/Workflow.type"; +import { getFunctionName } from "../internal"; +import { WorkflowClientOptions } from "../../types/workflow/WorkflowClientOption"; + +/** DaprWorkflowClient类定义了管理工作流实例的客户端操作。 */ + +export default class DaprWorkflowClient { + private readonly _innerClient: TaskHubGrpcClient; + + /** 初始化DaprWorkflowClient的新实例。 + */ + constructor(options: Partial = {}) { + const grpcEndpoint = generateEndpoint(options); + options.daprApiToken = getDaprApiToken(options); + this._innerClient = this.buildInnerClient(grpcEndpoint.endpoint, options); + } + + private buildInnerClient(hostAddress: string, options: Partial): TaskHubGrpcClient { + let innerOptions = options?.grpcOptions; + if (options.daprApiToken !== undefined && options.daprApiToken !== "") { + innerOptions = { + ...innerOptions, + interceptors: [generateApiTokenClientInterceptors(options), ...(innerOptions?.interceptors ?? [])], + }; + } + return new TaskHubGrpcClient(hostAddress, innerOptions); + } + + /** + * 使用DurableTask客户端调度新的工作流。 + */ + public async scheduleNewWorkflow( + workflow: TWorkflow | string, + input?: any, + instanceId?: string, + startAt?: Date, + ): Promise { + if (typeof workflow === "string") { + return await this._innerClient.scheduleNewOrchestration(workflow, input, instanceId, startAt); + } + return await this._innerClient.scheduleNewOrchestration(getFunctionName(workflow), input, instanceId, startAt); + } + + /** + * 终止与提供的实例ID关联的工作流。 + * + * @param {string} workflowInstanceId - 要终止的工作流实例ID。 + * @param {any} output - 为终止的工作流实例设置的可选输出。 + */ + public async terminateWorkflow(workflowInstanceId: string, output: any) { + await this._innerClient.terminateOrchestration(workflowInstanceId, output); + } + + /** + * 从配置的持久存储中获取工作流实例元数据。 + */ + public async getWorkflowState( + workflowInstanceId: string, + getInputsAndOutputs: boolean, + ): Promise { + const state = await this._innerClient.getOrchestrationState(workflowInstanceId, getInputsAndOutputs); + if (state !== undefined) { + return new WorkflowState(state); + } + } + + /** + * 等待工作流开始运行 + */ + public async waitForWorkflowStart( + workflowInstanceId: string, + fetchPayloads = true, + timeoutInSeconds = 60, + ): Promise { + const state = await this._innerClient.waitForOrchestrationStart( + workflowInstanceId, + fetchPayloads, + timeoutInSeconds, + ); + if (state !== undefined) { + return new WorkflowState(state); + } + } + + /** + * 等待工作流完成运行 + */ + public async waitForWorkflowCompletion( + workflowInstanceId: string, + fetchPayloads = true, + timeoutInSeconds = 60, + ): Promise { + const state = await this._innerClient.waitForOrchestrationCompletion( + workflowInstanceId, + fetchPayloads, + timeoutInSeconds, + ); + if (state != undefined) { + return new WorkflowState(state); + } + } + + /** + * 向等待的工作流实例发送事件通知消息 + */ + public async raiseEvent(workflowInstanceId: string, eventName: string, eventPayload?: any) { + this._innerClient.raiseOrchestrationEvent(workflowInstanceId, eventName, eventPayload); + } + + /** + * 从工作流状态存储中清除工作流实例状态。 + */ + public async purgeWorkflow(workflowInstanceId: string): Promise { + const purgeResult = await this._innerClient.purgeOrchestration(workflowInstanceId); + if (purgeResult !== undefined) { + return purgeResult.deletedInstanceCount > 0; + } + return false; + } + + /** + * 关闭内部DurableTask客户端并关闭GRPC通道。 + */ + public async stop() { + await this._innerClient.stop(); + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + + + +[在以下`Program.cs`示例中](https://github.com/dapr/dotnet-sdk/blob/master/examples/Workflow/WorkflowConsoleApp/Program.cs),对于使用.NET SDK的基本ASP.NET订单处理应用程序,您的项目代码将包括: + +- 一个名为`Dapr.Workflow`的NuGet包,用于接收.NET SDK功能 +- 一个带有扩展方法的构建器,称为`AddDaprWorkflow` + - 这将允许您注册工作流和工作流任务(工作流可以调度的任务) +- HTTP API调用 + - 一个用于提交新订单 + - 一个用于检查现有订单的状态 + +```csharp +using Dapr.Workflow; +//... + +// Dapr工作流作为服务配置的一部分注册 +builder.Services.AddDaprWorkflow(options => +{ + // 请注意,也可以将lambda函数注册为工作流或任务实现,而不是类。 + options.RegisterWorkflow(); + + // 这些是由工作流调用的任务。 + options.RegisterActivity(); + options.RegisterActivity(); + options.RegisterActivity(); +}); + +WebApplication app = builder.Build(); + +// POST启动新的订单工作流实例 +app.MapPost("/orders", async (DaprWorkflowClient client, [FromBody] OrderPayload orderInfo) => +{ + if (orderInfo?.Name == null) + { + return Results.BadRequest(new + { + message = "Order data was missing from the request", + example = new OrderPayload("Paperclips", 99.95), + }); + } + +//... +}); + +// GET获取订单工作流的状态以报告状态 +app.MapGet("/orders/{orderId}", async (string orderId, DaprWorkflowClient client) => +{ + WorkflowState state = await client.GetWorkflowStateAsync(orderId, true); + if (!state.Exists) + { + return Results.NotFound($"No order with ID = '{orderId}' was found."); + } + + var httpResponsePayload = new + { + details = state.ReadInputAs(), + status = state.RuntimeStatus.ToString(), + result = state.ReadOutputAs(), + }; + +//... +}).WithName("GetOrderInfoEndpoint"); + +app.Run(); +``` + +{{% /codetab %}} + +{{% codetab %}} + + + +[如以下示例所示](https://github.com/dapr/java-sdk/blob/master/examples/src/main/java/io/dapr/examples/workflows/DemoWorkflow.java),使用Java SDK和Dapr工作流的hello-world应用程序将包括: + +- 一个名为`io.dapr.workflows.client`的Java包,用于接收Java SDK客户端功能。 +- 导入`io.dapr.workflows.Workflow` +- 扩展`Workflow`的`DemoWorkflow`类 +- 使用输入和输出创建工作流。 +- API调用。在下面的示例中,这些调用启动并调用工作流任务。 + +```java +package io.dapr.examples.workflows; + +import com.microsoft.durabletask.CompositeTaskFailedException; +import com.microsoft.durabletask.Task; +import com.microsoft.durabletask.TaskCanceledException; +import io.dapr.workflows.Workflow; +import io.dapr.workflows.WorkflowStub; + +import java.time.Duration; +import java.util.Arrays; +import java.util.List; + +/** + * DemoWorkflow的服务器端实现。 + */ +public class DemoWorkflow extends Workflow { + @Override + public WorkflowStub create() { + return ctx -> { + ctx.getLogger().info("Starting Workflow: " + ctx.getName()); + // ... + ctx.getLogger().info("Calling Activity..."); + var input = new DemoActivityInput("Hello Activity!"); + var output = ctx.callActivity(DemoWorkflowActivity.class.getName(), input, DemoActivityOutput.class).await(); + // ... + }; + } +} +``` + +[查看上下文中的完整Java SDK工作流示例。](https://github.com/dapr/java-sdk/blob/master/examples/src/main/java/io/dapr/examples/workflows/DemoWorkflow.java) + +{{% /codetab %}} + +{{% codetab %}} + + + +[如以下示例所示](https://github.com/dapr/go-sdk/tree/main/examples/workflow/README.md),使用Go SDK和Dapr工作流的hello-world应用程序将包括: + +- 一个名为`client`的Go包,用于接收Go SDK客户端功能。 +- `TestWorkflow`方法 +- 使用输入和输出创建工作流。 +- API调用。在下面的示例中,这些调用启动并调用工作流任务。 + +```go +package main + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/dapr/go-sdk/client" + "github.com/dapr/go-sdk/workflow" +) + +var stage = 0 + +const ( + workflowComponent = "dapr" +) + +func main() { + w, err := workflow.NewWorker() + if err != nil { + log.Fatal(err) + } + + fmt.Println("Worker initialized") + + if err := w.RegisterWorkflow(TestWorkflow); err != nil { + log.Fatal(err) + } + fmt.Println("TestWorkflow registered") + + if err := w.RegisterActivity(TestActivity); err != nil { + log.Fatal(err) + } + fmt.Println("TestActivity registered") + + // Start workflow runner + if err := w.Start(); err != nil { + log.Fatal(err) + } + fmt.Println("runner started") + + daprClient, err := client.NewClient() + if err != nil { + log.Fatalf("failed to intialise client: %v", err) + } + defer daprClient.Close() + ctx := context.Background() + + // Start workflow test + respStart, err := daprClient.StartWorkflow(ctx, &client.StartWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + WorkflowName: "TestWorkflow", + Options: nil, + Input: 1, + SendRawInput: false, + }) + if err != nil { + log.Fatalf("failed to start workflow: %v", err) + } + fmt.Printf("workflow started with id: %v\n", respStart.InstanceID) + + // Pause workflow test + err = daprClient.PauseWorkflow(ctx, &client.PauseWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + }) + + if err != nil { + log.Fatalf("failed to pause workflow: %v", err) + } + + respGet, err := daprClient.GetWorkflow(ctx, &client.GetWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + }) + if err != nil { + log.Fatalf("failed to get workflow: %v", err) + } + + if respGet.RuntimeStatus != workflow.StatusSuspended.String() { + log.Fatalf("workflow not paused: %v", respGet.RuntimeStatus) + } + + fmt.Printf("workflow paused\n") + + // Resume workflow test + err = daprClient.ResumeWorkflow(ctx, &client.ResumeWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + }) + + if err != nil { + log.Fatalf("failed to resume workflow: %v", err) + } + + respGet, err = daprClient.GetWorkflow(ctx, &client.GetWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + }) + if err != nil { + log.Fatalf("failed to get workflow: %v", err) + } + + if respGet.RuntimeStatus != workflow.StatusRunning.String() { + log.Fatalf("workflow not running") + } + + fmt.Println("workflow resumed") + + fmt.Printf("stage: %d\n", stage) + + // Raise Event Test + + err = daprClient.RaiseEventWorkflow(ctx, &client.RaiseEventWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + EventName: "testEvent", + EventData: "testData", + SendRawData: false, + }) + + if err != nil { + fmt.Printf("failed to raise event: %v", err) + } + + fmt.Println("workflow event raised") + + time.Sleep(time.Second) // allow workflow to advance + + fmt.Printf("stage: %d\n", stage) + + respGet, err = daprClient.GetWorkflow(ctx, &client.GetWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + }) + if err != nil { + log.Fatalf("failed to get workflow: %v", err) + } + + fmt.Printf("workflow status: %v\n", respGet.RuntimeStatus) + + // Purge workflow test + err = daprClient.PurgeWorkflow(ctx, &client.PurgeWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + }) + if err != nil { + log.Fatalf("failed to purge workflow: %v", err) + } + + respGet, err = daprClient.GetWorkflow(ctx, &client.GetWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + }) + if err != nil && respGet != nil { + log.Fatal("failed to purge workflow") + } + + fmt.Println("workflow purged") + + fmt.Printf("stage: %d\n", stage) + + // Terminate workflow test + respStart, err = daprClient.StartWorkflow(ctx, &client.StartWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + WorkflowName: "TestWorkflow", + Options: nil, + Input: 1, + SendRawInput: false, + }) + if err != nil { + log.Fatalf("failed to start workflow: %v", err) + } + + fmt.Printf("workflow started with id: %s\n", respStart.InstanceID) + + err = daprClient.TerminateWorkflow(ctx, &client.TerminateWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + }) + if err != nil { + log.Fatalf("failed to terminate workflow: %v", err) + } + + respGet, err = daprClient.GetWorkflow(ctx, &client.GetWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + }) + if err != nil { + log.Fatalf("failed to get workflow: %v", err) + } + if respGet.RuntimeStatus != workflow.StatusTerminated.String() { + log.Fatal("failed to terminate workflow") + } + + fmt.Println("workflow terminated") + + err = daprClient.PurgeWorkflow(ctx, &client.PurgeWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + }) + + respGet, err = daprClient.GetWorkflow(ctx, &client.GetWorkflowRequest{ + InstanceID: "a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9", + WorkflowComponent: workflowComponent, + }) + if err == nil || respGet != nil { + log.Fatalf("failed to purge workflow: %v", err) + } + + fmt.Println("workflow purged") + + stage = 0 + fmt.Println("workflow client test") + + wfClient, err := workflow.NewClient() + if err != nil { + log.Fatalf("[wfclient] faield to initialize: %v", err) + } + + id, err := wfClient.ScheduleNewWorkflow(ctx, "TestWorkflow", workflow.WithInstanceID("a7a4168d-3a1c-41da-8a4f-e7f6d9c718d9"), workflow.WithInput(1)) + if err != nil { + log.Fatalf("[wfclient] failed to start workflow: %v", err) + } + + fmt.Printf("[wfclient] started workflow with id: %s\n", id) + + metadata, err := wfClient.FetchWorkflowMetadata(ctx, id) + if err != nil { + log.Fatalf("[wfclient] failed to get worfklow: %v", err) + } + + fmt.Printf("[wfclient] workflow status: %v\n", metadata.RuntimeStatus.String()) + + if stage != 1 { + log.Fatalf("Workflow assertion failed while validating the wfclient. Stage 1 expected, current: %d", stage) + } + + fmt.Printf("[wfclient] stage: %d\n", stage) + + // raise event + + if err := wfClient.RaiseEvent(ctx, id, "testEvent", workflow.WithEventPayload("testData")); err != nil { + log.Fatalf("[wfclient] failed to raise event: %v", err) + } + + fmt.Println("[wfclient] event raised") + + // Sleep to allow the workflow to advance + time.Sleep(time.Second) + + if stage != 2 { + log.Fatalf("Workflow assertion failed while validating the wfclient. Stage 2 expected, current: %d", stage) + } + + fmt.Printf("[wfclient] stage: %d\n", stage) + + // stop workflow + if err := wfClient.TerminateWorkflow(ctx, id); err != nil { + log.Fatalf("[wfclient] failed to terminate workflow: %v", err) + } + + fmt.Println("[wfclient] workflow terminated") + + if err := wfClient.PurgeWorkflow(ctx, id); err != nil { + log.Fatalf("[wfclient] failed to purge workflow: %v", err) + } + + fmt.Println("[wfclient] workflow purged") + + // stop workflow runtime + if err := w.Shutdown(); err != nil { + log.Fatalf("failed to shutdown runtime: %v", err) + } + + fmt.Println("workflow worker successfully shutdown") +} + +func TestWorkflow(ctx *workflow.WorkflowContext) (any, error) { + var input int + if err := ctx.GetInput(&input); err != nil { + return nil, err + } + var output string + if err := ctx.CallActivity(TestActivity, workflow.ActivityInput(input)).Await(&output); err != nil { + return nil, err + } + + err := ctx.WaitForExternalEvent("testEvent", time.Second*60).Await(&output) + if err != nil { + return nil, err + } + + if err := ctx.CallActivity(TestActivity, workflow.ActivityInput(input)).Await(&output); err != nil { + return nil, err + } + + return output, nil +} + +func TestActivity(ctx workflow.ActivityContext) (any, error) { + var input int + if err := ctx.GetInput(&input); err != nil { + return "", err + } + + stage += input + + return fmt.Sprintf("Stage: %d", stage), nil +} +``` + +[查看上下文中的完整Go SDK工作流示例。](https://github.com/dapr/go-sdk/tree/main/examples/workflow/README.md) + +{{% /codetab %}} + +{{< /tabs >}} + +{{% alert title="重要" color="warning" %}} +由于基于重放的工作流的执行方式,您将编写在任务内部执行I/O和与系统交互的逻辑。同时,工作流方法仅用于编排这些任务。 + +{{% /alert %}} + +## 下一步 + +现在您已经编写了一个工作流,学习如何管理它。 + +{{< button text="管理工作流 >>" page="howto-manage-workflow.md" >}} + +## 相关链接 +- [工作流概述]({{< ref workflow-overview.md >}}) +- [工作流API参考]({{< ref workflow_api.md >}}) +- 尝试完整的SDK示例: + - [Python示例](https://github.com/dapr/python-sdk/tree/master/examples/demo_workflow) + - [JavaScript示例](https://github.com/dapr/js-sdk/tree/main/examples/workflow) + - [.NET示例](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) + - [Java示例](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/workflows) + - [Go示例](https://github.com/dapr/go-sdk/tree/main/examples/workflow/README.md) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/howto-manage-workflow.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/howto-manage-workflow.md new file mode 100644 index 000000000..7690105ed --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/howto-manage-workflow.md @@ -0,0 +1,393 @@ +--- +type: docs +title: "如何:管理工作流" +linkTitle: "如何:管理工作流" +weight: 6000 +description: 管理和运行工作流 +--- + +现在您已经在应用程序中[编写了工作流及其活动]({{< ref howto-author-workflow.md >}}),您可以使用HTTP API调用来启动、终止和获取工作流的信息。有关更多信息,请阅读[工作流API参考]({{< ref workflow_api.md >}})。 + +{{< tabs Python JavaScript ".NET" Java Go HTTP >}} + + +{{% codetab %}} + +在代码中管理您的工作流。在[编写工作流]({{< ref "howto-author-workflow.md#write-the-application" >}})指南中的工作流示例中,工作流通过以下API在代码中注册: +- **start_workflow**: 启动工作流的一个实例 +- **get_workflow**: 获取工作流状态的信息 +- **pause_workflow**: 暂停或挂起一个工作流实例,稍后可以恢复 +- **resume_workflow**: 恢复一个暂停的工作流实例 +- **raise_workflow_event**: 在工作流上触发一个事件 +- **purge_workflow**: 删除与特定工作流实例相关的所有元数据 +- **terminate_workflow**: 终止或停止特定的工作流实例 + +```python +from dapr.ext.workflow import WorkflowRuntime, DaprWorkflowContext, WorkflowActivityContext +from dapr.clients import DaprClient + +# 合适的参数 +instanceId = "exampleInstanceID" +workflowComponent = "dapr" +workflowName = "hello_world_wf" +eventName = "event1" +eventData = "eventData" + +# 启动工作流 +start_resp = d.start_workflow(instance_id=instanceId, workflow_component=workflowComponent, + workflow_name=workflowName, input=inputData, workflow_options=workflowOptions) + +# 获取工作流信息 +getResponse = d.get_workflow(instance_id=instanceId, workflow_component=workflowComponent) + +# 暂停工作流 +d.pause_workflow(instance_id=instanceId, workflow_component=workflowComponent) + +# 恢复工作流 +d.resume_workflow(instance_id=instanceId, workflow_component=workflowComponent) + +# 在工作流上触发一个事件 +d.raise_workflow_event(instance_id=instanceId, workflow_component=workflowComponent, + event_name=eventName, event_data=eventData) + +# 清除工作流 +d.purge_workflow(instance_id=instanceId, workflow_component=workflowComponent) + +# 终止工作流 +d.terminate_workflow(instance_id=instanceId, workflow_component=workflowComponent) +``` + +{{% /codetab %}} + + +{{% codetab %}} + +在代码中管理您的工作流。在[编写工作流]({{< ref "howto-author-workflow.md#write-the-application" >}})指南中的工作流示例中,工作流通过以下API在代码中注册: +- **client.workflow.start**: 启动工作流的一个实例 +- **client.workflow.get**: 获取工作流状态的信息 +- **client.workflow.pause**: 暂停或挂起一个工作流实例,稍后可以恢复 +- **client.workflow.resume**: 恢复一个暂停的工作流实例 +- **client.workflow.purge**: 删除与特定工作流实例相关的所有元数据 +- **client.workflow.terminate**: 终止或停止特定的工作流实例 + +```javascript +import { DaprClient } from "@dapr/dapr"; + +async function printWorkflowStatus(client: DaprClient, instanceId: string) { + const workflow = await client.workflow.get(instanceId); + console.log( + `工作流 ${workflow.workflowName}, 创建于 ${workflow.createdAt.toUTCString()}, 状态为 ${ + workflow.runtimeStatus + }`, + ); + console.log(`附加属性: ${JSON.stringify(workflow.properties)}`); + console.log("--------------------------------------------------\n\n"); +} + +async function start() { + const client = new DaprClient(); + + // 启动一个新的工作流实例 + const instanceId = await client.workflow.start("OrderProcessingWorkflow", { + Name: "Paperclips", + TotalCost: 99.95, + Quantity: 4, + }); + console.log(`已启动工作流实例 ${instanceId}`); + await printWorkflowStatus(client, instanceId); + + // 暂停一个工作流实例 + await client.workflow.pause(instanceId); + console.log(`已暂停工作流实例 ${instanceId}`); + await printWorkflowStatus(client, instanceId); + + // 恢复一个工作流实例 + await client.workflow.resume(instanceId); + console.log(`已恢复工作流实例 ${instanceId}`); + await printWorkflowStatus(client, instanceId); + + // 终止一个工作流实例 + await client.workflow.terminate(instanceId); + console.log(`已终止工作流实例 ${instanceId}`); + await printWorkflowStatus(client, instanceId); + + // 等待工作流完成,30秒! + await new Promise((resolve) => setTimeout(resolve, 30000)); + await printWorkflowStatus(client, instanceId); + + // 清除一个工作流实例 + await client.workflow.purge(instanceId); + console.log(`已清除工作流实例 ${instanceId}`); + // 这将抛出一个错误,因为工作流实例不再存在。 + await printWorkflowStatus(client, instanceId); +} + +start().catch((e) => { + console.error(e); + process.exit(1); +}); +``` + +{{% /codetab %}} + + +{{% codetab %}} + +在代码中管理您的工作流。在[编写工作流]({{< ref "howto-author-workflow.md#write-the-application" >}})指南中的`OrderProcessingWorkflow`示例中,工作流在代码中注册。您现在可以启动、终止并获取正在运行的工作流的信息: + +```csharp +string orderId = "exampleOrderId"; +string workflowComponent = "dapr"; +string workflowName = "OrderProcessingWorkflow"; +OrderPayload input = new OrderPayload("Paperclips", 99.95); +Dictionary workflowOptions; // 这是一个可选参数 + +// 启动工作流。这将返回一个"StartWorkflowResponse",其中包含特定工作流实例的实例ID。 +StartWorkflowResponse startResponse = await daprClient.StartWorkflowAsync(orderId, workflowComponent, workflowName, input, workflowOptions); + +// 获取工作流的信息。此响应包含工作流的状态、启动时间等信息! +GetWorkflowResponse getResponse = await daprClient.GetWorkflowAsync(orderId, workflowComponent, eventName); + +// 终止工作流 +await daprClient.TerminateWorkflowAsync(orderId, workflowComponent); + +// 触发一个事件(一个传入的采购订单),您的工作流将等待此事件。这将返回等待购买的项目。 +await daprClient.RaiseWorkflowEventAsync(orderId, workflowComponent, workflowName, input); + +// 暂停 +await daprClient.PauseWorkflowAsync(orderId, workflowComponent); + +// 恢复 +await daprClient.ResumeWorkflowAsync(orderId, workflowComponent); + +// 清除工作流,删除与关联实例的所有收件箱和历史信息 +await daprClient.PurgeWorkflowAsync(orderId, workflowComponent); +``` + +{{% /codetab %}} + + +{{% codetab %}} + +在代码中管理您的工作流。[在Java SDK中的工作流示例](https://github.com/dapr/java-sdk/blob/master/examples/src/main/java/io/dapr/examples/workflows/)中,工作流通过以下API在代码中注册: + +- **scheduleNewWorkflow**: 启动一个新的工作流实例 +- **getInstanceState**: 获取工作流状态的信息 +- **waitForInstanceStart**: 暂停或挂起一个工作流实例,稍后可以恢复 +- **raiseEvent**: 为正在运行的工作流实例触发事件/任务 +- **waitForInstanceCompletion**: 等待工作流完成其任务 +- **purgeInstance**: 删除与特定工作流实例相关的所有元数据 +- **terminateWorkflow**: 终止工作流 +- **purgeInstance**: 删除与特定工作流相关的所有元数据 + +```java +package io.dapr.examples.workflows; + +import io.dapr.workflows.client.DaprWorkflowClient; +import io.dapr.workflows.client.WorkflowInstanceStatus; + +// ... +public class DemoWorkflowClient { + + // ... + public static void main(String[] args) throws InterruptedException { + DaprWorkflowClient client = new DaprWorkflowClient(); + + try (client) { + // 启动工作流 + String instanceId = client.scheduleNewWorkflow(DemoWorkflow.class, "input data"); + + // 获取工作流的状态信息 + WorkflowInstanceStatus workflowMetadata = client.getInstanceState(instanceId, true); + + // 等待或暂停工作流实例启动 + try { + WorkflowInstanceStatus waitForInstanceStartResult = + client.waitForInstanceStart(instanceId, Duration.ofSeconds(60), true); + } + + // 为工作流触发一个事件;您可以并行触发多个事件 + client.raiseEvent(instanceId, "TestEvent", "TestEventPayload"); + client.raiseEvent(instanceId, "event1", "TestEvent 1 Payload"); + client.raiseEvent(instanceId, "event2", "TestEvent 2 Payload"); + client.raiseEvent(instanceId, "event3", "TestEvent 3 Payload"); + + // 等待工作流完成任务 + try { + WorkflowInstanceStatus waitForInstanceCompletionResult = + client.waitForInstanceCompletion(instanceId, Duration.ofSeconds(60), true); + } + + // 清除工作流实例,删除与其相关的所有元数据 + boolean purgeResult = client.purgeInstance(instanceId); + + // 终止工作流实例 + client.terminateWorkflow(instanceToTerminateId, null); + + System.exit(0); + } +} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +在代码中管理您的工作流。[在Go SDK中的工作流示例](https://github.com/dapr/go-sdk/tree/main/examples/workflow)中,工作流通过以下API在代码中注册: + +- **StartWorkflow**: 启动一个新的工作流实例 +- **GetWorkflow**: 获取工作流状态的信息 +- **PauseWorkflow**: 暂停或挂起一个工作流实例,稍后可以恢复 +- **RaiseEventWorkflow**: 为正在运行的工作流实例触发事件/任务 +- **ResumeWorkflow**: 等待工作流完成其任务 +- **PurgeWorkflow**: 删除与特定工作流实例相关的所有元数据 +- **TerminateWorkflow**: 终止工作流 + +```go +// 启动工作流 +type StartWorkflowRequest struct { + InstanceID string // 可选实例标识符 + WorkflowComponent string + WorkflowName string + Options map[string]string // 可选元数据 + Input any // 可选输入 + SendRawInput bool // 设置为True以禁用输入的序列化 +} + +type StartWorkflowResponse struct { + InstanceID string +} + +// 获取工作流状态 +type GetWorkflowRequest struct { + InstanceID string + WorkflowComponent string +} + +type GetWorkflowResponse struct { + InstanceID string + WorkflowName string + CreatedAt time.Time + LastUpdatedAt time.Time + RuntimeStatus string + Properties map[string]string +} + +// 清除工作流 +type PurgeWorkflowRequest struct { + InstanceID string + WorkflowComponent string +} + +// 终止工作流 +type TerminateWorkflowRequest struct { + InstanceID string + WorkflowComponent string +} + +// 暂停工作流 +type PauseWorkflowRequest struct { + InstanceID string + WorkflowComponent string +} + +// 恢复工作流 +type ResumeWorkflowRequest struct { + InstanceID string + WorkflowComponent string +} + +// 为正在运行的工作流触发一个事件 +type RaiseEventWorkflowRequest struct { + InstanceID string + WorkflowComponent string + EventName string + EventData any + SendRawData bool // 设置为True以禁用数据的序列化 +} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +使用HTTP调用管理您的工作流。下面的示例将[编写工作流示例]({{< ref "howto-author-workflow.md#write-the-workflow" >}})中的属性与一个随机实例ID号结合使用。 + +### 启动工作流 + +要使用ID `12345678`启动您的工作流,请运行: + +```http +POST http://localhost:3500/v1.0/workflows/dapr/OrderProcessingWorkflow/start?instanceID=12345678 +``` + +请注意,工作流实例ID只能包含字母数字字符、下划线和破折号。 + +### 终止工作流 + +要使用ID `12345678`终止您的工作流,请运行: + +```http +POST http://localhost:3500/v1.0/workflows/dapr/12345678/terminate +``` + +### 触发一个事件 + +对于支持订阅外部事件的工作流组件,例如Dapr工作流引擎,您可以使用以下“触发事件”API将命名事件传递给特定的工作流实例。 + +```http +POST http://localhost:3500/v1.0/workflows///raiseEvent/ +``` + +> `eventName`可以是任何自定义的事件名称。 + +### 暂停或恢复工作流 + +为了计划停机时间、等待输入等,您可以暂停然后恢复工作流。要暂停ID为`12345678`的工作流,直到触发恢复,请运行: + +```http +POST http://localhost:3500/v1.0/workflows/dapr/12345678/pause +``` + +要恢复ID为`12345678`的工作流,请运行: + +```http +POST http://localhost:3500/v1.0/workflows/dapr/12345678/resume +``` + +### 清除工作流 + +清除API可用于从底层状态存储中永久删除工作流元数据,包括任何存储的输入、输出和工作流历史记录。这通常对于实施数据保留策略和释放资源很有用。 + +只有处于COMPLETED、FAILED或TERMINATED状态的工作流实例可以被清除。如果工作流处于其他状态,调用清除将返回错误。 + +```http +POST http://localhost:3500/v1.0/workflows/dapr/12345678/purge +``` + +### 获取工作流信息 + +要获取ID为`12345678`的工作流信息(输出和输入),请运行: + +```http +GET http://localhost:3500/v1.0/workflows/dapr/12345678 +``` + +在[工作流API参考指南]({{< ref workflow_api.md >}})中了解更多关于这些HTTP调用的信息。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 +- [尝试工作流快速入门]({{< ref workflow-quickstart.md >}}) +- 尝试完整的SDK示例: + - [Python示例](https://github.com/dapr/python-sdk/blob/master/examples/demo_workflow/app.py) + - [JavaScript示例](https://github.com/dapr/js-sdk/tree/main/examples/workflow) + - [.NET示例](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) + - [Java示例](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/workflows) + - [Go示例](https://github.com/dapr/go-sdk/tree/main/examples/workflow) + +- [工作流API参考]({{< ref workflow_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/workflow-architecture.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/workflow-architecture.md new file mode 100644 index 000000000..41d22c168 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/workflow-architecture.md @@ -0,0 +1,220 @@ +--- +type: docs +title: "工作流架构" +linkTitle: "工作流架构" +weight: 4000 +description: "Dapr 工作流引擎架构" +--- + +[Dapr 工作流]({{< ref "workflow-overview.md" >}}) 允许开发者使用多种编程语言的普通代码定义工作流。工作流引擎运行在 Dapr sidecar 内部,并协调作为应用程序一部分部署的工作流代码。本文描述了: + +- Dapr 工作流引擎的架构 +- 工作流引擎如何与应用程序代码交互 +- 工作流引擎如何融入整体 Dapr 架构 +- 不同的工作流后端如何与工作流引擎协作 + +有关如何在应用程序中编写 Dapr 工作流的更多信息,请参见 [如何:编写工作流]({{< ref "workflow-overview.md" >}})。 + +Dapr 工作流引擎的内部支持来自于 Dapr 的 actor 运行时。下图展示了 Kubernetes 模式下的 Dapr 工作流架构: + +展示 Kubernetes 模式下工作流架构如何工作的图示 + +要使用 Dapr 工作流构建块,您需要在应用程序中使用 Dapr 工作流 SDK 编写工作流代码,该 SDK 内部通过 gRPC 流连接到 sidecar。这会注册工作流和任何工作流活动,或工作流可以调度的任务。 + +引擎直接嵌入在 sidecar 中,并通过 [`durabletask-go`](https://github.com/microsoft/durabletask-go) 框架库实现。此框架允许您更换不同的存储提供者,包括为 Dapr 创建的存储提供者,该提供者在幕后利用内部 actor。由于 Dapr 工作流使用 actor,您可以将工作流状态存储在状态存储中。 + +## Sidecar 交互 + +当工作流应用程序启动时,它使用工作流编写 SDK 向 Dapr sidecar 发送 gRPC 请求,并根据 [服务器流式 RPC 模式](https://grpc.io/docs/what-is-grpc/core-concepts/#server-streaming-rpc) 获取工作流工作项流。这些工作项可以是从“启动一个新的 X 工作流”(其中 X 是工作流的类型)到“调度活动 Y,输入 Z 以代表工作流 X 运行”的任何内容。 + +工作流应用程序执行相应的工作流代码,然后将执行结果通过 gRPC 请求发送回 sidecar。 + +Dapr 工作流引擎协议 + +所有交互都通过单个 gRPC 通道进行,并由应用程序发起,这意味着应用程序不需要打开任何入站端口。这些交互的细节由特定语言的 Dapr 工作流编写 SDK 内部处理。 + +### 工作流和 actor sidecar 交互的区别 + +如果您熟悉 Dapr actor,您可能会注意到工作流与 actor 的 sidecar 交互方式有一些不同。 + +| Actor | 工作流 | +| ------ | --------- | +| Actor 可以使用 HTTP 或 gRPC 与 sidecar 交互。 | 工作流仅使用 gRPC。由于工作流 gRPC 协议的复杂性,实现工作流时需要一个 SDK。 | +| Actor 操作从 sidecar 推送到应用程序代码。这需要应用程序在特定的 _应用端口_ 上监听。 | 对于工作流,操作是由应用程序使用流协议从 sidecar 拉取的。应用程序不需要监听任何端口即可运行工作流。 | +| Actor 明确地向 sidecar 注册自己。 | 工作流不向 sidecar 注册自己。嵌入的引擎不跟踪工作流类型。这一责任被委托给工作流应用程序及其 SDK。 | + +## 工作流分布式追踪 + +工作流引擎使用 `durabletask-go` 核心通过 Open Telemetry SDKs 写入分布式追踪。这些追踪由 Dapr sidecar 自动捕获并导出到配置的 Open Telemetry 提供者,例如 Zipkin。 + +引擎管理的每个工作流实例都表示为一个或多个跨度。有一个单一的父跨度表示完整的工作流执行,以及各种任务的子跨度,包括活动任务执行和持久计时器的跨度。 + +> 工作流活动代码目前**无法**访问追踪上下文。 + +## 内部工作流 actor + +在 Dapr sidecar 内部注册了两种类型的 actor,以支持工作流引擎: + +- `dapr.internal.{namespace}.{appID}.workflow` +- `dapr.internal.{namespace}.{appID}.activity` + +`{namespace}` 值是 Dapr 命名空间,如果没有配置命名空间,则默认为 `default`。`{appID}` 值是应用程序的 ID。例如,如果您有一个名为 "wfapp" 的工作流应用程序,那么工作流 actor 的类型将是 `dapr.internal.default.wfapp.workflow`,活动 actor 的类型将是 `dapr.internal.default.wfapp.activity`。 + +下图展示了在 Kubernetes 场景中内部工作流 actor 如何操作: + +展示跨集群内部注册的 actor 的图示 + +与用户定义的 actor 一样,内部工作流 actor 由 actor 放置服务分布在集群中。它们也维护自己的状态并使用提醒。然而,与存在于应用程序代码中的 actor 不同,这些 _内部_ actor 嵌入在 Dapr sidecar 中。应用程序代码完全不知道这些 actor 的存在。 + +{{% alert title="注意" color="primary" %}} +只有在应用程序使用 Dapr 工作流 SDK 注册了工作流后,内部工作流 actor 类型才会被注册。如果应用程序从未注册工作流,则内部工作流 actor 永远不会被注册。 +{{% /alert %}} + +### 工作流 actor + +工作流 actor 负责管理应用程序中运行的所有工作流的状态和放置。每当创建一个工作流实例时,就会激活一个新的工作流 actor 实例。工作流 actor 的 ID 是工作流的 ID。这个内部 actor 存储工作流的状态,并通过 actor 放置服务确定工作流代码执行的节点。 + +每个工作流 actor 使用以下键在配置的状态存储中保存其状态: + +| 键 | 描述 | +| --- | ----------- | +| `inbox-NNNNNN` | 工作流的收件箱实际上是一个驱动工作流执行的 _消息_ 的 FIFO 队列。示例消息包括工作流创建消息、活动任务完成消息等。每条消息都存储在状态存储中的一个键中,名称为 `inbox-NNNNNN`,其中 `NNNNNN` 是一个 6 位数,表示消息的顺序。这些状态键在相应的消息被工作流消费后被移除。 | +| `history-NNNNNN` | 工作流的历史是一个有序的事件列表,表示工作流的执行历史。历史中的每个键保存单个历史事件的数据。像一个只追加的日志一样,工作流历史事件只会被添加而不会被移除(除非工作流执行“继续为新”操作,这会清除所有历史并使用新输入重新启动工作流)。 | +| `customStatus` | 包含用户定义的工作流状态值。每个工作流 actor 实例只有一个 `customStatus` 键。 | +| `metadata` | 以 JSON blob 形式包含有关工作流的元信息,包括收件箱的长度、历史的长度以及表示工作流生成的 64 位整数(用于实例 ID 被重用的情况)。长度信息用于确定在加载或保存工作流状态更新时需要读取或写入哪些键。 | + +{{% alert title="警告" color="warning" %}} +在 [Dapr 工作流引擎的 Alpha 版本]({{< ref support-preview-features.md >}}) 中,工作流 actor 状态将在工作流完成后仍保留在状态存储中。创建大量工作流可能导致存储使用不受限制。在未来的版本中,将引入数据保留策略,可以自动清除旧工作流状态的状态存储。 +{{% /alert %}} + +下图展示了工作流 actor 的典型生命周期。 + +Dapr 工作流 Actor 流程图 + +总结: + +1. 当工作流 actor 收到新消息时被激活。 +2. 新消息触发相关的工作流代码(在您的应用程序中)运行,并将执行结果返回给工作流 actor。 +3. 一旦收到结果,actor 会根据需要调度任何任务。 +4. 调度后,actor 在状态存储中更新其状态。 +5. 最后,actor 进入空闲状态,直到收到另一条消息。在此空闲时间内,sidecar 可能决定从内存中卸载工作流 actor。 + +### 活动 actor + +活动 actor 负责管理所有工作流活动调用的状态和放置。每当工作流调度一个活动任务时,就会激活一个新的活动 actor 实例。活动 actor 的 ID 是工作流的 ID 加上一个序列号(序列号从 0 开始)。例如,如果一个工作流的 ID 是 `876bf371`,并且是工作流调度的第三个活动,它的 ID 将是 `876bf371::2`,其中 `2` 是序列号。 + +每个活动 actor 将单个键存储到状态存储中: + +| 键 | 描述 | +| --- | ----------- | +| `activityState` | 键包含活动调用负载,其中包括序列化的活动输入数据。此键在活动调用完成后自动删除。 | + +下图展示了活动 actor 的典型生命周期。 + +工作流活动 Actor 流程图 + +活动 actor 是短暂的: + +1. 当工作流 actor 调度一个活动任务时,活动 actor 被激活。 +2. 活动 actor 然后立即调用工作流应用程序以调用相关的活动代码。 +3. 一旦活动代码完成运行并返回其结果,活动 actor 将执行结果的消息发送给父工作流 actor。 +4. 一旦结果被发送,工作流被触发以继续其下一步。 + +### 提醒使用和执行保证 + +Dapr 工作流通过使用 [actor 提醒]({{< ref "howto-actors.md#actor-timers-and-reminders" >}}) 来确保工作流的容错性,以从瞬态系统故障中恢复。在调用应用程序工作流代码之前,工作流或活动 actor 将创建一个新的提醒。如果应用程序代码执行没有中断,提醒将被删除。然而,如果托管相关工作流或活动的节点或 sidecar 崩溃,提醒将重新激活相应的 actor 并重试执行。 + +展示调用工作流 actor 过程的图示 + +{{% alert title="重要" color="warning" %}} +集群中过多的活动提醒可能导致性能问题。如果您的应用程序已经大量使用 actor 和提醒,请注意 Dapr 工作流可能给系统增加的额外负载。 +{{% /alert %}} + +### 状态存储使用 + +Dapr 工作流在内部使用 actor 来驱动工作流的执行。像任何 actor 一样,这些内部工作流 actor 将其状态存储在配置的状态存储中。任何支持 actor 的状态存储都隐式支持 Dapr 工作流。 + +如 [工作流 actor]({{< ref "workflow-architecture.md#workflow-actors" >}}) 部分所述,工作流通过追加到历史日志中增量保存其状态。工作流的历史日志分布在多个状态存储键中,以便每个“检查点”只需追加最新的条目。 + +每个检查点的大小由工作流在进入空闲状态之前调度的并发操作数决定。[顺序工作流]({{< ref "workflow-overview.md#task-chaining" >}}) 因此将对状态存储进行较小的批量更新,而 [扇出/扇入工作流]({{< ref "workflow-overview.md#fan-outfan-in" >}}) 将需要更大的批量。批量的大小还受到工作流 [调用活动]({{< ref "workflow-features-concepts.md#workflow-activities" >}}) 或 [子工作流]({{< ref "workflow-features-concepts.md#child-workflows" >}}) 时输入和输出大小的影响。 + +工作流 actor 状态存储交互图示 + +不同的状态存储实现可能隐式对您可以编写的工作流类型施加限制。例如,Azure Cosmos DB 状态存储将项目大小限制为 2 MB 的 UTF-8 编码 JSON([来源](https://learn.microsoft.com/azure/cosmos-db/concepts-limits#per-item-limits))。活动或子工作流的输入或输出负载作为状态存储中的单个记录存储,因此 2 MB 的项目限制意味着工作流和活动的输入和输出不能超过 2 MB 的 JSON 序列化数据。 + +同样,如果状态存储对批量事务的大小施加限制,这可能会限制工作流可以调度的并行操作数。 + +工作流状态可以从状态存储中清除,包括其所有历史记录。每个 Dapr SDK 都公开用于清除特定工作流实例的所有元数据的 API。 + +## 工作流可扩展性 + +由于 Dapr 工作流在内部使用 actor 实现,Dapr 工作流具有与 actor 相同的可扩展性特征。放置服务: + +- 不区分工作流 actor 和您在应用程序中定义的 actor +- 将使用与 actor 相同的算法对工作流进行负载均衡 + +工作流的预期可扩展性由以下因素决定: + +- 用于托管工作流应用程序的机器数量 +- 运行工作流的机器上可用的 CPU 和内存资源 +- 为 actor 配置的状态存储的可扩展性 +- actor 放置服务和提醒子系统的可扩展性 + +目标应用程序中工作流代码的实现细节也在个别工作流实例的可扩展性中起作用。每个工作流实例一次在单个节点上执行,但工作流可以调度在其他节点上运行的活动和子工作流。 + +工作流还可以调度这些活动和子工作流以并行运行,允许单个工作流可能将计算任务分布在集群中的所有可用节点上。 + +跨多个 Dapr 实例扩展的工作流和活动 actor 图示 + +{{% alert title="重要" color="warning" %}} +目前,没有对工作流和活动并发性施加全局限制。因此,一个失控的工作流可能会在尝试并行调度过多任务时消耗集群中的所有资源。在编写 Dapr 工作流时,请小心调度大量并行工作的批次。 + +此外,Dapr 工作流引擎要求每个工作流应用程序的所有实例注册完全相同的工作流和活动。换句话说,无法独立扩展某些工作流或活动。应用程序中的所有工作流和活动必须一起扩展。 +{{% /alert %}} + +工作流不控制负载在集群中的具体分布方式。例如,如果一个工作流调度 10 个活动任务并行运行,所有 10 个任务可能在多达 10 个不同的计算节点上运行,也可能在少至一个计算节点上运行。实际的扩展行为由 actor 放置服务决定,该服务管理表示工作流每个任务的 actor 的分布。 + +## 工作流后端 + +工作流后端负责协调和保存工作流的状态。在任何给定时间,只能支持一个后端。您可以将工作流后端配置为一个组件,类似于 Dapr 中的任何其他组件。配置要求: +1. 指定工作流后端的类型。 +1. 提供特定于该后端的配置。 + +例如,以下示例演示了如何定义一个 actor 后端组件。Dapr 工作流目前默认仅支持 actor 后端,用户不需要定义 actor 后端组件即可使用它。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: actorbackend +spec: + type: workflowbackend.actor + version: v1 +``` + +## 工作流延迟 + +为了提供关于持久性和弹性的保证,Dapr 工作流频繁地写入状态存储并依赖提醒来驱动执行。因此,Dapr 工作流可能不适合对延迟敏感的工作负载。预期的高延迟来源包括: + +- 在持久化工作流状态时来自状态存储的延迟。 +- 在使用大型历史记录重新加载工作流时来自状态存储的延迟。 +- 集群中过多活动提醒导致的延迟。 +- 集群中高 CPU 使用率导致的延迟。 + +有关工作流 actor 设计如何影响执行延迟的更多详细信息,请参见 [提醒使用和执行保证部分]({{< ref "workflow-architecture.md#reminder-usage-and-execution-guarantees" >}})。 + +## 下一步 + +{{< button text="编写工作流 >>" page="howto-author-workflow.md" >}} + +## 相关链接 + +- [工作流概述]({{< ref workflow-overview.md >}}) +- [工作流 API 参考]({{< ref workflow_api.md >}}) +- [尝试工作流快速入门]({{< ref workflow-quickstart.md >}}) +- 尝试以下示例: + - [Python](https://github.com/dapr/python-sdk/tree/master/examples/demo_workflow) + - [JavaScript 示例](https://github.com/dapr/js-sdk/tree/main/examples/workflow) + - [.NET](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) + - [Java](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/workflows) + - [Go 示例](https://github.com/dapr/go-sdk/tree/main/examples/workflow/README.md) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/workflow-features-concepts.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/workflow-features-concepts.md new file mode 100644 index 000000000..8eabd548b --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/workflow-features-concepts.md @@ -0,0 +1,499 @@ +--- +type: docs +title: "功能和概念" +linkTitle: "功能和概念" +weight: 2000 +description: "详细了解 Dapr 工作流的功能和概念" +--- + +在您已经从高层次了解了[工作流构建块]({{< ref workflow-overview.md >}})之后,让我们深入探讨 Dapr 工作流引擎和 SDK 所包含的功能和概念。Dapr 工作流在所有支持的语言中都提供了几个核心功能和概念。 + +{{% alert title="注意" color="primary" %}} +有关工作流状态管理的更多信息,请参阅[工作流架构指南]({{< ref workflow-architecture.md >}})。 +{{% /alert %}} + +## 工作流 + +Dapr 工作流是您编写的函数,用于定义一系列按特定顺序执行的任务。Dapr 工作流引擎负责调度和执行这些任务,包括管理故障和重试。如果托管工作流的应用程序在多台机器上扩展,工作流引擎还可以在多台机器上负载均衡工作流及其任务的执行。 + +工作流可以调度多种类型的任务,包括: +- 用于执行自定义逻辑的[活动]({{< ref "workflow-features-concepts.md#workflow-activities" >}}) +- 用于将工作流休眠任意时间长度的[持久计时器]({{< ref "workflow-features-concepts.md#durable-timers" >}}) +- 用于将较大的工作流分解为较小部分的[子工作流]({{< ref "workflow-features-concepts.md#child-workflows" >}}) +- 用于阻塞工作流直到接收到外部事件信号的[外部事件等待器]({{< ref "workflow-features-concepts.md#external-events" >}})。这些任务在其相应的部分中有更详细的描述。 + +### 工作流标识 + +每个您定义的工作流都有一个类型名称,工作流的每次执行都需要一个唯一的_实例 ID_。工作流实例 ID 可以由您的应用程序代码生成,这在工作流对应于业务实体(如文档或作业)时很有用,或者可以是自动生成的 UUID。工作流的实例 ID 对于调试以及使用[工作流 API]({{< ref workflow_api.md >}})管理工作流非常有用。 + +在任何给定时间,只能存在一个具有给定 ID 的工作流实例。然而,如果一个工作流实例完成或失败,其 ID 可以被新的工作流实例重用。但请注意,新工作流实例实际上会在配置的状态存储中替换旧的实例。 + +### 工作流重放 + +Dapr 工作流通过使用一种称为[事件溯源](https://learn.microsoft.com/azure/architecture/patterns/event-sourcing)的技术来维护其执行状态。工作流引擎不是将工作流的当前状态存储为快照,而是管理一个仅追加的历史事件日志,描述工作流所采取的各种步骤。当使用工作流 SDK 时,这些历史事件会在工作流“等待”计划任务的结果时自动存储。 + +当工作流“等待”计划任务时,它会从内存中卸载自己,直到任务完成。一旦任务完成,工作流引擎会再次调度工作流函数运行。此时的工作流函数执行被称为_重放_。 + +当工作流函数被重放时,它会从头开始再次运行。然而,当它遇到已经完成的任务时,工作流引擎不会再次调度该任务,而是: + +1. 将已完成任务的存储结果返回给工作流。 +1. 继续执行直到下一个“等待”点。 + +这种“重放”行为会持续到工作流函数完成或因错误而失败。 + +通过这种重放技术,工作流能够从任何“等待”点恢复执行,就像它从未从内存中卸载过一样。即使是先前运行的局部变量的值也可以恢复,而无需工作流引擎了解它们存储了什么数据。这种恢复状态的能力使 Dapr 工作流具有_持久性_和_容错性_。 + +{{% alert title="注意" color="primary" %}} +这里描述的工作流重放行为要求工作流函数代码是_确定性的_。确定性的工作流函数在提供完全相同的输入时采取完全相同的操作。[了解有关确定性工作流代码限制的更多信息。]({{< ref "workflow-features-concepts.md#workflow-determinism-and-code-restraints" >}}) +{{% /alert %}} + +### 无限循环和永恒工作流 + +如[工作流重放]({{< ref "#workflow-replay" >}})部分所述,工作流维护其所有操作的仅写事件溯源历史日志。为了避免资源使用失控,工作流必须限制其调度的操作数量。例如,确保您的工作流不会: + +- 在其实现中使用无限循环 +- 调度数千个任务。 + +您可以使用以下两种技术来编写可能需要调度极大量任务的工作流: + +1. **使用 _continue-as-new_ API**: + 每个工作流 SDK 都公开了一个 _continue-as-new_ API,工作流可以调用该 API 以使用新的输入和历史记录重新启动自己。_continue-as-new_ API 特别适合实现“永恒工作流”,如监控代理,否则将使用 `while (true)` 类构造实现。使用 _continue-as-new_ 是保持工作流历史记录小的好方法。 + + > _continue-as-new_ API 会截断现有历史记录,并用新的历史记录替换它。 + +1. **使用子工作流**: + 每个工作流 SDK 都公开了一个用于创建子工作流的 API。子工作流的行为与任何其他工作流相同,只是它由父工作流调度。子工作流具有: + - 自己的历史记录 + - 在多台机器上分布工作流函数执行的好处。 + + 如果一个工作流需要调度数千个或更多任务,建议将这些任务分布在子工作流中,以免单个工作流的历史记录大小过大。 + +### 更新工作流代码 + +由于工作流是长时间运行且持久的,因此更新工作流代码必须非常小心。如[工作流确定性]({{< ref "#workflow-determinism-and-code-restraints" >}})限制部分所述,工作流代码必须是确定性的。如果系统中有任何未完成的工作流实例,更新工作流代码必须保留这种确定性。否则,更新工作流代码可能会导致下次这些工作流执行时出现运行时故障。 + +[查看已知限制]({{< ref "#limitations" >}}) + +## 工作流活动 + +工作流活动是工作流中的基本工作单元,是在业务流程中被编排的任务。例如,您可能会创建一个工作流来处理订单。任务可能涉及检查库存、向客户收费和创建发货。每个任务将是一个单独的活动。这些活动可以串行执行、并行执行或两者的某种组合。 + +与工作流不同,活动在您可以在其中执行的工作类型上没有限制。活动经常用于进行网络调用或运行 CPU 密集型操作。活动还可以将数据返回给工作流。 + +Dapr 工作流引擎保证每个被调用的活动在工作流的执行过程中至少执行一次。由于活动仅保证至少一次执行,建议尽可能将活动逻辑实现为幂等。 + +## 子工作流 + +除了活动之外,工作流还可以调度其他工作流作为_子工作流_。子工作流具有独立于启动它的父工作流的实例 ID、历史记录和状态。 + +子工作流有许多好处: + +* 您可以将大型工作流拆分为一系列较小的子工作流,使您的代码更易于维护。 +* 您可以在多个计算节点上同时分布工作流逻辑,这在您的工作流逻辑需要协调大量任务时很有用。 +* 您可以通过保持父工作流的历史记录较小来减少内存使用和 CPU 开销。 + +子工作流的返回值是其输出。如果子工作流因异常而失败,则该异常会像活动任务失败时一样显示给父工作流。子工作流还支持自动重试策略。 + +终止父工作流会终止由工作流实例创建的所有子工作流。有关更多信息,请参阅[终止工作流 API]({{< ref "workflow_api.md#terminate-workflow-request" >}})。 + +## 持久计时器 + +Dapr 工作流允许您为任何时间范围安排类似提醒的持久延迟,包括分钟、天甚至年。这些_持久计时器_可以由工作流安排以实现简单的延迟或为其他异步任务设置临时超时。更具体地说,持久计时器可以设置为在特定日期触发或在指定持续时间后触发。持久计时器的最大持续时间没有限制,它们在内部由内部 actor 提醒支持。例如,跟踪服务 30 天免费订阅的工作流可以使用在工作流创建后 30 天触发的持久计时器实现。工作流在等待持久计时器触发时可以安全地从内存中卸载。 + +{{% alert title="注意" color="primary" %}} +工作流创作 SDK 中的一些 API 可能会在内部安排持久计时器以实现内部超时行为。 +{{% /alert %}} + +## 重试策略 + +工作流支持活动和子工作流的持久重试策略。工作流重试策略与[Dapr 弹性策略]({{< ref "resiliency-overview.md" >}})在以下方面是分开的和不同的。 + +- 工作流重试策略由工作流作者在代码中配置,而 Dapr 弹性策略由应用程序操作员在 YAML 中配置。 +- 工作流重试策略是持久的,并在应用程序重启时保持其状态,而 Dapr 弹性策略不是持久的,必须在应用程序重启后重新应用。 +- 工作流重试策略由活动和子工作流中的未处理错误/异常触发,而 Dapr 弹性策略由操作超时和连接故障触发。 + +重试在内部使用持久计时器实现。这意味着工作流在等待重试触发时可以安全地从内存中卸载,从而节省系统资源。这也意味着重试之间的延迟可以任意长,包括分钟、小时甚至天。 + +{{% alert title="注意" color="primary" %}} +重试策略执行的操作会保存到工作流的历史记录中。在工作流已经执行后,必须小心不要更改重试策略的行为。否则,工作流在重放时可能会表现出意外行为。有关更多信息,请参阅[更新工作流代码]({{< ref "#updating-workflow-code" >}})的说明。 +{{% /alert %}} + +可以同时使用工作流重试策略和 Dapr 弹性策略。例如,如果工作流活动使用 Dapr 客户端调用服务,则 Dapr 客户端使用配置的弹性策略。有关示例的更多信息,请参阅[快速入门:服务到服务的弹性]({{< ref "resiliency-serviceinvo-quickstart.md" >}})。但是,如果活动本身因任何原因失败,包括耗尽弹性策略的重试次数,则工作流的弹性策略会启动。 + +{{% alert title="注意" color="primary" %}} +同时使用工作流重试策略和弹性策略可能会导致意外行为。例如,如果工作流活动耗尽其配置的重试策略,工作流引擎仍会根据工作流重试策略重试该活动。这可能导致活动被重试的次数超过预期。 +{{% /alert %}} + +由于工作流重试策略是在代码中配置的,因此具体的开发者体验可能会因工作流 SDK 的版本而异。通常,工作流重试策略可以通过以下参数进行配置。 + +| 参数 | 描述 | +| --- | --- | +| **最大尝试次数** | 执行活动或子工作流的最大次数。 | +| **首次重试间隔** | 第一次重试前的等待时间。 | +| **退避系数** | 用于确定退避增长率的系数。例如,系数为 2 会使每次后续重试的等待时间加倍。 | +| **最大重试间隔** | 每次后续重试前的最大等待时间。 | +| **重试超时** | 重试的总体超时,无论配置的最大尝试次数如何。 | + +## 外部事件 + +有时工作流需要等待由外部系统引发的事件。例如,如果订单处理工作流中的总成本超过某个阈值,审批工作流可能需要人类明确批准订单请求。另一个例子是一个问答游戏编排工作流,它在等待所有参与者提交他们对问答问题的答案时暂停。这些中间执行输入被称为_外部事件_。 + +外部事件具有_名称_和_负载_,并传递给单个工作流实例。工作流可以创建“_等待外部事件_”任务,订阅外部事件并_等待_这些任务以阻止执行,直到接收到事件。然后,工作流可以读取这些事件的负载,并决定采取哪些下一步。外部事件可以串行或并行处理。外部事件可以由其他工作流或工作流代码引发。 + +工作流还可以等待同名的多个外部事件信号,在这种情况下,它们会以先进先出 (FIFO) 的方式分派给相应的工作流任务。如果工作流接收到外部事件信号,但尚未创建“等待外部事件”任务,则事件将保存到工作流的历史记录中,并在工作流请求事件后立即消费。 + +了解有关[外部系统交互]({{< ref "workflow-patterns.md#external-system-interaction" >}})的更多信息。 + +## 工作流后端 + +Dapr 工作流依赖于 Go 的持久任务框架(即 [durabletask-go](https://github.com/microsoft/durabletask-go))作为执行工作流的核心引擎。该引擎设计为支持多种后端实现。例如,[durabletask-go](https://github.com/microsoft/durabletask-go) 仓库包括一个 SQLite 实现,Dapr 仓库包括一个 actor 实现。 + +默认情况下,Dapr 工作流支持 actor 后端,该后端稳定且可扩展。然而,您可以选择 Dapr 工作流中支持的其他后端。例如,[SQLite](https://github.com/microsoft/durabletask-go/tree/main/backend/sqlite)(待定未来版本)可以是本地开发和测试的后端选项。 + +后端实现在很大程度上与您看到的工作流核心引擎或编程模型解耦。后端主要影响: +- 如何存储工作流状态 +- 如何在副本之间协调工作流执行 + +从这个意义上说,它类似于 Dapr 的状态存储抽象,但专为工作流设计。无论使用哪个后端,所有 API 和编程模型功能都是相同的。 + +## 清除 + +工作流状态可以从状态存储中清除,清除其所有历史记录并删除与特定工作流实例相关的所有元数据。清除功能用于已运行到 `COMPLETED`、`FAILED` 或 `TERMINATED` 状态的工作流。 + +在[工作流 API 参考指南]({{< ref workflow_api.md >}})中了解更多信息。 + +## 限制 + +### 工作流确定性和代码限制 + +为了利用工作流重放技术,您的工作流代码需要是确定性的。为了使您的工作流代码确定性,您可能需要绕过一些限制。 + +#### 工作流函数必须调用确定性 API。 +生成随机数、随机 UUID 或当前日期的 API 是_非确定性_的。要解决此限制,您可以: + - 在活动函数中使用这些 API,或 + - (首选)使用 SDK 提供的内置等效 API。例如,每个创作 SDK 都提供了一个以确定性方式检索当前时间的 API。 + +例如,不要这样做: + +{{< tabs ".NET" Java JavaScript Go >}} + +{{% codetab %}} + +```csharp +// 不要这样做! +DateTime currentTime = DateTime.UtcNow; +Guid newIdentifier = Guid.NewGuid(); +string randomString = GetRandomString(); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +// 不要这样做! +Instant currentTime = Instant.now(); +UUID newIdentifier = UUID.randomUUID(); +String randomString = getRandomString(); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +// 不要这样做! +const currentTime = new Date(); +const newIdentifier = uuidv4(); +const randomString = getRandomString(); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +// 不要这样做! +const currentTime = time.Now() +``` + +{{% /codetab %}} + +{{< /tabs >}} + +这样做: + +{{< tabs ".NET" Java JavaScript Go >}} + +{{% codetab %}} + +```csharp +// 这样做!! +DateTime currentTime = context.CurrentUtcDateTime; +Guid newIdentifier = context.NewGuid(); +string randomString = await context.CallActivityAsync("GetRandomString"); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +// 这样做!! +Instant currentTime = context.getCurrentInstant(); +Guid newIdentifier = context.newGuid(); +String randomString = context.callActivity(GetRandomString.class.getName(), String.class).await(); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +// 这样做!! +const currentTime = context.getCurrentUtcDateTime(); +const randomString = yield context.callActivity(getRandomString); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +const currentTime = ctx.CurrentUTCDateTime() +``` + +{{% /codetab %}} + +{{< /tabs >}} + +#### 工作流函数必须仅_间接_与外部状态交互。 +外部数据包括任何不存储在工作流状态中的数据。工作流不得与全局变量、环境变量、文件系统交互或进行网络调用。 + +相反,工作流应通过工作流输入、活动任务和外部事件处理_间接_与外部状态交互。 + +例如,不要这样做: + +{{< tabs ".NET" Java JavaScript Go >}} + +{{% codetab %}} + +```csharp +// 不要这样做! +string configuration = Environment.GetEnvironmentVariable("MY_CONFIGURATION")!; +string data = await new HttpClient().GetStringAsync("https://example.com/api/data"); +``` +{{% /codetab %}} + +{{% codetab %}} + +```java +// 不要这样做! +String configuration = System.getenv("MY_CONFIGURATION"); + +HttpRequest request = HttpRequest.newBuilder().uri(new URI("https://postman-echo.com/post")).GET().build(); +HttpResponse response = HttpClient.newBuilder().build().send(request, HttpResponse.BodyHandlers.ofString()); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +// 不要这样做! +// 访问环境变量(Node.js) +const configuration = process.env.MY_CONFIGURATION; + +fetch('https://postman-echo.com/get') + .then(response => response.text()) + .then(data => { + console.log(data); + }) + .catch(error => { + console.error('Error:', error); + }); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +// 不要这样做! +resp, err := http.Get("http://example.com/api/data") +``` + +{{% /codetab %}} + +{{< /tabs >}} + +这样做: + +{{< tabs ".NET" Java JavaScript Go >}} + +{{% codetab %}} + +```csharp +// 这样做!! +string configuration = workflowInput.Configuration; // 假想的工作流输入参数 +string data = await context.CallActivityAsync("MakeHttpCall", "https://example.com/api/data"); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +// 这样做!! +String configuration = ctx.getInput(InputType.class).getConfiguration(); // 假想的工作流输入参数 +String data = ctx.callActivity(MakeHttpCall.class, "https://example.com/api/data", String.class).await(); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```javascript +// 这样做!! +const configuration = workflowInput.getConfiguration(); // 假想的工作流输入参数 +const data = yield ctx.callActivity(makeHttpCall, "https://example.com/api/data"); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```go +// 这样做!! +err := ctx.CallActivity(MakeHttpCallActivity, workflow.ActivityInput("https://example.com/api/data")).Await(&output) + +``` + +{{% /codetab %}} +{{< /tabs >}} + +#### 工作流函数必须仅在工作流调度线程上执行。 +每种语言 SDK 的实现要求所有工作流函数操作在函数被调度的同一线程(goroutine 等)上运行。工作流函数绝不能: +- 调度后台线程,或 +- 使用调度回调函数在另一个线程上运行的 API。 + +不遵循此规则可能导致未定义的行为。任何后台处理都应委托给活动任务,这些任务可以串行或并行调度运行。 + +例如,不要这样做: + +{{< tabs ".NET" Java JavaScript Go >}} + +{{% codetab %}} + +```csharp +// 不要这样做! +Task t = Task.Run(() => context.CallActivityAsync("DoSomething")); +await context.CreateTimer(5000).ConfigureAwait(false); +``` +{{% /codetab %}} + +{{% codetab %}} + +```java +// 不要这样做! +new Thread(() -> { + ctx.callActivity(DoSomethingActivity.class.getName()).await(); +}).start(); +ctx.createTimer(Duration.ofSeconds(5)).await(); +``` + +{{% /codetab %}} + +{{% codetab %}} + +不要将 JavaScript 工作流声明为 `async`。Node.js 运行时不保证异步函数是确定性的。 + +{{% /codetab %}} + +{{% codetab %}} + +```go +// 不要这样做! +go func() { + err := ctx.CallActivity(DoSomething).Await(nil) +}() +err := ctx.CreateTimer(time.Second).Await(nil) +``` + +{{% /codetab %}} + +{{< /tabs >}} + +这样做: + +{{< tabs ".NET" Java JavaScript Go >}} + +{{% codetab %}} + +```csharp +// 这样做!! +Task t = context.CallActivityAsync("DoSomething"); +await context.CreateTimer(5000).ConfigureAwait(true); +``` + +{{% /codetab %}} + +{{% codetab %}} + +```java +// 这样做!! +ctx.callActivity(DoSomethingActivity.class.getName()).await(); +ctx.createTimer(Duration.ofSeconds(5)).await(); +``` + +{{% /codetab %}} + +{{% codetab %}} + +由于 Node.js 运行时不保证异步函数是确定性的,因此始终将 JavaScript 工作流声明为同步生成器函数。 + +{{% /codetab %}} + +{{% codetab %}} + +```go +// 这样做! +task := ctx.CallActivity(DoSomething) +task.Await(nil) +``` + +{{% /codetab %}} + +{{< /tabs >}} + +### 更新工作流代码 + +确保您对工作流代码所做的更新保持其确定性。以下是可能破坏工作流确定性的代码更新示例: + +- **更改工作流函数签名**: + 更改工作流或活动函数的名称、输入或输出被视为重大更改,必须避免。 + +- **更改工作流任务的数量或顺序**: + 更改工作流任务的数量或顺序会导致工作流实例的历史记录不再与代码匹配,可能导致运行时错误或其他意外行为。 + +要解决这些限制: + +- 不要更新现有工作流代码,而是保持现有工作流代码不变,并创建包含更新的新工作流定义。 +- 上游创建工作流的代码应仅更新以创建新工作流的实例。 +- 保留旧代码以确保现有工作流实例可以继续运行而不受干扰。如果已知旧工作流逻辑的所有实例都已完成,则可以安全地删除旧工作流代码。 + +## 下一步 + +{{< button text="工作流模式 >>" page="workflow-patterns.md" >}} + +## 相关链接 + +- [使用快速入门尝试 Dapr 工作流]({{< ref workflow-quickstart.md >}}) +- [工作流概述]({{< ref workflow-overview.md >}}) +- [工作流 API 参考]({{< ref workflow_api.md >}}) +- 尝试以下示例: + - [Python](https://github.com/dapr/python-sdk/tree/master/examples/demo_workflow) + - [JavaScript](https://github.com/dapr/js-sdk/tree/main/examples/workflow) + - [.NET](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) + - [Java](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/workflows) + - [Go](https://github.com/dapr/go-sdk/tree/main/examples/workflow/README.md) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/workflow-overview.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/workflow-overview.md new file mode 100644 index 000000000..bce215a27 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/workflow-overview.md @@ -0,0 +1,125 @@ +--- +type: docs +title: 工作流概述 +linkTitle: 概述 +weight: 1000 +description: "Dapr 工作流概述" +--- + +Dapr 工作流让开发人员能够可靠地编写业务逻辑和集成。由于 Dapr 工作流是有状态的,它们支持长时间运行和容错应用程序,非常适合编排微服务。Dapr 工作流与其他 Dapr 构建块(如服务调用、发布订阅、状态管理和绑定)无缝协作。 + +Dapr 工作流的耐用性和弹性功能包括: + +- 提供内置的工作流运行时以驱动 Dapr 工作流执行。 +- 提供用于在代码中编写工作流的 SDK,支持多种编程语言。 +- 提供用于管理工作流(启动、查询、暂停/恢复、触发事件、终止、清除)的 HTTP 和 gRPC API。 +- 通过工作流组件与其他工作流运行时集成。 + +显示 Dapr 工作流基础的图示 + +Dapr 工作流可以应用于以下场景: + +- 涉及库存管理、支付系统和运输服务之间编排的订单处理。 +- 协调多个部门和参与者任务的人力资源入职工作流。 +- 在全国餐饮连锁店中协调数字菜单更新的推出。 +- 涉及基于 API 的分类和存储的图像处理工作流。 + +## 功能 + +### 工作流和活动 + +使用 Dapr 工作流,您可以编写活动,然后在工作流中编排这些活动。工作流活动是: + +- 工作流中的基本工作单元 +- 用于调用其他(Dapr)服务、与状态存储交互以及发布订阅代理。 + +[了解更多关于工作流活动的信息。]({{< ref "workflow-features-concepts.md##workflow-activities" >}}) + +### 子工作流 + +除了活动之外,您还可以编写工作流以调度其他工作流作为子工作流。子工作流具有独立于启动它的父工作流的实例 ID、历史记录和状态,除了终止父工作流会终止由其创建的所有子工作流这一事实。子工作流还支持自动重试策略。 + +[了解更多关于子工作流的信息。]({{< ref "workflow-features-concepts.md#child-workflows" >}}) + +### 定时器和提醒 + +与 Dapr actor 相同,您可以为任何时间范围安排类似提醒的持久延迟。 + +[了解更多关于工作流定时器]({{< ref "workflow-features-concepts.md#durable-timers" >}})和[提醒]({{< ref "workflow-architecture.md#reminder-usage-and-execution-guarantees" >}}) + +### 使用 HTTP 调用管理工作流 + +当您使用工作流代码创建应用程序并使用 Dapr 运行它时,您可以调用驻留在应用程序中的特定工作流。每个单独的工作流可以: + +- 通过 POST 请求启动或终止 +- 通过 POST 请求触发以传递命名事件 +- 通过 POST 请求暂停然后恢复 +- 通过 POST 请求从您的状态存储中清除 +- 通过 GET 请求查询工作流状态 + +[了解更多关于如何使用 HTTP 调用管理工作流的信息。]({{< ref workflow_api.md >}}) + +## 工作流模式 + +Dapr 工作流简化了微服务架构中复杂的、有状态的协调需求。以下部分描述了可以从 Dapr 工作流中受益的几种应用程序模式。 + +了解更多关于[不同类型的工作流模式]({{< ref workflow-patterns.md >}}) + +## 工作流 SDK + +Dapr 工作流 _编写 SDK_ 是特定语言的 SDK,包含用于实现工作流逻辑的类型和函数。工作流逻辑存在于您的应用程序中,并由运行在 Dapr sidecar 中的 Dapr 工作流引擎通过 gRPC 流进行编排。 + +### 支持的 SDK + +您可以使用以下 SDK 编写工作流。 + +| 语言栈 | 包 | +| - | - | +| Python | [dapr-ext-workflow](https://github.com/dapr/python-sdk/tree/master/ext/dapr-ext-workflow) | +| JavaScript | [DaprWorkflowClient](https://github.com/dapr/js-sdk/blob/main/src/workflow/client/DaprWorkflowClient.ts) | +| .NET | [Dapr.Workflow](https://www.nuget.org/profiles/dapr.io) | +| Java | [io.dapr.workflows](https://dapr.github.io/java-sdk/io/dapr/workflows/package-summary.html) | +| Go | [workflow](https://github.com/dapr/go-sdk/tree/main/client/workflow.go) | + +## 试用工作流 + +### 快速入门和教程 + +想要测试工作流?通过以下快速入门和教程来查看工作流的实际应用: + +| 快速入门/教程 | 描述 | +| ------------------- | ----------- | +| [工作流快速入门]({{< ref workflow-quickstart.md >}}) | 运行一个包含四个工作流活动的工作流应用程序,查看 Dapr 工作流的实际应用 | +| [工作流 Python SDK 示例](https://github.com/dapr/python-sdk/tree/master/examples/demo_workflow) | 了解如何使用 Python `dapr-ext-workflow` 包创建和调用 Dapr 工作流。 | +| [工作流 JavaScript SDK 示例](https://github.com/dapr/js-sdk/tree/main/examples/workflow) | 了解如何使用 JavaScript SDK 创建和调用 Dapr 工作流。 | +| [工作流 .NET SDK 示例](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) | 了解如何使用 ASP.NET Core web API 创建和调用 Dapr 工作流。 | +| [工作流 Java SDK 示例](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/workflows) | 了解如何使用 Java `io.dapr.workflows` 包创建和调用 Dapr 工作流。 | +| [工作流 Go SDK 示例](https://github.com/dapr/go-sdk/tree/main/examples/workflow/README.md) | 了解如何使用 Go `workflow` 包创建和调用 Dapr 工作流。 | + +### 直接在您的应用中开始使用工作流 + +想要跳过快速入门?没问题。您可以直接在您的应用程序中试用工作流构建块。在[Dapr 安装完成后]({{< ref install-dapr-cli.md >}}),您可以开始使用工作流,从[如何编写工作流]({{< ref howto-author-workflow.md >}})开始。 + +## 限制 + +- **状态存储:** 由于某些数据库选择的底层限制,通常是 NoSQL 数据库,您可能会遇到存储内部状态的限制。例如,CosmosDB 在单个请求中最多只能有 100 个状态的单操作项限制。 + +## 观看演示 + +观看[此视频以了解 Dapr 工作流的概述](https://youtu.be/s1p9MNl4VGo?t=131): + + + +## 下一步 + +{{< button text="工作流功能和概念 >>" page="workflow-features-concepts.md" >}} + +## 相关链接 + +- [工作流 API 参考]({{< ref workflow_api.md >}}) +- 试用完整的 SDK 示例: + - [Python 示例](https://github.com/dapr/python-sdk/tree/master/examples/demo_workflow) + - [JavaScript 示例](https://github.com/dapr/js-sdk/tree/main/examples/workflow) + - [.NET 示例](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) + - [Java 示例](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/workflows) + - [Go 示例](https://github.com/dapr/go-sdk/tree/main/examples/workflow/README.md) diff --git a/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/workflow-patterns.md b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/workflow-patterns.md new file mode 100644 index 000000000..ddd750fac --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/building-blocks/workflow/workflow-patterns.md @@ -0,0 +1,1403 @@ +--- +type: docs +title: 工作流模式 +linkTitle: 工作流模式 +weight: 3000 +description: "编写不同类型的工作流模式" +--- + +Dapr 工作流简化了微服务架构中复杂且有状态的协调需求。以下部分描述了几种可以从 Dapr 工作流中受益的应用程序模式。 + +## 任务链 + +在任务链模式中,工作流中的多个步骤按顺序运行,一个步骤的输出可以作为下一个步骤的输入。任务链工作流通常涉及创建一系列需要对某些数据执行的操作,例如过滤、转换和归约。 + +显示任务链工作流模式如何工作的图示 + +在某些情况下,工作流的步骤可能需要在多个微服务之间进行协调。为了提高可靠性和可扩展性,您还可能使用队列来触发各个步骤。 + +虽然模式简单,但实现中隐藏了许多复杂性。例如: + +- 如果某个微服务长时间不可用,会发生什么? +- 可以自动重试失败的步骤吗? +- 如果不能,如何促进先前完成步骤的回滚(如果适用)? +- 除了实现细节之外,是否有办法可视化工作流,以便其他工程师可以理解它的作用和工作原理? + +Dapr 工作流通过允许您在所选编程语言中将任务链模式简洁地实现为简单函数来解决这些复杂性,如以下示例所示。 + +{{< tabs Python JavaScript ".NET" Java Go >}} + +{{% codetab %}} + + +```python +import dapr.ext.workflow as wf + + +def task_chain_workflow(ctx: wf.DaprWorkflowContext, wf_input: int): + try: + result1 = yield ctx.call_activity(step1, input=wf_input) + result2 = yield ctx.call_activity(step2, input=result1) + result3 = yield ctx.call_activity(step3, input=result2) + except Exception as e: + yield ctx.call_activity(error_handler, input=str(e)) + raise + return [result1, result2, result3] + + +def step1(ctx, activity_input): + print(f'步骤 1: 接收到输入: {activity_input}.') + # 执行一些操作 + return activity_input + 1 + + +def step2(ctx, activity_input): + print(f'步骤 2: 接收到输入: {activity_input}.') + # 执行一些操作 + return activity_input * 2 + + +def step3(ctx, activity_input): + print(f'步骤 3: 接收到输入: {activity_input}.') + # 执行一些操作 + return activity_input ^ 2 + + +def error_handler(ctx, error): + print(f'执行错误处理程序: {error}.') + # 执行一些补偿操作 +``` + +> **注意** 工作流重试策略将在 Python SDK 的未来版本中提供。 + +{{% /codetab %}} + +{{% codetab %}} + + +```javascript +import { DaprWorkflowClient, WorkflowActivityContext, WorkflowContext, WorkflowRuntime, TWorkflow } from "@dapr/dapr"; + +async function start() { + // 更新 gRPC 客户端和工作者以使用本地地址和端口 + const daprHost = "localhost"; + const daprPort = "50001"; + const workflowClient = new DaprWorkflowClient({ + daprHost, + daprPort, + }); + const workflowRuntime = new WorkflowRuntime({ + daprHost, + daprPort, + }); + + const hello = async (_: WorkflowActivityContext, name: string) => { + return `Hello ${name}!`; + }; + + const sequence: TWorkflow = async function* (ctx: WorkflowContext): any { + const cities: string[] = []; + + const result1 = yield ctx.callActivity(hello, "Tokyo"); + cities.push(result1); + const result2 = yield ctx.callActivity(hello, "Seattle"); + cities.push(result2); + const result3 = yield ctx.callActivity(hello, "London"); + cities.push(result3); + + return cities; + }; + + workflowRuntime.registerWorkflow(sequence).registerActivity(hello); + + // 将工作者启动包装在 try-catch 块中以处理启动期间的任何错误 + try { + await workflowRuntime.start(); + console.log("工作流运行时启动成功"); + } catch (error) { + console.error("启动工作流运行时时出错:", error); + } + + // 调度新的编排 + try { + const id = await workflowClient.scheduleNewWorkflow(sequence); + console.log(`编排已调度,ID: ${id}`); + + // 等待编排完成 + const state = await workflowClient.waitForWorkflowCompletion(id, undefined, 30); + + console.log(`编排完成!结果: ${state?.serializedOutput}`); + } catch (error) { + console.error("调度或等待编排时出错:", error); + } + + await workflowRuntime.stop(); + await workflowClient.stop(); + + // 停止 dapr sidecar + process.exit(0); +} + +start().catch((e) => { + console.error(e); + process.exit(1); +}); +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```csharp +// 支持长时间中断的指数退避重试策略 +var retryOptions = new WorkflowTaskOptions +{ + RetryPolicy = new WorkflowRetryPolicy( + firstRetryInterval: TimeSpan.FromMinutes(1), + backoffCoefficient: 2.0, + maxRetryInterval: TimeSpan.FromHours(1), + maxNumberOfAttempts: 10), +}; + +try +{ + var result1 = await context.CallActivityAsync("Step1", wfInput, retryOptions); + var result2 = await context.CallActivityAsync("Step2", result1, retryOptions); + var result3 = await context.CallActivityAsync("Step3", result2, retryOptions); + return string.Join(", ", result4); +} +catch (TaskFailedException) // 任务失败会作为 TaskFailedException 显示 +{ + // 重试过期 - 应用自定义补偿逻辑 + await context.CallActivityAsync("MyCompensation", options: retryOptions); + throw; +} +``` + +> **注意** 在上面的示例中,`"Step1"`、`"Step2"`、`"Step3"` 和 `"MyCompensation"` 代表工作流活动,它们是您代码中实际实现工作流步骤的函数。为了简洁起见,这些活动实现未包含在此示例中。 + +{{% /codetab %}} + +{{% codetab %}} + + +```java +public class ChainWorkflow extends Workflow { + @Override + public WorkflowStub create() { + return ctx -> { + StringBuilder sb = new StringBuilder(); + String wfInput = ctx.getInput(String.class); + String result1 = ctx.callActivity("Step1", wfInput, String.class).await(); + String result2 = ctx.callActivity("Step2", result1, String.class).await(); + String result3 = ctx.callActivity("Step3", result2, String.class).await(); + String result = sb.append(result1).append(',').append(result2).append(',').append(result3).toString(); + ctx.complete(result); + }; + } +} + + class Step1 implements WorkflowActivity { + + @Override + public Object run(WorkflowActivityContext ctx) { + Logger logger = LoggerFactory.getLogger(Step1.class); + logger.info("Starting Activity: " + ctx.getName()); + // Do some work + return null; + } + } + + class Step2 implements WorkflowActivity { + + @Override + public Object run(WorkflowActivityContext ctx) { + Logger logger = LoggerFactory.getLogger(Step2.class); + logger.info("Starting Activity: " + ctx.getName()); + // Do some work + return null; + } + } + + class Step3 implements WorkflowActivity { + + @Override + public Object run(WorkflowActivityContext ctx) { + Logger logger = LoggerFactory.getLogger(Step3.class); + logger.info("Starting Activity: " + ctx.getName()); + // Do some work + return null; + } + } +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```go +func TaskChainWorkflow(ctx *workflow.WorkflowContext) (any, error) { + var input int + if err := ctx.GetInput(&input); err != nil { + return "", err + } + var result1 int + if err := ctx.CallActivity(Step1, workflow.ActivityInput(input)).Await(&result1); err != nil { + return nil, err + } + var result2 int + if err := ctx.CallActivity(Step2, workflow.ActivityInput(input)).Await(&result2); err != nil { + return nil, err + } + var result3 int + if err := ctx.CallActivity(Step3, workflow.ActivityInput(input)).Await(&result3); err != nil { + return nil, err + } + return []int{result1, result2, result3}, nil +} +func Step1(ctx workflow.ActivityContext) (any, error) { + var input int + if err := ctx.GetInput(&input); err != nil { + return "", err + } + fmt.Printf("步骤 1: 接收到输入: %s", input) + return input + 1, nil +} +func Step2(ctx workflow.ActivityContext) (any, error) { + var input int + if err := ctx.GetInput(&input); err != nil { + return "", err + } + fmt.Printf("步骤 2: 接收到输入: %s", input) + return input * 2, nil +} +func Step3(ctx workflow.ActivityContext) (any, error) { + var input int + if err := ctx.GetInput(&input); err != nil { + return "", err + } + fmt.Printf("步骤 3: 接收到输入: %s", input) + return int(math.Pow(float64(input), 2)), nil +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +如您所见,工作流被表达为所选编程语言中的简单语句序列。这使得组织中的任何工程师都可以快速理解端到端的流程,而不必了解端到端的系统架构。 + +在幕后,Dapr 工作流运行时: + +- 负责执行工作流并确保其运行到完成。 +- 自动保存进度。 +- 如果工作流进程本身因任何原因失败,自动从上次完成的步骤恢复工作流。 +- 允许在目标编程语言中自然地表达错误处理,使您可以轻松实现补偿逻辑。 +- 提供内置的重试配置原语,以简化为工作流中的各个步骤配置复杂重试策略的过程。 + +## 扇出/扇入 + +在扇出/扇入设计模式中,您可以在多个工作者上同时执行多个任务,等待它们完成,并对结果进行一些聚合。 + +显示扇出/扇入工作流模式如何工作的图示 + +除了[前一个模式]({{< ref "workflow-patterns.md#task-chaining" >}})中提到的挑战外,在手动实现扇出/扇入模式时还有几个重要问题需要考虑: + +- 如何控制并行度? +- 如何知道何时触发后续聚合步骤? +- 如果并行步骤的数量是动态的怎么办? + +Dapr 工作流提供了一种将扇出/扇入模式表达为简单函数的方法,如以下示例所示: + +{{< tabs Python JavaScript ".NET" Java Go >}} + +{{% codetab %}} + + +```python +import time +from typing import List +import dapr.ext.workflow as wf + + +def batch_processing_workflow(ctx: wf.DaprWorkflowContext, wf_input: int): + # 获取一批 N 个工作项以并行处理 + work_batch = yield ctx.call_activity(get_work_batch, input=wf_input) + + # 调度 N 个并行任务以处理工作项并等待所有任务完成 + parallel_tasks = [ctx.call_activity(process_work_item, input=work_item) for work_item in work_batch] + outputs = yield wf.when_all(parallel_tasks) + + # 聚合结果并将其发送到另一个活动 + total = sum(outputs) + yield ctx.call_activity(process_results, input=total) + + +def get_work_batch(ctx, batch_size: int) -> List[int]: + return [i + 1 for i in range(batch_size)] + + +def process_work_item(ctx, work_item: int) -> int: + print(f'处理工作项: {work_item}.') + time.sleep(5) + result = work_item * 2 + print(f'工作项 {work_item} 已处理. 结果: {result}.') + return result + + +def process_results(ctx, final_result: int): + print(f'最终结果: {final_result}.') +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```javascript +import { + Task, + DaprWorkflowClient, + WorkflowActivityContext, + WorkflowContext, + WorkflowRuntime, + TWorkflow, +} from "@dapr/dapr"; + +// 将整个代码包装在一个立即调用的异步函数中 +async function start() { + // 更新 gRPC 客户端和工作者以使用本地地址和端口 + const daprHost = "localhost"; + const daprPort = "50001"; + const workflowClient = new DaprWorkflowClient({ + daprHost, + daprPort, + }); + const workflowRuntime = new WorkflowRuntime({ + daprHost, + daprPort, + }); + + function getRandomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + async function getWorkItemsActivity(_: WorkflowActivityContext): Promise { + const count: number = getRandomInt(2, 10); + console.log(`生成 ${count} 个工作项...`); + + const workItems: string[] = Array.from({ length: count }, (_, i) => `工作项 ${i}`); + return workItems; + } + + function sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + + async function processWorkItemActivity(context: WorkflowActivityContext, item: string): Promise { + console.log(`处理工作项: ${item}`); + + // 模拟一些需要可变时间的工作 + const sleepTime = Math.random() * 5000; + await sleep(sleepTime); + + // 返回给定工作项的结果,在这种情况下也是一个随机数 + // 有关工作流中随机数的更多信息,请查看 + // https://learn.microsoft.com/azure/azure-functions/durable/durable-functions-code-constraints?tabs=csharp#random-numbers + return Math.floor(Math.random() * 11); + } + + const workflow: TWorkflow = async function* (ctx: WorkflowContext): any { + const tasks: Task[] = []; + const workItems = yield ctx.callActivity(getWorkItemsActivity); + for (const workItem of workItems) { + tasks.push(ctx.callActivity(processWorkItemActivity, workItem)); + } + const results: number[] = yield ctx.whenAll(tasks); + const sum: number = results.reduce((accumulator, currentValue) => accumulator + currentValue, 0); + return sum; + }; + + workflowRuntime.registerWorkflow(workflow); + workflowRuntime.registerActivity(getWorkItemsActivity); + workflowRuntime.registerActivity(processWorkItemActivity); + + // 将工作者启动包装在 try-catch 块中以处理启动期间的任何错误 + try { + await workflowRuntime.start(); + console.log("工作者启动成功"); + } catch (error) { + console.error("启动工作者时出错:", error); + } + + // 调度新的编排 + try { + const id = await workflowClient.scheduleNewWorkflow(workflow); + console.log(`编排已调度,ID: ${id}`); + + // 等待编排完成 + const state = await workflowClient.waitForWorkflowCompletion(id, undefined, 30); + + console.log(`编排完成!结果: ${state?.serializedOutput}`); + } catch (error) { + console.error("调度或等待编排时出错:", error); + } + + // 停止工作者和客户端 + await workflowRuntime.stop(); + await workflowClient.stop(); + + // 停止 dapr sidecar + process.exit(0); +} + +start().catch((e) => { + console.error(e); + process.exit(1); +}); +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```csharp +// 获取要并行处理的 N 个工作项的列表。 +object[] workBatch = await context.CallActivityAsync("GetWorkBatch", null); + +// 调度并行任务,但不等待它们完成。 +var parallelTasks = new List>(workBatch.Length); +for (int i = 0; i < workBatch.Length; i++) +{ + Task task = context.CallActivityAsync("ProcessWorkItem", workBatch[i]); + parallelTasks.Add(task); +} + +// 一切都已调度。在此处等待,直到所有并行任务完成。 +await Task.WhenAll(parallelTasks); + +// 聚合所有 N 个输出并发布结果。 +int sum = parallelTasks.Sum(t => t.Result); +await context.CallActivityAsync("PostResults", sum); +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```java +public class FaninoutWorkflow extends Workflow { + @Override + public WorkflowStub create() { + return ctx -> { + // 获取要并行处理的 N 个工作项的列表。 + Object[] workBatch = ctx.callActivity("GetWorkBatch", Object[].class).await(); + // 调度并行任务,但不等待它们完成。 + List> tasks = Arrays.stream(workBatch) + .map(workItem -> ctx.callActivity("ProcessWorkItem", workItem, int.class)) + .collect(Collectors.toList()); + // 一切都已调度。在此处等待,直到所有并行任务完成。 + List results = ctx.allOf(tasks).await(); + // 聚合所有 N 个输出并发布结果。 + int sum = results.stream().mapToInt(Integer::intValue).sum(); + ctx.complete(sum); + }; + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```go +func BatchProcessingWorkflow(ctx *workflow.WorkflowContext) (any, error) { + var input int + if err := ctx.GetInput(&input); err != nil { + return 0, err + } + var workBatch []int + if err := ctx.CallActivity(GetWorkBatch, workflow.ActivityInput(input)).Await(&workBatch); err != nil { + return 0, err + } + parallelTasks := workflow.NewTaskSlice(len(workBatch)) + for i, workItem := range workBatch { + parallelTasks[i] = ctx.CallActivity(ProcessWorkItem, workflow.ActivityInput(workItem)) + } + var outputs int + for _, task := range parallelTasks { + var output int + err := task.Await(&output) + if err == nil { + outputs += output + } else { + return 0, err + } + } + if err := ctx.CallActivity(ProcessResults, workflow.ActivityInput(outputs)).Await(nil); err != nil { + return 0, err + } + return 0, nil +} +func GetWorkBatch(ctx workflow.ActivityContext) (any, error) { + var batchSize int + if err := ctx.GetInput(&batchSize); err != nil { + return 0, err + } + batch := make([]int, batchSize) + for i := 0; i < batchSize; i++ { + batch[i] = i + } + return batch, nil +} +func ProcessWorkItem(ctx workflow.ActivityContext) (any, error) { + var workItem int + if err := ctx.GetInput(&workItem); err != nil { + return 0, err + } + fmt.Printf("处理工作项: %d\n", workItem) + time.Sleep(time.Second * 5) + result := workItem * 2 + fmt.Printf("工作项 %d 已处理. 结果: %d\n", workItem, result) + return result, nil +} +func ProcessResults(ctx workflow.ActivityContext) (any, error) { + var finalResult int + if err := ctx.GetInput(&finalResult); err != nil { + return 0, err + } + fmt.Printf("最终结果: %d\n", finalResult) + return finalResult, nil +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +此示例的关键要点是: + +- 扇出/扇入模式可以使用普通编程构造表达为简单函数 +- 并行任务的数量可以是静态的或动态的 +- 工作流本身能够聚合并行执行的结果 + +此外,工作流的执行是持久的。如果一个工作流启动了 100 个并行任务执行,并且只有 40 个在进程崩溃前完成,工作流会自动重新启动并仅调度剩余的 60 个任务。 + +可以进一步使用简单的、特定语言的构造来限制并发度。下面的示例代码说明了如何将扇出的程度限制为仅 5 个并发活动执行: + +{{< tabs ".NET" >}} + +{{% codetab %}} + +```csharp + +// 回顾之前的示例... +// 获取要并行处理的 N 个工作项的列表。 +object[] workBatch = await context.CallActivityAsync("GetWorkBatch", null); + +const int MaxParallelism = 5; +var results = new List(); +var inFlightTasks = new HashSet>(); +foreach(var workItem in workBatch) +{ + if (inFlightTasks.Count >= MaxParallelism) + { + var finishedTask = await Task.WhenAny(inFlightTasks); + results.Add(finishedTask.Result); + inFlightTasks.Remove(finishedTask); + } + + inFlightTasks.Add(context.CallActivityAsync("ProcessWorkItem", workItem)); +} +results.AddRange(await Task.WhenAll(inFlightTasks)); + +var sum = results.Sum(t => t); +await context.CallActivityAsync("PostResults", sum); +``` + +{{% /codetab %}} + +{{< /tabs >}} + +以这种方式限制并发度对于限制对共享资源的争用可能很有用。例如,如果活动需要调用具有自身并发限制的外部资源(如数据库或外部 API),则确保不超过指定数量的活动同时调用该资源可能很有用。 + +## 异步 HTTP API + +异步 HTTP API 通常使用[异步请求-回复模式](https://learn.microsoft.com/azure/architecture/patterns/async-request-reply)实现。传统上实现此模式涉及以下步骤: + +1. 客户端向 HTTP API 端点(_启动 API_)发送请求 +1. _启动 API_ 将消息写入后端队列,从而触发长时间运行操作的开始 +1. 在调度后端操作后,_启动 API_ 立即向客户端返回 HTTP 202 响应,其中包含可用于轮询状态的标识符 +1. _状态 API_ 查询包含长时间运行操作状态的数据库 +1. 客户端重复轮询 _状态 API_,直到某个超时到期或收到“完成”响应 + +以下图示说明了端到端流程。 + +显示异步请求响应模式如何工作的图示 + +实现异步请求-回复模式的挑战在于它涉及使用多个 API 和状态存储。它还涉及正确实现协议,以便客户端知道如何自动轮询状态并知道操作何时完成。 + +Dapr 工作流 HTTP API 开箱即支持异步请求-回复模式,无需编写任何代码或进行任何状态管理。 + +以下 `curl` 命令说明了工作流 API 如何支持此模式。 + +```bash +curl -X POST http://localhost:3500/v1.0/workflows/dapr/OrderProcessingWorkflow/start?instanceID=12345678 -d '{"Name":"Paperclips","Quantity":1,"TotalCost":9.95}' +``` + +上一个命令将导致以下响应 JSON: + +```json +{"instanceID":"12345678"} +``` + +HTTP 客户端然后可以使用工作流实例 ID 构建状态查询 URL,并反复轮询,直到在负载中看到“COMPLETE”、“FAILURE”或“TERMINATED”状态。 + +```bash +curl http://localhost:3500/v1.0/workflows/dapr/12345678 +``` + +以下是进行中的工作流状态可能的样子。 + +```json +{ + "instanceID": "12345678", + "workflowName": "OrderProcessingWorkflow", + "createdAt": "2023-05-03T23:22:11.143069826Z", + "lastUpdatedAt": "2023-05-03T23:22:22.460025267Z", + "runtimeStatus": "RUNNING", + "properties": { + "dapr.workflow.custom_status": "", + "dapr.workflow.input": "{\"Name\":\"Paperclips\",\"Quantity\":1,\"TotalCost\":9.95}" + } +} +``` + +如上例所示,工作流的运行时状态为 `RUNNING`,这让客户端知道它应该继续轮询。 + +如果工作流已完成,状态可能如下所示。 + +```json +{ + "instanceID": "12345678", + "workflowName": "OrderProcessingWorkflow", + "createdAt": "2023-05-03T23:30:11.381146313Z", + "lastUpdatedAt": "2023-05-03T23:30:52.923870615Z", + "runtimeStatus": "COMPLETED", + "properties": { + "dapr.workflow.custom_status": "", + "dapr.workflow.input": "{\"Name\":\"Paperclips\",\"Quantity\":1,\"TotalCost\":9.95}", + "dapr.workflow.output": "{\"Processed\":true}" + } +} +``` + +如上例所示,工作流的运行时状态现在为 `COMPLETED`,这意味着客户端可以停止轮询更新。 + +## 监控 + +监控模式是一个通常包括以下步骤的重复过程: + +1. 检查系统状态 +1. 根据该状态采取某些行动 - 例如发送通知 +1. 休眠一段时间 +1. 重复 + +下图提供了此模式的粗略说明。 + +显示监控模式如何工作的图示 + +根据业务需求,可能只有一个监控器,也可能有多个监控器,每个业务实体(例如股票)一个。此外,休眠时间可能需要根据情况进行更改。这些要求使得使用基于 cron 的调度系统不切实际。 + +Dapr 工作流通过允许您实现_永恒工作流_本地支持此模式。Dapr 工作流公开了一个 _continue-as-new_ API,工作流作者可以使用该 API 从头开始使用新输入重新启动工作流函数,而不是编写无限循环([这是一种反模式]({{< ref "workflow-features-concepts.md#infinite-loops-and-eternal-workflows" >}}))。 + +{{< tabs Python JavaScript ".NET" Java Go >}} + +{{% codetab %}} + + +```python +from dataclasses import dataclass +from datetime import timedelta +import random +import dapr.ext.workflow as wf + + +@dataclass +class JobStatus: + job_id: str + is_healthy: bool + + +def status_monitor_workflow(ctx: wf.DaprWorkflowContext, job: JobStatus): + # 轮询与此 job 关联的状态端点 + status = yield ctx.call_activity(check_status, input=job) + if not ctx.is_replaying: + print(f"Job '{job.job_id}' is {status}.") + + if status == "healthy": + job.is_healthy = True + next_sleep_interval = 60 # 在健康状态下检查频率较低 + else: + if job.is_healthy: + job.is_healthy = False + ctx.call_activity(send_alert, input=f"Job '{job.job_id}' is unhealthy!") + next_sleep_interval = 5 # 在不健康状态下检查频率较高 + + yield ctx.create_timer(fire_at=ctx.current_utc_datetime + timedelta(minutes=next_sleep_interval)) + + # 使用新的 JobStatus 输入从头开始重新启动 + ctx.continue_as_new(job) + + +def check_status(ctx, _) -> str: + return random.choice(["healthy", "unhealthy"]) + + +def send_alert(ctx, message: str): + print(f'*** Alert: {message}') +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```javascript +const statusMonitorWorkflow: TWorkflow = async function* (ctx: WorkflowContext): any { + let duration; + const status = yield ctx.callActivity(checkStatusActivity); + if (status === "healthy") { + // 在健康状态下检查频率较低 + // 设置持续时间为 1 小时 + duration = 60 * 60; + } else { + yield ctx.callActivity(alertActivity, "job unhealthy"); + // 在不健康状态下检查频率较高 + // 设置持续时间为 5 分钟 + duration = 5 * 60; + } + + // 将工作流置于休眠状态,直到确定的时间 + ctx.createTimer(duration); + + // 使用更新的状态从头开始重新启动 + ctx.continueAsNew(); + }; +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```csharp +public override async Task RunAsync(WorkflowContext context, MyEntityState myEntityState) +{ + TimeSpan nextSleepInterval; + + var status = await context.CallActivityAsync("GetStatus"); + if (status == "healthy") + { + myEntityState.IsHealthy = true; + + // 在健康状态下检查频率较低 + nextSleepInterval = TimeSpan.FromMinutes(60); + } + else + { + if (myEntityState.IsHealthy) + { + myEntityState.IsHealthy = false; + await context.CallActivityAsync("SendAlert", myEntityState); + } + + // 在不健康状态下检查频率较高 + nextSleepInterval = TimeSpan.FromMinutes(5); + } + + // 将工作流置于休眠状态,直到确定的时间 + await context.CreateTimer(nextSleepInterval); + + // 使用更新的状态从头开始重新启动 + context.ContinueAsNew(myEntityState); + return null; +} +``` + +> 此示例假设您有一个预定义的 `MyEntityState` 类,其中包含一个布尔 `IsHealthy` 属性。 + +{{% /codetab %}} + +{{% codetab %}} + + +```java +public class MonitorWorkflow extends Workflow { + + @Override + public WorkflowStub create() { + return ctx -> { + + Duration nextSleepInterval; + + var status = ctx.callActivity(DemoWorkflowStatusActivity.class.getName(), DemoStatusActivityOutput.class).await(); + var isHealthy = status.getIsHealthy(); + + if (isHealthy) { + // 在健康状态下检查频率较低 + nextSleepInterval = Duration.ofMinutes(60); + } else { + + ctx.callActivity(DemoWorkflowAlertActivity.class.getName()).await(); + + // 在不健康状态下检查频率较高 + nextSleepInterval = Duration.ofMinutes(5); + } + + // 将工作流置于休眠状态,直到确定的时间 + try { + ctx.createTimer(nextSleepInterval); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + // 使用更新的状态从头开始重新启动 + ctx.continueAsNew(); + } + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```go +type JobStatus struct { + JobID string `json:"job_id"` + IsHealthy bool `json:"is_healthy"` +} +func StatusMonitorWorkflow(ctx *workflow.WorkflowContext) (any, error) { + var sleepInterval time.Duration + var job JobStatus + if err := ctx.GetInput(&job); err != nil { + return "", err + } + var status string + if err := ctx.CallActivity(CheckStatus, workflow.ActivityInput(job)).Await(&status); err != nil { + return "", err + } + if status == "healthy" { + job.IsHealthy = true + sleepInterval = time.Minutes * 60 + } else { + if job.IsHealthy { + job.IsHealthy = false + err := ctx.CallActivity(SendAlert, workflow.ActivityInput(fmt.Sprintf("Job '%s' is unhealthy!", job.JobID))).Await(nil) + if err != nil { + return "", err + } + } + sleepInterval = time.Minutes * 5 + } + if err := ctx.CreateTimer(sleepInterval).Await(nil); err != nil { + return "", err + } + ctx.ContinueAsNew(job, false) + return "", nil +} +func CheckStatus(ctx workflow.ActivityContext) (any, error) { + statuses := []string{"healthy", "unhealthy"} + return statuses[rand.Intn(1)], nil +} +func SendAlert(ctx workflow.ActivityContext) (any, error) { + var message string + if err := ctx.GetInput(&message); err != nil { + return "", err + } + fmt.Printf("*** Alert: %s", message) + return "", nil +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +实现监控模式的工作流可以永远循环,也可以通过不调用 _continue-as-new_ 来优雅地终止自身。 + +{{% alert title="注意" color="primary" %}} +此模式也可以使用 actor 和提醒来表达。不同之处在于此工作流被表达为具有输入和状态存储在局部变量中的单个函数。如果需要,工作流还可以执行具有更强可靠性保证的操作序列。 +{{% /alert %}} + +## 外部系统交互 + +在某些情况下,工作流可能需要暂停并等待外部系统执行某些操作。例如,工作流可能需要暂停并等待接收到付款。在这种情况下,支付系统可能会在收到付款时将事件发布到 pub/sub 主题,并且该主题上的侦听器可以使用[触发事件工作流 API]({{< ref "howto-manage-workflow.md#raise-an-event" >}})向工作流触发事件。 + +另一个非常常见的场景是工作流需要暂停并等待人类,例如在批准采购订单时。Dapr 工作流通过[外部事件]({{< ref "workflow-features-concepts.md#external-events" >}})功能支持此事件模式。 + +以下是涉及人类的采购订单工作流示例: + +1. 收到采购订单时触发工作流。 +1. 工作流中的规则确定需要人类执行某些操作。例如,采购订单成本超过某个自动批准阈值。 +1. 工作流发送请求人类操作的通知。例如,它向指定的审批人发送带有批准链接的电子邮件。 +1. 工作流暂停并等待人类通过点击链接批准或拒绝订单。 +1. 如果在指定时间内未收到批准,工作流将恢复并执行某些补偿逻辑,例如取消订单。 + +下图说明了此流程。 + +显示外部系统交互模式如何与人类交互的图示 + +以下示例代码显示了如何使用 Dapr 工作流实现此模式。 + +{{< tabs Python JavaScript ".NET" Java Go >}} + +{{% codetab %}} + + +```python +from dataclasses import dataclass +from datetime import timedelta +import dapr.ext.workflow as wf + + +@dataclass +class Order: + cost: float + product: str + quantity: int + + def __str__(self): + return f'{self.product} ({self.quantity})' + + +@dataclass +class Approval: + approver: str + + @staticmethod + def from_dict(dict): + return Approval(**dict) + + +def purchase_order_workflow(ctx: wf.DaprWorkflowContext, order: Order): + # 低于 $1000 的订单自动批准 + if order.cost < 1000: + return "Auto-approved" + + # $1000 或以上的订单需要经理批准 + yield ctx.call_activity(send_approval_request, input=order) + + # 必须在 24 小时内收到批准,否则将被取消。 + approval_event = ctx.wait_for_external_event("approval_received") + timeout_event = ctx.create_timer(timedelta(hours=24)) + winner = yield wf.when_any([approval_event, timeout_event]) + if winner == timeout_event: + return "Cancelled" + + # 订单已获批准 + yield ctx.call_activity(place_order, input=order) + approval_details = Approval.from_dict(approval_event.get_result()) + return f"Approved by '{approval_details.approver}'" + + +def send_approval_request(_, order: Order) -> None: + print(f'*** 发送审批请求: {order}') + + +def place_order(_, order: Order) -> None: + print(f'*** 下订单: {order}') +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```javascript +import { + Task, + DaprWorkflowClient, + WorkflowActivityContext, + WorkflowContext, + WorkflowRuntime, + TWorkflow, +} from "@dapr/dapr"; +import * as readlineSync from "readline-sync"; + +// 将整个代码包装在一个立即调用的异步函数中 +async function start() { + class Order { + cost: number; + product: string; + quantity: number; + constructor(cost: number, product: string, quantity: number) { + this.cost = cost; + this.product = product; + this.quantity = quantity; + } + } + + function sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); + } + + // 更新 gRPC 客户端和工作者以使用本地地址和端口 + const daprHost = "localhost"; + const daprPort = "50001"; + const workflowClient = new DaprWorkflowClient({ + daprHost, + daprPort, + }); + const workflowRuntime = new WorkflowRuntime({ + daprHost, + daprPort, + }); + + // 发送审批请求给经理的活动函数 + const sendApprovalRequest = async (_: WorkflowActivityContext, order: Order) => { + // 模拟一些需要时间的工作 + await sleep(3000); + console.log(`发送审批请求: ${order.product}`); + }; + + // 下订单的活动函数 + const placeOrder = async (_: WorkflowActivityContext, order: Order) => { + console.log(`下订单: ${order.product}`); + }; + + // 表示采购订单工作流的编排函数 + const purchaseOrderWorkflow: TWorkflow = async function* (ctx: WorkflowContext, order: Order): any { + // 低于 $1000 的订单自动批准 + if (order.cost < 1000) { + return "Auto-approved"; + } + + // $1000 或以上的订单需要经理批准 + yield ctx.callActivity(sendApprovalRequest, order); + + // 必须在 24 小时内收到批准,否则将被取消。 + const tasks: Task[] = []; + const approvalEvent = ctx.waitForExternalEvent("approval_received"); + const timeoutEvent = ctx.createTimer(24 * 60 * 60); + tasks.push(approvalEvent); + tasks.push(timeoutEvent); + const winner = ctx.whenAny(tasks); + + if (winner == timeoutEvent) { + return "Cancelled"; + } + + yield ctx.callActivity(placeOrder, order); + const approvalDetails = approvalEvent.getResult(); + return `Approved by ${approvalDetails.approver}`; + }; + + workflowRuntime + .registerWorkflow(purchaseOrderWorkflow) + .registerActivity(sendApprovalRequest) + .registerActivity(placeOrder); + + // 将工作者启动包装在 try-catch 块中以处理启动期间的任何错误 + try { + await workflowRuntime.start(); + console.log("工作者启动成功"); + } catch (error) { + console.error("启动工作者时出错:", error); + } + + // 调度新的编排 + try { + const cost = readlineSync.questionInt("输入订单金额:"); + const approver = readlineSync.question("输入审批人:"); + const timeout = readlineSync.questionInt("输入订单超时时间(秒):"); + const order = new Order(cost, "MyProduct", 1); + const id = await workflowClient.scheduleNewWorkflow(purchaseOrderWorkflow, order); + console.log(`编排已调度,ID: ${id}`); + + // 异步提示批准 + promptForApproval(approver, workflowClient, id); + + // 等待编排完成 + const state = await workflowClient.waitForWorkflowCompletion(id, undefined, timeout + 2); + + console.log(`编排完成!结果: ${state?.serializedOutput}`); + } catch (error) { + console.error("调度或等待编排时出错:", error); + } + + // 停止工作者和客户端 + await workflowRuntime.stop(); + await workflowClient.stop(); + + // 停止 dapr sidecar + process.exit(0); +} + +async function promptForApproval(approver: string, workflowClient: DaprWorkflowClient, id: string) { + if (readlineSync.keyInYN("按 [Y] 批准订单... Y/是, N/否")) { + const approvalEvent = { approver: approver }; + await workflowClient.raiseEvent(id, "approval_received", approvalEvent); + } else { + return "订单被拒绝"; + } +} + +start().catch((e) => { + console.error(e); + process.exit(1); +}); +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```csharp +public override async Task RunAsync(WorkflowContext context, OrderPayload order) +{ + // ...(其他步骤)... + + // 需要对超过某个阈值的订单进行批准 + if (order.TotalCost > OrderApprovalThreshold) + { + try + { + // 请求人类批准此订单 + await context.CallActivityAsync(nameof(RequestApprovalActivity), order); + + // 暂停并等待人类批准订单 + ApprovalResult approvalResult = await context.WaitForExternalEventAsync( + eventName: "ManagerApproval", + timeout: TimeSpan.FromDays(3)); + if (approvalResult == ApprovalResult.Rejected) + { + // 订单被拒绝,在此结束工作流 + return new OrderResult(Processed: false); + } + } + catch (TaskCanceledException) + { + // 批准超时会导致自动取消订单 + return new OrderResult(Processed: false); + } + } + + // ...(其他步骤)... + + // 以成功结果结束工作流 + return new OrderResult(Processed: true); +} +``` + +> **注意** 在上面的示例中,`RequestApprovalActivity` 是要调用的工作流活动的名称,`ApprovalResult` 是由工作流应用程序定义的枚举。为了简洁起见,这些定义未包含在示例代码中。 + +{{% /codetab %}} + +{{% codetab %}} + + +```java +public class ExternalSystemInteractionWorkflow extends Workflow { + @Override + public WorkflowStub create() { + return ctx -> { + // ...其他步骤... + Integer orderCost = ctx.getInput(int.class); + // 需要对超过某个阈值的订单进行批准 + if (orderCost > ORDER_APPROVAL_THRESHOLD) { + try { + // 请求人类批准此订单 + ctx.callActivity("RequestApprovalActivity", orderCost, Void.class).await(); + // 暂停并等待人类批准订单 + boolean approved = ctx.waitForExternalEvent("ManagerApproval", Duration.ofDays(3), boolean.class).await(); + if (!approved) { + // 订单被拒绝,在此结束工作流 + ctx.complete("Process reject"); + } + } catch (TaskCanceledException e) { + // 批准超时会导致自动取消订单 + ctx.complete("Process cancel"); + } + } + // ...其他步骤... + + // 以成功结果结束工作流 + ctx.complete("Process approved"); + }; + } +} +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```go +type Order struct { + Cost float64 `json:"cost"` + Product string `json:"product"` + Quantity int `json:"quantity"` +} +type Approval struct { + Approver string `json:"approver"` +} +func PurchaseOrderWorkflow(ctx *workflow.WorkflowContext) (any, error) { + var order Order + if err := ctx.GetInput(&order); err != nil { + return "", err + } + // 低于 $1000 的订单自动批准 + if order.Cost < 1000 { + return "Auto-approved", nil + } + // $1000 或以上的订单需要经理批准 + if err := ctx.CallActivity(SendApprovalRequest, workflow.ActivityInput(order)).Await(nil); err != nil { + return "", err + } + // 必须在 24 小时内收到批准,否则将被取消 + var approval Approval + if err := ctx.WaitForExternalEvent("approval_received", time.Hour*24).Await(&approval); err != nil { + // 假设发生了超时 - 无论如何;一个错误。 + return "error/cancelled", err + } + // 订单已获批准 + if err := ctx.CallActivity(PlaceOrder, workflow.ActivityInput(order)).Await(nil); err != nil { + return "", err + } + return fmt.Sprintf("Approved by %s", approval.Approver), nil +} +func SendApprovalRequest(ctx workflow.ActivityContext) (any, error) { + var order Order + if err := ctx.GetInput(&order); err != nil { + return "", err + } + fmt.Printf("*** 发送审批请求: %v\n", order) + return "", nil +} +func PlaceOrder(ctx workflow.ActivityContext) (any, error) { + var order Order + if err := ctx.GetInput(&order); err != nil { + return "", err + } + fmt.Printf("*** 下订单: %v", order) + return "", nil +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +恢复工作流执行的事件的代码在工作流之外。可以使用[触发事件]({{< ref "howto-manage-workflow.md#raise-an-event" >}})工作流管理 API 将工作流事件传递给等待的工作流实例,如以下示例所示: + +{{< tabs Python JavaScript ".NET" Java Go >}} + +{{% codetab %}} + + +```python +from dapr.clients import DaprClient +from dataclasses import asdict + +with DaprClient() as d: + d.raise_workflow_event( + instance_id=instance_id, + workflow_component="dapr", + event_name="approval_received", + event_data=asdict(Approval("Jane Doe"))) +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```javascript +import { DaprClient } from "@dapr/dapr"; + + public async raiseEvent(workflowInstanceId: string, eventName: string, eventPayload?: any) { + this._innerClient.raiseOrchestrationEvent(workflowInstanceId, eventName, eventPayload); + } +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```csharp +// 向等待的工作流触发工作流事件 +await daprClient.RaiseWorkflowEventAsync( + instanceId: orderId, + workflowComponent: "dapr", + eventName: "ManagerApproval", + eventData: ApprovalResult.Approved); +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```java +System.out.println("**SendExternalMessage: RestartEvent**"); +client.raiseEvent(restartingInstanceId, "RestartEvent", "RestartEventPayload"); +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```go +func raiseEvent() { + daprClient, err := client.NewClient() + if err != nil { + log.Fatalf("failed to initialize the client") + } + err = daprClient.RaiseEventWorkflow(context.Background(), &client.RaiseEventWorkflowRequest{ + InstanceID: "instance_id", + WorkflowComponent: "dapr", + EventName: "approval_received", + EventData: Approval{ + Approver: "Jane Doe", + }, + }) + if err != nil { + log.Fatalf("failed to raise event on workflow") + } + log.Println("raised an event on specified workflow") +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +外部事件不必由人类直接触发。它们也可以由其他系统触发。例如,工作流可能需要暂停并等待接收到付款。在这种情况下,支付系统可能会在收到付款时将事件发布到 pub/sub 主题,并且该主题上的侦听器可以使用触发事件工作流 API 向工作流触发事件。 + +## 下一步 + +{{< button text="工作流架构 >>" page="workflow-architecture.md" >}} + +## 相关链接 + +- [使用快速入门尝试 Dapr 工作流]({{< ref workflow-quickstart.md >}}) +- [工作流概述]({{< ref workflow-overview.md >}}) +- [工作流 API 参考]({{< ref workflow_api.md >}}) +- 尝试以下示例: + - [Python](https://github.com/dapr/python-sdk/tree/master/examples/demo_workflow) + - [JavaScript](https://github.com/dapr/js-sdk/tree/main/examples/workflow) + - [.NET](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) + - [Java](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/workflows) + - [Go](https://github.com/dapr/go-sdk/tree/main/examples/workflow/README.md) diff --git a/src/translated_content/zh_CN/docs/developing-applications/debugging/_index.md b/src/translated_content/zh_CN/docs/developing-applications/debugging/_index.md new file mode 100644 index 000000000..a5f6b2129 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/debugging/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "调试Dapr应用和控制面板" +linkTitle: "调试" +weight: 60 +description: "指导如何调试Dapr应用和控制面板的指南" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/debugging/bridge-to-kubernetes.md b/src/translated_content/zh_CN/docs/developing-applications/debugging/bridge-to-kubernetes.md new file mode 100644 index 000000000..003bfbdc3 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/debugging/bridge-to-kubernetes.md @@ -0,0 +1,28 @@ +--- +type: docs +title: "Bridge to Kubernetes 对 Dapr 服务的支持" +linkTitle: "Bridge to Kubernetes" +weight: 300 +description: "在本地调试 Dapr 应用程序,同时保持与 Kubernetes 集群的连接" +--- + +Bridge to Kubernetes 允许您在开发计算机上运行和调试代码,同时保持与 Kubernetes 集群中其他应用程序或服务的连接。这种调试方式通常被称为*本地隧道调试*。 + +{{< button text="了解更多 Bridge to Kubernetes 信息" link="https://aka.ms/bridge-vscode-dapr" >}} + +## 调试 Dapr 应用程序 + +Bridge to Kubernetes 支持在您的计算机上调试 Dapr 应用程序,同时与 Kubernetes 集群中的服务和应用程序进行交互。以下示例展示了 Bridge to Kubernetes 如何帮助开发人员调试[分布式计算器快速入门](https://github.com/dapr/quickstarts/tree/master/tutorials/distributed-calculator): + +
+ +
+ +{{% alert title="隔离模式" color="warning" %}} +[隔离模式](https://aka.ms/bridge-isolation-vscode-dapr) 目前不支持 Dapr 应用程序。请确保启动 Bridge to Kubernetes 模式时不使用隔离模式。 +{{% /alert %}} + +## 进一步阅读 + +- [Bridge to Kubernetes 文档](https://code.visualstudio.com/docs/containers/bridge-to-kubernetes) +- [VSCode 集成]({{< ref vscode >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/debugging/debug-k8s/_index.md b/src/translated_content/zh_CN/docs/developing-applications/debugging/debug-k8s/_index.md new file mode 100644 index 000000000..a740e7956 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/debugging/debug-k8s/_index.md @@ -0,0 +1,38 @@ +--- +type: docs +title: "在 Kubernetes 环境中调试 Dapr" +linkTitle: "Kubernetes" +weight: 200 +description: "如何在 Kubernetes 集群中调试 Dapr" +--- +``` + +在 Kubernetes 集群中调试 Dapr 是确保应用程序正常运行的关键。通过调试,开发者可以识别并解决 Dapr 组件之间的通信问题、actor 的状态管理问题,以及其他与 Dapr 集成相关的挑战。 + +在开始调试之前,请确保您的 Kubernetes 集群已正确配置,并且 Dapr 已成功部署。您可以使用以下命令检查 Dapr 的状态: + +```bash +kubectl get pods -n dapr-system +``` + +这将列出所有正在运行的 Dapr 组件的 pod。确保所有 pod 都处于 `Running` 状态。 + +### 常见调试步骤 + +1. **检查 Dapr sidecar 日志**:Dapr sidecar 是每个应用程序 pod 中的重要组件。通过查看 sidecar 的日志,您可以获取有关服务调用、发布订阅、绑定等的详细信息。 + + ```bash + kubectl logs daprd + ``` + +2. **验证配置和密钥**:确保您的 Dapr 配置和 Kubernetes 密钥正确无误。错误的配置可能导致服务无法正常工作。 + +3. **测试服务调用**:使用 Dapr CLI 工具测试服务调用,以确保服务之间的通信正常。 + + ```bash + dapr invoke --app-id --method + ``` + +4. **监控状态存储**:检查 actor 的状态存储,确保数据持久化和检索正常。 + +通过这些步骤,您可以有效地调试和优化 Dapr 在 Kubernetes 集群中的运行 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/debugging/debug-k8s/debug-dapr-services.md b/src/translated_content/zh_CN/docs/developing-applications/debugging/debug-k8s/debug-dapr-services.md new file mode 100644 index 000000000..b604762a2 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/debugging/debug-k8s/debug-dapr-services.md @@ -0,0 +1,114 @@ +--- +type: docs +title: "在 Kubernetes 上调试 Dapr 控制平面" +linkTitle: "Dapr 控制平面" +weight: 1000 +description: "如何在 Kubernetes 集群上调试 Dapr 控制平面" +--- + +## 概述 + +有时我们需要了解 Dapr 控制平面(即 Kubernetes 服务)的运行情况,包括 `dapr-sidecar-injector`、`dapr-operator`、`dapr-placement` 和 `dapr-sentry`,特别是在诊断 Dapr 应用程序时,想知道 Dapr 本身是否存在问题。此外,您可能正在为 Kubernetes 上的 Dapr 开发新功能,并希望调试您的代码。 + +本指南将介绍如何使用 Dapr 调试二进制文件来调试 Kubernetes 集群上的 Dapr 服务。 + +## 调试 Dapr Kubernetes 服务 + +### 前置条件 + +- 熟悉[本指南]({{< ref kubernetes-deploy.md >}})以了解如何将 Dapr 部署到您的 Kubernetes 集群。 +- 设置您的[开发环境](https://github.com/dapr/dapr/blob/master/docs/development/developing-dapr.md) +- [Helm](https://github.com/helm/helm/releases) + +### 1. 构建 Dapr 调试二进制文件 + +为了调试 Dapr Kubernetes 服务,需要重新构建所有 Dapr 二进制文件和 Docker 镜像以禁用编译器优化。为此,执行以下命令: + +```bash +git clone https://github.com/dapr/dapr.git +cd dapr +make release GOOS=linux GOARCH=amd64 DEBUG=1 +``` + +> 在 Windows 上下载 [MingGW](https://sourceforge.net/projects/mingw/files/MinGW/Extension/make/mingw32-make-3.80-3/) 并使用 `ming32-make.exe` 替代 `make`。 + +在上述命令中,通过将 'DEBUG' 设置为 '1' 来禁用编译器优化。'GOOS=linux' 和 'GOARCH=amd64' 也是必要的,因为二进制文件将在下一步中打包到基于 Linux 的 Docker 镜像中。 + +二进制文件可以在 'dapr' 目录下的 'dist/linux_amd64/debug' 子目录中找到。 + +### 2. 构建 Dapr 调试 Docker 镜像 + +使用以下命令将调试二进制文件打包到 Docker 镜像中。在此之前,您需要登录您的 docker.io 账户,如果还没有账户,您可能需要考虑在 "https://hub.docker.com/" 注册一个。 + +```bash +export DAPR_TAG=dev +export DAPR_REGISTRY= +docker login +make docker-push DEBUG=1 +``` + +一旦 Dapr Docker 镜像构建并推送到 Docker hub 上,您就可以在 Kubernetes 集群中重新安装 Dapr。 + +### 3. 安装 Dapr 调试二进制文件 + +如果 Dapr 已经安装在您的 Kubernetes 集群中,首先卸载它: + +```bash +dapr uninstall -k +``` + +我们将使用 'helm' 来安装 Dapr 调试二进制文件。在接下来的部分中,我们将以 Dapr operator 为例,演示如何在 Kubernetes 环境中配置、安装和调试 Dapr 服务。 + +首先配置一个 values 文件,包含以下选项: + +```yaml +global: + registry: docker.io/ + tag: "dev-linux-amd64" +dapr_operator: + debug: + enabled: true + initialDelaySeconds: 3000 +``` + +{{% alert title="注意" color="primary" %}} +如果您需要调试 Dapr 服务的启动时间,您可以将 `initialDelaySeconds` 配置为一个较长的时间值,例如 "3000" 秒。如果不需要,请将其配置为一个较短的时间值,例如 "3" 秒。 +{{% /alert %}} + +然后进入本指南开头从 GitHub 克隆的 'dapr' 目录中,如果还没有,执行以下命令: + +```bash +helm install dapr charts/dapr --namespace dapr-system --values values.yml --wait +``` + +### 4. 转发调试端口 + +要调试目标 Dapr 服务(在本例中为 Dapr operator),其预配置的调试端口需要对您的 IDE 可见。为此,我们需要首先找到目标 Dapr 服务的 pod: + +```bash +$ kubectl get pods -n dapr-system -o wide + +NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES +dapr-dashboard-64b46f98b6-dl2n9 1/1 Running 0 61s 172.17.0.9 minikube +dapr-operator-7878f94fcd-6bfx9 1/1 Running 1 61s 172.17.0.7 minikube +dapr-placement-server-0 1/1 Running 1 61s 172.17.0.8 minikube +dapr-sentry-68c7d4c7df-sc47x 1/1 Running 0 61s 172.17.0.6 minikube +dapr-sidecar-injector-56c8f489bb-t2st9 1/1 Running 0 61s 172.17.0.10 minikube +``` + +然后使用 kubectl 的 `port-forward` 命令将内部调试端口暴露给外部 IDE: + +```bash +$ kubectl port-forward dapr-operator-7878f94fcd-6bfx9 40000:40000 -n dapr-system + +Forwarding from 127.0.0.1:40000 -> 40000 +Forwarding from [::1]:40000 -> 40000 +``` + +一切就绪。现在您可以指向端口 40000 并从您喜欢的 IDE 开始远程调试会话。 + +## 相关链接 + +- [Kubernetes 上的 Dapr 概述]({{< ref kubernetes-overview >}}) +- [将 Dapr 部署到 Kubernetes 集群]({{< ref kubernetes-deploy >}}) +- [Dapr Kubernetes 快速入门](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-kubernetes) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/debugging/debug-k8s/debug-daprd.md b/src/translated_content/zh_CN/docs/developing-applications/debugging/debug-k8s/debug-daprd.md new file mode 100644 index 000000000..ca1c88803 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/debugging/debug-k8s/debug-daprd.md @@ -0,0 +1,150 @@ +--- +type: docs +title: "在 Kubernetes 上调试 daprd" +linkTitle: "Dapr sidecar" +weight: 2000 +description: "如何在 Kubernetes 集群上调试 Dapr sidecar (daprd)" +--- + +## 概述 + +有时我们需要了解 Dapr sidecar (daprd) 的运行情况,特别是在诊断 Dapr 应用程序时,怀疑 Dapr 本身是否存在问题。此外,您可能正在为 Kubernetes 上的 Dapr 开发新功能,并需要调试您的代码。 + +本指南介绍如何使用 Dapr 的内置调试功能来调试 Kubernetes pod 中的 Dapr sidecar。要了解如何查看日志和排查 Kubernetes 中的 Dapr 问题,请参阅[配置和查看 Dapr 日志指南]({{< ref "logs-troubleshooting.md#logs-in-kubernetes-mode" >}})。 + +## 前提条件 + +- 请参阅[本指南]({{< ref kubernetes-deploy.md >}})了解如何将 Dapr 部署到您的 Kubernetes 集群。 +- 按照[本指南]({{< ref "debug-dapr-services.md">}})构建您将在下一步中部署的 Dapr 调试二进制文件。 + +## 初始化 Dapr 调试模式 + +如果 Dapr 已经安装在您的 Kubernetes 集群中,请先卸载它: + +```bash +dapr uninstall -k +``` + +我们将使用 'helm' 来安装 Dapr 调试二进制文件。有关更多信息,请参阅[使用 Helm 安装]({{< ref "kubernetes-deploy.md#install-with-helm-advanced" >}})。 + +首先配置一个名为 `values.yml` 的值文件,选项如下: + +```yaml +global: + registry: docker.io/ + tag: "dev-linux-amd64" +``` + +然后进入从您的克隆 [dapr/dapr 仓库](https://github.com/dapr/dapr) 中的 'dapr' 目录,并执行以下命令: + +```bash +helm install dapr charts/dapr --namespace dapr-system --values values.yml --wait +``` + +要为 daprd 启用调试模式,您需要在应用程序的部署文件中添加一个额外的注解 `dapr.io/enable-debug`。让我们以 [quickstarts/hello-kubernetes](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-kubernetes) 为例。像下面这样修改 'deploy/node.yaml': + +```diff +diff --git a/hello-kubernetes/deploy/node.yaml b/hello-kubernetes/deploy/node.yaml +index 23185a6..6cdb0ae 100644 +--- a/hello-kubernetes/deploy/node.yaml ++++ b/hello-kubernetes/deploy/node.yaml +@@ -33,6 +33,7 @@ spec: + dapr.io/enabled: "true" + dapr.io/app-id: "nodeapp" + dapr.io/app-port: "3000" ++ dapr.io/enable-debug: "true" + spec: + containers: + - name: node +``` + +注解 `dapr.io/enable-debug` 会指示 Dapr 注入器将 Dapr sidecar 置于调试模式。您还可以通过注解 `dapr.io/debug-port` 指定调试端口,否则默认端口将是 "40000"。 + +使用以下命令部署应用程序。完整指南请参阅 [Dapr Kubernetes 快速入门](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-kubernetes): + +```bash +kubectl apply -f ./deploy/node.yaml +``` + +使用以下命令找出目标应用程序的 pod 名称: + +```bash +$ kubectl get pods + +NAME READY STATUS RESTARTS AGE +nodeapp-78866448f5-pqdtr 1/2 Running 0 14s +``` + +然后使用 kubectl 的 `port-forward` 命令将内部调试端口暴露给外部 IDE: + +```bash +$ kubectl port-forward nodeapp-78866448f5-pqdtr 40000:40000 + +Forwarding from 127.0.0.1:40000 -> 40000 +Forwarding from [::1]:40000 -> 40000 +``` + +一切就绪。现在您可以指向端口 40000 并从您喜欢的 IDE 开始远程调试会话到 daprd。 + +## 常用的 `kubectl` 命令 + +在调试 daprd 和在 Kubernetes 上运行的应用程序时,使用以下常用的 `kubectl` 命令。 + +获取所有 pod、事件和服务: + +```bash +kubectl get all +kubectl get all --n +kubectl get all --all-namespaces +``` + +分别获取每个: + +```bash +kubectl get pods +``` + +```bash +kubectl get events --n +kubectl get events --sort-by=.metadata.creationTimestamp --n +``` + +```bash +kubectl get services +``` + +检查日志: + +```bash +kubectl logs daprd +kubectl logs +kuebctl logs daprd +kubectl logs +``` + +```bash +kubectl describe pod +kubectl describe deploy +kubectl describe replicaset +``` + +通过运行以下命令重启 pod: + +```bash +kubectl delete pod +``` + +这将导致 `replicaset` 控制器在删除后重启 pod。 + +## 观看演示 + +在 [Dapr 社区电话 #36](https://youtu.be/pniLPRbuLD8?si=bGid7oYSp9cThtiI&t=838) 中观看关于在 Kubernetes 上排查 Dapr 问题的演示。 + + + +## 相关链接 + +- [Kubernetes 上的 Dapr 概述]({{< ref kubernetes-overview >}}) +- [将 Dapr 部署到 Kubernetes 集群]({{< ref kubernetes-deploy >}}) +- [在 Kubernetes 上调试 Dapr 服务]({{< ref debug-dapr-services >}}) +- [Dapr Kubernetes 快速入门](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-kubernetes) diff --git a/src/translated_content/zh_CN/docs/developing-applications/debugging/debugging-docker-compose.md b/src/translated_content/zh_CN/docs/developing-applications/debugging/debugging-docker-compose.md new file mode 100644 index 000000000..3ad96a394 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/debugging/debugging-docker-compose.md @@ -0,0 +1,81 @@ +--- +type: docs +title: "在 Docker Compose 中调试 Dapr 应用" +linkTitle: "调试 Docker Compose" +weight: 300 +description: "本地调试作为 Docker Compose 部署一部分的 Dapr 应用" +--- + +本文旨在介绍一种方法,如何通过你的 IDE 在本地调试一个或多个使用 Dapr 的应用,同时保持与其他通过 Docker Compose 部署的应用的集成。 + +我们以一个包含两个服务的 Docker Compose 文件的简单示例为例: +- `nodeapp` - 你的应用 +- `nodeapp-dapr` - 你的 `nodeapp` 服务的 Dapr sidecar 进程 + +#### compose.yml +```yaml +services: + nodeapp: + build: ./node + ports: + - "50001:50001" + networks: + - hello-dapr + nodeapp-dapr: + image: "daprio/daprd:edge" + command: [ + "./daprd", + "--app-id", "nodeapp", + "--app-port", "3000", + "--resources-path", "./components" + ] + volumes: + - "./components/:/components" + depends_on: + - nodeapp + network_mode: "service:nodeapp" +networks: + hello-dapr +``` + +当你使用 `docker compose -f compose.yml up` 运行这个 Docker 文件时,它将部署到 Docker 并正常运行。 + +但是,如何在保持与正在运行的 Dapr sidecar 进程以及其他通过 Docker Compose 文件部署的服务集成的情况下调试 `nodeapp` 呢? + +我们可以通过引入一个名为 `compose.debug.yml` 的*第二个* Docker Compose 文件来实现。当运行 `up` 命令时,这个第二个 Compose 文件将与第一个文件结合使用。 + +#### compose.debug.yml +```yaml +services: + nodeapp: # 通过移除其端口并将其从网络中移除来隔离 nodeapp + ports: !reset [] + networks: !reset + - "" + nodeapp-dapr: + command: ["./daprd", + "--app-id", "nodeapp", + "--app-port", "8080", # 这必须与在 IDE 中调试时应用暴露的端口匹配 + "--resources-path", "./components", + "--app-channel-address", "host.docker.internal"] # 让 sidecar 在主机上查找应用通道 + network_mode: !reset "" # 重置 network_mode... + networks: # ... 以便 sidecar 可以进入正常网络 + - hello-dapr + ports: + - "3500:3500" # 将 HTTP 端口暴露给主机 + - "50001:50001" # 将 GRPC 端口暴露给主机(Dapr 工作流依赖于 GRPC 通道) + +``` + +接下来,确保你的 `nodeapp` 在你选择的 IDE 中运行/调试,并在你在 `compose.debug.yml` 中上面指定的相同端口上暴露 - 在上面的示例中,这设置为端口 `8080`。 + +接下来,停止你可能已启动的任何现有 Compose 会话,并运行以下命令以组合运行两个 Docker Compose 文件: + +`docker compose -f compose.yml -f compose.debug.yml up` + +现在,你应该会发现 Dapr sidecar 和你的调试应用可以相互通信,就像它们在 Docker Compose 环境中正常一起运行一样。 + +**注意**:需要强调的是,Docker Compose 环境中的 `nodeapp` 服务实际上仍在运行,但它已从 Docker 网络中移除,因此实际上被孤立,因为没有任何东西可以与之通信。 + +**演示**:观看此视频,了解如何使用 Docker Compose 调试本地 Dapr 应用 + + \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/develop-components/_index.md b/src/translated_content/zh_CN/docs/developing-applications/develop-components/_index.md new file mode 100644 index 000000000..62ed69eba --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/develop-components/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "组件" +linkTitle: "组件" +weight: 40 +description: "了解更多关于 Dapr 的可插拔组件和中间件的开发" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/develop-components/develop-middleware.md b/src/translated_content/zh_CN/docs/developing-applications/develop-components/develop-middleware.md new file mode 100644 index 000000000..cc78e8494 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/develop-components/develop-middleware.md @@ -0,0 +1,53 @@ +--- +type: docs +title: "如何:编写中间件组件" +linkTitle: "中间件组件" +weight: 200 +description: "学习如何开发中间件组件" +aliases: + - /zh-hans/developing-applications/middleware/middleware-overview/ + - /zh-hans/concepts/middleware-concept/ +--- + +Dapr 允许通过将一系列中间件组件链接在一起来定义自定义处理管道。在本指南中,您将学习如何创建一个中间件组件。要了解如何配置已有的中间件组件,请参阅[配置中间件组件]({{< ref middleware.md >}}) + +## 编写自定义 HTTP 中间件 + +Dapr 中的 HTTP 中间件是对标准 Go [net/http](https://pkg.go.dev/net/http) 处理函数的封装。 + +您的中间件需要实现一个中间件接口,该接口定义了一个 **GetHandler** 方法,该方法返回一个 [**http.Handler**](https://pkg.go.dev/net/http#Handler) 回调函数和一个 **error**: + +```go +type Middleware interface { + GetHandler(metadata middleware.Metadata) (func(next http.Handler) http.Handler, error) +} +``` + +处理器接收一个 `next` 回调函数,该函数应被调用以继续处理请求。 + +您的处理器实现可以包括入站逻辑、出站逻辑,或同时包括两者: + +```go + +func (m *customMiddleware) GetHandler(metadata middleware.Metadata) (func(next http.Handler) http.Handler, error) { + var err error + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // 入站逻辑 + // ... + + // 调用下一个处理器 + next.ServeHTTP(w, r) + + // 出站逻辑 + // ... + } + }, err +} +``` + +## 相关链接 + +- [组件模式]({{< ref component-schema.md >}}) +- [配置概述]({{< ref configuration-overview.md >}}) +- [API 中间件示例](https://github.com/dapr/samples/tree/master/middleware-oauth-google) diff --git a/src/translated_content/zh_CN/docs/developing-applications/develop-components/pluggable-components/_index.md b/src/translated_content/zh_CN/docs/developing-applications/develop-components/pluggable-components/_index.md new file mode 100644 index 000000000..cfe0fd229 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/develop-components/pluggable-components/_index.md @@ -0,0 +1,9 @@ +--- +type: docs +title: "可插拔组件" +linkTitle: "可插拔组件" +description: "关于如何使用可插拔组件的指南" +weight: 100 +aliases: + - "/zh-hans/operations/components/pluggable-components/pluggable-components-overview/" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/develop-components/pluggable-components/develop-pluggable.md b/src/translated_content/zh_CN/docs/developing-applications/develop-components/pluggable-components/develop-pluggable.md new file mode 100644 index 000000000..da6296399 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/develop-components/pluggable-components/develop-pluggable.md @@ -0,0 +1,312 @@ +--- +type: docs +title: "如何:实现可插拔组件" +linkTitle: "实现可插拔组件" +weight: 1100 +description: "学习如何编写和实现可插拔组件" +--- + +在本指南中,您将学习实现可插拔组件的原因和方法。要了解如何配置和注册可插拔组件,请参阅[如何:注册可插拔组件]({{< ref pluggable-components-registration.md >}})。 + +## 实现可插拔组件 + +要实现可插拔组件,需在组件中实现 gRPC 服务。实现 gRPC 服务需要三个步骤: + +### 找到 proto 定义文件 + +每个支持的服务接口(如状态存储、发布订阅、绑定、密钥存储)都提供了 proto 定义。 + +目前支持以下组件 API: + +- 状态存储 +- 发布订阅 +- 绑定 +- 密钥存储 + +| 组件 | 类型 | gRPC 定义 | 内置参考实现 | 文档 | +| :---------: | :--------: | :--------------: | :----------------------------------------------------------------------------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 状态存储 | `state` | [state.proto](https://github.com/dapr/dapr/blob/master/dapr/proto/components/v1/state.proto) | [Redis](https://github.com/dapr/components-contrib/tree/master/state/redis) | [概念]({{< ref "state-management-overview" >}}), [如何]({{< ref "howto-get-save-state" >}}), [API 规范]({{< ref "state_api" >}}) | +| 发布订阅 | `pubsub` | [pubsub.proto](https://github.com/dapr/dapr/blob/master/dapr/proto/components/v1/pubsub.proto) | [Redis](https://github.com/dapr/components-contrib/tree/master/pubsub/redis) | [概念]({{< ref "pubsub-overview" >}}), [如何]({{< ref "howto-publish-subscribe" >}}), [API 规范]({{< ref "pubsub_api" >}}) | +| 绑定 | `bindings` | [bindings.proto](https://github.com/dapr/dapr/blob/master/dapr/proto/components/v1/bindings.proto) | [Kafka](https://github.com/dapr/components-contrib/tree/master/bindings/kafka) | [概念]({{< ref "bindings-overview" >}}), [输入如何]({{< ref "howto-triggers" >}}), [输出如何]({{< ref "howto-bindings" >}}), [API 规范]({{< ref "bindings_api" >}}) | +| 密钥存储 | `secretstores` | [secretstore.proto](https://github.com/dapr/dapr/blob/master/dapr/proto/components/v1/secretstore.proto) | [Hashicorp/Vault](https://github.com/dapr/components-contrib/blob/master/secretstores/hashicorp/vault/vault.go) | [概念]({{< ref "secrets-overview" >}}), [如何-secrets]({{< ref "howto-secrets" >}}), [API 规范]({{< ref "secrets_api" >}}) | + +以下是可插拔组件状态存储的 gRPC 服务定义片段([state.proto]): + +```protobuf +// StateStore 服务为状态存储组件提供 gRPC 接口。 +service StateStore { + // 使用给定的元数据初始化状态存储组件。 + rpc Init(InitRequest) returns (InitResponse) {} + // 返回已实现的状态存储功能列表。 + rpc Features(FeaturesRequest) returns (FeaturesResponse) {} + // Ping 状态存储。用于活跃性目的。 + rpc Ping(PingRequest) returns (PingResponse) {} + + // 从状态存储中删除指定的键。 + rpc Delete(DeleteRequest) returns (DeleteResponse) {} + // 从给定的键获取数据。 + rpc Get(GetRequest) returns (GetResponse) {} + // 设置指定键的值。 + rpc Set(SetRequest) returns (SetResponse) {} + + // 一次删除多个键。 + rpc BulkDelete(BulkDeleteRequest) returns (BulkDeleteResponse) {} + // 一次检索多个键。 + rpc BulkGet(BulkGetRequest) returns (BulkGetResponse) {} + // 一次设置多个键的值。 + rpc BulkSet(BulkSetRequest) returns (BulkSetResponse) {} +} +``` + +`StateStore` 服务接口总共公开了 9 个方法: + +- 2 个用于初始化和组件能力广告的方法(Init 和 Features) +- 1 个用于健康或活跃性检查的方法(Ping) +- 3 个用于 CRUD 的方法(Get、Set、Delete) +- 3 个用于批量 CRUD 操作的方法(BulkGet、BulkSet、BulkDelete) + +### 创建服务脚手架 + +使用 [protocol buffers 和 gRPC 工具](https://grpc.io)生成服务的脚手架。通过 [gRPC 概念文档](https://grpc.io/docs/what-is-grpc/core-concepts/)了解更多关于这些工具的信息。 + +这些工具生成针对[任何 gRPC 支持的语言](https://grpc.io/docs/what-is-grpc/introduction/#protocol-buffer-versions)的代码。此代码作为您的服务器的基础,并提供: +- 处理客户端调用的功能 +- 基础设施以: + - 解码传入请求 + - 执行服务方法 + - 编码服务响应 + +生成的代码是不完整的。它缺少: + +- 您的目标服务定义的方法的具体实现(您可插拔组件的核心)。 +- 关于如何处理 Unix Socket Domain 集成的代码,这是 Dapr 特有的。 +- 处理与下游服务集成的代码。 + +在下一步中了解更多关于填补这些空白的信息。 + +### 定义服务 + +提供所需服务的具体实现。每个组件都有一个 gRPC 服务定义,用于其核心功能,与核心组件接口相同。例如: + +- **状态存储** + + 可插拔状态存储**必须**提供 `StateStore` 服务接口的实现。 + + 除了这个核心功能外,一些组件可能还会在其他**可选**服务下公开功能。例如,您可以通过定义 `QueriableStateStore` 服务和 `TransactionalStateStore` 服务的实现来添加额外功能。 + +- **发布订阅** + + 可插拔发布订阅组件只有一个核心服务接口定义 [pubsub.proto](https://github.com/dapr/dapr/blob/master/dapr/proto/components/v1/pubsub.proto)。它们没有可选的服务接口。 + +- **绑定** + + 可插拔输入和输出绑定在 [bindings.proto](https://github.com/dapr/dapr/blob/master/dapr/proto/components/v1/bindings.proto) 上有一个核心服务定义。它们没有可选的服务接口。 + +- **密钥存储** + + 可插拔密钥存储在 [secretstore.proto](https://github.com/dapr/dapr/blob/master/dapr/proto/components/v1/secretstore.proto) 上有一个核心服务定义。它们没有可选的服务接口。 + +在使用 gRPC 和 protocol buffers 工具生成上述状态存储示例的服务脚手架代码后,您可以为 `service StateStore` 下定义的 9 个方法定义具体实现,以及初始化和与依赖项通信的代码。 + +这个具体实现和辅助代码是您可插拔组件的**核心**。它们定义了您的组件在处理来自 Dapr 的 gRPC 请求时的行为。 + +## 返回语义错误 + +返回语义错误也是可插拔组件协议的一部分。组件必须返回对用户应用程序具有语义意义的特定 gRPC 代码,这些错误用于从并发要求到仅信息的各种情况。 + +| 错误 | gRPC 错误代码 | 源组件 | 描述 | +| ------------------------ | ------------------------------- | ---------------- | ----------- | +| ETag 不匹配 | `codes.FailedPrecondition` | 状态存储 | 错误映射以满足并发要求 | +| ETag 无效 | `codes.InvalidArgument` | 状态存储 | | +| 批量删除行不匹配 | `codes.Internal` | 状态存储 | | + +在 [状态管理概述]({{< ref "state-management-overview.md#concurrency" >}})中了解更多关于并发要求的信息。 + +以下示例演示了如何在您自己的可插拔组件中返回错误,并根据需要更改消息。 + +{{< tabs ".NET" "Java" "Go" >}} + +{{% codetab %}} + +> **重要提示:** 为了使用 .NET 进行错误映射,首先安装 [`Google.Api.CommonProtos` NuGet 包](https://www.nuget.org/packages/Google.Api.CommonProtos/)。 + +**ETag 不匹配** + +```csharp +var badRequest = new BadRequest(); +var des = "提供的 ETag 字段与存储中的不匹配"; +badRequest.FieldViolations.Add(    + new Google.Rpc.BadRequest.Types.FieldViolation +    {        + Field = "etag", + Description = des +    }); + +var baseStatusCode = Grpc.Core.StatusCode.FailedPrecondition; +var status = new Google.Rpc.Status{    + Code = (int)baseStatusCode +}; + +status.Details.Add(Google.Protobuf.WellKnownTypes.Any.Pack(badRequest)); + +var metadata = new Metadata(); +metadata.Add("grpc-status-details-bin", status.ToByteArray()); +throw new RpcException(new Grpc.Core.Status(baseStatusCode, "fake-err-msg"), metadata); +``` + +**ETag 无效** + +```csharp +var badRequest = new BadRequest(); +var des = "ETag 字段只能包含字母数字字符"; +badRequest.FieldViolations.Add( + new Google.Rpc.BadRequest.Types.FieldViolation + { + Field = "etag", + Description = des + }); + +var baseStatusCode = Grpc.Core.StatusCode.InvalidArgument; +var status = new Google.Rpc.Status +{ + Code = (int)baseStatusCode +}; + +status.Details.Add(Google.Protobuf.WellKnownTypes.Any.Pack(badRequest)); + +var metadata = new Metadata(); +metadata.Add("grpc-status-details-bin", status.ToByteArray()); +throw new RpcException(new Grpc.Core.Status(baseStatusCode, "fake-err-msg"), metadata); +``` + +**批量删除行不匹配** + +```csharp +var errorInfo = new Google.Rpc.ErrorInfo(); + +errorInfo.Metadata.Add("expected", "100"); +errorInfo.Metadata.Add("affected", "99"); + +var baseStatusCode = Grpc.Core.StatusCode.Internal; +var status = new Google.Rpc.Status{ +    Code = (int)baseStatusCode +}; + +status.Details.Add(Google.Protobuf.WellKnownTypes.Any.Pack(errorInfo)); + +var metadata = new Metadata(); +metadata.Add("grpc-status-details-bin", status.ToByteArray()); +throw new RpcException(new Grpc.Core.Status(baseStatusCode, "fake-err-msg"), metadata); +``` + +{{% /codetab %}} + + +{{% codetab %}} + +就像 [Dapr Java SDK](https://github.com/tmacam/dapr-java-sdk/) 一样,Java 可插拔组件 SDK 使用 [Project Reactor](https://projectreactor.io/),它为 Java 提供了异步 API。 + +错误可以通过以下方式直接返回: +1. 在您的方法返回的 `Mono` 或 `Flux` 中调用 `.error()` 方法 +1. 提供适当的异常作为参数。 + +您也可以引发异常,只要它被捕获并反馈到您结果的 `Mono` 或 `Flux` 中。 + +**ETag 不匹配** + +```java +final Status status = Status.newBuilder() + .setCode(io.grpc.Status.Code.FAILED_PRECONDITION.value()) + .setMessage("fake-err-msg-for-etag-mismatch") + .addDetails(Any.pack(BadRequest.FieldViolation.newBuilder() + .setField("etag") + .setDescription("提供的 ETag 字段与存储中的不匹配") + .build())) + .build(); +return Mono.error(StatusProto.toStatusException(status)); +``` + +**ETag 无效** + +```java +final Status status = Status.newBuilder() + .setCode(io.grpc.Status.Code.INVALID_ARGUMENT.value()) + .setMessage("fake-err-msg-for-invalid-etag") + .addDetails(Any.pack(BadRequest.FieldViolation.newBuilder() + .setField("etag") + .setDescription("ETag 字段只能包含字母数字字符") + .build())) + .build(); +return Mono.error(StatusProto.toStatusException(status)); +``` + +**批量删除行不匹配** + +```java +final Status status = Status.newBuilder() + .setCode(io.grpc.Status.Code.INTERNAL.value()) + .setMessage("fake-err-msg-for-bulk-delete-row-mismatch") + .addDetails(Any.pack(ErrorInfo.newBuilder() + .putAllMetadata(Map.ofEntries( + Map.entry("affected", "99"), + Map.entry("expected", "100") + )) + .build())) + .build(); +return Mono.error(StatusProto.toStatusException(status)); +``` + +{{% /codetab %}} + + +{{% codetab %}} + +**ETag 不匹配** + +```go +st := status.New(codes.FailedPrecondition, "fake-err-msg") +desc := "提供的 ETag 字段与存储中的不匹配" +v := &errdetails.BadRequest_FieldViolation{ + Field: etagField, + Description: desc, +} +br := &errdetails.BadRequest{} +br.FieldViolations = append(br.FieldViolations, v) +st, err := st.WithDetails(br) +``` + +**ETag 无效** + +```go +st := status.New(codes.InvalidArgument, "fake-err-msg") +desc := "ETag 字段只能包含字母数字字符" +v := &errdetails.BadRequest_FieldViolation{ + Field: etagField, + Description: desc, +} +br := &errdetails.BadRequest{} +br.FieldViolations = append(br.FieldViolations, v) +st, err := st.WithDetails(br) +``` + +**批量删除行不匹配** + +```go +st := status.New(codes.Internal, "fake-err-msg") +br := &errdetails.ErrorInfo{} +br.Metadata = map[string]string{ + affected: "99", + expected: "100", +} +st, err := st.WithDetails(br) +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 + +- 使用此[示例代码](https://github.com/dapr/samples/tree/master/pluggable-components-dotnet-template)开始开发 .NET 可插拔组件 +- [查看可插拔组件概述]({{< ref pluggable-components-overview.md >}}) +- [了解如何注册您的可插拔组件]({{< ref pluggable-components-registration >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/develop-components/pluggable-components/pluggable-components-overview.md b/src/translated_content/zh_CN/docs/developing-applications/develop-components/pluggable-components/pluggable-components-overview.md new file mode 100644 index 000000000..aa11f552b --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/develop-components/pluggable-components/pluggable-components-overview.md @@ -0,0 +1,65 @@ +--- +type: docs +title: "可插拔组件概述" +linkTitle: "概述" +weight: 1000 +description: "可插拔组件的结构和支持的组件类型概述" +--- + +可插拔组件是指那些不包含在运行时中的组件,与 `dapr init` 中的内置组件相对。您可以配置 Dapr 使用这些可插拔组件,它们利用构建块 API,但注册方式与[内置 Dapr 组件](https://github.com/dapr/components-contrib)不同。 + + + +## 可插拔组件与内置组件 + +Dapr 提供了两种注册和创建组件的方法: + +- 运行时中包含的内置组件,可以在[components-contrib 仓库](https://github.com/dapr/components-contrib)中找到。 +- 独立部署和注册的可插拔组件。 + +这两种注册选项虽然都利用了 Dapr 的构建块 API,但实现过程不同。 + +| 组件详情 | [内置组件](https://github.com/dapr/components-contrib/blob/master/docs/developing-component.md) | 可插拔组件 | +| ---------------------------- | :--------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **语言** | 只能用 Go 编写 | [可以用任何支持 gRPC 的语言编写](https://grpc.io/docs/what-is-grpc/introduction/#protocol-buffer-versions) | +| **运行位置** | 作为 Dapr 运行时可执行文件的一部分 | 作为 pod 中的独立进程或容器运行,与 Dapr 本身分开运行。 | +| **与 Dapr 的注册方式** | 包含在 Dapr 代码库中 | 通过 Unix 域套接字(使用 gRPC)与 Dapr 注册 | +| **分发** | 随 Dapr 版本发布。组件的新功能与 Dapr 版本保持一致 | 独立于 Dapr 本身分发。可以在需要时添加新功能,并遵循自己的发布周期。 | +| **组件激活方式** | Dapr 启动运行组件(自动) | 用户启动组件(手动) | + +## 为什么创建可插拔组件? + +在以下场景中,可插拔组件非常有用: + +- 您需要一个私有组件。 +- 您希望将组件与 Dapr 的发布过程分开。 +- 您对 Go 不太熟悉,或者用 Go 实现组件并不理想。 + +## 特性 + +### 实现可插拔组件 + +要实现可插拔组件,您需要在组件中实现一个 gRPC 服务。实现 gRPC 服务需要三个步骤: + +1. 找到 proto 定义文件 +1. 创建服务脚手架 +1. 定义服务 + +了解更多关于[如何开发和实现可插拔组件]({{< ref develop-pluggable.md >}}) + +### 为组件利用多个构建块 + +除了从同一组件实现多个 gRPC 服务(例如 `StateStore`、`QueriableStateStore`、`TransactionalStateStore` 等),可插拔组件还可以为其他组件接口提供实现。这意味着单个可插拔组件可以同时作为状态存储、pub/sub 和输入或输出绑定工作。换句话说,您可以将多个组件接口实现到一个可插拔组件中,并将其作为 gRPC 服务公开。 + +虽然在同一个可插拔组件上公开多个组件接口降低了部署多个组件的操作负担,但这使得实现和调试组件变得更加困难。如果不确定,请坚持“关注点分离”,仅在必要时将多个组件接口合并到同一个可插拔组件中。 + +## 如何使可插拔组件投入使用 + +内置组件和可插拔组件有一个共同点:都需要一个[组件规范]({{< ref "components-concept.md#component-specification" >}})。内置组件不需要任何额外步骤即可使用:Dapr 已准备好自动使用它们。 + +相反,可插拔组件在与 Dapr 通信之前需要额外的步骤。您需要首先运行组件并促进 Dapr-组件通信以启动注册过程。 + +## 下一步 + +- [实现可插拔组件]({{< ref develop-pluggable.md >}}) +- [可插拔组件注册]({{< ref "pluggable-components-registration" >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/develop-components/pluggable-components/pluggable-components-sdks/_index.md b/src/translated_content/zh_CN/docs/developing-applications/develop-components/pluggable-components/pluggable-components-sdks/_index.md new file mode 100644 index 000000000..5510934e9 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/develop-components/pluggable-components/pluggable-components-sdks/_index.md @@ -0,0 +1,18 @@ +--- +type: docs +title: "可插拔组件的SDK" +linkTitle: "软件开发工具包" +weight: 2000 +description: "使用您喜欢的语言开发可插拔组件" +no_list: true +is_preview: true +--- + +Dapr SDK 是帮助您轻松创建可插拔组件的最佳工具。选择您喜欢的编程语言,几分钟内即可开始开发组件。 + +## 可插拔组件的SDK + +| 语言 | 进度 | +|------|:----:| +| [Go]({{< ref pluggable-components-go >}}) | 正在开发 | +| [.NET]({{< ref pluggable-components-dotnet >}}) | 正在开发 | \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/error-codes/_index.md b/src/translated_content/zh_CN/docs/developing-applications/error-codes/_index.md new file mode 100644 index 000000000..974f0c3e7 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/error-codes/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "错误代码" +linkTitle: "错误代码" +weight: 20 +description: "在使用Dapr时可能遇到的错误代码和信息" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/error-codes/error-codes-reference.md b/src/translated_content/zh_CN/docs/developing-applications/error-codes/error-codes-reference.md new file mode 100644 index 000000000..cc3c97c53 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/error-codes/error-codes-reference.md @@ -0,0 +1,193 @@ +--- +type: docs +title: "错误代码参考指南" +linkTitle: "参考" +description: "Dapr 中 gRPC 和 HTTP 错误代码列表及其描述" +weight: 20 +--- + +以下表格列出了 Dapr 运行时返回的错误代码。 +错误代码会在 HTTP 请求的响应体中或 gRPC 状态响应的 `ErrorInfo` 部分返回(如果存在)。 +我们正在努力根据 [更丰富的错误模型]({{< ref "grpc-error-codes.md#richer-grpc-error-model" >}}) 来改进所有 gRPC 错误响应。没有对应 gRPC 代码的错误代码表示这些错误尚未更新到此模型。 + +### 演员 API + +| HTTP 代码 | gRPC 代码 | 描述 | +| ---------------------------------- | --------- | ---------------------------------------------------------------- | +| `ERR_ACTOR_INSTANCE_MISSING` | | 缺少演员实例 | +| `ERR_ACTOR_INVOKE_METHOD` | | 调用演员方法时发生错误 | +| `ERR_ACTOR_RUNTIME_NOT_FOUND` | | 找不到演员运行时 | +| `ERR_ACTOR_STATE_GET` | | 获取演员状态时发生错误 | +| `ERR_ACTOR_STATE_TRANSACTION_SAVE` | | 保存演员事务时发生错误 | +| `ERR_ACTOR_REMINDER_CREATE` | | 创建演员提醒时发生错误 | +| `ERR_ACTOR_REMINDER_DELETE` | | 删除演员提醒时发生错误 | +| `ERR_ACTOR_REMINDER_GET` | | 获取演员提醒时发生错误 | +| `ERR_ACTOR_REMINDER_NON_HOSTED` | | 非托管演员类型的提醒操作 | +| `ERR_ACTOR_TIMER_CREATE` | | 创建演员计时器时发生错误 | +| `ERR_ACTOR_NO_APP_CHANNEL` | | 应用通道未初始化 | +| `ERR_ACTOR_STACK_DEPTH` | | 超过演员调用堆栈的最大深度 | +| `ERR_ACTOR_NO_PLACEMENT` | | 未配置放置服务 | +| `ERR_ACTOR_RUNTIME_CLOSED` | | 演员运行时已关闭 | +| `ERR_ACTOR_NAMESPACE_REQUIRED` | | 在 Kubernetes 模式下运行时,演员必须配置命名空间 | +| `ERR_ACTOR_NO_ADDRESS` | | 找不到演员的地址 | + +### 工作流 API + +| HTTP 代码 | gRPC 代码 | 描述 | +| ---------------------------------- | --------- | -------------------------------------------------------------------------------- | +| `ERR_GET_WORKFLOW` | | 获取工作流时发生错误 | +| `ERR_START_WORKFLOW` | | 启动工作流时发生错误 | +| `ERR_PAUSE_WORKFLOW` | | 暂停工作流时发生错误 | +| `ERR_RESUME_WORKFLOW` | | 恢复工作流时发生错误 | +| `ERR_TERMINATE_WORKFLOW` | | 终止工作流时发生错误 | +| `ERR_PURGE_WORKFLOW` | | 清除工作流时发生错误 | +| `ERR_RAISE_EVENT_WORKFLOW` | | 在工作流中引发事件时发生错误 | +| `ERR_WORKFLOW_COMPONENT_MISSING` | | 缺少工作流组件 | +| `ERR_WORKFLOW_COMPONENT_NOT_FOUND` | | 找不到工作流组件 | +| `ERR_WORKFLOW_EVENT_NAME_MISSING` | | 缺少工作流事件名称 | +| `ERR_WORKFLOW_NAME_MISSING` | | 未配置工作流名称 | +| `ERR_INSTANCE_ID_INVALID` | | 无效的工作流实例 ID。(仅允许字母数字和下划线字符) | +| `ERR_INSTANCE_ID_NOT_FOUND` | | 找不到工作流实例 ID | +| `ERR_INSTANCE_ID_PROVIDED_MISSING` | | 缺少工作流实例 ID | +| `ERR_INSTANCE_ID_TOO_LONG` | | 工作流实例 ID 过长 | + +### 状态管理 API + +| HTTP 代码 | gRPC 代码 | 描述 | +| --------------------------------------- | --------------------------------------- | ---------------------------------- | +| `ERR_STATE_TRANSACTION` | | 状态事务出错 | +| `ERR_STATE_SAVE` | | 保存状态时出错 | +| `ERR_STATE_GET` | | 获取状态时出错 | +| `ERR_STATE_DELETE` | | 删除状态时出错 | +| `ERR_STATE_BULK_DELETE` | | 批量删除状态时出错 | +| `ERR_STATE_BULK_GET` | | 批量获取状态时出错 | +| `ERR_NOT_SUPPORTED_STATE_OPERATION` | | 事务中不支持的操作 | +| `ERR_STATE_QUERY` | `DAPR_STATE_QUERY_FAILED` | 查询状态时出错 | +| `ERR_STATE_STORE_NOT_FOUND` | `DAPR_STATE_NOT_FOUND` | 找不到状态存储 | +| `ERR_STATE_STORE_NOT_CONFIGURED` | `DAPR_STATE_NOT_CONFIGURED` | 未配置状态存储 | +| `ERR_STATE_STORE_NOT_SUPPORTED` | `DAPR_STATE_TRANSACTIONS_NOT_SUPPORTED` | 状态存储不支持事务 | +| `ERR_STATE_STORE_NOT_SUPPORTED` | `DAPR_STATE_QUERYING_NOT_SUPPORTED` | 状态存储不支持查询 | +| `ERR_STATE_STORE_TOO_MANY_TRANSACTIONS` | `DAPR_STATE_TOO_MANY_TRANSACTIONS` | 每个事务的操作过多 | +| `ERR_MALFORMED_REQUEST` | `DAPR_STATE_ILLEGAL_KEY` | 无效的键 | + +### 配置 API + +| HTTP 代码 | gRPC 代码 | 描述 | +| ---------------------------------------- | --------- | ------------------------------- | +| `ERR_CONFIGURATION_GET` | | 获取配置时出错 | +| `ERR_CONFIGURATION_STORE_NOT_CONFIGURED` | | 未配置配置存储 | +| `ERR_CONFIGURATION_STORE_NOT_FOUND` | | 找不到配置存储 | +| `ERR_CONFIGURATION_SUBSCRIBE` | | 订阅配置时出错 | +| `ERR_CONFIGURATION_UNSUBSCRIBE` | | 取消订阅配置时出错 | + +### 加密 API + +| HTTP 代码 | gRPC 代码 | 描述 | +| ------------------------------------- | --------- | ------------------------ | +| `ERR_CRYPTO` | | 加密操作出错 | +| `ERR_CRYPTO_KEY` | | 检索加密密钥时出错 | +| `ERR_CRYPTO_PROVIDER_NOT_FOUND` | | 找不到加密提供者 | +| `ERR_CRYPTO_PROVIDERS_NOT_CONFIGURED` | | 未配置加密提供者 | + +### 密钥管理 API + +| HTTP 代码 | gRPC 代码 | 描述 | +| ---------------------------------- | --------- | -------------------- | +| `ERR_SECRET_GET` | | 获取密钥时出错 | +| `ERR_SECRET_STORE_NOT_FOUND` | | 找不到密钥存储 | +| `ERR_SECRET_STORES_NOT_CONFIGURED` | | 未配置密钥存储 | +| `ERR_PERMISSION_DENIED` | | 策略拒绝权限 | + +### 发布/订阅和消息传递错误 + +| HTTP 代码 | gRPC 代码 | 描述 | +| ----------------------------- | -------------------------------------- | ----------------------------------- | +| `ERR_PUBSUB_EMPTY` | `DAPR_PUBSUB_NAME_EMPTY` | 发布/订阅名称为空 | +| `ERR_PUBSUB_NOT_FOUND` | `DAPR_PUBSUB_NOT_FOUND` | 找不到发布/订阅 | +| `ERR_PUBSUB_NOT_FOUND` | `DAPR_PUBSUB_TEST_NOT_FOUND` | 找不到发布/订阅 | +| `ERR_PUBSUB_NOT_CONFIGURED` | `DAPR_PUBSUB_NOT_CONFIGURED` | 未配置发布/订阅 | +| `ERR_TOPIC_NAME_EMPTY` | `DAPR_PUBSUB_TOPIC_NAME_EMPTY` | 主题名称为空 | +| `ERR_PUBSUB_FORBIDDEN` | `DAPR_PUBSUB_FORBIDDEN` | 禁止访问主题的应用 ID | +| `ERR_PUBSUB_PUBLISH_MESSAGE` | `DAPR_PUBSUB_PUBLISH_MESSAGE` | 发布消息时出错 | +| `ERR_PUBSUB_REQUEST_METADATA` | `DAPR_PUBSUB_METADATA_DESERIALIZATION` | 反序列化元数据时出错 | +| `ERR_PUBSUB_CLOUD_EVENTS_SER` | `DAPR_PUBSUB_CLOUD_EVENT_CREATION` | 创建 CloudEvent 时出错 | +| `ERR_PUBSUB_EVENTS_SER` | `DAPR_PUBSUB_MARSHAL_ENVELOPE` | 编组 Cloud Event 信封时出错 | +| `ERR_PUBSUB_EVENTS_SER` | `DAPR_PUBSUB_MARSHAL_EVENTS` | 将事件编组为字节时出错 | +| `ERR_PUBSUB_EVENTS_SER` | `DAPR_PUBSUB_UNMARSHAL_EVENTS` | 解组事件时出错 | +| `ERR_PUBLISH_OUTBOX` | | 将消息发布到 outbox 时出错 | + +### 对话 API + +| HTTP 代码 | gRPC 代码 | 描述 | +| --------------------------------- | --------- | -------------------------------------- | +| `ERR_CONVERSATION_INVALID_PARMS` | | 对话组件的参数无效 | +| `ERR_CONVERSATION_INVOKE` | | 调用对话时出错 | +| `ERR_CONVERSATION_MISSING_INPUTS` | | 对话缺少输入 | +| `ERR_CONVERSATION_NOT_FOUND` | | 找不到对话 | + +### 服务调用 / 直接消息传递 API + +| HTTP 代码 | gRPC 代码 | 描述 | +| ------------------- | --------- | --------------------- | +| `ERR_DIRECT_INVOKE` | | 调用服务时出错 | + +### 绑定 API + +| HTTP 代码 | gRPC 代码 | 描述 | +| --------------------------- | --------- | ------------------------ | +| `ERR_INVOKE_OUTPUT_BINDING` | | 调用输出绑定时出错 | + +### 分布式锁 API + +| HTTP 代码 | gRPC 代码 | 描述 | +| ------------------------------- | --------- | ------------------------ | +| `ERR_LOCK_STORE_NOT_CONFIGURED` | | 未配置锁存储 | +| `ERR_LOCK_STORE_NOT_FOUND` | | 找不到锁存储 | +| `ERR_TRY_LOCK` | | 获取锁时出错 | +| `ERR_UNLOCK` | | 释放锁时出错 | + +### 健康检查 + +| HTTP 代码 | gRPC 代码 | 描述 | +| ------------------------------- | --------- | ------------------------ | +| `ERR_HEALTH_NOT_READY` | | Dapr 未准备好 | +| `ERR_HEALTH_APPID_NOT_MATCH` | | Dapr 应用 ID 不匹配 | +| `ERR_OUTBOUND_HEALTH_NOT_READY` | | Dapr 出站未准备好 | + +### 通用 + +| HTTP 代码 | gRPC 代码 | 描述 | +| ---------------------------- | --------- | ------------------------ | +| `ERR_API_UNIMPLEMENTED` | | API 未实现 | +| `ERR_APP_CHANNEL_NIL` | | 应用通道为 nil | +| `ERR_BAD_REQUEST` | | 错误请求 | +| `ERR_BODY_READ` | | 读取请求体时出错 | +| `ERR_INTERNAL` | | 内部错误 | +| `ERR_MALFORMED_REQUEST` | | 请求格式错误 | +| `ERR_MALFORMED_REQUEST_DATA` | | 请求数据格式错误 | +| `ERR_MALFORMED_RESPONSE` | | 响应格式错误 | + +### 调度/作业 API + +| HTTP 代码 | gRPC 代码 | 描述 | +| ------------------------------- | ------------------------------- | ----------------------------------- | +| `DAPR_SCHEDULER_SCHEDULE_JOB` | `DAPR_SCHEDULER_SCHEDULE_JOB` | 调度作业时出错 | +| `DAPR_SCHEDULER_JOB_NAME` | `DAPR_SCHEDULER_JOB_NAME` | 作业名称应仅在 URL 中设置 | +| `DAPR_SCHEDULER_JOB_NAME_EMPTY` | `DAPR_SCHEDULER_JOB_NAME_EMPTY` | 作业名称为空 | +| `DAPR_SCHEDULER_GET_JOB` | `DAPR_SCHEDULER_GET_JOB` | 获取作业时出错 | +| `DAPR_SCHEDULER_LIST_JOBS` | `DAPR_SCHEDULER_LIST_JOBS` | 列出作业时出错 | +| `DAPR_SCHEDULER_DELETE_JOB` | `DAPR_SCHEDULER_DELETE_JOB` | 删除作业时出错 | +| `DAPR_SCHEDULER_EMPTY` | `DAPR_SCHEDULER_EMPTY` | 必需的参数为空 | +| `DAPR_SCHEDULER_SCHEDULE_EMPTY` | `DAPR_SCHEDULER_SCHEDULE_EMPTY` | 未提供作业的调度 | + +### 通用 + +| HTTP 代码 | gRPC 代码 | 描述 | +| --------- | --------- | ------------ | +| `ERROR` | `ERROR` | 通用错误 | + +## 下一步 + +- [处理 HTTP 错误代码]({{< ref http-error-codes.md >}}) +- [处理 gRPC 错误代码]({{< ref grpc-error-codes.md >}}) +` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/error-codes/errors-overview.md b/src/translated_content/zh_CN/docs/developing-applications/error-codes/errors-overview.md new file mode 100644 index 000000000..011e6bc5e --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/error-codes/errors-overview.md @@ -0,0 +1,62 @@ +--- +type: docs +title: "错误概述" +linkTitle: "概述" +weight: 10 +description: "Dapr 错误概述" +--- + +错误代码是用于指示错误性质的数字或字母数字代码,并在可能的情况下,说明其发生的原因。 + +Dapr 错误代码是标准化的字符串,适用于 Dapr API 中 HTTP 和 gRPC 请求的 80 多种常见错误。这些代码会: +- 在请求的 JSON 响应体中返回。 +- 启用后,会在运行时的调试级别日志中记录。 + - 如果您在 Kubernetes 中运行,错误代码会记录在 sidecar 中。 + - 如果您在自托管中运行,可以启用并查看调试日志。 + +## 错误格式 + +Dapr 错误代码由前缀、类别和错误本身的简写组成。例如: + +| 前缀 | 类别 | 错误简写 | +| ------ | -------- | --------------- | +| ERR_ | PUBSUB_ | NOT_FOUND | + +一些最常见的返回错误包括: + +- ERR_ACTOR_TIMER_CREATE +- ERR_PURGE_WORKFLOW +- ERR_STATE_STORE_NOT_FOUND +- ERR_HEALTH_NOT_READY + +> **注意:** [查看 Dapr 中错误代码的完整列表。]({{< ref error-codes-reference.md >}}) + +对于未找到的状态存储返回的错误可能如下所示: + +```json +{ + "error": "Bad Request", + "error_msg": "{\"errorCode\":\"ERR_STATE_STORE_NOT_FOUND\",\"message\":\"state store is not found\",\"details\":[{\"@type\":\"type.googleapis.com/google.rpc.ErrorInfo\",\"domain\":\"dapr.io\",\"metadata\":{\"appID\":\"nodeapp\"},\"reason\":\"DAPR_STATE_NOT_FOUND\"}]}", + "status": 400 +} +``` + +返回的错误包括: +- 错误代码:`ERR_STATE_STORE_NOT_FOUND` +- 描述问题的错误消息:`state store is not found` +- 发生错误的应用程序 ID:`nodeapp` +- 错误的原因:`DAPR_STATE_NOT_FOUND` + +## Dapr 错误代码指标 + +指标帮助您查看错误在运行时发生的具体时间。错误代码指标通过 `error_code_total` 端点收集。此端点默认情况下是禁用的。您可以[通过配置文件中的 `recordErrorCodes` 字段启用它]({{< ref "metrics-overview.md#configuring-metrics-for-error-codes" >}})。 + +## 演示 + +观看 [Diagrid 的 Dapr v1.15 庆祝活动](https://www.diagrid.io/videos/dapr-1-15-deep-dive) 中的演示,了解如何启用错误代码指标以及处理运行时返回的错误代码。 + + + +## 下一步 + +{{< button text="查看所有 Dapr 错误代码的列表" page="error-codes-reference" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/error-codes/grpc-error-codes.md b/src/translated_content/zh_CN/docs/developing-applications/error-codes/grpc-error-codes.md new file mode 100644 index 000000000..6a18b58dc --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/error-codes/grpc-error-codes.md @@ -0,0 +1,96 @@ +--- +type: docs +title: 处理 gRPC 错误代码 +linkTitle: "gRPC" +weight: 40 +description: "关于 Dapr gRPC 错误及其处理方法的信息" +--- + +最初,错误是按照 [标准 gRPC 错误模型](https://grpc.io/docs/guides/error/#standard-error-model) 进行处理的。然而,为了提供更详细且信息丰富的错误消息,定义了一个增强的错误模型,与 gRPC 的 [更丰富的错误模型](https://grpc.io/docs/guides/error/#richer-error-model) 保持一致。 + +{{% alert title="注意" color="primary" %}} +并不是所有的 Dapr 错误都已转换为更丰富的 gRPC 错误模型。 +{{% /alert %}} + +## 标准 gRPC 错误模型 + +[标准 gRPC 错误模型](https://grpc.io/docs/guides/error/#standard-error-model) 是 gRPC 中的一种错误报告方法。每个错误响应都包含一个错误代码和一条错误消息。错误代码是标准化的,反映了常见的错误情况。 + +**标准 gRPC 错误响应示例:** +``` +ERROR: + Code: InvalidArgument + Message: 输入键/键前缀 'bad||keyname' 不能包含 '||' +``` + +## 更丰富的 gRPC 错误模型 + +[更丰富的 gRPC 错误模型](https://grpc.io/docs/guides/error/#richer-error-model) 通过提供关于错误的额外上下文和详细信息来扩展标准错误模型。此模型包括标准错误 `code` 和 `message`,以及一个 `details` 部分,可以包含各种类型的信息,如 `ErrorInfo`、`ResourceInfo` 和 `BadRequest` 详细信息。 + +**更丰富的 gRPC 错误响应示例:** +``` +ERROR: + Code: InvalidArgument + Message: 输入键/键前缀 'bad||keyname' 不能包含 '||' + Details: + 1) { + "@type": "type.googleapis.com/google.rpc.ErrorInfo", + "domain": "dapr.io", + "reason": "DAPR_STATE_ILLEGAL_KEY" + } + 2) { + "@type": "type.googleapis.com/google.rpc.ResourceInfo", + "resourceName": "statestore", + "resourceType": "state" + } + 3) { + "@type": "type.googleapis.com/google.rpc.BadRequest", + "fieldViolations": [ + { + "field": "bad||keyname", + "description": "输入键/键前缀 'bad||keyname' 不能包含 '||'" + } + ] + } +``` + +对于 HTTP 客户端,Dapr 会将 gRPC 错误模型转换为类似的 JSON 格式结构。响应包括一个 `errorCode`、一个 `message` 和一个 `details` 数组,反映了更丰富的 gRPC 模型中的结构。 + +**HTTP 错误响应示例:** +```json +{ + "errorCode": "ERR_MALFORMED_REQUEST", + "message": "api error: code = InvalidArgument desc = 输入键/键前缀 'bad||keyname' 不能包含 '||'", + "details": [ + { + "@type": "type.googleapis.com/google.rpc.ErrorInfo", + "domain": "dapr.io", + "metadata": null, + "reason": "DAPR_STATE_ILLEGAL_KEY" + }, + { + "@type": "type.googleapis.com/google.rpc.ResourceInfo", + "description": "", + "owner": "", + "resource_name": "statestore", + "resource_type": "state" + }, + { + "@type": "type.googleapis.com/google.rpc.BadRequest", + "field_violations": [ + { + "field": "bad||keyname", + "description": "api error: code = InvalidArgument desc = 输入键/键前缀 'bad||keyname' 不能包含 '||'" + } + ] + } + ] +} +``` + +您可以在[这里](https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto)找到所有可能状态详细信息的规范。 + +## 相关链接 + +- [编写错误代码](https://github.com/dapr/dapr/tree/master/pkg/api/errors) +- [在 Go SDK 中使用错误代码](https://docs.dapr.io/developing-applications/sdks/go/go-client/#error-handling) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/error-codes/http-error-codes.md b/src/translated_content/zh_CN/docs/developing-applications/error-codes/http-error-codes.md new file mode 100644 index 000000000..44960617b --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/error-codes/http-error-codes.md @@ -0,0 +1,21 @@ +--- +type: docs +title: "处理 HTTP 错误代码" +linkTitle: "HTTP" +description: "Dapr HTTP 错误代码的详细参考及其处理方法" +weight: 30 +--- + +在向 Dapr 运行时发出的 HTTP 调用中,如果发生错误,响应体会返回一个错误的 JSON。该 JSON 包含错误代码和描述性错误信息。 + +``` +{ + "errorCode": "ERR_STATE_GET", + "message": "请求的状态键在状态存储中不存在。" +} +``` + +## 相关内容 + +- [错误代码参考列表]({{< ref error-codes-reference.md >}}) +- [处理 gRPC 错误代码]({{< ref grpc-error-codes.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/AWS/_index.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/AWS/_index.md new file mode 100644 index 000000000..1d0c88734 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/AWS/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "AWS 集成" +linkTitle: "AWS" +weight: 1000 +description: "Dapr 集成 AWS 服务" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/AWS/authenticating-aws.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/AWS/authenticating-aws.md new file mode 100644 index 000000000..5014aa4b7 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/AWS/authenticating-aws.md @@ -0,0 +1,171 @@ +--- +type: docs +title: "AWS 认证" +linkTitle: "AWS 认证" +weight: 10 +description: "关于 AWS 的认证和配置选项的信息" +aliases: + - /zh-hans/developing-applications/integrations/authenticating/authenticating-aws/ +--- + +Dapr 组件通过 AWS SDK 使用 AWS 服务(例如,DynamoDB、SQS、S3),并支持标准化的配置属性。[了解更多关于 AWS SDK 如何处理凭证的信息](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials)。 + +您可以使用 AWS SDK 的默认提供者链,或者选择以下列出的预定义 AWS 认证配置文件之一来进行认证配置。通过测试和检查 Dapr 运行时日志来验证组件配置,确保正确初始化。 + +### 术语 +- **ARN (Amazon Resource Name):** 用于唯一标识 AWS 资源的标识符。格式为:`arn:partition:service:region:account-id:resource`。示例:`arn:aws:iam::123456789012:role/example-role`。 +- **IAM (Identity and Access Management):** AWS 提供的用于安全管理对 AWS 资源访问的服务。 + +### 认证配置文件 + +#### 访问密钥 ID 和秘密访问密钥 +使用静态访问密钥和秘密密钥凭证,可以通过组件元数据字段或通过[默认 AWS 配置](https://docs.aws.amazon.com/sdkref/latest/guide/creds-config-files.html)进行配置。 + +{{% alert title="重要" color="warning" %}} +在以下场景中,建议通过默认 AWS 配置加载凭证: +- 在 EKS(AWS Kubernetes)上运行 Dapr sidecar (`daprd`) 和您的应用程序。 +- 使用附加了定义 AWS 资源访问的 IAM 策略的节点或 pod。 +{{% /alert %}} + +| 属性 | 必需 | 描述 | 示例 | +| --------- | ----------- | ----------- | ----------- | +| `region` | Y | 要连接的 AWS 区域。 | "us-east-1" | +| `accessKey` | N | AWS 访问密钥 ID。在 Dapr v1.17 中将是必需的。 | "AKIAIOSFODNN7EXAMPLE" | +| `secretKey` | N | AWS 秘密访问密钥,与 `accessKey` 一起使用。在 Dapr v1.17 中将是必需的。 | "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" | +| `sessionToken` | N | AWS 会话令牌,与 `accessKey` 和 `secretKey` 一起使用。对于 IAM 用户密钥通常不需要。 | | + +#### 假设 IAM 角色 +此配置文件允许 Dapr 假设特定的 IAM 角色。通常在 Dapr sidecar 在 EKS 或链接到 IAM 策略的节点/pod 上运行时使用。目前由 Kafka 和 PostgreSQL 组件支持。 + +| 属性 | 必需 | 描述 | 示例 | +| --------- | ----------- | ----------- | ----------- | +| `region` | Y | 要连接的 AWS 区域。 | "us-east-1" | +| `assumeRoleArn` | N | 具有 AWS 资源访问权限的 IAM 角色的 ARN。在 Dapr v1.17 中将是必需的。 | "arn:aws:iam::123456789:role/mskRole" | +| `sessionName` | N | 角色假设的会话名称。默认是 `"DaprDefaultSession"`。 | "MyAppSession" | + +#### 从环境变量获取凭证 +使用[环境变量](https://docs.aws.amazon.com/sdkref/latest/guide/environment-variables.html)进行认证。这对于在自托管模式下运行的 Dapr 特别有用,因为 sidecar 注入器不会配置环境变量。 + +此认证配置文件不需要任何元数据字段。 + +#### IAM Roles Anywhere +[IAM Roles Anywhere](https://aws.amazon.com/iam/roles-anywhere/) 将基于 IAM 角色的认证扩展到外部工作负载。通过使用加密签名的证书,消除了长期凭证的需求,这些证书基于 Dapr PKI 的信任关系。Dapr SPIFFE 身份 X.509 证书用于认证到 AWS 服务,Dapr 在会话生命周期的一半时处理凭证轮换。 + +要配置此认证配置文件: +1. 使用 Dapr 证书包作为 `外部证书包` 在信任的 AWS 账户中创建一个信任锚。 +2. 创建一个具有必要资源权限策略的 IAM 角色,以及一个为 Roles Anywhere AWS 服务指定的信任实体。在此处,您指定允许的 SPIFFE 身份。 +3. 在 Roles Anywhere 服务下创建一个 IAM 配置文件,链接 IAM 角色。 + +| 属性 | 必需 | 描述 | 示例 | +| --------- | ----------- | ----------- | ----------- | +| `trustAnchorArn` | Y | 在 AWS 账户中授予 Dapr 证书颁发机构信任的信任锚的 ARN。 | arn:aws:rolesanywhere:us-west-1:012345678910:trust-anchor/01234568-0123-0123-0123-012345678901 | +| `trustProfileArn` | Y | 在信任的 AWS 账户中的 AWS IAM 配置文件的 ARN。 | arn:aws:rolesanywhere:us-west-1:012345678910:profile/01234568-0123-0123-0123-012345678901 | +| `assumeRoleArn` | Y | 在信任的 AWS 账户中要假设的 AWS IAM 角色的 ARN。 | arn:aws:iam:012345678910:role/exampleIAMRoleName | + +### 其他字段 + +一些 AWS 组件包括额外的可选字段: + +| 属性 | 必需 | 描述 | 示例 | +| --------- | ----------- | ----------- | ----------- | +| `endpoint` | N | 端点通常由 AWS SDK 内部处理。然而,在某些情况下,可能需要在本地设置它 - 例如,如果针对 [DynamoDB Local](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html) 进行开发。 | | + +此外,支持 AWS 认证配置文件的非原生 AWS 组件(如 Kafka 和 PostgreSQL)具有触发 AWS 认证逻辑的元数据字段。请务必查看特定组件文档。 + +## 在组件清单文件中显式指定凭证的替代方案 + +在生产场景中,建议使用以下解决方案: +- [Kiam](https://github.com/uswitch/kiam) +- [Kube2iam](https://github.com/jtblin/kube2iam) + +如果在 AWS EKS 上运行,您可以[将 IAM 角色链接到 Kubernetes 服务账户](https://docs.aws.amazon.com/eks/latest/userguide/create-service-account-iam-policy-and-role.html),您的 pod 可以使用该账户。 + +所有这些解决方案都解决了同一个问题:它们允许 Dapr 运行时进程(或 sidecar)动态检索凭证,因此不需要显式凭证。这提供了几个好处,例如自动密钥轮换,以及避免管理 secret。 + +Kiam 和 Kube2IAM 都通过拦截对[实例元数据服务](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html)的调用来工作。 + +### 在 AWS EC2 上以独立模式运行时使用实例配置文件 + +如果直接在 AWS EC2 实例上以独立模式运行 Dapr,您可以使用实例配置文件。 + +1. 配置一个 IAM 角色。 +1. [将其附加到实例配置文件](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_use_switch-role-ec2_instance-profiles.html)以用于 ec2 实例。 + +然后,Dapr 在 Dapr 组件清单中不指定凭证的情况下认证到 AWS。 + +### 在本地以独立模式运行 dapr 时认证到 AWS + +{{< tabs "Linux/MacOS" "Windows" >}} + +{{% codetab %}} + +在独立模式下运行 Dapr(或直接运行 Dapr 运行时)时,您可以将环境变量注入到进程中,如以下示例: + +```bash +FOO=bar daprd --app-id myapp +``` + +如果您在本地[配置了命名的 AWS 配置文件](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html),您可以通过指定 "AWS_PROFILE" 环境变量来告诉 Dapr(或 Dapr 运行时)使用哪个配置文件: + +```bash +AWS_PROFILE=myprofile dapr run... +``` + +或 + +```bash +AWS_PROFILE=myprofile daprd... +``` + +您可以使用任何[支持的环境变量](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html#envvars-list)以这种方式配置 Dapr。 + +{{% /codetab %}} + + +{{% codetab %}} + +在 Windows 上,需要在启动 `dapr` 或 `daprd` 命令之前设置环境变量,像在 Linux/MacOS 中那样内联设置是不支持的。 + +{{% /codetab %}} + +{{< /tabs >}} + +### 如果使用基于 AWS SSO 的配置文件认证到 AWS + +如果您使用 [AWS SSO](https://aws.amazon.com/single-sign-on/) 认证到 AWS,某些 AWS SDK(包括 Go SDK)尚不支持此功能。您可以使用几个实用程序来“弥合” AWS SSO 凭证和“传统”凭证之间的差距,例如: +- [AwsHelper](https://pypi.org/project/awshelper/) +- [aws-sso-util](https://github.com/benkehoe/aws-sso-util) + +{{< tabs "Linux/MacOS" "Windows" >}} + +{{% codetab %}} + +如果使用 AwsHelper,像这样启动 Dapr: + +```bash +AWS_PROFILE=myprofile awshelper dapr run... +``` + +或 + +```bash +AWS_PROFILE=myprofile awshelper daprd... +``` +{{% /codetab %}} + + +{{% codetab %}} + +在 Windows 上,需要在启动 `awshelper` 命令之前设置环境变量,像在 Linux/MacOS 中那样内联设置是不支持的。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 + +{{< button text="参考 AWS 组件规范 >>" page="components-reference" >}} + +## 相关链接 + +有关更多信息,请参阅[如何 AWS SDK(Dapr 使用的)处理凭证](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html#specifying-credentials)。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/_index.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/_index.md new file mode 100644 index 000000000..c0b86d101 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "Azure 集成" +linkTitle: "Azure" +weight: 1000 +description: "Dapr 集成 Azure 服务" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-api-management.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-api-management.md new file mode 100644 index 000000000..b8b29f9e1 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-api-management.md @@ -0,0 +1,16 @@ +--- +type: docs +title: "Azure API Management 与 Dapr 的集成策略" +linkTitle: "Azure API Management" +description: "通过 Azure API Management 策略发布 Dapr 服务和组件的 API" +weight: 2000 +--- + +[Azure API Management](https://learn.microsoft.com/azure/api-management/api-management-key-concepts) 是一种用于为后端服务创建一致且现代的 API 网关的方法,其中也包括使用 Dapr 构建的服务。您可以在自托管的 API Management 网关中启用 Dapr 支持,从而实现以下功能: +- 将请求转发至 Dapr 服务 +- 向 Dapr 发布/订阅主题发送消息 +- 激活 Dapr 输出绑定 + +试用 [Dapr & Azure API Management 集成示例](https://github.com/dapr/samples/tree/master/dapr-apim-integration)。 + +{{< button text="了解更多关于 Dapr 集成策略的信息" link="https://docs.microsoft.com/azure/api-management/api-management-dapr-policies" >}} diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-authentication/_index.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-authentication/_index.md new file mode 100644 index 000000000..5561e2b97 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-authentication/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "Azure 身份验证" +linkTitle: "Azure 身份验证" +weight: 1600 +description: "了解如何使用 Microsoft Entra ID 或托管身份来进行 Azure 组件的身份验证" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-authentication/authenticating-azure.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-authentication/authenticating-azure.md new file mode 100644 index 000000000..2a0a429cf --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-authentication/authenticating-azure.md @@ -0,0 +1,302 @@ +--- +type: docs +title: "Azure 身份验证" +linkTitle: "概述" +description: "如何使用 Microsoft Entra ID 和/或托管身份验证 Azure 组件" +aliases: + - "/zh-hans/operations/components/setup-secret-store/supported-secret-stores/azure-keyvault-managed-identity/" + - "/zh-hans/reference/components-reference/supported-secret-stores/azure-keyvault-managed-identity/" +weight: 10000 +--- + +大多数 Dapr 的 Azure 组件支持使用 Microsoft Entra ID 进行身份验证。通过这种方式: + +- 管理员可以充分利用 Azure 基于角色的访问控制 (RBAC) 的精细权限。 +- 在 Azure 服务(如 Azure 容器应用、Azure Kubernetes 服务、Azure 虚拟机或其他 Azure 平台服务)上运行的应用程序可以使用 [托管身份 (MI)](https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview) 和 [工作负载身份](https://learn.microsoft.com/azure/aks/workload-identity-overview)。这些功能使您的应用程序能够在不需要管理敏感凭据的情况下进行身份验证。 + +## 关于 Microsoft Entra ID 的身份验证 + +Microsoft Entra ID 是 Azure 的身份和访问管理 (IAM) 解决方案,用于对用户和服务进行身份验证和授权。 + +Microsoft Entra ID 基于 OAuth 2.0 等开放标准,允许服务(应用程序)获取访问令牌以请求 Azure 服务,包括 Azure 存储、Azure 服务总线、Azure 密钥保管库、Azure Cosmos DB、Azure PostgreSQL 数据库、Azure SQL 等。 + +> 在 Azure 术语中,应用程序也被称为“服务主体”。 + +一些 Azure 组件提供其他身份验证方法,例如基于“共享密钥”或“访问令牌”的系统。尽管这些方法在 Dapr 中是有效且受支持的,但建议尽可能使用 Microsoft Entra ID 对 Dapr 组件进行身份验证,以利用其众多优势,包括: + +- [托管身份和工作负载身份](#托管身份和工作负载身份) +- [基于角色的访问控制](#基于角色的访问控制) +- [审计](#审计) +- [(可选)使用证书进行身份验证](#可选使用证书进行身份验证) + +### 托管身份和工作负载身份 + +使用托管身份 (MI),您的应用程序可以通过 Microsoft Entra ID 进行身份验证并获取访问令牌以请求 Azure 服务。当您的应用程序在支持的 Azure 服务(如 Azure 虚拟机、Azure 容器应用、Azure Web 应用等)上运行时,可以在基础设施级别为您的应用程序分配一个身份。 + +使用 MI 后,您的代码无需处理凭据,这样可以: + +- 消除安全管理凭据的挑战 +- 允许开发和运营团队之间更好的职责分离 +- 减少有权访问凭据的人员数量 +- 简化操作,尤其是在使用多个环境时 + +在 Azure Kubernetes 服务上运行的应用程序可以类似地利用 [工作负载身份](https://learn.microsoft.com/azure/aks/workload-identity-overview) 自动为单个 pod 提供身份。 + +### 基于角色的访问控制 + +使用支持服务的 Azure 基于角色的访问控制 (RBAC) 时,可以对应用程序授予的权限进行精细调整。例如,您可以限制对数据子集的访问或将访问权限设为只读。 + +### 审计 + +使用 Microsoft Entra ID 提供了改进的访问审计体验。租户的管理员可以查阅审计日志以跟踪身份验证请求。 + +### (可选)使用证书进行身份验证 + +虽然 Microsoft Entra ID 允许您使用 MI,但您仍然可以选择使用证书进行身份验证。 + +## 对其他 Azure 环境的支持 + +默认情况下,Dapr 组件配置为与“公共云”中的 Azure 资源交互。如果您的应用程序部署到其他云(如 Azure 中国或 Azure 政府“主权云”),您可以通过将 `azureEnvironment` 元数据属性设置为以下支持的值之一来启用该功能: + +- Azure 公共云(默认):`"AzurePublicCloud"` +- Azure 中国:`"AzureChinaCloud"` +- Azure 政府:`"AzureUSGovernmentCloud"` + +> 对主权云的支持是实验性的。 + +## 凭据元数据字段 + +要使用 Microsoft Entra ID 进行身份验证,您需要将以下凭据作为值添加到您的 [Dapr 组件](#在-dapr-组件中的示例用法) 的元数据中。 + +### 元数据选项 + +根据您向 Dapr 服务传递凭据的方式,您有多种元数据选项。 + +- [关于 Microsoft Entra ID 的身份验证](#关于-microsoft-entra-id-的身份验证) + - [托管身份和工作负载身份](#托管身份和工作负载身份) + - [基于角色的访问控制](#基于角色的访问控制) + - [审计](#审计) + - [(可选)使用证书进行身份验证](#可选使用证书进行身份验证) +- [对其他 Azure 环境的支持](#对其他-azure-环境的支持) +- [凭据元数据字段](#凭据元数据字段) + - [元数据选项](#元数据选项) + - [使用客户端凭据进行身份验证](#使用客户端凭据进行身份验证) + - [使用证书进行身份验证](#使用证书进行身份验证) + - [使用托管身份 (MI) 进行身份验证](#使用托管身份-mi-进行身份验证) + - [在 AKS 上使用工作负载身份进行身份验证](#在-aks-上使用工作负载身份进行身份验证) + - [使用 Azure CLI 凭据进行身份验证(仅限开发)](#使用-azure-cli-凭据进行身份验证仅限开发) + - [在 Dapr 组件中的示例用法](#在-dapr-组件中的示例用法) +- [下一步](#下一步) +- [参考资料](#参考资料) + +#### 使用客户端凭据进行身份验证 + +| 字段 | 必需 | 详情 | 示例 | +|---------------------|----------|--------------------------------------|----------------------------------------------| +| `azureTenantId` | Y | Microsoft Entra ID 租户的 ID | `"cd4b2887-304c-47e1-b4d5-65447fdd542b"` | +| `azureClientId` | Y | 客户端 ID(应用程序 ID) | `"c7dd251f-811f-4ba2-a905-acd4d3f8f08b"` | +| `azureClientSecret` | Y | 客户端密钥(应用程序密码) | `"Ecy3XG7zVZK3/vl/a2NSB+a1zXLa8RnMum/IgD0E"` | + +在 Kubernetes 上运行时,您还可以使用对 Kubernetes secret 的引用来获取上述任何或所有值。 + +#### 使用证书进行身份验证 + +| 字段 | 必需 | 详情 | 示例 | +|--------|--------|--------|--------| +| `azureTenantId` | Y | Microsoft Entra ID 租户的 ID | `"cd4b2887-304c-47e1-b4d5-65447fdd542b"` | +| `azureClientId` | Y | 客户端 ID(应用程序 ID) | `"c7dd251f-811f-4ba2-a905-acd4d3f8f08b"` | +| `azureCertificate` | `azureCertificate` 和 `azureCertificateFile` 之一 | 证书和私钥(PFX/PKCS#12 格式) | `"-----BEGIN PRIVATE KEY-----\n MIIEvgI... \n -----END PRIVATE KEY----- \n -----BEGIN CERTIFICATE----- \n MIICoTC... \n -----END CERTIFICATE-----` | +| `azureCertificateFile` | `azureCertificate` 和 `azureCertificateFile` 之一 | 包含证书和私钥的 PFX/PKCS#12 文件的路径 | `"/path/to/file.pem"` | +| `azureCertificatePassword` | N | 如果加密,证书的密码 | `"password"` | + +在 Kubernetes 上运行时,您还可以使用对 Kubernetes secret 的引用来获取上述任何或所有值。 + +#### 使用托管身份 (MI) 进行身份验证 + +| 字段 | 必需 | 详情 | 示例 | +|-----------------|----------|----------------------------|------------------------------------------| +| `azureClientId` | N | 客户端 ID(应用程序 ID) | `"c7dd251f-811f-4ba2-a905-acd4d3f8f08b"` | + +[使用托管身份]({{< ref howto-mi.md >}}),通常推荐使用 `azureClientId` 字段。使用系统分配的身份时该字段是可选的,但使用用户分配的身份时可能是必需的。 + +#### 在 AKS 上使用工作负载身份进行身份验证 + +在 Azure Kubernetes 服务 (AKS) 上运行时,您可以使用工作负载身份对组件进行身份验证。请参阅 Azure AKS 文档以了解如何为您的 Kubernetes 资源 [启用工作负载身份](https://learn.microsoft.com/azure/aks/workload-identity-overview)。 + +#### 使用 Azure CLI 凭据进行身份验证(仅限开发) + +> **重要提示:** 此身份验证方法仅推荐用于 **开发**。 + +此身份验证方法在本地机器上开发时可能很有用。您将需要: + +- 安装 [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) +- 使用 `az login` 命令成功进行身份验证 + +当 Dapr 在主机上运行时,如果 Azure CLI 有可用的凭据,组件可以自动使用这些凭据进行身份验证,而无需配置其他身份验证方法。 + +使用此身份验证方法不需要设置任何元数据选项。 + +### 在 Dapr 组件中的示例用法 + +在此示例中,您将设置一个使用 Microsoft Entra ID 进行身份验证的 Azure 密钥保管库 secret 存储组件。 + +{{< tabs "自托管" "Kubernetes">}} + +{{% codetab %}} + +要使用 **客户端密钥**,请在组件目录中创建一个名为 `azurekeyvault.yaml` 的文件,并填写上述设置过程中的详细信息: + +```yaml +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: azureTenantId + value: "[your_tenant_id]" + - name: azureClientId + value: "[your_client_id]" + - name: azureClientSecret + value : "[your_client_secret]" +``` + +如果您想使用保存在本地磁盘上的 **证书**,请改用: + +```yaml +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: azureTenantId + value: "[your_tenant_id]" + - name: azureClientId + value: "[your_client_id]" + - name: azureCertificateFile + value : "[pfx_certificate_file_fully_qualified_local_path]" +``` +{{% /codetab %}} + +{{% codetab %}} +在 Kubernetes 中,您将客户端密钥或证书存储到 Kubernetes Secret Store 中,然后在 YAML 文件中引用它们。 + +要使用 **客户端密钥**: + +1. 使用以下命令创建一个 Kubernetes secret: + + ```bash + kubectl create secret generic [your_k8s_secret_name] --from-literal=[your_k8s_secret_key]=[your_client_secret] + ``` + + - `[your_client_secret]` 是上面生成的应用程序客户端密钥 + - `[your_k8s_secret_name]` 是 Kubernetes secret store 中的 secret 名称 + - `[your_k8s_secret_key]` 是 Kubernetes secret store 中的 secret 键 + +1. 创建一个 `azurekeyvault.yaml` 组件文件。 + + 组件 yaml 使用 `auth` 属性引用 Kubernetes secretstore,并且 `secretKeyRef` 引用存储在 Kubernetes secret store 中的客户端密钥。 + + ```yaml + 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: azureTenantId + value: "[your_tenant_id]" + - name: azureClientId + value: "[your_client_id]" + - name: azureClientSecret + secretKeyRef: + name: "[your_k8s_secret_name]" + key: "[your_k8s_secret_key]" + auth: + secretStore: kubernetes + ``` + +1. 应用 `azurekeyvault.yaml` 组件: + + ```bash + kubectl apply -f azurekeyvault.yaml + ``` + +要使用 **证书**: + +1. 使用以下命令创建一个 Kubernetes secret: + + ```bash + kubectl create secret generic [your_k8s_secret_name] --from-file=[your_k8s_secret_key]=[pfx_certificate_file_fully_qualified_local_path] + ``` + + - `[pfx_certificate_file_fully_qualified_local_path]` 是您之前获取的 PFX 文件的路径 + - `[your_k8s_secret_name]` 是 Kubernetes secret store 中的 secret 名称 + - `[your_k8s_secret_key]` 是 Kubernetes secret store 中的 secret 键 + +1. 创建一个 `azurekeyvault.yaml` 组件文件。 + + 组件 yaml 使用 `auth` 属性引用 Kubernetes secretstore,并且 `secretKeyRef` 引用存储在 Kubernetes secret store 中的证书。 + + ```yaml + 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: azureTenantId + value: "[your_tenant_id]" + - name: azureClientId + value: "[your_client_id]" + - name: azureCertificate + secretKeyRef: + name: "[your_k8s_secret_name]" + key: "[your_k8s_secret_key]" + auth: + secretStore: kubernetes + ``` + +1. 应用 `azurekeyvault.yaml` 组件: + + ```bash + kubectl apply -f azurekeyvault.yaml + ``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 + +{{< button text="生成新的 Microsoft Entra ID 应用程序和服务主体 >>" page="howto-aad.md" >}} + +## 参考资料 + +- [Microsoft Entra ID 应用凭据:Azure CLI 参考](https://docs.microsoft.com/cli/azure/ad/app/credential) +- [Azure 托管服务身份 (MSI) 概述](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview) +- [Secrets 构建块]({{< ref secrets >}}) +- [操作指南:检索 secret]({{< ref "howto-secrets.md" >}}) +- [操作指南:在 Dapr 组件中引用 secret]({{< ref component-secrets.md >}}) +- [Secrets API 参考]({{< ref secrets_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-authentication/howto-aad.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-authentication/howto-aad.md new file mode 100644 index 000000000..2c755c411 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-authentication/howto-aad.md @@ -0,0 +1,136 @@ +--- +type: docs +title: "如何创建新的 Microsoft Entra ID 应用程序和服务主体" +linkTitle: "如何创建 Microsoft Entra ID 应用程序和服务主体" +weight: 30000 +description: "了解如何创建 Microsoft Entra ID 应用程序并将其用作服务主体" +--- + +## 先决条件 + +- [一个 Azure 订阅](https://azure.microsoft.com/free/) +- [Azure CLI](https://docs.microsoft.com/cli/azure/install-azure-cli) +- [jq](https://stedolan.github.io/jq/download/) +- OpenSSL(默认包含在所有 Linux 和 macOS 系统中,以及 WSL 中) +- 确保您使用的是 bash 或 zsh shell + +## 使用 Azure CLI 登录 Azure + +在新终端中,运行以下命令: + +```sh +az login +az account set -s [your subscription id] +``` + +### 创建 Microsoft Entra ID 应用程序 + +使用以下命令创建 Microsoft Entra ID 应用程序: + +```sh +# 应用程序 / 服务主体的友好名称 +APP_NAME="dapr-application" + +# 创建应用程序 +APP_ID=$(az ad app create --display-name "${APP_NAME}" | jq -r .appId) +``` + +选择传递凭据的方式。 + +{{< tabs "客户端密钥" "PFX 证书">}} + +{{% codetab %}} + +要创建一个**客户端密钥**,运行以下命令。 + +```sh +az ad app credential reset \ + --id "${APP_ID}" \ + --years 2 +``` + +这将生成一个基于 `base64` 字符集的随机40字符长的密码。此密码有效期为2年,之后需要更新。 + +请保存返回的输出值;您将需要它们来让 Dapr 通过 Azure 进行身份验证。预期输出: + +```json +{ + "appId": "", + "password": "", + "tenant": "" +} +``` + +在将返回的值添加到您的 Dapr 组件的元数据时: + +- `appId` 是 `azureClientId` 的值 +- `password` 是 `azureClientSecret` 的值(这是随机生成的) +- `tenant` 是 `azureTenantId` 的值 + +{{% /codetab %}} + +{{% codetab %}} +对于 **PFX (PKCS#12) 证书**,运行以下命令以创建自签名证书: + +```sh +az ad app credential reset \ + --id "${APP_ID}" \ + --create-cert +``` + +> **注意:** 自签名证书仅建议用于开发环境。在生产环境中,您应使用由 CA 签名并通过 `--cert` 标志导入的证书。 + +上述命令的输出应如下所示: + +请保存返回的输出值;您将需要它们来让 Dapr 通过 Azure 进行身份验证。预期输出: + +```json +{ + "appId": "", + "fileWithCertAndPrivateKey": "", + "password": null, + "tenant": "" +} +``` + +在将返回的值添加到您的 Dapr 组件的元数据时: + +- `appId` 是 `azureClientId` 的值 +- `tenant` 是 `azureTenantId` 的值 +- `fileWithCertAndPrivateKey` 表示自签名 PFX 证书和私钥的位置。使用该文件的内容作为 `azureCertificate`(或将其写入服务器上的文件并使用 `azureCertificateFile`) + +> **注意:** 虽然生成的文件具有 `.pem` 扩展名,但它包含编码为 PFX (PKCS#12) 的证书和私钥。 + +{{% /codetab %}} + +{{< /tabs >}} + +### 创建服务主体 + +一旦您创建了 Microsoft Entra ID 应用程序,为该应用程序创建一个服务主体。通过此服务主体,您可以授予其访问 Azure 资源的权限。 + +要创建服务主体,运行以下命令: + +```sh +SERVICE_PRINCIPAL_ID=$(az ad sp create \ + --id "${APP_ID}" \ + | jq -r .id) +echo "服务主体 ID: ${SERVICE_PRINCIPAL_ID}" +``` + +预期输出: + +```text +服务主体 ID: 1d0ccf05-5427-4b5e-8eb4-005ac5f9f163 +``` + +上面返回的值是**服务主体 ID**,它与 Microsoft Entra ID 应用程序 ID(客户端 ID)不同。服务主体 ID 在 Azure 租户内定义,用于授予应用程序访问 Azure 资源的权限。 +您将使用服务主体 ID 授予应用程序访问 Azure 资源的权限。 + +同时,**客户端 ID** 由您的应用程序用于身份验证。您将在 Dapr 清单中使用客户端 ID 来配置与 Azure 服务的身份验证。 + +请记住,刚刚创建的服务主体默认没有访问任何 Azure 资源的权限。需要根据需要为每个资源授予访问权限,如组件文档中所述。 + +## 下一步 + +{{< button text="使用托管身份" page="howto-mi.md" >}} diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-authentication/howto-mi.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-authentication/howto-mi.md new file mode 100644 index 000000000..fe33f9067 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-authentication/howto-mi.md @@ -0,0 +1,143 @@ +--- +type: docs +title: "如何使用托管身份" +linkTitle: "如何使用托管身份" +weight: 40000 +aliases: + - "/zh-hans/developing-applications/integrations/azure/azure-authentication/howto-msi/" +description: "学习如何使用托管身份" +--- + +托管身份可以自动进行身份验证,因为您的应用程序运行在具有系统分配或用户分配身份的 Azure 服务上。 + +要开始使用,您需要在各种 Azure 服务中启用托管身份作为服务选项/功能,这与 Dapr 无关。启用后,会在后台为 Microsoft Entra ID(以前称为 Azure Active Directory ID)创建一个身份(或应用程序)。 + +然后,您的 Dapr 服务可以利用该身份与 Microsoft Entra ID 进行认证,过程是透明的,您无需指定任何凭据。 + +在本指南中,您将学习如何: +- 通过官方 Azure 文档将您的身份授予您正在使用的 Azure 服务 +- 在您的组件中设置系统管理或用户分配身份 + +以上是全部内容。 + +{{% alert title="注意" color="primary" %}} +在您的组件 YAML 中,如果使用用户分配身份,您只需要 [`azureClientId` 属性]({{< ref "authenticating-azure.md#authenticating-with-managed-identities-mi" >}})。否则,您可以省略此属性,默认使用系统管理身份。 +{{% /alert %}} + +## 授予服务访问权限 + +为特定 Azure 资源(由资源范围标识)设置必要的 Microsoft Entra ID 角色分配或自定义权限给您的系统管理或用户分配身份。 + +您可以为新的或现有的 Azure 资源设置托管身份。说明取决于所使用的服务。请查看以下官方文档以获取最合适的说明: + +- [Azure Kubernetes Service (AKS)](https://docs.microsoft.com/azure/aks/use-managed-identity) +- [Azure Container Apps (ACA)](https://learn.microsoft.com/azure/container-apps/dapr-components?tabs=yaml#using-managed-identity) +- [Azure App Service](https://docs.microsoft.com/azure/app-service/overview-managed-identity)(包括 Azure Web Apps 和 Azure Functions) +- [Azure Virtual Machines (VM)](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/qs-configure-cli-windows-vm) +- [Azure Virtual Machines Scale Sets (VMSS)](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/qs-configure-cli-windows-vmss) +- [Azure Container Instance (ACI)](https://docs.microsoft.com/azure/container-instances/container-instances-managed-identity) + +在为您的 Azure 资源分配系统管理身份后,您将获得如下信息: + +```json +{ + "principalId": "", + "tenantId": "", + "type": "SystemAssigned", + "userAssignedIdentities": null +} +``` + +请注意 **`principalId`** 值,这是为您的身份创建的 [服务主体 ID]({{< ref "howto-aad.md#create-a-service-principal" >}})。使用它来授予您的 Azure 资源组件访问权限。 + +{{% alert title="Azure Container Apps 中的托管身份" color="primary" %}} +每个容器应用都有一个完全不同的系统管理身份,这使得在多个应用之间处理所需的角色分配非常难以管理。 + +因此,_强烈建议_ 使用用户分配身份并将其附加到所有应加载组件的应用中。然后,您应将组件范围限定在这些相同的应用上。 +{{% /alert %}} + +## 在您的组件中设置身份 + +默认情况下,Dapr Azure 组件会查找其运行环境的系统管理身份并以此进行认证。通常,对于给定组件,除了服务名称、存储帐户名称和 Azure 服务所需的任何其他属性(在文档中列出)外,没有使用系统管理身份的必需属性。 + +对于用户分配身份,除了您正在使用的服务所需的基本属性外,您还需要在组件中指定 `azureClientId`(用户分配身份 ID)。确保用户分配身份已附加到 Dapr 运行的 Azure 服务上,否则您将无法使用该身份。 + +{{% alert title="注意" color="primary" %}} +如果 sidecar 加载的组件未指定 `azureClientId`,它只会尝试系统分配身份。如果组件指定了 `azureClientId` 属性,它只会尝试具有该 ID 的特定用户分配身份。 +{{% /alert %}} + +以下示例演示了在 Azure KeyVault secrets 组件中设置系统管理或用户分配身份。 + +{{< tabs "系统管理" "用户分配" "Kubernetes" >}} + + +{{% codetab %}} + +如果您使用 Azure KeyVault 组件设置系统管理身份,YAML 将如下所示: + +```yml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: azurekeyvault +spec: + type: secretstores.azure.keyvault + version: v1 + metadata: + - name: vaultName + value: mykeyvault +``` + +在此示例中,系统管理身份查找服务身份并与 `mykeyvault` 保管库通信。接下来,授予您的系统管理身份访问所需服务的权限。 + +{{% /codetab %}} + + +{{% codetab %}} + +如果您使用 Azure KeyVault 组件设置用户分配身份,YAML 将如下所示: + +```yml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: azurekeyvault +spec: + type: secretstores.azure.keyvault + version: v1 + metadata: + - name: vaultName + value: mykeyvault + - name: azureClientId + value: someAzureIdentityClientIDHere +``` + +一旦您在组件 YAML 中设置了 `azureClientId` 属性,您就可以授予您的用户分配身份访问您的服务。 + +{{% /codetab %}} + + +{{% codetab %}} + +有关 Kubernetes 或 AKS 中的组件配置,请参阅 [工作负载身份指南。](https://learn.microsoft.com/azure/aks/workload-identity-overview?tabs=dotnet) + +{{% /codetab %}} + +{{< /tabs >}} + +## 故障排除 + +如果您收到错误或托管身份未按预期工作,请检查以下项目是否为真: + +- 系统管理身份或用户分配身份没有目标资源的所需权限。 +- 用户分配身份未附加到您加载组件的 Azure 服务(容器应用或 pod)。这尤其可能发生在: + - 您有一个未限定范围的组件(由环境中的所有容器应用或 AKS 集群中的所有部署加载的组件)。 + - 您仅将用户分配身份附加到 AKS 中的一个容器应用或一个部署(使用 [Azure 工作负载身份](https://learn.microsoft.com/azure/aks/workload-identity-overview?tabs=dotnet))。 + + 在这种情况下,由于身份未附加到 AKS 中的每个其他容器应用或部署,引用用户分配身份的组件通过 `azureClientId` 失败。 + +> **最佳实践:** 使用用户分配身份时,请确保将您的组件范围限定在特定应用上! + +## 下一步 + +{{< button text="参考 Azure 组件规范 >>" page="components-reference" >}} diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-functions.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-functions.md new file mode 100644 index 000000000..738b2c313 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-functions.md @@ -0,0 +1,15 @@ +--- +type: docs +title: "Azure Functions 运行时的 Dapr 扩展" +linkTitle: "Dapr 扩展 for Azure Functions" +description: "在 Azure Functions 运行时应用程序中访问 Dapr 功能" +weight: 3000 +--- + +Dapr 通过一个扩展与 [Azure Functions 运行时](https://learn.microsoft.com/azure/azure-functions/functions-overview) 集成,使函数能够轻松地与 Dapr 交互。 +- **Azure Functions** 提供了一种事件驱动的编程模型。 +- **Dapr** 提供了云原生的构建模块。 + +该扩展结合了两者的优势,适用于无服务器和事件驱动的应用程序。 + +{{< button text="体验 Dapr 扩展 for Azure Functions" link="https://learn.microsoft.com/azure/azure-functions/functions-bindings-dapr" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-kubernetes-service-extension.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-kubernetes-service-extension.md new file mode 100644 index 000000000..8df06657e --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/Azure/azure-kubernetes-service-extension.md @@ -0,0 +1,23 @@ +--- +type: docs +title: "适用于 Azure Kubernetes Service (AKS) 的 Dapr 扩展" +linkTitle: "适用于 Azure Kubernetes Service (AKS) 的 Dapr 扩展" +description: "通过 Dapr 扩展在您的 Azure Kubernetes Service (AKS) 集群上部署 Dapr" +weight: 4000 +--- + +在 AKS 上安装 Dapr 的推荐方法是使用 AKS Dapr 扩展。该扩展提供以下功能: +- 通过 Azure CLI 命令行参数支持所有原生 Dapr 配置功能 +- 可选择自动升级 Dapr 运行时的小版本 + +{{% alert title="注意" color="warning" %}} +如果通过 AKS 扩展安装 Dapr,最佳实践是继续使用该扩展进行 Dapr 的后续管理,而不是使用 Dapr CLI。混合使用这两种工具可能会导致冲突并产生意外行为。 +{{% /alert %}} + +使用 AKS 的 Dapr 扩展的先决条件: +- [一个 Azure 订阅](https://azure.microsoft.com/free/?WT.mc_id=A261C142F) +- [最新版本的 Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) +- [已有的 AKS 集群](https://learn.microsoft.com/azure/aks/tutorial-kubernetes-deploy-cluster) +- [Azure Kubernetes Service RBAC 管理员角色](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#azure-kubernetes-service-rbac-admin) + +{{< button text="了解有关 AKS 的 Dapr 扩展的更多信息" link="https://learn.microsoft.com/azure/aks/dapr" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/Diagrid/_index.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/Diagrid/_index.md new file mode 100644 index 000000000..eb6d559f9 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/Diagrid/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "Diagrid 集成" +linkTitle: "Diagrid" +weight: 1000 +description: "Dapr 和 Diagrid 的集成" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/Diagrid/diagrid-conductor.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/Diagrid/diagrid-conductor.md new file mode 100644 index 000000000..42a89fb53 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/Diagrid/diagrid-conductor.md @@ -0,0 +1,29 @@ +--- +type: docs +title: "Conductor: 企业级 Dapr 的 Kubernetes 解决方案" +linkTitle: "Diagrid Conductor" +description: "自动化操作,执行安全最佳实践,提高系统稳定性,并增强 Dapr 集群的可视化能力" +weight: 2000 +--- + +
Diagrid Conductor 图示 + +[Diagrid Conductor](https://www.diagrid.io/conductor) 能快速且安全地连接到所有运行 Dapr 和 Dapr 化应用程序的 Kubernetes 集群,提供卓越的操作管理、安全性、可靠性以及洞察力和协作能力。 + +**Dapr 管理自动化** + +一键完成 Dapr 的安装、升级和修补,选择性应用更新并自动回滚,确保您始终使用最新版本。 + +**智能顾问:发现并自动化最佳实践** + +提供信息并自动应用生产环境的最佳实践,持续监测以防止配置错误,提高安全性、可靠性和性能。 + +**资源使用报告与优化** + +通过分析历史资源使用情况,推荐应用程序的资源优化方案,显著降低 CPU 和内存成本。 + +**应用程序可视化工具** + +应用程序图表提供服务和基础设施组件的动态概览,促进开发与运维团队之间的协作。 + +{{< button text="了解更多关于 Diagrid Conductor" link="https://www.diagrid.io/conductor" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/Diagrid/test-containers.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/Diagrid/test-containers.md new file mode 100644 index 000000000..9743f06c4 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/Diagrid/test-containers.md @@ -0,0 +1,21 @@ +--- +type: docs +title: "如何使用 Testcontainers Dapr 模块进行集成" +linkTitle: "Dapr Testcontainers" +weight: 3000 +description: "在 Java 应用中集成 Dapr Testcontainer 模块" +--- + +您可以通过 Diagrid 提供的 Testcontainers Dapr 模块,在本地为您的 Java 应用集成 Dapr。只需在您的 Maven 项目中添加以下依赖项: + +```xml + + io.diagrid.dapr + testcontainers-dapr + 0.10.x + +``` + +[如果您使用 Spring Boot,也可以使用 Spring Boot Starter。](https://github.com/diagridio/spring-boot-starter-dapr) + +{{< button text="了解更多关于 Testcontainers Dapr 模块" link="https://github.com/diagridio/testcontainers-dapr" >}} diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/_index.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/_index.md new file mode 100644 index 000000000..ed72416ac --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "技术集成" +linkTitle: "技术集成" +weight: 70 +description: "Dapr与其他技术的无缝集成" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/autoscale-keda.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/autoscale-keda.md new file mode 100644 index 000000000..b04106a0b --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/autoscale-keda.md @@ -0,0 +1,162 @@ +--- +type: docs +title: "如何:使用 KEDA 自动扩展 Dapr 应用" +linkTitle: "KEDA" +description: "如何配置您的 Dapr 应用程序以使用 KEDA 进行自动扩展" +weight: 3000 +--- + +Dapr 通过其构建块 API 方法和众多 [pubsub 组件]({{< ref pubsub >}}),简化了消息处理应用程序的编写。由于 Dapr 可以在虚拟机、裸机、云或边缘 Kubernetes 等多种环境中运行,因此 Dapr 应用程序的自动扩展由其运行环境的管理层负责。 + +在 Kubernetes 环境中,Dapr 与 [KEDA](https://github.com/kedacore/keda) 集成,KEDA 是一个用于 Kubernetes 的事件驱动自动扩展器。Dapr 的许多 pubsub 组件与 KEDA 提供的扩展器功能相似,因此可以轻松配置您的 Dapr 部署在 Kubernetes 上使用 KEDA 根据负载进行自动扩展。 + +在本指南中,您将配置一个可扩展的 Dapr 应用程序,并在 Kafka 主题上进行负载管理。不过,您可以将此方法应用于 Dapr 提供的 _任何_ [pubsub 组件]({{< ref pubsub >}})。 + +{{% alert title="注意" color="primary" %}} + 如果您正在使用 Azure 容器应用,请参阅官方 Azure 文档以了解[使用 KEDA 扩展器扩展 Dapr 应用程序](https://learn.microsoft.com/azure/container-apps/dapr-keda-scaling)。 +{{% /alert %}} + +## 安装 KEDA + +要安装 KEDA,请按照 KEDA 网站上的[部署 KEDA](https://keda.sh/docs/latest/deploy/)说明进行操作。 + +## 安装和部署 Kafka + +如果您无法访问 Kafka 服务,可以使用 Helm 将其安装到您的 Kubernetes 集群中以进行此示例: + +```bash +helm repo add confluentinc https://confluentinc.github.io/cp-helm-charts/ +helm repo update +kubectl create ns kafka +helm install kafka confluentinc/cp-helm-charts -n kafka \ + --set cp-schema-registry.enabled=false \ + --set cp-kafka-rest.enabled=false \ + --set cp-kafka-connect.enabled=false +``` + +检查 Kafka 部署的状态: + +```shell +kubectl rollout status deployment.apps/kafka-cp-control-center -n kafka +kubectl rollout status deployment.apps/kafka-cp-ksql-server -n kafka +kubectl rollout status statefulset.apps/kafka-cp-kafka -n kafka +kubectl rollout status statefulset.apps/kafka-cp-zookeeper -n kafka +``` + +安装完成后,部署 Kafka 客户端并等待其准备就绪: + +```shell +kubectl apply -n kafka -f deployment/kafka-client.yaml +kubectl wait -n kafka --for=condition=ready pod kafka-client --timeout=120s +``` + +## 创建 Kafka 主题 + +创建本示例中使用的主题(`demo-topic`): + +```shell +kubectl -n kafka exec -it kafka-client -- kafka-topics \ + --zookeeper kafka-cp-zookeeper-headless:2181 \ + --topic demo-topic \ + --create \ + --partitions 10 \ + --replication-factor 3 \ + --if-not-exists +``` + +> 主题 `partitions` 的数量与 KEDA 为您的部署创建的最大副本数相关。 + +## 部署 Dapr pubsub 组件 + +为 Kubernetes 部署 Dapr Kafka pubsub 组件。将以下 YAML 粘贴到名为 `kafka-pubsub.yaml` 的文件中: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: autoscaling-pubsub +spec: + type: pubsub.kafka + version: v1 + metadata: + - name: brokers + value: kafka-cp-kafka.kafka.svc.cluster.local:9092 + - name: authRequired + value: "false" + - name: consumerID + value: autoscaling-subscriber +``` + +上述 YAML 定义了您的应用程序订阅的 pubsub 组件,以及 [您之前创建的 (`demo-topic`)]({{< ref "#create-the-kakfa-topic" >}})。 + +如果您使用了 [Kafka Helm 安装说明]({{< ref "#install-and-deploy-kafka" >}}),可以保持 `brokers` 值不变。否则,请将此值更改为您的 Kafka brokers 的连接字符串。 + +注意为 `consumerID` 设置的 `autoscaling-subscriber` 值。此值用于确保 KEDA 和您的部署使用相同的 [Kafka 分区偏移量](http://cloudurable.com/blog/kafka-architecture-topics/index.html#:~:text=Kafka%20continually%20appended%20to%20partitions,fit%20on%20a%20single%20server.),以便正确进行扩展。 + +现在,将组件部署到集群: + +```bash +kubectl apply -f kafka-pubsub.yaml +``` + +## 为 Kafka 部署 KEDA 自动扩展器 + +部署 KEDA 扩展对象,该对象: +- 监控指定 Kafka 主题上的滞后 +- 配置 Kubernetes 水平 Pod 自动扩展器 (HPA) 以扩展您的 Dapr 部署 + +将以下内容粘贴到名为 `kafka_scaler.yaml` 的文件中,并在需要的地方配置您的 Dapr 部署: + +```yaml +apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + name: subscriber-scaler +spec: + scaleTargetRef: + name: + pollingInterval: 15 + minReplicaCount: 0 + maxReplicaCount: 10 + triggers: + - type: kafka + metadata: + topic: demo-topic + bootstrapServers: kafka-cp-kafka.kafka.svc.cluster.local:9092 + consumerGroup: autoscaling-subscriber + lagThreshold: "5" +``` + +让我们回顾一下上面文件中的一些元数据值: + +| 值 | 描述 | +| ------ | ----------- | +| `scaleTargetRef`/`name` | 在部署中定义的应用程序的 Dapr ID(`dapr.io/id` 注释的值)。 | +| `pollingInterval` | KEDA 检查 Kafka 当前主题分区偏移量的频率(以秒为单位)。 | +| `minReplicaCount` | KEDA 为您的部署创建的最小副本数。如果您的应用程序启动时间较长,最好将其设置为 `1` 以确保您的部署始终至少有一个副本在运行。否则,设置为 `0`,KEDA 会为您创建第一个副本。 | +| `maxReplicaCount` | 您的部署的最大副本数。鉴于 [Kafka 分区偏移量](http://cloudurable.com/blog/kafka-architecture-topics/index.html#:~:text=Kafka%20continually%20appended%20to%20partitions,fit%20on%20a%20single%20server.) 的工作原理,您不应将该值设置得高于主题分区的总数。 | +| `triggers`/`metadata`/`topic` | 应设置为您的 Dapr 部署订阅的相同主题(在本示例中为 `demo-topic`)。 | +| `triggers`/`metadata`/`bootstrapServers` | 应设置为 `kafka-pubsub.yaml` 文件中使用的相同 broker 连接字符串。 | +| `triggers`/`metadata`/`consumerGroup` | 应设置为 `kafka-pubsub.yaml` 文件中 `consumerID` 的相同值。 | + +{{% alert title="重要" color="warning" %}} + 为 Dapr 服务订阅和 KEDA 扩展器配置设置相同的连接字符串、主题和消费者组值对于确保自动扩展正常工作至关重要。 +{{% /alert %}} + +将 KEDA 扩展器部署到 Kubernetes: + +```bash +kubectl apply -f kafka_scaler.yaml +``` + +全部完成! + +## 查看 KEDA 扩展器工作 + +现在 `ScaledObject` KEDA 对象已配置,您的部署将根据 Kafka 主题的滞后进行扩展。[了解有关为 Kafka 主题配置 KEDA 的更多信息](https://keda.sh/docs/2.0/scalers/apache-kafka/)。 + +如 KEDA 扩展器清单中定义的,您现在可以开始向您的 Kafka 主题 `demo-topic` 发布消息,并在滞后阈值高于 `5` 个主题时观察 pod 自动扩展。使用 Dapr [发布]({{< ref dapr-publish >}}) CLI 命令向 Kafka Dapr 组件发布消息。 + +## 下一步 + +[了解有关在 Azure 容器应用中使用 KEDA 扩展 Dapr pubsub 或绑定应用程序的信息](https://learn.microsoft.com/azure/container-apps/dapr-keda-scaling) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/gRPC-integration.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/gRPC-integration.md new file mode 100644 index 000000000..49c951891 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/gRPC-integration.md @@ -0,0 +1,257 @@ +--- +type: docs +title: "如何:在你的 Dapr 应用中使用 gRPC 接口" +linkTitle: "gRPC 接口" +weight: 6000 +description: "在你的应用中使用 Dapr gRPC API" +--- + +Dapr 提供了用于本地调用的 HTTP 和 gRPC API。[gRPC](https://grpc.io/) 适用于低延迟、高性能的场景,并通过 proto 客户端进行语言集成。 + +[在 Dapr SDK 文档中查找自动生成的客户端列表]({{< ref sdks >}})。 + +Dapr 运行时提供了一个 [proto 服务](https://github.com/dapr/dapr/blob/master/dapr/proto/runtime/v1/dapr.proto),应用可以通过 gRPC 与其通信。 + +除了通过 gRPC 调用 Dapr,Dapr 还支持通过代理方式进行服务到服务的调用。[在 gRPC 服务调用指南中了解更多]({{< ref howto-invoke-services-grpc.md >}})。 + +本指南演示了如何使用 Go SDK 配置和调用 Dapr 的 gRPC。 + +## 配置 Dapr 通过 gRPC 与应用通信 + +{{< tabs "自托管" "Kubernetes">}} + +{{% codetab %}} + +在自托管模式下运行时,使用 `--app-protocol` 标志指定 Dapr 使用 gRPC 与应用通信。 + +```bash +dapr run --app-protocol grpc --app-port 5005 node app.js +``` + +这使 Dapr 通过端口 `5005` 使用 gRPC 与应用进行通信。 + +{{% /codetab %}} + + +{{% codetab %}} + +在 Kubernetes 上,在你的部署 YAML 中设置以下注解: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myapp + namespace: default + labels: + app: myapp +spec: + replicas: 1 + selector: + matchLabels: + app: myapp + template: + metadata: + labels: + app: myapp + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "myapp" + dapr.io/app-protocol: "grpc" + dapr.io/app-port: "5005" +... +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 使用 gRPC 调用 Dapr + +以下步骤展示了如何创建一个 Dapr 客户端并调用其 `SaveStateData` 操作。 + +1. 导入包: + + ```go + package main + + import ( + "context" + "log" + "os" + + dapr "github.com/dapr/go-sdk/client" + ) + ``` + +1. 创建客户端: + + ```go + // 仅用于此演示 + ctx := context.Background() + data := []byte("ping") + + // 创建客户端 + client, err := dapr.NewClient() + if err != nil { + log.Panic(err) + } + defer client.Close() + ``` + + 3. 调用 `SaveState` 方法: + + ```go + // 使用键 key1 保存状态 + err = client.SaveState(ctx, "statestore", "key1", data) + if err != nil { + log.Panic(err) + } + log.Println("数据已保存") + ``` + +现在你可以探索 Dapr 客户端上的所有不同方法。 + +## 使用 Dapr 创建 gRPC 应用 + +以下步骤将展示如何创建一个应用,该应用暴露一个服务器,Dapr 可以与之通信。 + +1. 导入包: + + ```go + package main + + import ( + "context" + "fmt" + "log" + "net" + + "github.com/golang/protobuf/ptypes/any" + "github.com/golang/protobuf/ptypes/empty" + + commonv1pb "github.com/dapr/dapr/pkg/proto/common/v1" + pb "github.com/dapr/dapr/pkg/proto/runtime/v1" + "google.golang.org/grpc" + ) + ``` + +1. 实现接口: + + ```go + // server 是我们的用户应用 + type server struct { + pb.UnimplementedAppCallbackServer + } + + // EchoMethod 是一个简单的演示方法 + func (s *server) EchoMethod() string { + return "pong" + } + + // 当远程服务通过 Dapr 调用应用时,此方法被调用 + // 负载携带一个方法以识别方法、一组元数据属性和一个可选负载 + func (s *server) OnInvoke(ctx context.Context, in *commonv1pb.InvokeRequest) (*commonv1pb.InvokeResponse, error) { + var response string + + switch in.Method { + case "EchoMethod": + response = s.EchoMethod() + } + + return &commonv1pb.InvokeResponse{ + ContentType: "text/plain; charset=UTF-8", + Data: &any.Any{Value: []byte(response)}, + }, nil + } + + // Dapr 将调用此方法以获取应用想要订阅的主题列表。在此示例中,我们告诉 Dapr + // 订阅名为 TopicA 的主题 + func (s *server) ListTopicSubscriptions(ctx context.Context, in *empty.Empty) (*pb.ListTopicSubscriptionsResponse, error) { + return &pb.ListTopicSubscriptionsResponse{ + Subscriptions: []*pb.TopicSubscription{ + {Topic: "TopicA"}, + }, + }, nil + } + + // Dapr 将调用此方法以获取应用将被调用的绑定列表。在此示例中,我们告诉 Dapr + // 使用名为 storage 的绑定调用我们的应用 + func (s *server) ListInputBindings(ctx context.Context, in *empty.Empty) (*pb.ListInputBindingsResponse, error) { + return &pb.ListInputBindingsResponse{ + Bindings: []string{"storage"}, + }, nil + } + + // 每当从注册的绑定触发新事件时,此方法被调用。消息携带绑定名称、负载和可选元数据 + func (s *server) OnBindingEvent(ctx context.Context, in *pb.BindingEventRequest) (*pb.BindingEventResponse, error) { + fmt.Println("从绑定调用") + return &pb.BindingEventResponse{}, nil + } + + // 每当消息发布到已订阅的主题时,此方法被触发。Dapr 在 CloudEvents 0.3 信封中发送已发布的消息。 + func (s *server) OnTopicEvent(ctx context.Context, in *pb.TopicEventRequest) (*pb.TopicEventResponse, error) { + fmt.Println("主题消息到达") + return &pb.TopicEventResponse{}, nil + } + + ``` + +1. 创建服务器: + + ```go + func main() { + // 创建监听器 + lis, err := net.Listen("tcp", ":50001") + if err != nil { + log.Fatalf("监听失败: %v", err) + } + + // 创建 grpc 服务器 + s := grpc.NewServer() + pb.RegisterAppCallbackServer(s, &server{}) + + fmt.Println("客户端启动中...") + + // 并开始... + if err := s.Serve(lis); err != nil { + log.Fatalf("服务失败: %v", err) + } + } + ``` + + 这将在端口 50001 上为你的应用创建一个 gRPC 服务器。 + +## 运行应用 + +{{< tabs "自托管" "Kubernetes">}} + +{{% codetab %}} + +要在本地运行,使用 Dapr CLI: + +```bash +dapr run --app-id goapp --app-port 50001 --app-protocol grpc go run main.go +``` + +{{% /codetab %}} + + +{{% codetab %}} + +在 Kubernetes 上,如上所述,在你的 pod 规范模板中设置所需的 `dapr.io/app-protocol: "grpc"` 和 `dapr.io/app-port: "50001` 注解。 + +{{% /codetab %}} + +{{< /tabs >}} + + +## 其他语言 + +你可以使用任何 Protobuf 支持的语言与 Dapr 一起使用,而不仅限于当前可用的生成 SDK。 + +使用 [protoc](https://developers.google.com/protocol-buffers/docs/downloads) 工具,你可以为其他语言(如 Ruby、C++、Rust 等)生成 Dapr 客户端。 + +## 相关主题 +- [服务调用构建块]({{< ref service-invocation >}}) +- [服务调用 API 规范]({{< ref service_invocation_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/github_actions.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/github_actions.md new file mode 100644 index 000000000..953296ad4 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/github_actions.md @@ -0,0 +1,53 @@ +--- +type: docs +weight: 5000 +title: "如何:在 GitHub Actions 工作流中使用 Dapr CLI" +linkTitle: "GitHub Actions" +description: "将 Dapr CLI 集成到您的 GitHub Actions 中,以便在您的环境中部署和管理 Dapr。" +--- + +Dapr 可以通过 GitHub Marketplace 上的 [Dapr 工具安装器](https://github.com/marketplace/actions/dapr-tool-installer)与 GitHub Actions 进行集成。这个安装器会将 Dapr CLI 添加到您的工作流中,使您能够在不同环境中部署、管理和升级 Dapr。 + +## 使用 Dapr 工具安装器安装 Dapr CLI + +请将以下代码片段复制并粘贴到您的应用程序的 YAML 文件中: + +```yaml +- name: Dapr 工具安装器 + uses: dapr/setup-dapr@v1 +``` + +[`dapr/setup-dapr` action](https://github.com/dapr/setup-dapr) 可以在 macOS、Linux 和 Windows 运行器上安装指定版本的 Dapr CLI。安装完成后,您可以运行任何 [Dapr CLI 命令]({{< ref cli >}}) 来管理您的 Dapr 环境。 + +有关所有输入的详细信息,请参阅 [`action.yml` 元数据文件](https://github.com/dapr/setup-dapr/blob/main/action.yml)。 + +## 示例 + +例如,如果您的应用程序使用了 [Azure Kubernetes Service (AKS) 的 Dapr 扩展]({{< ref azure-kubernetes-service-extension.md >}}),那么您的应用程序 YAML 文件可能如下所示: + +```yaml +- name: 安装 Dapr + uses: dapr/setup-dapr@v1 + with: + version: '{{% dapr-latest-version long="true" %}}' + +- name: 初始化 Dapr + shell: bash + run: | + # 获取用于 dapr init 的 K8s 凭据 + az aks get-credentials --resource-group ${{ env.RG_NAME }} --name "${{ steps.azure-deployment.outputs.aksName }}" + + # 初始化 Dapr + # 将 Dapr init 日志分组,以便可以折叠这些行。 + echo "::group::初始化 Dapr" + dapr init --kubernetes --wait --runtime-version ${{ env.DAPR_VERSION }} + echo "::endgroup::" + + dapr status --kubernetes + working-directory: ./demos/demo3 +``` + +## 下一步 + +- 了解更多关于 [GitHub Actions](https://docs.github.com/en/actions) 的信息。 +- 通过教程学习 [GitHub Actions 如何与您的 Dapr 容器应用程序(Azure 容器应用程序)协作](https://learn.microsoft.com/azure/container-apps/dapr-github-actions?tabs=azure-cli)。 diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/kratix-marketplace.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/kratix-marketplace.md new file mode 100644 index 000000000..43cf28e6e --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/kratix-marketplace.md @@ -0,0 +1,17 @@ +--- +type: docs +title: "如何:与 Kratix 集成" +linkTitle: "Kratix 市场" +weight: 8000 +description: "使用 Dapr promise 与 Kratix 集成" +--- + +在 [Kratix 市场](https://docs.kratix.io/marketplace) 中,Dapr 可以用于构建满足您需求的定制平台。 + +{{% alert title="注意" color="warning" %}} +Dapr Helm chart 生成的静态公钥和私钥对会被发布在仓库中。此 promise 仅适用于本地演示。如果您计划将此 promise 用于其他用途,建议手动更新 promise 中的所有 secret,并使用您自己的凭据。 +{{% /alert %}} + +只需安装 Dapr Promise,即可在所有匹配的集群上安装 Dapr。 + +{{< button text="安装 Dapr Promise" link="https://github.com/syntasso/kratix-marketplace/tree/main/dapr" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/integrations/kubernetes-operator.md b/src/translated_content/zh_CN/docs/developing-applications/integrations/kubernetes-operator.md new file mode 100644 index 000000000..d84aba4e5 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/integrations/kubernetes-operator.md @@ -0,0 +1,11 @@ +--- +type: docs +title: "如何使用 Dapr Kubernetes Operator" +linkTitle: "Dapr Kubernetes Operator" +weight: 7000 +description: "通过 Dapr Kubernetes Operator 管理 Dapr 控制平面" +--- + +您可以通过 Dapr Kubernetes Operator 来管理 Dapr 的控制平面。这个工具可以帮助您自动化管理在 Kubernetes 环境中 Dapr 控制平面的生命周期任务。 + +{{< button text="安装和使用 Dapr Kubernetes Operator" link="https://github.com/dapr/kubernetes-operator" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/local-development/_index.md b/src/translated_content/zh_CN/docs/developing-applications/local-development/_index.md new file mode 100644 index 000000000..93d296284 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/local-development/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "本地开发" +linkTitle: "本地开发" +weight: 50 +description: "Dapr应用的本地开发功能" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/_index.md b/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/_index.md new file mode 100644 index 000000000..3e7db69b2 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "IDE 支持" +linkTitle: "IDE 支持" +weight: 200 +description: "支持常见的集成开发环境 (IDEs)" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/intellij.md b/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/intellij.md new file mode 100644 index 000000000..a1f5c34e9 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/intellij.md @@ -0,0 +1,152 @@ +--- +type: docs +title: "IntelliJ" +linkTitle: "IntelliJ" +weight: 2000 +description: "在IntelliJ社区版中配置Dapr调试环境" +--- + +在开发Dapr应用程序时,通常会使用Dapr CLI来启动您的服务,例如: + +```bash +dapr run --app-id nodeapp --app-port 3000 --dapr-http-port 3500 app.js +``` + +这会使用默认的组件yaml文件(在执行`dapr init`时创建),使您的服务能够与本地Redis容器交互。这种方式在初期非常有用,但如果您需要附加调试器来逐步调试代码,该怎么办?此时,您可以选择不通过Dapr CLI直接启动应用程序。 + +一种方法是先通过命令行运行`dapr run --`,然后启动您的代码并附加调试器。虽然这种方法可行,但需要在终端和IDE之间切换,并且对其他开发人员来说可能不够直观。 + +本文档将介绍如何直接在IntelliJ中使用`dapr`进行调试。在开始之前,请确保您已通过`dapr init`初始化了Dapr的开发环境。 + +让我们开始吧! + +## 将Dapr添加为“外部工具” + +首先,在修改配置文件之前,请退出IntelliJ。 + +### IntelliJ配置文件位置 +对于版本[2020.1](https://www.jetbrains.com/help/idea/2020.1/tuning-the-ide.html#config-directory)及以上,工具的配置文件应位于: + +{{< tabs Windows Linux MacOS >}} + +{{% codetab %}} + +```powershell +%USERPROFILE%\AppData\Roaming\JetBrains\IntelliJIdea2020.1\tools\ +``` +{{% /codetab %}} + + +{{% codetab %}} + ```shell + $HOME/.config/JetBrains/IntelliJIdea2020.1/tools/ + ``` +{{% /codetab %}} + + +{{% codetab %}} +```shell +~/Library/Application\ Support/JetBrains/IntelliJIdea2020.1/tools/ +``` +{{% /codetab %}} + + +{{< /tabs >}} + +> 对于2019.3或更早版本,配置文件位置不同。请参见[此处](https://www.jetbrains.com/help/idea/2019.3/tuning-the-ide.html#config-directory)了解更多详情。 + +如有需要,请更改路径中的IntelliJ版本。 + +在`/tools/External\ Tools.xml`中创建或编辑文件(如有需要更改路径中的IntelliJ版本)。``是操作系统相关的,如上所示。 + +添加一个新的``条目: + +```xml + + ... + + + + + + + ... + +``` + +可选地,您还可以为可以在多个项目中重用的sidecar工具创建一个新条目: + +```xml + + ... + + + + + + + + + + + + + ... + +``` + +## 创建或编辑运行配置 + +现在,为要调试的应用程序创建或编辑运行配置。它可以在`main()`函数旁边的菜单中找到。 + +![编辑运行配置菜单](/images/intellij_debug_menu.png) + +现在,添加程序参数和环境变量。这些需要与上面“外部工具”条目中定义的端口匹配。 + +* 此示例的命令行参数:`-p 3000` +* 此示例的环境变量:`DAPR_HTTP_PORT=3005;DAPR_GRPC_PORT=52000` + +![编辑运行配置](/images/intellij_edit_run_configuration.png) + +## 开始调试 + +一旦完成上述一次性配置,调试IntelliJ中的Java应用程序与Dapr需要两个步骤: + +1. 通过IntelliJ中的`工具` -> `外部工具`启动`dapr`。 + +![将dapr作为“外部工具”运行](/images/intellij_start_dapr.png) + +2. 以调试模式启动您的应用程序。 + +![以调试模式启动应用程序](/images/intellij_debug_app.png) + +## 总结 + +调试后,请确保在IntelliJ中停止`dapr`和您的应用程序。 + +>注意:由于您使用**dapr** ***run*** CLI命令启动了服务,**dapr** ***list***命令将在当前运行的Dapr应用程序列表中显示来自IntelliJ的运行。 + +祝调试愉快! + +## 相关链接 + + + +- [更改](https://intellij-support.jetbrains.com/hc/en-us/articles/206544519-Directories-used-by-the-IDE-to-store-settings-caches-plugins-and-logs) IntelliJ配置目录位置 + + \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/vscode/_index.md b/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/vscode/_index.md new file mode 100644 index 000000000..746ada61a --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/vscode/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "Dapr 与 Visual Studio Code 的集成" +linkTitle: "Visual Studio Code" +weight: 1000 +description: "在 Visual Studio Code 中如何高效地开发和运行 Dapr 应用程序" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/vscode/vscode-dapr-extension.md b/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/vscode/vscode-dapr-extension.md new file mode 100644 index 000000000..9853df2b8 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/vscode/vscode-dapr-extension.md @@ -0,0 +1,69 @@ +--- +type: docs +title: "Dapr Visual Studio Code 扩展概述" +linkTitle: "Dapr 扩展" +weight: 10000 +description: "如何使用 Dapr 扩展开发和运行 Dapr 应用程序" +--- + +Dapr 提供了一个*预览版*的 [Dapr Visual Studio Code 扩展](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-dapr),专为本地开发设计。该扩展为用户提供多种功能,以便更好地管理 Dapr 应用程序,并调试支持的 Dapr 语言的应用程序,包括 .NET、Go、PHP、Python 和 Java。 + +在 VSCode 中打开 + +## 功能 + +### 脚手架 Dapr 调试任务 + +Dapr 扩展利用 Visual Studio Code 的[内置调试功能](https://code.visualstudio.com/Docs/editor/debugging)帮助您调试应用程序。 + +通过 `Dapr: Scaffold Dapr Tasks` [命令面板](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette)操作,您可以更新现有的 `task.json` 和 `launch.json` 文件,以便在开始调试时启动和配置 Dapr sidecar。 + +1. 确保为您的应用程序设置了启动配置。([了解更多](https://code.visualstudio.com/Docs/editor/debugging)) +2. 使用 `Ctrl+Shift+P` 打开命令面板 +3. 选择 `Dapr: Scaffold Dapr Tasks` +4. 使用 `F5` 或通过运行视图运行您的应用程序和 Dapr sidecar。 + +### 脚手架 Dapr 组件 + +在将 Dapr 添加到应用程序时,您可能希望创建一个独立的组件目录,以区别于 `dapr init` 初始化的默认组件。 + +要使用默认的 `statestore`、`pubsub` 和 `zipkin` 组件创建一个专用的组件文件夹,请使用 `Dapr: Scaffold Dapr Components` [命令面板](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette)操作。 + +1. 在 Visual Studio Code 中打开您的应用程序目录 +2. 使用 `Ctrl+Shift+P` 打开命令面板 +3. 选择 `Dapr: Scaffold Dapr Components` +4. 使用 `dapr run --resources-path ./components -- ...` 运行您的应用程序 + +### 查看正在运行的 Dapr 应用程序 + +应用程序视图显示在您的机器上本地运行的 Dapr 应用程序。 + +
Dapr VSCode 扩展视图运行应用程序选项的截图 + +### 调用 Dapr 应用程序 + +在应用程序视图中,用户可以右键单击并通过 GET 或 POST 方法调用 Dapr 应用程序,并可选择指定一个负载。 + +
Dapr VSCode 扩展调用选项的截图 + +### 向 Dapr 应用程序发布事件 + +在应用程序视图中,用户可以右键单击并向正在运行的 Dapr 应用程序发布消息,指定主题和负载。 + +用户还可以向所有正在运行的 Dapr 应用程序发布消息。 + +
Dapr VSCode 扩展发布选项的截图 + +## 其他资源 + +### 同时调试多个 Dapr 应用程序 + +使用 VS Code 扩展,您可以使用[多目标调试](https://code.visualstudio.com/docs/editor/debugging#_multitarget-debugging)同时调试多个 Dapr 应用程序。 + +### 社区电话演示 + +观看此[视频](https://www.youtube.com/watch?v=OtbYCBt9C34&t=85),了解如何使用 Dapr VS Code 扩展: + +
+ +
\ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/vscode/vscode-how-to-debug-multiple-dapr-apps.md b/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/vscode/vscode-how-to-debug-multiple-dapr-apps.md new file mode 100644 index 000000000..95839518b --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/vscode/vscode-how-to-debug-multiple-dapr-apps.md @@ -0,0 +1,200 @@ +--- +type: docs +title: "如何:使用 Visual Studio Code 调试 Dapr 应用程序" +linkTitle: "如何:使用 VSCode 调试" +weight: 20000 +description: "学习如何配置 VSCode 以调试 Dapr 应用程序" +aliases: + - /zh-hans/developing-applications/ides/vscode/vscode-manual-configuration/ +--- + +## 手动调试 + +在开发 Dapr 应用程序时,通常使用 Dapr CLI 启动服务,命令如下: + +```bash +dapr run --app-id nodeapp --app-port 3000 --dapr-http-port 3500 app.js +``` + +一种将调试器附加到服务的方法是先在命令行中使用正确的参数运行 daprd,然后启动代码并附加调试器。虽然这种方法可行,但需要额外的步骤,并且需要为那些可能克隆您的仓库并希望直接点击“播放”按钮开始调试的开发人员提供一些指导。 + +如果您的应用程序由多个微服务组成,并且每个微服务都有一个 Dapr 辅助进程,那么在 Visual Studio Code 中同时调试它们会非常有帮助。本页面将使用 [hello world 快速入门](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-world) 来展示如何配置 VSCode 以使用 [VSCode 调试](https://code.visualstudio.com/Docs/editor/debugging) 调试多个 Dapr 应用程序。 + +## 先决条件 + +- 安装 [Dapr 扩展]({{< ref vscode-dapr-extension.md >}})。您将在后续步骤中使用它提供的 [tasks](https://code.visualstudio.com/docs/editor/tasks)。 +- 可选地克隆 [hello world 快速入门](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-world) + +## 步骤 1:配置 launch.json + +文件 `.vscode/launch.json` 包含 VS Code 调试运行的 [启动配置](https://code.visualstudio.com/Docs/editor/debugging#_launch-configurations)。该文件定义了用户开始调试时将启动什么以及如何配置。每种编程语言的配置都可以在 [Visual Studio Code marketplace](https://marketplace.visualstudio.com/VSCode) 中找到。 + +{{% alert title="生成调试配置" color="primary" %}} +[Dapr VSCode 扩展]({{< ref vscode-dapr-extension.md >}}) 提供内置的脚手架来为您生成 `launch.json` 和 `tasks.json`。 + +{{< button text="了解更多" page="vscode-dapr-extension#scaffold-dapr-components" >}} +{{% /alert %}} + +在 hello world 快速入门的例子中,启动了两个应用程序,每个都有自己的 Dapr 辅助进程。一个是用 Node.JS 编写的,另一个是用 Python 编写的。您会注意到每个配置都包含一个 `daprd run` 的 preLaunchTask 和一个 `daprd stop` 的 postDebugTask。 + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "type": "pwa-node", + "request": "launch", + "name": "Nodeapp with Dapr", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/node/app.js", + "preLaunchTask": "daprd-debug-node", + "postDebugTask": "daprd-down-node" + }, + { + "type": "python", + "request": "launch", + "name": "Pythonapp with Dapr", + "program": "${workspaceFolder}/python/app.py", + "console": "integratedTerminal", + "preLaunchTask": "daprd-debug-python", + "postDebugTask": "daprd-down-python" + } + ] +} +``` + +如果您使用的端口不是代码中默认的端口,请在 `launch.json` 调试配置中设置 `DAPR_HTTP_PORT` 和 `DAPR_GRPC_PORT` 环境变量。确保与 `tasks.json` 中的 `httpPort` 和 `grpcPort` 相匹配。例如,`launch.json`: + +```json +{ + // 设置非默认的 HTTP 和 gRPC 端口 + "env": { + "DAPR_HTTP_PORT": "3502", + "DAPR_GRPC_PORT": "50002" + }, +} +``` + +`tasks.json`: + +```json +{ + // 与 launch.json 中设置的端口匹配 + "httpPort": 3502, + "grpcPort": 50002 +} +``` + +每个配置都需要一个 `request`、`type` 和 `name`。这些参数帮助 VSCode 识别 `.vscode/tasks.json` 文件中的任务配置。 + +- `type` 定义使用的语言。根据语言,可能需要在市场中找到的扩展,例如 [Python 扩展](https://marketplace.visualstudio.com/items?itemName=ms-python.python)。 +- `name` 是配置的唯一名称。这用于在项目中调用多个配置时的复合配置。 +- `${workspaceFolder}` 是一个 VS Code 变量引用。这是 VS Code 中打开的工作区的路径。 +- `preLaunchTask` 和 `postDebugTask` 参数指的是在启动应用程序之前和之后运行的程序配置。请参阅步骤 2 了解如何配置这些。 + +有关 VSCode 调试参数的更多信息,请参阅 [VS Code 启动属性](https://code.visualstudio.com/Docs/editor/debugging#_launchjson-attributes)。 + +## 步骤 2:配置 tasks.json + +对于 `.vscode/launch.json` 中定义的每个 [任务](https://code.visualstudio.com/docs/editor/tasks),必须在 `.vscode/tasks.json` 中存在相应的任务定义。 + +对于快速入门,每个服务都需要一个任务来启动带有 `daprd` 类型的 Dapr 辅助进程,以及一个带有 `daprd-down` 的任务来停止辅助进程。参数 `appId`、`httpPort`、`metricsPort`、`label` 和 `type` 是必需的。还有其他可选参数可用,请参阅 [参考表](#daprd-parameter-table")。 + +```json +{ + "version": "2.0.0", + "tasks": [ + { + "label": "daprd-debug-node", + "type": "daprd", + "appId": "nodeapp", + "appPort": 3000, + "httpPort": 3500, + "metricsPort": 9090 + }, + { + "label": "daprd-down-node", + "type": "daprd-down", + "appId": "nodeapp" + }, + { + "label": "daprd-debug-python", + "type": "daprd", + "appId": "pythonapp", + "httpPort": 53109, + "grpcPort": 53317, + "metricsPort": 9091 + }, + { + "label": "daprd-down-python", + "type": "daprd-down", + "appId": "pythonapp" + } + ] +} +``` + +## 步骤 3:在 launch.json 中配置复合启动 + +可以在 `.vscode/launch.json` 中定义复合启动配置,它是一组两个或多个并行启动的启动配置。可以选择指定一个 `preLaunchTask` 并在单个调试会话开始之前运行。 + +对于此示例,复合配置为: + +```json +{ + "version": "2.0.0", + "configurations": [...], + "compounds": [ + { + "name": "Node/Python Dapr", + "configurations": ["Nodeapp with Dapr","Pythonapp with Dapr"] + } + ] +} +``` + +## 步骤 4:启动您的调试会话 + +您现在可以通过在 VS Code 调试器中找到您在上一步中定义的复合命令名称来以调试模式运行应用程序: + + + +您现在正在调试多个带有 Dapr 的应用程序! + +## Daprd 参数表 + +以下是 VS Code 任务支持的参数。这些参数等同于 [此参考](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-world) 中详细说明的 `daprd` 参数: + +| 参数 | 描述 | 必需 | 示例 | +|--------------|---------------|-------------|---------| +| `allowedOrigins` | 允许的 HTTP 来源(默认 "\*") | 否 | `"allowedOrigins": "*"` +| `appId`| 应用程序的唯一 ID。用于服务发现、状态封装和 pub/sub 消费者 ID | 是 | `"appId": "divideapp"` +| `appMaxConcurrency` | 限制应用程序的并发性。有效值是大于 0 的任何数字 | 否 | `"appMaxConcurrency": -1` +| `appPort` | 此参数告诉 Dapr 您的应用程序正在监听哪个端口 | 是 | `"appPort": 4000` +| `appProtocol` | 告诉 Dapr 您的应用程序正在使用的协议。有效选项是 `http`、`grpc`、`https`、`grpcs`、`h2c`。默认是 `http`。 | 否 | `"appProtocol": "http"` +| `args` | 设置传递给 Dapr 应用程序的参数列表 | 否 | "args": [] +| `componentsPath` | 组件目录的路径。如果为空,则不会加载组件。 | 否 | `"componentsPath": "./components"` +| `config` | 告诉 Dapr 使用哪个配置资源 | 否 | `"config": "./config"` +| `controlPlaneAddress` | Dapr 控制平面的地址 | 否 | `"controlPlaneAddress": "http://localhost:1366/"` +| `enableProfiling` | 启用分析 | 否 | `"enableProfiling": false` +| `enableMtls` | 为 daprd 到 daprd 通信通道启用自动 mTLS | 否 | `"enableMtls": false` +| `grpcPort` | Dapr API 监听的 gRPC 端口(默认 “50001”) | 是,如果有多个应用 | `"grpcPort": 50004` +| `httpPort` | Dapr API 的 HTTP 端口 | 是 | `"httpPort": 3502` +| `internalGrpcPort` | Dapr 内部 API 监听的 gRPC 端口 | 否 | `"internalGrpcPort": 50001` +| `logAsJson` | 将此参数设置为 true 会以 JSON 格式输出日志。默认是 false | 否 | `"logAsJson": false` +| `logLevel` | 设置 Dapr sidecar 的日志级别。允许的值是 debug、info、warn、error。默认是 info | 否 | `"logLevel": "debug"` +| `metricsPort` | 设置 sidecar 指标服务器的端口。默认是 9090 | 是,如果有多个应用 | `"metricsPort": 9093` +| `mode` | Dapr 的运行模式(默认 “standalone”) | 否 | `"mode": "standalone"` +| `placementHostAddress` | Dapr actor 放置服务器的地址 | 否 | `"placementHostAddress": "http://localhost:1313/"` +| `profilePort` | 配置文件服务器的端口(默认 “7777”) | 否 | `"profilePort": 7777` +| `sentryAddress` | Sentry CA 服务的地址 | 否 | `"sentryAddress": "http://localhost:1345/"` +| `type` | 告诉 VS Code 它将是一个 daprd 任务类型 | 是 | `"type": "daprd"` + + +## 相关链接 + +- [Visual Studio Code 扩展概述]({{< ref vscode-dapr-extension.md >}}) +- [Visual Studio Code 调试](https://code.visualstudio.com/docs/editor/debugging) +` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/vscode/vscode-remote-dev-containers.md b/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/vscode/vscode-remote-dev-containers.md new file mode 100644 index 000000000..25383ff64 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/local-development/ides/vscode/vscode-remote-dev-containers.md @@ -0,0 +1,106 @@ +--- +type: docs +title: "使用开发容器开发Dapr应用" +linkTitle: "开发容器" +weight: 30000 +description: "如何使用Dapr设置容器化的开发环境" +--- + +Visual Studio Code 的 [开发容器扩展](https://code.visualstudio.com/docs/remote/containers)允许您使用一个自包含的 Docker 容器作为完整的开发环境,而无需在本地文件系统中安装任何额外的软件包、库或工具。 + +Dapr 提供了预构建的 C# 和 JavaScript/TypeScript 开发容器,您可以选择其中一个来快速搭建开发环境。请注意,这些预构建的容器会自动更新到 Dapr 的最新版本。 + +我们还发布了一个开发容器功能,可以在任何开发容器中安装 Dapr CLI。 + +## 设置开发环境 + +### 先决条件 + +- [Docker Desktop](https://docs.docker.com/desktop/) +- [Visual Studio Code](https://code.visualstudio.com/) +- [VS Code 远程开发扩展包](https://aka.ms/vscode-remote/download/extension) + +### 使用开发容器功能添加 Dapr CLI + +您可以使用 [开发容器功能](https://containers.dev/features) 在任何开发容器中安装 Dapr CLI。 + +为此,请编辑您的 `devcontainer.json` 文件,并在 `"features"` 部分添加以下两个对象: + +```json +"features": { + // 安装 Dapr CLI + "ghcr.io/dapr/cli/dapr-cli:0": {}, + // 启用 Docker(通过 Docker-in-Docker) + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + // 或者,使用 Docker-outside-of-Docker(使用主机中的 Docker) + //"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}, +} +``` + +保存 JSON 文件并重新构建托管您开发环境的容器后,您将拥有 Dapr CLI(和 Docker),并可以通过在容器中运行以下命令来安装 Dapr: + +```sh +dapr init +``` + +#### 示例:为 Dapr 创建 Java 开发容器 + +以下是一个用于开发 Dapr Java 应用的开发容器示例,基于 [官方 Java 17 开发容器镜像](https://github.com/devcontainers/images/tree/main/src/java)。 + +将其放置在项目中的 `.devcontainer/devcontainer.json` 文件中: + +```json +// 有关格式详细信息,请参阅 https://aka.ms/devcontainer.json。有关配置选项,请参阅 +// README:https://github.com/devcontainers/templates/tree/main/src/java +{ + "name": "Java", + // 或者使用 Dockerfile 或 Docker Compose 文件。更多信息:https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/java:0-17", + + "features": { + "ghcr.io/devcontainers/features/java:1": { + "version": "none", + "installMaven": "false", + "installGradle": "false" + }, + // 安装 Dapr CLI + "ghcr.io/dapr/cli/dapr-cli:0": {}, + // 启用 Docker(通过 Docker-in-Docker) + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + // 或者,使用 Docker-outside-of-Docker(使用主机中的 Docker) + //"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}, + } + + // 使用 'forwardPorts' 在本地提供容器内的端口列表。 + // "forwardPorts": [], + + // 使用 'postCreateCommand' 在创建容器后运行命令。 + // "postCreateCommand": "java -version", + + // 配置工具特定的属性。 + // "customizations": {}, + + // 取消注释以改为以 root 身份连接。更多信息:https://aka.ms/dev-containers-non-root。 + // "remoteUser": "root" +} +``` + +然后,使用 VS Code 命令面板(在 Windows 上为 `CTRL + SHIFT + P` 或在 Mac 上为 `CMD + SHIFT + P`),选择 `Dev Containers: Rebuild and Reopen in Container`。 + +### 使用预构建的开发容器(C# 和 JavaScript/TypeScript) + +1. 在 VS Code 中打开您的应用工作区 +2. 在命令面板中(在 Windows 上为 `CTRL + SHIFT + P` 或在 Mac 上为 `CMD + SHIFT + P`)输入并选择 `Dev Containers: Add Development Container Configuration Files...` +
添加远程容器的截图 +3. 输入 `dapr` 以过滤可用的 Dapr 远程容器列表,并选择与您的应用匹配的语言容器。请注意,您可能需要选择 `Show All Definitions...` +
添加 Dapr 容器的截图 +4. 按照提示在容器中重新打开您的工作区。 +
在开发容器中重新打开应用的截图 + +#### 示例 + +观看此 [视频](https://www.youtube.com/watch?v=D2dO4aGpHcg&t=120) 了解如何在您的应用中使用 Dapr 开发容器。 + +
+ +
\ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/local-development/multi-app-dapr-run/_index.md b/src/translated_content/zh_CN/docs/developing-applications/local-development/multi-app-dapr-run/_index.md new file mode 100644 index 000000000..c44a69b90 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/local-development/multi-app-dapr-run/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "多应用同时运行" +linkTitle: "多应用同时运行" +weight: 300 +description: "支持使用单个命令同时运行多个 Dapr 应用" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/local-development/multi-app-dapr-run/multi-app-overview.md b/src/translated_content/zh_CN/docs/developing-applications/local-development/multi-app-dapr-run/multi-app-overview.md new file mode 100644 index 000000000..a4e8e4b67 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/local-development/multi-app-dapr-run/multi-app-overview.md @@ -0,0 +1,172 @@ +--- +type: docs +title: 多应用运行概述 +linkTitle: 多应用运行概述 +weight: 1000 +description: 使用一个CLI命令运行多个应用程序 +--- + +{{% alert title="注意" color="primary" %}} +**Kubernetes** 的多应用运行目前是一个预览功能。 +{{% /alert %}} + +如果您想在本地运行多个应用程序进行联合测试,类似于生产环境,多应用运行功能可以帮助您同时启动和停止一组应用程序。这些应用程序可以是: +- 本地/自托管的进程,或 +- 通过构建容器镜像并部署到Kubernetes集群 + - 您可以使用本地Kubernetes集群(如KiND)或将其部署到云(如AKS、EKS和GKE)。 + +多应用运行模板文件描述了如何启动多个应用程序,类似于您运行多个单独的CLI `run`命令。默认情况下,此模板文件名为`dapr.yaml`。 + +{{< tabs 自托管 Kubernetes>}} + +{{% codetab %}} + + +## 多应用运行模板文件 + +执行`dapr run -f .`时,它会启动当前目录中的多应用模板文件(名为`dapr.yaml`)以运行所有应用程序。 + +您可以使用自己喜欢的名称命名模板文件,而不是默认名称。例如`dapr run -f ./.yaml`。 + +以下示例展示了一些您可以为应用程序自定义的模板属性。在示例中,您可以同时启动2个应用程序,应用程序ID分别为`processor`和`emit-metrics`。 + +```yaml +version: 1 +apps: + - appID: processor + appDirPath: ../apps/processor/ + appPort: 9081 + daprHTTPPort: 3510 + command: ["go","run", "app.go"] + - appID: emit-metrics + appDirPath: ../apps/emit-metrics/ + daprHTTPPort: 3511 + env: + DAPR_HOST_ADD: localhost + command: ["go","run", "app.go"] +``` + +有关模板属性的更深入示例和解释,请参见[多应用模板]({{< ref multi-app-template.md >}})。 + +## 资源和配置文件的位置 + +使用多应用运行时,您可以选择将应用程序的资源和配置文件放置在哪里。 + +### 单一文件位置(遵循约定) + +您可以将所有应用程序的资源和配置放在`~/.dapr`根目录下。当所有应用程序共享相同的资源路径时,这种方式很有帮助,比如在本地机器上测试时。 + +### 独立文件位置(遵循约定) + +使用多应用运行时,每个应用程序目录可以有一个`.dapr`文件夹,其中包含一个`config.yaml`文件和一个`resources`目录。如果应用程序目录中不存在`.dapr`目录,则使用默认的`~/.dapr/resources/`和`~/.dapr/config.yaml`位置。 + +如果您决定在每个应用程序目录中添加一个`.dapr`目录,其中包含一个`/resources`目录和`config.yaml`文件,您可以为每个应用程序指定不同的资源路径。这种方法仍然遵循默认的`~/.dapr`约定。 + +### 自定义位置 + +您还可以将每个应用程序目录的`.dapr`目录命名为其他名称,例如`webapp`或`backend`。如果您希望明确资源或应用程序目录路径,这将有所帮助。 + +## 日志 + +运行模板为每个应用程序及其关联的daprd进程提供了两个日志目标字段: + +1. `appLogDestination`:此字段配置应用程序的日志目标。可能的值是`console`、`file`和`fileAndConsole`。默认值是`fileAndConsole`,应用程序日志默认写入控制台和文件。 + +2. `daprdLogDestination`:此字段配置`daprd`进程的日志目标。可能的值是`console`、`file`和`fileAndConsole`。默认值是`file`,`daprd`日志默认写入文件。 + +### 日志文件格式 + +应用程序和`daprd`的日志分别捕获在不同的文件中。这些日志文件会自动创建在每个应用程序目录(模板中的`appDirPath`)下的`.dapr/logs`目录中。这些日志文件名遵循以下模式: + +- `_app_.log`(`app`日志的文件名格式) +- `_daprd_.log`(`daprd`日志的文件名格式) + +即使您决定将资源文件夹重命名为其他名称,日志文件也只会写入应用程序目录中创建的`.dapr/logs`文件夹。 + +## 观看演示 + +观看[此视频以了解多应用运行的概述](https://youtu.be/s1p9MNl4VGo?t=2456): + + + +{{% /codetab %}} + +{{% codetab %}} + + +## 多应用运行模板文件 + +执行`dapr run -k -f .`或`dapr run -k -f dapr.yaml`时,`dapr.yaml`多应用运行模板文件中定义的应用程序将在Kubernetes默认命名空间中启动。 + +> **注意:** 目前,多应用运行模板只能在默认的Kubernetes命名空间中启动应用程序。 + +Kubernetes所需的默认服务和部署定义会在`dapr.yaml`模板中为每个应用程序生成在`.dapr/deploy`文件夹中。 + +如果`dapr.yaml`模板中应用程序的`createService`字段设置为`true`,则会在应用程序的`.dapr/deploy`文件夹中生成`service.yaml`文件。 + +否则,只会为每个设置了`containerImage`字段的应用程序生成`deployment.yaml`文件。 + +文件`service.yaml`和`deployment.yaml`用于在Kubernetes的`default`命名空间中部署应用程序。此功能专门针对在Kubernetes中运行多个应用程序的开发/测试环境。 + +您可以使用任何首选名称命名模板文件,而不是默认名称。例如: + +```bash +dapr run -k -f ./.yaml +``` + +以下示例展示了一些您可以为应用程序自定义的模板属性。在示例中,您可以同时启动2个应用程序,应用程序ID分别为`nodeapp`和`pythonapp`。 + +```yaml +version: 1 +common: +apps: + - appID: nodeapp + appDirPath: ./nodeapp/ + appPort: 3000 + containerImage: ghcr.io/dapr/samples/hello-k8s-node:latest + createService: true + env: + APP_PORT: 3000 + - appID: pythonapp + appDirPath: ./pythonapp/ + containerImage: ghcr.io/dapr/samples/hello-k8s-python:latest +``` + +> **注意:** +> - 如果未指定`containerImage`字段,`dapr run -k -f`会产生错误。 +> - `createService`字段定义了一个基本的Kubernetes服务(ClusterIP或LoadBalancer),目标是模板中指定的`--app-port`。如果未指定`createService`,则应用程序无法从集群外部访问。 + +有关模板属性的更深入示例和解释,请参见[多应用模板]({{< ref multi-app-template.md >}})。 + +## 日志 + +运行模板为每个应用程序及其关联的daprd进程提供了两个日志目标字段: + +1. `appLogDestination`:此字段配置应用程序的日志目标。可能的值是`console`、`file`和`fileAndConsole`。默认值是`fileAndConsole`,应用程序日志默认写入控制台和文件。 + +2. `daprdLogDestination`:此字段配置`daprd`进程的日志目标。可能的值是`console`、`file`和`fileAndConsole`。默认值是`file`,`daprd`日志默认写入文件。 + +### 日志文件格式 + +应用程序和`daprd`的日志分别捕获在不同的文件中。这些日志文件会自动创建在每个应用程序目录(模板中的`appDirPath`)下的`.dapr/logs`目录中。这些日志文件名遵循以下模式: + +- `_app_.log`(`app`日志的文件名格式) +- `_daprd_.log`(`daprd`日志的文件名格式) + +即使您决定将资源文件夹重命名为其他名称,日志文件也只会写入应用程序目录中创建的`.dapr/logs`文件夹。 + +## 观看演示 + +观看[此视频以了解Kubernetes中的多应用运行概述](https://youtu.be/nWatANwaAik?si=O8XR-TUaiY0gclgO&t=1024): + + + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 + +- [了解多应用运行模板文件结构及其属性]({{< ref multi-app-template.md >}}) +- [尝试使用服务调用快速入门的自托管多应用运行模板]({{< ref serviceinvocation-quickstart.md >}}) +- [尝试使用`hello-kubernetes`教程的Kubernetes多应用运行模板](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-kubernetes) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/local-development/multi-app-dapr-run/multi-app-template.md b/src/translated_content/zh_CN/docs/developing-applications/local-development/multi-app-dapr-run/multi-app-template.md new file mode 100644 index 000000000..27964258e --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/local-development/multi-app-dapr-run/multi-app-template.md @@ -0,0 +1,329 @@ +--- +type: docs +title: "如何使用多应用运行模板文件" +linkTitle: "如何使用多应用运行模板" +weight: 2000 +description: 解压多应用运行模板文件及其属性 +--- + +{{% alert title="注意" color="primary" %}} +目前,多应用运行在 **Kubernetes** 中是一个预览功能。 +{{% /alert %}} + +多应用运行模板文件是一个 YAML 文件,您可以使用它一次运行多个应用。在本指南中,您将学习如何: +- 使用多应用运行模板 +- 查看已启动的应用 +- 停止多应用运行模板 +- 结构化多应用运行模板文件 + +## 使用多应用运行模板 + +您可以通过以下两种方式之一使用多应用运行模板文件: + +### 通过提供目录路径执行 + +当您提供目录路径时,CLI 会在该目录中寻找名为 `dapr.yaml` 的多应用运行模板文件。如果找不到该文件,CLI 会返回错误。 + +执行以下 CLI 命令以读取默认名为 `dapr.yaml` 的多应用运行模板文件: + +{{< tabs Self-hosted Kubernetes>}} + +{{% codetab %}} + + +```cmd +# 如果给定目录路径,模板文件需要默认命名为 `dapr.yaml` + +dapr run -f +``` +{{% /codetab %}} + +{{% codetab %}} + + +```cmd +dapr run -f -k +``` +{{% /codetab %}} + +{{< /tabs >}} + +### 通过提供文件路径执行 + +如果多应用运行模板文件的名称不是 `dapr.yaml`,您可以将相对或绝对文件路径提供给命令: + +{{< tabs Self-hosted Kubernetes>}} + +{{% codetab %}} + + +```cmd +dapr run -f ./path/to/.yaml +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```cmd +dapr run -f ./path/to/.yaml -k +``` +{{% /codetab %}} + +{{< /tabs >}} + +## 查看已启动的应用 + +一旦多应用模板正在运行,您可以使用以下命令查看已启动的应用: + +{{< tabs Self-hosted Kubernetes>}} + +{{% codetab %}} + + +```cmd +dapr list +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```cmd +dapr list -k +``` +{{% /codetab %}} + +{{< /tabs >}} + +## 停止多应用运行模板 + +您可以随时使用以下任一命令停止多应用运行模板: + +{{< tabs Self-hosted Kubernetes>}} + +{{% codetab %}} + + +```cmd +# 如果给定目录路径,模板文件需要默认命名为 `dapr.yaml` + +dapr stop -f +``` +或: + +```cmd +dapr stop -f ./path/to/.yaml +``` + +{{% /codetab %}} + +{{% codetab %}} + + +```cmd +# 如果给定目录路径,模板文件需要默认命名为 `dapr.yaml` + +dapr stop -f -k +``` +或: + +```cmd +dapr stop -f ./path/to/.yaml -k +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 模板文件结构 + +多应用运行模板文件可以包含以下属性。下面是一个示例模板,展示了两个应用及其配置的一些属性。 + +{{< tabs Self-hosted Kubernetes>}} + +{{% codetab %}} + + +```yaml +version: 1 +common: # 可选部分,用于跨应用共享变量 + resourcesPath: ./app/components # 任何要跨应用共享的 dapr 资源 + env: # 任何跨应用共享的环境变量 + DEBUG: true +apps: + - appID: webapp # 可选 + appDirPath: .dapr/webapp/ # 必需 + resourcesPath: .dapr/resources # 已弃用 + resourcesPaths: .dapr/resources # 逗号分隔的资源路径。(可选)可以按约定保留为默认值。 + appChannelAddress: 127.0.0.1 # 应用监听的网络地址。(可选)可以按约定保留为默认值。 + configFilePath: .dapr/config.yaml # (可选)也可以按约定为默认值,如果未找到文件则忽略。 + appProtocol: http + appPort: 8080 + appHealthCheckPath: "/healthz" + command: ["python3", "app.py"] + appLogDestination: file # (可选),可以是 file, console 或 fileAndConsole。默认是 fileAndConsole。 + daprdLogDestination: file # (可选),可以是 file, console 或 fileAndConsole。默认是 file。 + - appID: backend # 可选 + appDirPath: .dapr/backend/ # 必需 + appProtocol: grpc + appPort: 3000 + unixDomainSocket: "/tmp/test-socket" + env: + DEBUG: false + command: ["./backend"] +``` + +模板文件中所有路径适用以下规则: + - 如果路径是绝对的,则按原样使用。 + - common 部分下的所有相对路径应相对于模板文件路径提供。 + - apps 部分下的 `appDirPath` 应相对于模板文件路径提供。 + - apps 部分下的所有其他相对路径应相对于 `appDirPath` 提供。 + +{{% /codetab %}} + +{{% codetab %}} + + +```yaml +version: 1 +common: # 可选部分,用于跨应用共享变量 + env: # 任何跨应用共享的环境变量 + DEBUG: true +apps: + - appID: webapp # 可选 + appDirPath: .dapr/webapp/ # 必需 + appChannelAddress: 127.0.0.1 # 应用监听的网络地址。(可选)可以按约定保留为默认值。 + appProtocol: http + appPort: 8080 + appHealthCheckPath: "/healthz" + appLogDestination: file # (可选),可以是 file, console 或 fileAndConsole。默认是 fileAndConsole。 + daprdLogDestination: file # (可选),可以是 file, console 或 fileAndConsole。默认是 file。 + containerImage: ghcr.io/dapr/samples/hello-k8s-node:latest # (可选)在 Kubernetes 开发/测试环境中部署时使用的容器镜像 URI。 + createService: true # (可选)在开发/测试环境中部署应用时创建 Kubernetes 服务。 + - appID: backend # 可选 + appDirPath: .dapr/backend/ # 必需 + appProtocol: grpc + appPort: 3000 + unixDomainSocket: "/tmp/test-socket" + env: + DEBUG: false +``` + +模板文件中所有路径适用以下规则: + - 如果路径是绝对的,则按原样使用。 + - apps 部分下的 `appDirPath` 应相对于模板文件路径提供。 + - app 部分下的所有相对路径应相对于 `appDirPath` 提供。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 模板属性 + +{{< tabs Self-hosted Kubernetes>}} + +{{% codetab %}} + + +多应用运行模板的属性与 `dapr run` CLI 标志对齐,[在 CLI 参考文档中列出]({{< ref "dapr-run.md#flags" >}})。 + +{{< table "table table-white table-striped table-bordered" >}} + +| 属性 | 必需 | 详情 | 示例 | +|--------------------------|:----:|------|------| +| `appDirPath` | Y | 应用代码的路径 | `./webapp/`, `./backend/` | +| `appID` | N | 应用的 app ID。如果未提供,将从 `appDirPath` 派生 | `webapp`, `backend` | +| `resourcesPath` | N | **已弃用**。Dapr 资源的路径。可以按约定为默认值 | `./app/components`, `./webapp/components` | +| `resourcesPaths` | N | 逗号分隔的 Dapr 资源路径。可以按约定为默认值 | `./app/components`, `./webapp/components` | +| `appChannelAddress` | N | 应用监听的网络地址。可以按约定保留为默认值。 | `127.0.0.1` | `localhost` | +| `configFilePath` | N | 应用配置文件的路径 | `./webapp/config.yaml` | +| `appProtocol` | N | Dapr 用于与应用通信的协议。 | `http`, `grpc` | +| `appPort` | N | 应用监听的端口 | `8080`, `3000` | +| `daprHTTPPort` | N | Dapr HTTP 端口 | | +| `daprGRPCPort` | N | Dapr GRPC 端口 | | +| `daprInternalGRPCPort` | N | Dapr 内部 API 监听的 gRPC 端口;用于从本地 DNS 组件解析值时 | | +| `metricsPort` | N | Dapr 发送其指标信息的端口 | | +| `unixDomainSocket` | N | Unix 域套接字目录挂载的路径。如果指定,与 Dapr 边车的通信使用 Unix 域套接字,与使用 TCP 端口相比,具有更低的延迟和更高的吞吐量。在 Windows 上不可用。 | `/tmp/test-socket` | +| `profilePort` | N | 配置文件服务器监听的端口 | | +| `enableProfiling` | N | 通过 HTTP 端点启用分析 | | +| `apiListenAddresses` | N | Dapr API 监听地址 | | +| `logLevel` | N | 日志详细程度。 | | +| `appMaxConcurrency` | N | 应用的并发级别;默认是无限制 | | +| `placementHostAddress` | N | | | +| `appSSL` | N | 启用 https,当 Dapr 调用应用时 | | +| `daprHTTPMaxRequestSize` | N | 请求体的最大大小(MB)。 | | +| `daprHTTPReadBufferSize` | N | HTTP 读取缓冲区的最大大小(KB)。这也限制了 HTTP 头的最大大小。默认是 4 KB | | +| `enableAppHealthCheck` | N | 启用应用的健康检查 | `true`, `false` | +| `appHealthCheckPath` | N | 健康检查文件的路径 | `/healthz` | +| `appHealthProbeInterval` | N | 应用健康探测的间隔(秒) | | +| `appHealthProbeTimeout` | N | 应用健康探测的超时时间(毫秒) | | +| `appHealthThreshold` | N | 应用被认为不健康的连续失败次数 | | +| `enableApiLogging` | N | 启用从应用到 Dapr 的所有 API 调用的日志记录 | | +| `runtimePath` | N | Dapr 运行时安装路径 | | +| `env` | N | 环境变量的映射;每个应用应用的环境变量将覆盖跨应用共享的环境变量 | `DEBUG`, `DAPR_HOST_ADD` | +| `appLogDestination` | N | 输出应用日志的日志目标;其值可以是 file, console 或 fileAndConsole。默认是 fileAndConsole | `file`, `console`, `fileAndConsole` | +| `daprdLogDestination` | N | 输出 daprd 日志的日志目标;其值可以是 file, console 或 fileAndConsole。默认是 file | `file`, `console`, `fileAndConsole` | + +{{< /table >}} + +## 下一步 + +观看[此视频以了解多应用运行的概述](https://youtu.be/s1p9MNl4VGo?t=2456): + + +{{% /codetab %}} + +{{% codetab %}} + + +多应用运行模板的属性与 `dapr run -k` CLI 标志对齐,[在 CLI 参考文档中列出]({{< ref "dapr-run.md#flags" >}})。 + +{{< table "table table-white table-striped table-bordered" >}} + +| 属性 | 必需 | 详情 | 示例 | +|--------------------------|:----:|------|------| +| `appDirPath` | Y | 应用代码的路径 | `./webapp/`, `./backend/` | +| `appID` | N | 应用的 app ID。如果未提供,将从 `appDirPath` 派生 | `webapp`, `backend` | +| `appChannelAddress` | N | 应用监听的网络地址。可以按约定保留为默认值。 | `127.0.0.1` | `localhost` | +| `appProtocol` | N | Dapr 用于与应用通信的协议。 | `http`, `grpc` | +| `appPort` | N | 应用监听的端口 | `8080`, `3000` | +| `daprHTTPPort` | N | Dapr HTTP 端口 | | +| `daprGRPCPort` | N | Dapr GRPC 端口 | | +| `daprInternalGRPCPort` | N | Dapr 内部 API 监听的 gRPC 端口;用于从本地 DNS 组件解析值时 | | +| `metricsPort` | N | Dapr 发送其指标信息的端口 | | +| `unixDomainSocket` | N | Unix 域套接字目录挂载的路径。如果指定,与 Dapr 边车的通信使用 Unix 域套接字,与使用 TCP 端口相比,具有更低的延迟和更高的吞吐量。在 Windows 上不可用。 | `/tmp/test-socket` | +| `profilePort` | N | 配置文件服务器监听的端口 | | +| `enableProfiling` | N | 通过 HTTP 端点启用分析 | | +| `apiListenAddresses` | N | Dapr API 监听地址 | | +| `logLevel` | N | 日志详细程度。 | | +| `appMaxConcurrency` | N | 应用的并发级别;默认是无限制 | | +| `placementHostAddress` | N | | | +| `appSSL` | N | 启用 https,当 Dapr 调用应用时 | | +| `daprHTTPMaxRequestSize` | N | 请求体的最大大小(MB)。 | | +| `daprHTTPReadBufferSize` | N | HTTP 读取缓冲区的最大大小(KB)。这也限制了 HTTP 头的最大大小。默认是 4 KB | | +| `enableAppHealthCheck` | N | 启用应用的健康检查 | `true`, `false` | +| `appHealthCheckPath` | N | 健康检查文件的路径 | `/healthz` | +| `appHealthProbeInterval` | N | 应用健康探测的间隔(秒) | | +| `appHealthProbeTimeout` | N | 应用健康探测的超时时间(毫秒) | | +| `appHealthThreshold` | N | 应用被认为不健康的连续失败次数 | | +| `enableApiLogging` | N | 启用从应用到 Dapr 的所有 API 调用的日志记录 | | +| `env` | N | 环境变量的映射;每个应用应用的环境变量将覆盖跨应用共享的环境变量 | `DEBUG`, `DAPR_HOST_ADD` | +| `appLogDestination` | N | 输出应用日志的日志目标;其值可以是 file, console 或 fileAndConsole。默认是 fileAndConsole | `file`, `console`, `fileAndConsole` | +| `daprdLogDestination` | N | 输出 daprd 日志的日志目标;其值可以是 file, console 或 fileAndConsole。默认是 file | `file`, `console`, `fileAndConsole` | +| `containerImage`| N | 在 Kubernetes 开发/测试环境中部署时使用的容器镜像 URI。 | `ghcr.io/dapr/samples/hello-k8s-python:latest` +| `createService`| N | 在开发/测试环境中部署应用时创建 Kubernetes 服务。 | `true`, `false` | + +{{< /table >}} + +## 下一步 + +观看[此视频以了解 Kubernetes 中多应用运行的概述](https://youtu.be/nWatANwaAik?si=O8XR-TUaiY0gclgO&t=1024): + + + +{{% /codetab %}} + +{{< /tabs >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/developing-applications/sdks/_index.md b/src/translated_content/zh_CN/docs/developing-applications/sdks/_index.md new file mode 100644 index 000000000..b2e155be1 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/sdks/_index.md @@ -0,0 +1,36 @@ +--- +type: docs +title: "Dapr 软件开发工具包 (SDKs)" +linkTitle: "SDKs" +weight: 30 +description: "使用您喜欢的语言与 Dapr 一起工作" +no_list: true +--- + +Dapr SDKs 是将 Dapr 集成到应用程序中的最简单方法。选择您喜欢的语言,几分钟内即可开始使用 Dapr。 + +## SDK 包 + +选择您[偏好的语言]({{< ref "#sdk-languages" >}})以了解有关客户端、服务扩展、actor 和工作流包的更多信息。 + +- **客户端**: Dapr 客户端允许您调用 Dapr 构建块 API 并执行每个构建块的操作。 +- **服务扩展**: Dapr 服务扩展使您能够创建可被其他服务调用的服务并订阅主题。 +- **actor**: Dapr actor SDK 允许您构建具有方法、状态、计时器和持久性提醒的虚拟 actor。 +- **工作流**: Dapr 工作流使您能够可靠地编写长时间运行的业务逻辑和集成。 + +## SDK 语言 + +| 语言 | 状态 | 客户端 | 服务扩展 | actor | 工作流 | +|----------|:------|:----------:|:-----------:|:---------:|:---------:| +| [.NET]({{< ref dotnet >}}) | 稳定 | ✔ | [ASP.NET Core](https://github.com/dapr/dotnet-sdk/tree/master/examples/AspNetCore) | ✔ | ✔ | +| [Python]({{< ref python >}}) | 稳定 | ✔ | [gRPC]({{< ref python-grpc.md >}})
[FastAPI]({{< ref python-fastapi.md >}})
[Flask]({{< ref python-flask.md >}})| ✔ | ✔ | +| [Java]({{< ref java >}}) | 稳定 | ✔ | Spring Boot
Quarkus| ✔ | ✔ | +| [Go]({{< ref go >}}) | 稳定 | ✔ | ✔ | ✔ | ✔ | +| [PHP]({{< ref php >}}) | 稳定 | ✔ | ✔ | ✔ | | +| [JavaScript]({{< ref js >}}) | 稳定| ✔ | | ✔ | ✔ | +| [C++](https://github.com/dapr/cpp-sdk) | 开发中 | ✔ | | | +| [Rust]({{< ref rust >}}) | 开发中 | ✔ | | ✔ | | + +## 进一步阅读 + +- [Dapr SDKs 中的序列化]({{< ref sdk-serialization.md >}}) diff --git a/src/translated_content/zh_CN/docs/developing-applications/sdks/sdk-serialization.md b/src/translated_content/zh_CN/docs/developing-applications/sdks/sdk-serialization.md new file mode 100644 index 000000000..0e62b9384 --- /dev/null +++ b/src/translated_content/zh_CN/docs/developing-applications/sdks/sdk-serialization.md @@ -0,0 +1,153 @@ +--- +type: docs +title: "Dapr SDK中的序列化" +linkTitle: "序列化" +description: "Dapr如何在SDK中序列化数据" +weight: 2000 +aliases: + - '/zh-hans/developing-applications/sdks/serialization/' +--- + +Dapr的SDK应该提供两种用例的序列化功能。首先是通过请求和响应负载发送的API对象。其次是需要持久化的对象。对于这两种用例,SDK提供了默认的序列化。在Java SDK中,使用[DefaultObjectSerializer](https://dapr.github.io/java-sdk/io/dapr/serializer/DefaultObjectSerializer.html)类来进行JSON序列化。 + +## 服务调用 + +```java + DaprClient client = (new DaprClientBuilder()).build(); + client.invokeService("myappid", "saySomething", "My Message", HttpExtension.POST).block(); +``` + +在上面的示例中,应用程序会收到一个针对`saySomething`方法的`POST`请求,请求负载为`"My Message"` - 引号是因为序列化器会将输入字符串序列化为JSON格式。 + +```text +POST /saySomething HTTP/1.1 +Host: localhost +Content-Type: text/plain +Content-Length: 12 + +"My Message" +``` + +## 状态管理 + +```java + DaprClient client = (new DaprClientBuilder()).build(); + client.saveState("MyStateStore", "MyKey", "My Message").block(); +``` +在此示例中,`My Message`将被保存。它没有加引号,因为Dapr的API会在内部解析JSON请求对象后再保存它。 + +```JSON +[ + { + "key": "MyKey", + "value": "My Message" + } +] +``` + +## 发布订阅 + +```java + DaprClient client = (new DaprClientBuilder()).build(); + client.publishEvent("TopicName", "My Message").block(); +``` + +事件被发布,内容被序列化为`byte[]`并发送到Dapr sidecar。订阅者将以[CloudEvent](https://github.com/cloudevents/spec)的形式接收它。CloudEvent定义`data`为字符串。Dapr SDK还为`CloudEvent`对象提供了内置的反序列化器。 + +```java + @PostMapping(path = "/TopicName") + public void handleMessage(@RequestBody(required = false) byte[] body) { + // Dapr的事件符合CloudEvent。 + CloudEvent event = CloudEvent.deserialize(body); + } +``` + +## 绑定 + +在这种情况下,对象也被序列化为`byte[]`,输入绑定接收原始的`byte[]`并将其反序列化为预期的对象类型。 + +* 输出绑定: +```java + DaprClient client = (new DaprClientBuilder()).build(); + client.invokeBinding("sample", "My Message").block(); +``` + +* 输入绑定: +```java + @PostMapping(path = "/sample") + public void handleInputBinding(@RequestBody(required = false) byte[] body) { + String message = (new DefaultObjectSerializer()).deserialize(body, String.class); + System.out.println(message); + } +``` +它应该打印: +``` +My Message +``` + +## actor方法调用 +actor方法调用的对象序列化和反序列化与服务方法调用相同,唯一的区别是应用程序不需要手动反序列化请求或序列化响应,因为这些操作都由SDK自动完成。 + +对于actor的方法,SDK仅支持具有零个或一个参数的方法。 + +* 调用actor的方法: +```java +public static void main() { + ActorProxyBuilder builder = new ActorProxyBuilder("DemoActor"); + String result = actor.invokeActorMethod("say", "My Message", String.class).block(); +} +``` + +* 实现actor的方法: +```java +public String say(String something) { + System.out.println(something); + return "OK"; +} +``` +它应该打印: +``` + My Message +``` + +## actor的状态管理 +actor也可以有状态。在这种情况下,状态管理器将使用状态序列化器来序列化和反序列化对象,并自动处理这些操作。 + +```java +public String actorMethod(String message) { + // 从键读取状态并将其反序列化为字符串。 + String previousMessage = super.getActorStateManager().get("lastmessage", String.class).block(); + + // 在序列化后为键设置新状态。 + super.getActorStateManager().set("lastmessage", message).block(); + return previousMessage; +} +``` + +## 默认序列化器 + +Dapr的默认序列化器是一个JSON序列化器,具有以下期望: + +1. 使用基本的[JSON数据类型](https://www.w3schools.com/js/js_json_datatypes.asp)以实现跨语言和跨平台的兼容性:字符串、数字、数组、布尔值、null和另一个JSON对象。应用程序可序列化对象中的每个复杂属性类型(例如DateTime)都应表示为JSON的基本类型之一。 +2. 使用默认序列化器持久化的数据也应保存为JSON对象,没有额外的引号或编码。下面的示例显示了字符串和JSON对象在Redis存储中的样子。 +```bash +redis-cli MGET "ActorStateIT_StatefulActorService||StatefulActorTest||1581130928192||message +"This is a message to be saved and retrieved." +``` +```bash + redis-cli MGET "ActorStateIT_StatefulActorService||StatefulActorTest||1581130928192||mydata +{"value":"My data value."} +``` +3. 自定义序列化器必须将对象序列化为`byte[]`。 +4. 自定义序列化器必须将`byte[]`反序列化为对象。 +5. 当用户提供自定义序列化器时,它应作为`byte[]`传输或持久化。持久化时,也要编码为Base64字符串。这是大多数JSON库本地完成的。 +```bash +redis-cli MGET "ActorStateIT_StatefulActorService||StatefulActorTest||1581130928192||message +"VGhpcyBpcyBhIG1lc3NhZ2UgdG8gYmUgc2F2ZWQgYW5kIHJldHJpZXZlZC4=" +``` +```bash + redis-cli MGET "ActorStateIT_StatefulActorService||StatefulActorTest||1581130928192||mydata +"eyJ2YWx1ZSI6Ik15IGRhdGEgdmFsdWUuIn0=" +``` + +*截至目前,[Java SDK](https://github.com/dapr/java-sdk/)是唯一实现此规范的Dapr SDK。在不久的将来,其他SDK也将实现相同的功能。* \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/getting-started/_index.md b/src/translated_content/zh_CN/docs/getting-started/_index.md new file mode 100644 index 000000000..a32c6f4a6 --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/_index.md @@ -0,0 +1,20 @@ +--- +type: docs +title: "Dapr 快速入门指南" +linkTitle: "快速入门" +weight: 20 +description: "几分钟内快速上手 Dapr" +--- + +欢迎来到 Dapr 快速入门指南! + +{{% alert title="Dapr 概念" color="primary" %}} +如果您想了解 Dapr 的基本概念和术语,我们建议您先查看[概念部分]({{}})。 +{{% /alert %}} + +我们的入门指南将逐步引导您完成安装、初始化、试用和开始使用 Dapr 的过程。 + +
+ +{{< button text="第一步:安装 Dapr CLI >>" page="install-dapr-cli" >}} +

diff --git a/src/translated_content/zh_CN/docs/getting-started/get-started-api.md b/src/translated_content/zh_CN/docs/getting-started/get-started-api.md new file mode 100644 index 000000000..758ecf522 --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/get-started-api.md @@ -0,0 +1,153 @@ +--- +type: docs +title: "使用 Dapr API" +linkTitle: "使用 Dapr API" +weight: 30 +description: "运行 Dapr sidecar 并尝试使用状态管理 API" +--- + +在本指南中,您将通过运行 sidecar 并直接调用状态管理 API 来模拟应用程序的操作。在使用 Dapr CLI 运行 Dapr 之后,您将: + +- 保存一个状态对象。 +- 读取/获取状态对象。 +- 删除状态对象。 + +[了解更多关于状态构建块及其工作原理的概念文档]({{< ref state-management >}})。 + +### 前置条件 + +- [安装 Dapr CLI]({{< ref install-dapr-cli.md >}})。 +- [运行 `dapr init`]({{< ref install-dapr-selfhost.md>}})。 + +### 步骤 1: 运行 Dapr sidecar + +[`dapr run`]({{< ref dapr-run.md >}}) 命令通常会运行您的应用程序和一个 Dapr sidecar。在这种情况下,由于您直接与状态管理 API 交互,它只运行 sidecar。 + +启动一个 Dapr sidecar,它将在端口 3500 上监听一个名为 `myapp` 的空白应用程序: + +```bash +dapr run --app-id myapp --dapr-http-port 3500 +``` + +由于上述命令没有定义自定义组件文件夹,Dapr 使用在 [`dapr init` 流程]({{< ref "install-dapr-selfhost.md#step-5-verify-components-directory-has-been-initialized" >}})中创建的默认组件定义。 + +### 步骤 2: 保存状态 + +使用一个对象更新状态。新的状态将如下所示: + +```json +[ + { + "key": "name", + "value": "Bruce Wayne" + } +] +``` + +注意,状态中包含的每个对象都有一个 `key`,其值为 `name`。您将在下一步中使用该 key。 + +使用以下命令保存一个新的状态对象: + +{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)">}} +{{% codetab %}} + +```bash +curl -X POST -H "Content-Type: application/json" -d '[{ "key": "name", "value": "Bruce Wayne"}]' http://localhost:3500/v1.0/state/statestore +``` + +{{% /codetab %}} + +{{% codetab %}} + +```powershell +Invoke-RestMethod -Method Post -ContentType 'application/json' -Body '[{ "key": "name", "value": "Bruce Wayne"}]' -Uri 'http://localhost:3500/v1.0/state/statestore' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +### 步骤 3: 获取状态 + +使用状态管理 API 和 key `name` 检索您刚刚存储在状态中的对象。在同一个终端窗口中,运行以下命令: + +{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + +```bash +curl http://localhost:3500/v1.0/state/statestore/name +``` + +{{% /codetab %}} + +{{% codetab %}} + +```powershell +Invoke-RestMethod -Uri 'http://localhost:3500/v1.0/state/statestore/name' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +### 步骤 4: 查看状态如何存储在 Redis 中 + +查看 Redis 容器并验证 Dapr 是否将其用作状态存储。使用以下命令与 Redis CLI 交互: + +```bash +docker exec -it dapr_redis redis-cli +``` + +列出 Redis 键以查看 Dapr 如何使用您提供给 `dapr run` 的 app-id 作为键的前缀创建键值对: + +```bash +keys * +``` + +**输出:** +`1) "myapp||name"` + +通过运行以下命令查看状态值: + +```bash +hgetall "myapp||name" +``` + +**输出:** +`1) "data"` +`2) "\"Bruce Wayne\""` +`3) "version"` +`4) "1"` + +使用以下命令退出 Redis CLI: + +```bash +exit +``` + +### 步骤 5: 删除状态 + +在同一个终端窗口中,从状态存储中删除 `name` 状态对象。 + +{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)">}} + +{{% codetab %}} + +```bash +curl -v -X DELETE -H "Content-Type: application/json" http://localhost:3500/v1.0/state/statestore/name +``` + +{{% /codetab %}} + +{{% codetab %}} + +```powershell +Invoke-RestMethod -Method Delete -ContentType 'application/json' -Uri 'http://localhost:3500/v1.0/state/statestore/name' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +{{< button text="下一步:Dapr 快速入门 >>" page="getting-started/quickstarts" >}} diff --git a/src/translated_content/zh_CN/docs/getting-started/install-dapr-cli.md b/src/translated_content/zh_CN/docs/getting-started/install-dapr-cli.md new file mode 100644 index 000000000..6c6028dd3 --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/install-dapr-cli.md @@ -0,0 +1,254 @@ +--- +type: docs +title: "安装 Dapr CLI" +linkTitle: "安装 Dapr CLI" +weight: 10 +description: "安装 Dapr CLI 作为运行 Dapr 相关任务的主要工具" +--- + +Dapr CLI 是执行各种 Dapr 相关任务的主要工具。您可以使用它来: + +- 运行带有 Dapr 边车的应用程序。 +- 查看边车日志。 +- 列出正在运行的服务。 +- 运行 Dapr 仪表板。 + +Dapr CLI 可在 [自托管]({{< ref self-hosted >}}) 和 [Kubernetes]({{< ref Kubernetes >}}) 环境中使用。 + +{{% alert title="开始之前" color="primary" %}} +请在 Docker Desktop 的高级选项中确认已启用默认的 Docker socket。如果您在 Windows 上使用 WSL 集成,则此选项不可用。 + +{{% /alert %}} + +### 步骤 1:安装 Dapr CLI + +{{< tabs Linux Windows MacOS Binaries>}} + +{{% codetab %}} + +#### 从终端安装 + +将最新的 Linux Dapr CLI 安装到 `/usr/local/bin`: + +```bash +wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash +``` + +##### 安装特定的 CLI 版本 + +以下示例展示如何安装 CLI 版本 `{{% dapr-latest-version cli="true" %}}`。您还可以通过指定版本来安装候选版本(例如,`1.10.0-rc.3`)。 + +```bash +wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash -s {{% dapr-latest-version cli="true" %}} +``` + +#### 无需 `sudo` 安装 + +如果您无法使用 `sudo` 命令或您的用户名不在 `sudoers` 文件中,可以通过 `DAPR_INSTALL_DIR` 环境变量将 Dapr 安装到其他目录。此目录必须已存在并且当前用户可访问。 + +```bash +wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | DAPR_INSTALL_DIR="$HOME/dapr" /bin/bash +``` + +##### 无需 `sudo` 安装特定的 CLI 版本 + +以下示例展示如何安装 CLI 版本 `{{% dapr-latest-version cli="true" %}}`。您还可以通过指定版本来安装候选版本(例如,`1.10.0-rc.3`)。 + +```bash +wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | DAPR_INSTALL_DIR="$HOME/dapr" /bin/bash -s {{% dapr-latest-version cli="true" %}} +``` + +{{% /codetab %}} + +{{% codetab %}} + +#### 从命令提示符安装 + +将最新的 Windows Dapr CLI 安装到 `$Env:SystemDrive\dapr` 并将此目录添加到用户 PATH 环境变量: + +```powershell +powershell -Command "iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1 | iex" +``` + +**注意:** PATH 的更新可能在您重新启动终端应用程序之前不可见。 + +##### 安装特定的 CLI 版本 + +以下示例展示如何安装 CLI 版本 `{{% dapr-latest-version cli="true" %}}`。您还可以通过指定版本来安装候选版本(例如,`1.10.0-rc.3`)。 + +```powershell +powershell -Command "$script=iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1; $block=[ScriptBlock]::Create($script); invoke-command -ScriptBlock $block -ArgumentList {{% dapr-latest-version cli="true" %}}" +``` + +#### 无需管理员权限安装 + +如果您没有管理员权限,可以通过 `DAPR_INSTALL_DIR` 环境变量将 Dapr 安装到其他目录。以下脚本将在目录不存在时创建它。 + +```powershell +$Env:DAPR_INSTALL_DIR = "" +$script=iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1; $block=[ScriptBlock]::Create($script); invoke-command -ScriptBlock $block -ArgumentList "", "$Env:DAPR_INSTALL_DIR" +``` + +#### 无需管理员权限安装特定的 CLI 版本 + +以下示例展示如何安装 CLI 版本 `{{% dapr-latest-version cli="true" %}}`。您还可以通过指定版本来安装候选版本(例如,`1.10.0-rc.3`)。 + +```powershell +$Env:DAPR_INSTALL_DIR = "" +$script=iwr -useb https://raw.githubusercontent.com/dapr/cli/master/install/install.ps1; $block=[ScriptBlock]::Create($script); invoke-command -ScriptBlock $block -ArgumentList "{{% dapr-latest-version cli="true" %}}", "$Env:DAPR_INSTALL_DIR" +``` + +#### 使用 winget 安装 + +将最新的 Windows Dapr CLI 安装到 `$Env:SystemDrive\dapr` 并将此目录添加到用户 PATH 环境变量: + +```powershell +winget install Dapr.CLI +``` + +**对于预览版本:** + +安装最新的预览版本: + +```powershell +winget install Dapr.CLI.Preview +``` + +#### 使用 MSI 安装程序安装 + +每个 Dapr CLI 版本还包括一个 Windows 安装程序。您可以手动下载 MSI: + +1. 从最新的 [Dapr 版本](https://github.com/dapr/cli/releases) 下载 MSI 包 `dapr.msi`。 +2. 导航到下载的 MSI 文件并双击文件以运行它。 +3. 按照安装提示接受许可和安装目录。所选文件夹将添加到用户 PATH 环境变量。默认值设置为 `$Env:SystemDrive\dapr`。 +4. 点击 `Install` 开始安装。安装完成后,您将看到最终消息。 + +{{% /codetab %}} + +{{% codetab %}} + +### 从终端安装 + +将最新的 Darwin Dapr CLI 安装到 `/usr/local/bin`: + +```bash +curl -fsSL https://raw.githubusercontent.com/dapr/cli/master/install/install.sh | /bin/bash +``` + +##### 安装特定的 CLI 版本 + +以下示例展示如何安装 CLI 版本 `{{% dapr-latest-version cli="true" %}}`。您还可以通过指定版本来安装候选版本(例如,`1.10.0-rc.3`)。 + +```bash +curl -fsSL https://raw.githubusercontent.com/dapr/cli/master/install/install.sh | /bin/bash -s {{% dapr-latest-version cli="true" %}} +``` + +**对于 ARM64 Mac:** + +从终端安装时,原生 ARM64 二进制文件可用。 + +要安装 Rosetta 仿真: + +```bash +softwareupdate --install-rosetta +``` + +#### 从 Homebrew 安装 + +通过 [Homebrew](https://brew.sh) 安装: + +```bash +brew install dapr/tap/dapr-cli +``` + +**对于 ARM64 Mac:** + +对于 ARM64 Mac,支持 Homebrew 3.0 及更高版本。更新 Homebrew 至 3.0.0 或更高版本,然后运行以下命令: + +```bash +arch -arm64 brew install dapr/tap/dapr-cli +``` + +#### 无需 `sudo` 安装 +如果您无法使用 `sudo` 命令或您的用户名不在 `sudoers` 文件中,可以通过 `DAPR_INSTALL_DIR` 环境变量将 Dapr 安装到其他目录。此目录必须已存在并且当前用户可访问。 + +```bash +curl -fsSL https://raw.githubusercontent.com/dapr/cli/master/install/install.sh | DAPR_INSTALL_DIR="$HOME/dapr" /bin/bash +``` + +##### 无需 `sudo` 安装特定的 CLI 版本 + +以下示例展示如何安装 CLI 版本 `{{% dapr-latest-version cli="true" %}}`。您还可以通过指定版本来安装候选版本(例如,`1.10.0-rc.3`)。 + +```bash +curl -fsSL https://raw.githubusercontent.com/dapr/cli/master/install/install.sh | DAPR_INSTALL_DIR="$HOME/dapr" -s {{% dapr-latest-version cli="true" %}} +``` + +{{% /codetab %}} + +{{% codetab %}} +每个 Dapr CLI 版本都包括各种操作系统和架构。您可以手动下载并安装这些二进制版本。 + +1. 从最新的 [Dapr 版本](https://github.com/dapr/cli/releases) 下载所需的 Dapr CLI。 +2. 解压缩它(例如,dapr_linux_amd64.tar.gz,dapr_windows_amd64.zip)。 +3. 将其移动到您想要的位置。 + - 对于 Linux/MacOS,我们推荐 `/usr/local/bin`。 + - 对于 Windows,创建一个目录并将其添加到您的系统 PATH。例如: + - 创建一个名为 `C:\dapr` 的目录。 + - 通过编辑系统环境变量,将新创建的目录添加到用户 PATH。 + +{{% /codetab %}} + +{{< /tabs >}} + +### 步骤 2:验证安装 + +通过重新启动您的终端/命令提示符并运行以下命令来验证 CLI 是否已安装: + +```bash +dapr -h +``` + +**输出:** + +```md + __ + ____/ /___ _____ _____ + / __ / __ '/ __ \/ ___/ + / /_/ / /_/ / /_/ / / + \__,_/\__,_/ .___/_/ + /_/ + +=============================== +分布式应用程序运行时 + +用法: + dapr [命令] + +可用命令: + completion 生成 shell 补全脚本 + components 列出所有 Dapr 组件。支持的平台:Kubernetes + configurations 列出所有 Dapr 配置。支持的平台:Kubernetes + dashboard 启动 Dapr 仪表板。支持的平台:Kubernetes 和自托管 + help 获取任何命令的帮助 + init 在支持的托管平台上安装 Dapr。支持的平台:Kubernetes 和自托管 + invoke 调用给定 Dapr 应用程序上的方法。支持的平台:自托管 + list 列出所有 Dapr 实例。支持的平台:Kubernetes 和自托管 + logs 获取应用程序的 Dapr 边车日志。支持的平台:Kubernetes + mtls 检查是否启用了 mTLS。支持的平台:Kubernetes + publish 发布一个 pub-sub 事件。支持的平台:自托管 + run 运行 Dapr 并(可选)与您的应用程序并排运行。支持的平台:自托管 + status 显示 Dapr 服务的健康状态。支持的平台:Kubernetes + stop 停止 Dapr 实例及其关联的应用程序。支持的平台:自托管 + uninstall 卸载 Dapr 运行时。支持的平台:Kubernetes 和自托管 + upgrade 升级集群中的 Dapr 控制平面安装。支持的平台:Kubernetes + version 打印 Dapr 运行时和 CLI 版本 + +标志: + -h, --help 获取 dapr 的帮助 + -v, --version 获取 dapr 的版本 + +使用 "dapr [命令] --help" 获取有关命令的更多信息。 +``` + +{{< button text="下一步:初始化 Dapr >>" page="install-dapr-selfhost" >}} diff --git a/src/translated_content/zh_CN/docs/getting-started/install-dapr-selfhost.md b/src/translated_content/zh_CN/docs/getting-started/install-dapr-selfhost.md new file mode 100644 index 000000000..a8e021c67 --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/install-dapr-selfhost.md @@ -0,0 +1,180 @@ +--- +type: docs +title: "在本地环境中配置 Dapr" +linkTitle: "本地配置 Dapr" +weight: 20 +description: "使用 `dapr init` 获取并在本地安装 Dapr sidecar 二进制文件" +aliases: + - /zh-hans/getting-started/set-up-dapr/install-dapr/ +--- + +现在您已经[安装了 Dapr CLI]({{}}),可以使用 CLI 在本地计算机上配置 Dapr。 + +Dapr 作为一个附属进程与您的应用程序一起运行。在自托管模式下,这意味着它在您的本地计算机上作为一个进程运行。通过配置 Dapr,您可以: + +- 获取并在本地安装 Dapr sidecar 的二进制文件。 +- 创建一个简化应用程序开发的环境。 + +Dapr 的配置过程包括: + +1. 启动一个 **Redis 容器实例** 作为本地状态存储和消息代理。 +2. 启动一个 **Zipkin 容器实例** 以实现可观测性。 +3. 创建一个包含上述组件定义的 **默认组件文件夹**。 +4. 启动一个 **Dapr placement service 容器实例** 以支持本地 actor。 +5. 启动一个 **Dapr scheduler service 容器实例** 以进行任务调度。 + +{{% alert title="Kubernetes 开发环境" color="primary" %}} +要在本地或远程 **Kubernetes** 集群中配置 Dapr 进行开发(包括上面列出的 Redis 和 Zipkin 容器),请参阅[如何在 Kubernetes 上配置 Dapr 进行开发]({{}}) +{{% /alert %}} + +{{% alert title="Docker" color="primary" %}} +推荐的开发环境需要 [Docker](https://docs.docker.com/install/)。虽然您可以[在没有 Docker 依赖的情况下配置 Dapr]({{< ref self-hosted-no-docker.md >}}),但本指南的下一步假设您使用推荐的 Docker 开发环境。 + +您也可以安装 [Podman](https://podman.io/) 代替 Docker。阅读更多关于[使用 Podman 配置 Dapr]({{< ref dapr-init.md >}})的信息。 +{{% /alert %}} + +### 步骤 1:打开具有管理员权限的终端 + +{{< tabs "Linux/MacOS" "Windows">}} + +{{% codetab %}} + +如果您在运行 Docker 命令时使用 `sudo`,或者安装路径是 `/usr/local/bin`(默认安装路径),则需要在此快速入门中使用 `sudo`。 + +{{% /codetab %}} + +{{% codetab %}} + +以管理员身份运行 Windows Terminal 或命令提示符。 + +1. 右键单击 Windows Terminal 或命令提示符图标。 +2. 选择 **以管理员身份运行**。 + +{{% /codetab %}} + +{{< /tabs >}} + +### 步骤 2:运行 init CLI 命令 + +{{< tabs "Linux/MacOS" "Windows">}} + +{{% codetab %}} + +安装最新的 Dapr 运行时二进制文件: + +```bash +dapr init +``` + +如果您在运行 Docker 命令时使用 sudo,则需要使用: + +```bash +sudo dapr init +``` + +如果您在 **Mac OS Silicon** 上使用 Docker 安装,可能需要执行以下变通方法以使 `dapr init` 能够在不使用 Kubernetes 的情况下与 Docker 通信。 +1. 导航到 **Docker Desktop** > **Settings** > **Advanced**。 +2. 选中 **允许使用默认 Docker 套接字(需要密码)** 复选框。 + +{{% /codetab %}} + +{{% codetab %}} + +安装最新的 Dapr 运行时二进制文件: + +```bash +dapr init +``` + +{{% /codetab %}} + +{{< /tabs >}} + +**预期输出:** + + + +[如果您遇到任何关于 Docker 未安装或未运行的错误消息,请参阅故障排除指南。]({{< ref "common_issues.md#dapr-cant-connect-to-docker-when-installing-the-dapr-cli" >}}) + +### 步骤 3:验证 Dapr 版本 + +```bash +dapr --version +``` + +**输出:** + +`CLI version: {{% dapr-latest-version cli="true" %}}`
+`Runtime version: {{% dapr-latest-version long="true" %}}` + +### 步骤 4:验证容器是否正在运行 + +如前所述,`dapr init` 命令启动了几个容器,这些容器将帮助您开始使用 Dapr。通过 `daprio/dapr`、`openzipkin/zipkin` 和 `redis` 镜像验证您是否有容器实例在运行: + +```bash +docker ps +``` + +**输出:** + + + +### 步骤 5:验证组件目录是否已初始化 + +在 `dapr init` 时,CLI 还会创建一个默认组件文件夹,其中包含几个 YAML 文件,这些文件定义了状态存储、发布/订阅和 Zipkin。Dapr sidecar 将读取这些组件并使用: + +- Redis 容器进行状态管理和消息传递。 +- Zipkin 容器用于收集跟踪。 + +通过打开您的组件目录进行验证: + +- 在 Windows 上,位于 `%UserProfile%\.dapr` +- 在 Linux/MacOS 上,位于 `~/.dapr` + +{{< tabs "Linux/MacOS" "Windows">}} + +{{% codetab %}} + +```bash +ls $HOME/.dapr +``` + +**输出:** + +`bin components config.yaml` + +
+ +{{% /codetab %}} + +{{% codetab %}} +您可以使用 PowerShell 或命令行进行验证。如果使用 PowerShell,运行: +```powershell +explorer "$env:USERPROFILE\.dapr" +``` + +如果使用命令行,运行: +```cmd +explorer "%USERPROFILE%\.dapr" +``` + +**结果:** + + + +{{% /codetab %}} + +{{< /tabs >}} + +
+ +### 精简初始化 + +要安装没有任何默认配置文件或 Docker 容器的 CLI,请使用 `--slim` 标志。[了解更多关于 `init` 命令及其标志的信息。]({{< ref dapr-init.md >}}) + +```bash +dapr init --slim +``` + +{{< button text="下一步:使用 Dapr API >>" page="getting-started/get-started-api.md" >}} diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/_index.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/_index.md new file mode 100644 index 000000000..aa5623c4f --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/_index.md @@ -0,0 +1,37 @@ + +--- +type: docs +title: "Dapr 快速入门" +linkTitle: "Dapr 快速入门" +weight: 70 +description: "通过代码示例快速掌握 Dapr,帮助您轻松上手" +no_list: true +--- + +通过我们的 Dapr 快速入门指南,结合代码示例,帮助您轻松掌握 Dapr。 + +{{% alert title="注意" color="primary" %}} +我们正在不断丰富快速入门指南。同时,您可以通过我们的[教程]({{< ref "getting-started/tutorials/_index.md" >}})进一步探索 Dapr。 + +{{% /alert %}} + +#### 开始之前 + +- [安装本地 Dapr 环境]({{< ref "install-dapr-cli.md" >}})。 + +## 快速入门 + +| 快速入门 | 描述 | +| ----------- | ----------- | +| [服务调用]({{< ref serviceinvocation-quickstart.md >}}) | 通过 HTTP 或 gRPC 实现两个服务之间的同步通信。 | +| [发布和订阅]({{< ref pubsub-quickstart.md >}}) | 通过消息实现两个服务之间的异步通信。 | +| [工作流]({{< ref workflow-quickstart.md >}}) | 在长时间运行的应用中协调业务流程,确保容错和状态管理。 | +| [状态管理]({{< ref statemanagement-quickstart.md >}}) | 以键/值对形式存储服务数据,支持多种状态存储。 | +| [绑定]({{< ref bindings-quickstart.md >}}) | 使用输入绑定响应外部事件,使用输出绑定执行操作。 | +| [参与者]({{< ref actors-quickstart.md >}}) | 运行微服务和简单客户端,展示 Dapr 参与者的状态化对象模式。 | +| [秘密管理]({{< ref secrets-quickstart.md >}}) | 安全获取和管理敏感信息。 | +| [配置]({{< ref configuration-quickstart.md >}}) | 获取配置项并监听配置更新。 | +| [弹性]({{< ref resiliency >}}) | 为 Dapr API 请求定义和应用容错策略。 | +| [加密]({{< ref cryptography-quickstart.md >}}) | 使用 Dapr 的加密 API 进行数据加密和解密。 | +| [作业]({{< ref jobs-quickstart.md >}}) | 使用 Dapr 的作业 API 进行作业调度、检索和删除。 | + diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/actors-quickstart.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/actors-quickstart.md new file mode 100644 index 000000000..3149618ec --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/actors-quickstart.md @@ -0,0 +1,257 @@ +--- +type: docs +title: "快速入门:Actors" +linkTitle: "Actors" +weight: 76 +description: "开始使用 Dapr 的 Actors 构建模块" +--- + +我们来了解一下 Dapr 的 [Actors 构建模块]({{< ref actors >}})。在这个快速入门中,您将运行一个智能设备微服务和一个简单的控制台客户端,以演示 Dapr Actors 中的有状态对象模式。 + +目前,您可以通过 .NET SDK 体验这个 actors 快速入门。 + +{{< tabs ".NET" >}} + + +{{% codetab %}} + +以下是 .NET actors 快速入门的简要概述: + +1. 使用 `SmartDevice.Service` 微服务,您将托管: + - 两个 `SmokeDetectorActor` 烟雾报警对象 + - 一个 `ControllerActor` 对象,用于指挥和控制智能设备 +2. 使用 `SmartDevice.Client` 控制台应用程序,客户端应用程序与每个 actor 或控制器交互,以执行聚合操作。 +3. `SmartDevice.Interfaces` 包含服务和客户端应用程序使用的共享接口和数据类型。 + + + +### 先决条件 + +对于这个示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + +- 安装 [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0)、[.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) 或 [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) + +**注意:** .NET 6 是此版本中 Dapr .NET SDK 包的最低支持版本。只有 .NET 8 和 .NET 9 将在 Dapr v1.16 及更高版本中得到支持。 + +### 步骤 1:设置环境 + +克隆 [Quickstarts 仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/actors/csharp/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:运行服务应用程序 + +在一个新的终端窗口中,导航到 `actors/csharp/sdk/service` 目录并恢复依赖项: + +```bash +cd actors/csharp/sdk/service +dotnet build +``` + +运行 `SmartDevice.Service`,这将启动服务本身和 Dapr 边车: + +```bash +dapr run --app-id actorservice --app-port 5001 --dapr-http-port 3500 --resources-path ../../../resources -- dotnet run --urls=http://localhost:5001/ +``` + +预期输出: + +```bash +== APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[1] +== APP == Request starting HTTP/1.1 GET http://127.0.0.1:5001/healthz - - +== APP == info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0] +== APP == Executing endpoint 'Dapr Actors Health Check' +== APP == info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1] +== APP == Executed endpoint 'Dapr Actors Health Check' +== APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[2] +== APP == Request finished HTTP/1.1 GET http://127.0.0.1:5001/healthz - - - 200 - text/plain 5.2599ms +``` + +### 步骤 3:运行客户端应用程序 + +在一个新的终端实例中,导航到 `actors/csharp/sdk/client` 目录并安装依赖项: + +```bash +cd ./actors/csharp/sdk/client +dotnet build +``` + +运行 `SmartDevice.Client` 应用程序: + +```bash +dapr run --app-id actorclient -- dotnet run +``` + +预期输出: + +```bash +== APP == Startup up... +== APP == Calling SetDataAsync on SmokeDetectorActor:1... +== APP == Got response: Success +== APP == Calling GetDataAsync on SmokeDetectorActor:1... +== APP == Device 1 state: Location: First Floor, Status: Ready +== APP == Calling SetDataAsync on SmokeDetectorActor:2... +== APP == Got response: Success +== APP == Calling GetDataAsync on SmokeDetectorActor:2... +== APP == Device 2 state: Location: Second Floor, Status: Ready +== APP == Registering the IDs of both Devices... +== APP == Registered devices: 1, 2 +== APP == Detecting smoke on Device 1... +== APP == Device 1 state: Location: First Floor, Status: Alarm +== APP == Device 2 state: Location: Second Floor, Status: Alarm +== APP == Sleeping for 16 seconds before checking status again to see reminders fire and clear alarms +== APP == Device 1 state: Location: First Floor, Status: Ready +== APP == Device 2 state: Location: Second Floor, Status: Ready +``` + +### (可选)步骤 4:在 Zipkin 中查看 + +如果您在本地机器上为 Dapr 配置了 Zipkin,您可以在 Zipkin Web UI 中查看 actor 与客户端的交互(通常在 `http://localhost:9411/zipkin/`)。 + + + +### 发生了什么? + +当您运行客户端应用程序时,发生了一些事情: + +1. 两个 `SmokeDetectorActor` actors 在 [客户端应用程序中创建](https://github.com/dapr/quickstarts/blob/master/actors/csharp/sdk/client/Program.cs) 并使用对象状态初始化: + - `ActorProxy.Create(actorId, actorType)` + - `proxySmartDevice.SetDataAsync(data)` + + 这些对象是可重入的并持有状态,如 `proxySmartDevice.GetDataAsync()` 所示。 + + ```csharp + // Actor Ids 和类型 + var deviceId1 = "1"; + var deviceId2 = "2"; + var smokeDetectorActorType = "SmokeDetectorActor"; + var controllerActorType = "ControllerActor"; + + Console.WriteLine("Startup up..."); + + // ActorId 唯一标识第一个设备的第一个 actor 实例 + var deviceActorId1 = new ActorId(deviceId1); + + // 创建将存储在第一个 actor 中的数据类的新实例 + var deviceData1 = new SmartDeviceData(){ + Location = "First Floor", + Status = "Ready", + }; + + // 使用服务实现的相同接口创建本地代理。 + var proxySmartDevice1 = ActorProxy.Create(deviceActorId1, smokeDetectorActorType); + + // 现在您可以使用 actor 接口调用 actor 的方法。 + Console.WriteLine($"Calling SetDataAsync on {smokeDetectorActorType}:{deviceActorId1}..."); + var setDataResponse1 = await proxySmartDevice1.SetDataAsync(deviceData1); + Console.WriteLine($"Got response: {setDataResponse1}"); + + Console.WriteLine($"Calling GetDataAsync on {smokeDetectorActorType}:{deviceActorId1}..."); + var storedDeviceData1 = await proxySmartDevice1.GetDataAsync(); + Console.WriteLine($"Device 1 state: {storedDeviceData1}"); + + // 为第二个设备创建第二个 actor + var deviceActorId2 = new ActorId(deviceId2); + + // 创建将存储在第一个 actor 中的数据类的新实例 + var deviceData2 = new SmartDeviceData(){ + Location = "Second Floor", + Status = "Ready", + }; + + // 使用服务实现的相同接口创建本地代理。 + var proxySmartDevice2 = ActorProxy.Create(deviceActorId2, smokeDetectorActorType); + + // 现在您可以使用 actor 接口调用第二个 actor 的方法。 + Console.WriteLine($"Calling SetDataAsync on {smokeDetectorActorType}:{deviceActorId2}..."); + var setDataResponse2 = await proxySmartDevice2.SetDataAsync(deviceData2); + Console.WriteLine($"Got response: {setDataResponse2}"); + + Console.WriteLine($"Calling GetDataAsync on {smokeDetectorActorType}:{deviceActorId2}..."); + var storedDeviceData2 = await proxySmartDevice2.GetDataAsync(); + Console.WriteLine($"Device 2 state: {storedDeviceData2}"); + ``` + +1. [`SmokeDetectorActor 1` 的 `DetectSmokeAsync` 方法被调用](https://github.com/dapr/quickstarts/blob/master/actors/csharp/sdk/service/SmokeDetectorActor.cs#L70)。 + + ```csharp + public async Task DetectSmokeAsync() + { + var controllerActorId = new ActorId("controller"); + var controllerActorType = "ControllerActor"; + var controllerProxy = ProxyFactory.CreateActorProxy(controllerActorId, controllerActorType); + await controllerProxy.TriggerAlarmForAllDetectors(); + } + ``` + +1. [`ControllerActor` 的 `TriggerAlarmForAllDetectors` 方法被调用](https://github.com/dapr/quickstarts/blob/master/actors/csharp/sdk/service/ControllerActor.cs#L54)。当检测到烟雾时,`ControllerActor` 内部触发所有警报 + + ```csharp + public async Task TriggerAlarmForAllDetectors() + { + var deviceIds = await ListRegisteredDeviceIdsAsync(); + foreach (var deviceId in deviceIds) + { + var actorId = new ActorId(deviceId); + var proxySmartDevice = ProxyFactory.CreateActorProxy(actorId, "SmokeDetectorActor"); + await proxySmartDevice.SoundAlarm(); + } + + // 注册一个提醒,每 15 秒刷新并清除警报状态 + await this.RegisterReminderAsync("AlarmRefreshReminder", null, TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); + } + ``` + + 控制台 [打印一条消息,指示检测到烟雾](https://github.com/dapr/quickstarts/blob/master/actors/csharp/sdk/client/Program.cs#L65)。 + + ```csharp + // 在设备 1 上检测到烟雾,触发所有设备的警报。 + Console.WriteLine($"Detecting smoke on Device 1..."); + proxySmartDevice1 = ActorProxy.Create(deviceActorId1, smokeDetectorActorType); + await proxySmartDevice1.DetectSmokeAsync(); + ``` + +1. `SmokeDetectorActor 1` 和 `2` 的 [`SoundAlarm` 方法](https://github.com/dapr/quickstarts/blob/master/actors/csharp/sdk/service/SmokeDetectorActor.cs#L78) 被调用。 + + ```csharp + storedDeviceData1 = await proxySmartDevice1.GetDataAsync(); + Console.WriteLine($"Device 1 state: {storedDeviceData1}"); + storedDeviceData2 = await proxySmartDevice2.GetDataAsync(); + Console.WriteLine($"Device 2 state: {storedDeviceData2}"); + ``` + +1. `ControllerActor` 还使用 `RegisterReminderAsync` 创建一个持久提醒,在 15 秒后调用 `ClearAlarm`。 + + ```csharp + // 注册一个提醒,每 15 秒刷新并清除警报状态 + await this.RegisterReminderAsync("AlarmRefreshReminder", null, TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); + ``` + +要了解示例的完整上下文,请查看以下代码: + +- [`SmokeDetectorActor.cs`](https://github.com/dapr/quickstarts/blob/master/actors/csharp/sdk/service/SmokeDetectorActor.cs):实现智能设备 actors +- [`ControllerActor.cs`](https://github.com/dapr/quickstarts/blob/master/actors/csharp/sdk/service/ControllerActor.cs):实现管理所有设备的控制器 actor +- [`ISmartDevice`](https://github.com/dapr/quickstarts/blob/master/actors/csharp/sdk/interfaces/ISmartDevice.cs):每个 `SmokeDetectorActor` 的方法定义和共享数据类型 +- [`IController`](https://github.com/dapr/quickstarts/blob/master/actors/csharp/sdk/interfaces/IController.cs):`ControllerActor` 的方法定义和共享数据类型 + +{{% /codetab %}} + +{{< /tabs >}} + +## 告诉我们您的想法! + +我们正在不断努力改进我们的快速入门示例,并重视您的反馈。您觉得这个快速入门有帮助吗?您有改进的建议吗? + +加入我们的 [discord 频道](https://discord.com/channels/778680217417809931/953427615916638238) 讨论。 + +## 下一步 + +了解更多关于 [Actor 构建模块]({{< ref actors >}}) 的信息 + +{{< button text="探索 Dapr 教程 >>" page="getting-started/tutorials/_index.md" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/bindings-quickstart.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/bindings-quickstart.md new file mode 100644 index 000000000..12e5b3220 --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/bindings-quickstart.md @@ -0,0 +1,1096 @@ +--- +type: docs +title: "快速入门:输入和输出绑定" +linkTitle: "绑定" +weight: 75 +description: "开始使用 Dapr 的绑定构建块" +--- + +我们来了解一下 Dapr 的[绑定构建块]({{< ref bindings >}})。通过使用绑定,您可以: + +- 让您的应用程序响应来自外部系统的事件。 +- 与外部系统进行交互。 + +在本快速入门中,您将使用输入 [Cron]({{< ref cron.md >}}) 绑定每 10 秒调度一次批处理脚本。该脚本处理一个 JSON 文件,并使用 [PostgreSQL]({{< ref postgresql.md >}}) Dapr 绑定将数据输出到 SQL 数据库。 + + + +在继续快速入门之前,请选择您偏好的 Dapr SDK 语言版本。 + +{{< tabs "Python" "JavaScript" ".NET" "Java" "Go" >}} + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装 Python 3.7+](https://www.python.org/downloads/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/bindings/python/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:本地运行 PostgreSQL Docker 容器 + +在您的机器上通过 Docker 容器本地运行 [PostgreSQL 实例](https://www.postgresql.org/)。快速入门示例中包含一个 Docker Compose 文件,用于本地自定义、构建、运行和初始化带有默认 `orders` 表的 `postgres` 容器。 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `bindings/db` 目录。 + +```bash +cd bindings/db +``` + +运行以下命令以设置容器: + +```bash +docker compose up +``` + +验证容器是否在本地运行。 + +```bash +docker ps +``` + +输出应包括: + +```bash +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +55305d1d378b postgres "docker-entrypoint.s…" 3 seconds ago Up 2 seconds 0.0.0.0:5432->5432/tcp sql_db +``` + +### 步骤 3:调度 Cron 作业并写入数据库 + +在新的终端窗口中,导航到 SDK 目录。 + +```bash +cd bindings/python/sdk/batch +``` + +安装依赖项: + +```bash +pip3 install -r requirements.txt +``` + +与 Dapr 边车一起运行 `batch-sdk` 服务。 + +```bash +dapr run --app-id batch-sdk --app-port 50051 --resources-path ../../../components -- python3 app.py +``` + +> **注意**:在 Windows 中,由于未定义 Python3.exe,您可能需要使用 `python app.py` 而不是 `python3 app.py`。 + +`process_batch` 函数中的代码每 10 秒执行一次(在 `components` 目录中的 [`binding-cron.yaml`]({{< ref "#componentsbinding-cronyaml-component-file" >}}) 中定义)。绑定触发器通过 Dapr 边车在您的应用程序中查找通过 HTTP POST 调用的路由。 + +```python +# 由 Dapr 输入绑定触发 +@app.route('/' + cron_binding_name, methods=['POST']) +def process_batch(): +``` + +`batch-sdk` 服务使用在 [`binding-postgresql.yaml`]({{< ref "#componentbinding-postgresyaml-component-file" >}}) 组件中定义的 PostgreSQL 输出绑定将 `OrderId`、`Customer` 和 `Price` 记录插入到 `orders` 表中。 + +```python +with DaprClient() as d: + sqlCmd = ('insert into orders (orderid, customer, price) values ' + + '(%s, \'%s\', %s)' % (order_line['orderid'], + order_line['customer'], + order_line['price'])) + payload = {'sql': sqlCmd} + + print(sqlCmd, flush=True) + + try: + # 使用 Dapr 输出绑定通过 HTTP Post 插入订单 + resp = d.invoke_binding(binding_name=sql_binding, operation='exec', + binding_metadata=payload, data='') + return resp + except Exception as e: + print(e, flush=True) + raise SystemExit(e) +``` + +### 步骤 4:查看作业的输出 + +请注意,如上所述,代码使用 `OrderId`、`Customer` 和 `Price` 作为负载调用输出绑定。 + +您的输出绑定的 `print` 语句输出: + +``` +== APP == Processing batch.. +== APP == insert into orders (orderid, customer, price) values (1, 'John Smith', 100.32) +== APP == insert into orders (orderid, customer, price) values (2, 'Jane Bond', 15.4) +== APP == insert into orders (orderid, customer, price) values (3, 'Tony James', 35.56) +== APP == Finished processing batch +``` + +在新的终端中,验证相同的数据已插入到数据库中。导航到 `bindings/db` 目录。 + +```bash +cd bindings/db +``` + +运行以下命令以启动交互式 *psql* CLI: + +```bash +docker exec -i -t postgres psql --username postgres -p 5432 -h localhost --no-password +``` + +在 `admin=#` 提示符下,切换到 `orders` 表: + +```bash +\c orders; +``` + +在 `orders=#` 提示符下,选择所有行: + +```bash +select * from orders; +``` + +输出应如下所示: + +``` + orderid | customer | price +---------+------------+-------- + 1 | John Smith | 100.32 + 2 | Jane Bond | 15.4 + 3 | Tony James | 35.56 +``` + +#### `components\binding-cron.yaml` 组件文件 + +当您执行 `dapr run` 命令并指定组件路径时,Dapr 边车: + +- 启动 Cron [绑定构建块]({{< ref bindings >}}) +- 每 10 秒调用绑定端点(`batch`) + +为此快速入门包含的 Cron `binding-cron.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: cron + namespace: quickstarts +spec: + type: bindings.cron + version: v1 + metadata: + - name: schedule + value: "@every 10s" # 有效的 cron 调度 + - name: direction + value: "input" # cron 绑定的方向 +``` + +**注意:** `binding-cron.yaml` 的 `metadata` 部分包含一个 [Cron 表达式]({{< ref cron.md >}}),指定绑定被调用的频率。 + +#### `component\binding-postgresql.yaml` 组件文件 + +当您执行 `dapr run` 命令并指定组件路径时,Dapr 边车: + +- 启动 PostgreSQL [绑定构建块]({{< ref postgresql.md >}}) +- 使用 `binding-postgresql.yaml` 文件中指定的设置连接到 PostgreSQL + +使用 `binding-postgresql.yaml` 组件,您可以轻松地更换后端数据库[绑定]({{< ref supported-bindings.md >}}),而无需进行代码更改。 + +为此快速入门包含的 PostgreSQL `binding-postgresql.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: sqldb + namespace: quickstarts +spec: + type: bindings.postgresql + version: v1 + metadata: + - name: url # 必需 + value: "user=postgres password=docker host=localhost port=5432 dbname=orders pool_min_conns=1 pool_max_conns=10" + - name: direction + value: "output" # postgresql 绑定的方向 +``` + +在 YAML 文件中: + +- `spec/type` 指定 PostgreSQL 用于此绑定。 +- `spec/metadata` 定义组件使用的 PostgreSQL 实例的连接。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装最新的 Node.js](https://nodejs.org/download/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/bindings/javascript/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:本地运行 PostgreSQL Docker 容器 + +在您的机器上通过 Docker 容器本地运行 [PostgreSQL 实例](https://www.postgresql.org/)。快速入门示例中包含一个 Docker Compose 文件,用于本地自定义、构建、运行和初始化带有默认 `orders` 表的 `postgres` 容器。 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `bindings/db` 目录。 + +```bash +cd bindings/db +``` + +运行以下命令以设置容器: + +```bash +docker compose up +``` + +验证容器是否在本地运行。 + +```bash +docker ps +``` + +输出应包括: + +```bash +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +55305d1d378b postgres "docker-entrypoint.s…" 3 seconds ago Up 2 seconds 0.0.0.0:5432->5432/tcp sql_db +``` + +### 步骤 3:调度 Cron 作业并写入数据库 + +在新的终端窗口中,导航到 SDK 目录。 + +```bash +cd bindings/javascript/sdk/batch +``` + +安装依赖项: + +```bash +npm install +``` + +与 Dapr 边车一起运行 `batch-sdk` 服务。 + +```bash +dapr run --app-id batch-sdk --app-port 5002 --dapr-http-port 3500 --resources-path ../../../components -- node index.js +``` + +`process_batch` 函数中的代码每 10 秒执行一次(在 `components` 目录中的 [`binding-cron.yaml`]({{< ref "#componentsbinding-cronyaml-component-file" >}}) 中定义)。绑定触发器通过 Dapr 边车在您的应用程序中查找通过 HTTP POST 调用的路由。 + +```javascript +async function start() { + await server.binding.receive(cronBindingName,processBatch); + await server.start(); +} +``` + +`batch-sdk` 服务使用在 [`binding-postgresql.yaml`]({{< ref "##componentsbinding-postgresyaml-component-file" >}}) 组件中定义的 PostgreSQL 输出绑定将 `OrderId`、`Customer` 和 `Price` 记录插入到 `orders` 表中。 + +```javascript +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; +} +``` + +### 步骤 4:查看作业的输出 + +请注意,如上所述,代码使用 `OrderId`、`Customer` 和 `Price` 作为负载调用输出绑定。 + +您的输出绑定的 `print` 语句输出: + +``` +== APP == Processing batch.. +== APP == insert into orders (orderid, customer, price) values(1, 'John Smith', 100.32) +== APP == insert into orders (orderid, customer, price) values(2, 'Jane Bond', 15.4) +== APP == insert into orders (orderid, customer, price) values(3, 'Tony James', 35.56) +``` + +在新的终端中,验证相同的数据已插入到数据库中。导航到 `bindings/db` 目录。 + +```bash +cd bindings/db +``` + +运行以下命令以启动交互式 Postgres CLI: + +```bash +docker exec -i -t postgres psql --username postgres -p 5432 -h localhost --no-password +``` + +在 `admin=#` 提示符下,切换到 `orders` 表: + +```bash +\c orders; +``` + +在 `orders=#` 提示符下,选择所有行: + +```bash +select * from orders; +``` + +输出应如下所示: + +``` + orderid | customer | price +---------+------------+-------- + 1 | John Smith | 100.32 + 2 | Jane Bond | 15.4 + 3 | Tony James | 35.56 +``` + +#### `components\binding-cron.yaml` 组件文件 + +当您执行 `dapr run` 命令并指定组件路径时,Dapr 边车: + +- 启动 Cron [绑定构建块]({{< ref bindings >}}) +- 每 10 秒调用绑定端点(`batch`) + +为此快速入门包含的 Cron `binding-cron.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: cron + namespace: quickstarts +spec: + type: bindings.cron + version: v1 + metadata: + - name: schedule + value: "@every 10s" # 有效的 cron 调度 + - name: direction + value: "input" # cron 绑定的方向 +``` + +**注意:** `binding-cron.yaml` 的 `metadata` 部分包含一个 [Cron 表达式]({{< ref cron.md >}}),指定绑定被调用的频率。 + +#### `component\binding-postgresql.yaml` 组件文件 + +当您执行 `dapr run` 命令并指定组件路径时,Dapr 边车: + +- 启动 PostgreSQL [绑定构建块]({{< ref postgresql.md >}}) +- 使用 `binding-postgresql.yaml` 文件中指定的设置连接到 PostgreSQL + +使用 `binding-postgresql.yaml` 组件,您可以轻松地更换后端数据库[绑定]({{< ref supported-bindings.md >}}),而无需进行代码更改。 + +为此快速入门包含的 PostgreSQL `binding-postgresql.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: sqldb + namespace: quickstarts +spec: + type: bindings.postgresql + version: v1 + metadata: + - name: url # 必需 + value: "user=postgres password=docker host=localhost port=5432 dbname=orders pool_min_conns=1 pool_max_conns=10" + - name: direction + value: "output" # postgresql 绑定的方向 +``` + +在 YAML 文件中: + +- `spec/type` 指定 PostgreSQL 用于此绑定。 +- `spec/metadata` 定义组件使用的 PostgreSQL 实例的连接。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + +- [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0)、[.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) 或 [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) 已安装 + +**注意:** .NET 6 是此版本中 Dapr .NET SDK 包的最低支持版本。仅 .NET 8 和 .NET 9 将在 Dapr v1.16 及更高版本中得到支持。 + +### 步骤 1:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/bindings/csharp/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:本地运行 PostgreSQL Docker 容器 + +在您的机器上通过 Docker 容器本地运行 [PostgreSQL 实例](https://www.postgresql.org/)。快速入门示例中包含一个 Docker Compose 文件,用于本地自定义、构建、运行和初始化带有默认 `orders` 表的 `postgres` 容器。 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `bindings/db` 目录。 + +```bash +cd bindings/db +``` + +运行以下命令以设置容器: + +```bash +docker compose up +``` + +验证容器是否在本地运行。 + +```bash +docker ps +``` + +输出应包括: + +```bash +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +55305d1d378b postgres "docker-entrypoint.s…" 3 seconds ago Up 2 seconds 0.0.0.0:5432->5432/tcp sql_db +``` + +### 步骤 3:调度 Cron 作业并写入数据库 + +在新的终端窗口中,导航到 SDK 目录。 + +```bash +cd bindings/csharp/sdk/batch +``` + +安装依赖项: + +```bash +dotnet restore +dotnet build batch.csproj +``` + +与 Dapr 边车一起运行 `batch-sdk` 服务。 + +```bash +dapr run --app-id batch-sdk --app-port 7002 --resources-path ../../../components -- dotnet run +``` + +`process_batch` 函数中的代码每 10 秒执行一次(在 `components` 目录中的 [`binding-cron.yaml`]({{< ref "#componentsbinding-cronyaml-component-file" >}}) 中定义)。绑定触发器通过 Dapr 边车在您的应用程序中查找通过 HTTP POST 调用的路由。 + +```csharp +app.MapPost("/" + cronBindingName, async () => { +// ... +}); +``` + +`batch-sdk` 服务使用在 [`binding-postgresql.yaml`]({{< ref "#componentbinding-postgresyaml-component-file" >}}) 组件中定义的 PostgreSQL 输出绑定将 `OrderId`、`Customer` 和 `Price` 记录插入到 `orders` 表中。 + +```csharp +// ... +string jsonFile = File.ReadAllText("../../../orders.json"); +var ordersArray = JsonSerializer.Deserialize(jsonFile); +using var client = new DaprClientBuilder().Build(); +foreach(Order ord in ordersArray?.orders ?? new Order[] {}){ + var sqlText = $"insert into orders (orderid, customer, price) values ({ord.OrderId}, '{ord.Customer}', {ord.Price});"; + var command = new Dictionary(){ + {"sql", + sqlText} + }; +// ... +} + +// 使用 Dapr 输出绑定通过 Dapr Client SDK 插入订单 +await client.InvokeBindingAsync(bindingName: sqlBindingName, operation: "exec", data: "", metadata: command); +``` + +### 步骤 4:查看作业的输出 + +请注意,如上所述,代码使用 `OrderId`、`Customer` 和 `Price` 作为负载调用输出绑定。 + +您的输出绑定的 `print` 语句输出: + +``` +== APP == Processing batch.. +== APP == insert into orders (orderid, customer, price) values (1, 'John Smith', 100.32); +== APP == insert into orders (orderid, customer, price) values (2, 'Jane Bond', 15.4); +== APP == insert into orders (orderid, customer, price) values (3, 'Tony James', 35.56); +== APP == Finished processing batch +``` + +在新的终端中,验证相同的数据已插入到数据库中。导航到 `bindings/db` 目录。 + +```bash +cd bindings/db +``` + +运行以下命令以启动交互式 Postgres CLI: + +```bash +docker exec -i -t postgres psql --username postgres -p 5432 -h localhost --no-password +``` + +在 `admin=#` 提示符下,切换到 `orders` 表: + +```bash +\c orders; +``` + +在 `orders=#` 提示符下,选择所有行: + +```bash +select * from orders; +``` + +输出应如下所示: + +``` + orderid | customer | price +---------+------------+-------- + 1 | John Smith | 100.32 + 2 | Jane Bond | 15.4 + 3 | Tony James | 35.56 +``` + +#### `components\binding-cron.yaml` 组件文件 + +当您执行 `dapr run` 命令并指定组件路径时,Dapr 边车: + +- 启动 Cron [绑定构建块]({{< ref bindings >}}) +- 每 10 秒调用绑定端点(`batch`) + +为此快速入门包含的 Cron `binding-cron.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: cron + namespace: quickstarts +spec: + type: bindings.cron + version: v1 + metadata: + - name: schedule + value: "@every 10s" # 有效的 cron 调度 + - name: direction + value: "input" # cron 绑定的方向 +``` + +**注意:** `binding-cron.yaml` 的 `metadata` 部分包含一个 [Cron 表达式]({{< ref cron.md >}}),指定绑定被调用的频率。 + +#### `component\binding-postgresql.yaml` 组件文件 + +当您执行 `dapr run` 命令并指定组件路径时,Dapr 边车: + +- 启动 PostgreSQL [绑定构建块]({{< ref postgresql.md >}}) +- 使用 `binding-postgresql.yaml` 文件中指定的设置连接到 PostgreSQL + +使用 `binding-postgresql.yaml` 组件,您可以轻松地更换后端数据库[绑定]({{< ref supported-bindings.md >}}),而无需进行代码更改。 + +为此快速入门包含的 PostgreSQL `binding-postgresql.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: sqldb + namespace: quickstarts +spec: + type: bindings.postgresql + version: v1 + metadata: + - name: url # 必需 + value: "user=postgres password=docker host=localhost port=5432 dbname=orders pool_min_conns=1 pool_max_conns=10" + - name: direction + value: "output" # postgresql 绑定的方向 +``` + +在 YAML 文件中: + +- `spec/type` 指定 PostgreSQL 用于此绑定。 +- `spec/metadata` 定义组件使用的 PostgreSQL 实例的连接。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- Java JDK 17(或更高版本): + - [Oracle JDK](https://www.oracle.com/java/technologies/downloads),或 + - OpenJDK +- [Apache Maven](https://maven.apache.org/install.html),版本 3.x。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/bindings/java/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:本地运行 PostgreSQL Docker 容器 + +在您的机器上通过 Docker 容器本地运行 [PostgreSQL 实例](https://www.postgresql.org/)。快速入门示例中包含一个 Docker Compose 文件,用于本地自定义、构建、运行和初始化带有默认 `orders` 表的 `postgres` 容器。 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `bindings/db` 目录。 + +```bash +cd bindings/db +``` + +运行以下命令以设置容器: + +```bash +docker compose up +``` + +验证容器是否在本地运行。 + +```bash +docker ps +``` + +输出应包括: + +```bash +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +55305d1d378b postgres "docker-entrypoint.s…" 3 seconds ago Up 2 seconds 0.0.0.0:5432->5432/tcp sql_db +``` + +### 步骤 3:调度 Cron 作业并写入数据库 + +在新的终端窗口中,导航到 SDK 目录。 + +```bash +cd bindings/java/sdk/batch +``` + +安装依赖项: + +```bash +mvn clean install +``` + +与 Dapr 边车一起运行 `batch-sdk` 服务。 + +```bash +dapr run --app-id batch-sdk --app-port 8080 --resources-path ../../../components -- java -jar target/BatchProcessingService-0.0.1-SNAPSHOT.jar +``` + +`process_batch` 函数中的代码每 10 秒执行一次(在 `components` 目录中的 [`binding-cron.yaml`]({{< ref "#componentsbinding-cronyaml-component-file" >}}) 中定义)。绑定触发器通过 Dapr 边车在您的应用程序中查找通过 HTTP POST 调用的路由。 + +```java +@PostMapping(path = cronBindingPath, consumes = MediaType.ALL_VALUE) +public ResponseEntity processBatch() throws IOException, Exception +``` + +`batch-sdk` 服务使用在 [`binding-postgresql.yaml`]({{< ref "#componentbinding-postgresyaml-component-file" >}}) 组件中定义的 PostgreSQL 输出绑定将 `OrderId`、`Customer` 和 `Price` 记录插入到 `orders` 表中。 + +```java +try (DaprClient client = new DaprClientBuilder().build()) { + + for (Order order : ordList.orders) { + String sqlText = String.format( + "insert into orders (orderid, customer, price) " + + "values (%s, '%s', %s);", + order.orderid, order.customer, order.price); + logger.info(sqlText); + + Map metadata = new HashMap(); + metadata.put("sql", sqlText); + + // 使用 Dapr SDK 调用 sql 输出绑定 + client.invokeBinding(sqlBindingName, "exec", null, metadata).block(); + } + + logger.info("Finished processing batch"); + + return ResponseEntity.ok("Finished processing batch"); +} +``` + +### 步骤 4:查看作业的输出 + +请注意,如上所述,代码使用 `OrderId`、`Customer` 和 `Price` 作为负载调用输出绑定。 + +您的输出绑定的 `print` 语句输出: + +``` +== APP == 2022-06-22 16:39:17.012 INFO 35772 --- [nio-8080-exec-4] c.s.c.BatchProcessingServiceController : Processing batch.. +== APP == 2022-06-22 16:39:17.268 INFO 35772 --- [nio-8080-exec-4] c.s.c.BatchProcessingServiceController : insert into orders (orderid, customer, price) values (1, 'John Smith', 100.32); +== APP == 2022-06-22 16:39:17.838 INFO 35772 --- [nio-8080-exec-4] c.s.c.BatchProcessingServiceController : insert into orders (orderid, customer, price) values (2, 'Jane Bond', 15.4); +== APP == 2022-06-22 16:39:17.844 INFO 35772 --- [nio-8080-exec-4] c.s.c.BatchProcessingServiceController : insert into orders (orderid, customer, price) values (3, 'Tony James', 35.56); +== APP == 2022-06-22 16:39:17.848 INFO 35772 --- [nio-8080-exec-4] c.s.c.BatchProcessingServiceController : Finished processing batch +``` + +在新的终端中,验证相同的数据已插入到数据库中。导航到 `bindings/db` 目录。 + +```bash +cd bindings/db +``` + +运行以下命令以启动交互式 Postgres CLI: + +```bash +docker exec -i -t postgres psql --username postgres -p 5432 -h localhost --no-password +``` + +在 `admin=#` 提示符下,切换到 `orders` 表: + +```bash +\c orders; +``` + +在 `orders=#` 提示符下,选择所有行: + +```bash +select * from orders; +``` + +输出应如下所示: + +``` + orderid | customer | price +---------+------------+-------- + 1 | John Smith | 100.32 + 2 | Jane Bond | 15.4 + 3 | Tony James | 35.56 +``` + +#### `components\binding-cron.yaml` 组件文件 + +当您执行 `dapr run` 命令并指定组件路径时,Dapr 边车: + +- 启动 Cron [绑定构建块]({{< ref bindings >}}) +- 每 10 秒调用绑定端点(`batch`) + +为此快速入门包含的 Cron `binding-cron.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: cron + namespace: quickstarts +spec: + type: bindings.cron + version: v1 + metadata: + - name: schedule + value: "@every 10s" # 有效的 cron 调度 + - name: direction + value: "input" # cron 绑定的方向 +``` + +**注意:** `binding-cron.yaml` 的 `metadata` 部分包含一个 [Cron 表达式]({{< ref cron.md >}}),指定绑定被调用的频率。 + +#### `component\binding-postgresql.yaml` 组件文件 + +当您执行 `dapr run` 命令并指定组件路径时,Dapr 边车: + +- 启动 PostgreSQL [绑定构建块]({{< ref postgresql.md >}}) +- 使用 `binding-postgresql.yaml` 文件中指定的设置连接到 PostgreSQL + +使用 `binding-postgresql.yaml` 组件,您可以轻松地更换后端数据库[绑定]({{< ref supported-bindings.md >}}),而无需进行代码更改。 + +为此快速入门包含的 PostgreSQL `binding-postgresql.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: sqldb + namespace: quickstarts +spec: + type: bindings.postgresql + version: v1 + metadata: + - name: url # 必需 + value: "user=postgres password=docker host=localhost port=5432 dbname=orders pool_min_conns=1 pool_max_conns=10" + - name: direction + value: "output" # postgresql 绑定的方向 +``` + +在 YAML 文件中: + +- `spec/type` 指定 PostgreSQL 用于此绑定。 +- `spec/metadata` 定义组件使用的 PostgreSQL 实例的连接。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的 Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/bindings/go/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:本地运行 PostgreSQL Docker 容器 + +在您的机器上通过 Docker 容器本地运行 [PostgreSQL 实例](https://www.postgresql.org/)。快速入门示例中包含一个 Docker Compose 文件,用于本地自定义、构建、运行和初始化带有默认 `orders` 表的 `postgres` 容器。 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `bindings/db` 目录。 + +```bash +cd bindings/db +``` + +运行以下命令以设置容器: + +```bash +docker compose up +``` + +验证容器是否在本地运行。 + +```bash +docker ps +``` + +输出应包括: + +```bash +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +55305d1d378b postgres "docker-entrypoint.s…" 3 seconds ago Up 2 seconds 0.0.0.0:5432->5432/tcp sql_db +``` + +### 步骤 3:调度 Cron 作业并写入数据库 + +在新的终端窗口中,导航到 SDK 目录。 + +```bash +cd bindings/go/sdk/batch +``` + +安装依赖项: + +```bash +go build . +``` + +与 Dapr 边车一起运行 `batch-sdk` 服务。 + +```bash +dapr run --app-id batch-sdk --app-port 6002 --dapr-http-port 3502 --dapr-grpc-port 60002 --resources-path ../../../components -- go run . +``` + +`process_batch` 函数中的代码每 10 秒执行一次(在 `components` 目录中的 [`binding-cron.yaml`]({{< ref "#componentsbinding-cronyaml-component-file" >}}) 中定义)。绑定触发器通过 Dapr 边车在您的应用程序中查找通过 HTTP POST 调用的路由。 + +```go +// 由 Dapr 输入绑定触发 +r.HandleFunc("/"+cronBindingName, processBatch).Methods("POST") +``` + +`batch-sdk` 服务使用在 [`binding-postgresql.yaml`]({{< ref "#componentbinding-postgresyaml-component-file" >}}) 组件中定义的 PostgreSQL 输出绑定将 `OrderId`、`Customer` 和 `Price` 记录插入到 `orders` 表中。 + +```go +func sqlOutput(order Order) (err error) { + + client, err := dapr.NewClient() + if err != nil { + return err + } + + ctx := context.Background() + + sqlCmd := fmt.Sprintf("insert into orders (orderid, customer, price) values (%d, '%s', %s);", order.OrderId, order.Customer, strconv.FormatFloat(order.Price, 'f', 2, 64)) + fmt.Println(sqlCmd) + + // 使用 Dapr 输出绑定通过 Dapr SDK 插入订单 + in := &dapr.InvokeBindingRequest{ + Name: sqlBindingName, + Operation: "exec", + Data: []byte(""), + Metadata: map[string]string{"sql": sqlCmd}, + } + err = client.InvokeOutputBinding(ctx, in) + if err != nil { + return err + } + + return nil +} +``` + +### 步骤 4:查看作业的输出 + +请注意,如上所述,代码使用 `OrderId`、`Customer` 和 `Price` 作为负载调用输出绑定。 + +您的输出绑定的 `print` 语句输出: + +``` +== APP == Processing batch.. +== APP == insert into orders (orderid, customer, price) values(1, 'John Smith', 100.32) +== APP == insert into orders (orderid, customer, price) values(2, 'Jane Bond', 15.4) +== APP == insert into orders (orderid, customer, price) values(3, 'Tony James', 35.56) +``` + +在新的终端中,验证相同的数据已插入到数据库中。导航到 `bindings/db` 目录。 + +```bash +cd bindings/db +``` + +运行以下命令以启动交互式 Postgres CLI: + +```bash +docker exec -i -t postgres psql --username postgres -p 5432 -h localhost --no-password +``` + +在 `admin=#` 提示符下,切换到 `orders` 表: + +```bash +\c orders; +``` + +在 `orders=#` 提示符下,选择所有行: + +```bash +select * from orders; +``` + +输出应如下所示: + +``` + orderid | customer | price +---------+------------+-------- + 1 | John Smith | 100.32 + 2 | Jane Bond | 15.4 + 3 | Tony James | 35.56 +``` + +#### `components\binding-cron.yaml` 组件文件 + +当您执行 `dapr run` 命令并指定组件路径时,Dapr 边车: + +- 启动 Cron [绑定构建块]({{< ref bindings >}}) +- 每 10 秒调用绑定端点(`batch`) + +为此快速入门包含的 Cron `binding-cron.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: cron + namespace: quickstarts +spec: + type: bindings.cron + version: v1 + metadata: + - name: schedule + value: "@every 10s" # 有效的 cron 调度 + - name: direction + value: "input" # cron 绑定的方向 +``` + +**注意:** `binding-cron.yaml` 的 `metadata` 部分包含一个 [Cron 表达式]({{< ref cron.md >}}),指定绑定被调用的频率。 + +#### `component\binding-postgresql.yaml` 组件文件 + +当您执行 `dapr run` 命令并指定组件路径时,Dapr 边车: + +- 启动 PostgreSQL [绑定构建块]({{< ref postgresql.md >}}) +- 使用 `binding-postgresql.yaml` 文件中指定的设置连接到 PostgreSQL + +使用 `binding-postgresql.yaml` 组件,您可以轻松地更换后端数据库[绑定]({{< ref supported-bindings.md >}}),而无需进行代码更改。 + +为此快速入门包含的 PostgreSQL `binding-postgresql.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: sqldb + namespace: quickstarts +spec: + type: bindings.postgresql + version: v1 + metadata: + - name: url # 必需 + value: "user=postgres password=docker host=localhost port=5432 dbname=orders pool_min_conns=1 pool_max_conns=10" + - name: direction + value: "output" # postgresql 绑定的方向 +``` + +在 YAML 文件中: + +- `spec/type` 指定 PostgreSQL 用于此绑定。 +- `spec/metadata` 定义组件使用的 PostgreSQL 实例的连接。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 告诉我们您的想法! + +我们正在不断努力改进我们的快速入门示例,并重视您的反馈。您觉得这个快速入门有帮助吗?您有改进建议吗? + +加入我们的 [discord 频道](https://discord.com/channels/778680217417809931/953427615916638238)进行讨论。 + +## 下一步 + +- 使用 HTTP 而不是 SDK 使用 Dapr 绑定。 + - [Python](https://github.com/dapr/quickstarts/tree/master/bindings/python/http) + - [JavaScript](https://github.com/dapr/quickstarts/tree/master/bindings/javascript/http) + - [.NET](https://github.com/dapr/quickstarts/tree/master/bindings/csharp/http) + - [Java](https://github.com/dapr/quickstarts/tree/master/bindings/java/http) + - [Go](https://github.com/dapr/quickstarts/tree/master/bindings/go/http) +- 了解更多关于[绑定构建块]({{< ref bindings >}}) + +{{< button text="探索 Dapr 教程 >>" page="getting-started/tutorials/_index.md" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/configuration-quickstart.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/configuration-quickstart.md new file mode 100644 index 000000000..cc4f1e8ea --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/configuration-quickstart.md @@ -0,0 +1,645 @@ +--- +type: docs +title: "快速入门:配置" +linkTitle: 配置 +weight: 78 +description: 开始使用 Dapr 的配置模块 +--- + +接下来,我们将介绍 Dapr 的[配置模块]({{< ref configuration-api-overview.md >}})。配置项通常具有动态特性,并且与应用程序的需求紧密相关。配置项是包含配置信息的键/值对,例如: +- 应用程序 ID +- 分区键 +- 数据库名称等 + +在本快速入门中,您将运行一个使用配置 API 的 `order-processor` 微服务。该服务将: +1. 从配置存储中获取配置项。 +2. 订阅配置更新。 + +展示配置 API 快速入门流程的图示,使用了键/值对。 + +在继续快速入门之前,请选择您偏好的 Dapr SDK 语言版本。 + +{{< tabs "Python" "JavaScript" ".NET" "Java" "Go" >}} + +{{% codetab %}} + +### 前提条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装 Python 3.7+](https://www.python.org/downloads/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/configuration/python/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +克隆后,打开一个新终端并运行以下命令,为配置项 `orderId1` 和 `orderId2` 设置值。 + +```bash +docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102" +``` + +### 步骤 2:运行 `order-processor` 服务 + +从快速入门克隆目录的根目录,导航到 `order-processor` 目录。 + +```bash +cd configuration/python/sdk/order-processor +``` + +安装依赖项: + +```bash +pip3 install -r requirements.txt +``` + +在 Dapr 边车环境中运行 `order-processor` 服务。 + +```bash +dapr run --app-id order-processor --resources-path ../../../components/ --app-port 6001 -- python3 app.py +``` + +> **注意**:在 Windows 中,您可能需要使用 `python app.py` 而不是 `python3 app.py`。 + +预期输出: + +``` +== APP == Configuration for orderId1 : value: "101" +== APP == +== APP == Configuration for orderId2 : value: "102" +== APP == +== APP == App unsubscribed from config changes +``` + +### (可选)步骤 3:更新配置项值 + +应用程序取消订阅后,尝试更新配置项值。使用以下命令更改 `orderId1` 和 `orderId2` 的值: + +```bash +docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104" +``` + +再次运行 `order-processor` 服务: + +```bash +dapr run --app-id order-processor --resources-path ../../../components/ --app-port 6001 -- python3 app.py +``` + +> **注意**:在 Windows 中,您可能需要使用 `python app.py` 而不是 `python3 app.py`。 + +应用程序将显示更新后的配置值: + +``` +== APP == Configuration for orderId1 : value: "103" +== APP == +== APP == Configuration for orderId2 : value: "104" +== APP == +``` + +### `order-processor` 服务 + +`order-processor` 服务包括以下代码: +- 从配置存储中获取配置项 +- 订阅配置更新(您之前在 CLI 中进行的操作) +- 取消订阅配置更新,并在 20 秒不活动后退出应用程序。 + +获取配置项: + +```python +# 从配置存储中获取配置项 +for config_item in CONFIGURATION_ITEMS: + config = client.get_configuration(store_name=DAPR_CONFIGURATION_STORE, keys=[config_item], config_metadata={}) + print(f"Configuration for {config_item} : {config.items[config_item]}", flush=True) +``` + +订阅配置更新: + +```python +# 订阅配置更改 +configuration = await client.subscribe_configuration(DAPR_CONFIGURATION_STORE, CONFIGURATION_ITEMS) +``` + +取消订阅配置更新并退出应用程序: + +```python +# 取消订阅配置更新 +unsubscribed = True +for config_item in CONFIGURATION_ITEMS: + unsub_item = client.unsubscribe_configuration(DAPR_CONFIGURATION_STORE, config_item) + #... +if unsubscribed == True: + print("App unsubscribed from config changes", flush=True) +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前提条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装最新的 Node.js](https://nodejs.org/download/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/configuration/javascript/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +克隆后,打开一个新终端并运行以下命令,为配置项 `orderId1` 和 `orderId2` 设置值。 + +```bash +docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102" +``` + +### 步骤 2:运行 `order-processor` 服务 + +从快速入门克隆目录的根目录,导航到 `order-processor` 目录。 + +```bash +cd configuration/javascript/sdk/order-processor +``` + +安装依赖项: + +```bash +npm install +``` + +在 Dapr 边车环境中运行 `order-processor` 服务。 + +```bash +dapr run --app-id order-processor --resources-path ../../../components/ --app-protocol grpc --dapr-grpc-port 3500 -- node index.js +``` + +预期输出: + +``` +== APP == Configuration for orderId1: {"key":"orderId1","value":"101","version":"","metadata":{}} +== APP == Configuration for orderId2: {"key":"orderId2","value":"102","version":"","metadata":{}} +== APP == App unsubscribed to config changes +``` + +### (可选)步骤 3:更新配置项值 + +应用程序取消订阅后,尝试更新配置项值。使用以下命令更改 `orderId1` 和 `orderId2` 的值: + +```bash +docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104" +``` + +再次运行 `order-processor` 服务: + +```bash +dapr run --app-id order-processor --resources-path ../../../components/ --app-protocol grpc --dapr-grpc-port 3500 -- node index.js +``` + +应用程序将显示更新后的配置值: + +``` +== APP == Configuration for orderId1: {"key":"orderId1","value":"103","version":"","metadata":{}} +== APP == Configuration for orderId2: {"key":"orderId2","value":"104","version":"","metadata":{}} +``` + +### `order-processor` 服务 + +`order-processor` 服务包括以下代码: +- 从配置存储中获取配置项 +- 订阅配置更新(您之前在 CLI 中进行的操作) +- 取消订阅配置更新,并在 20 秒不活动后退出应用程序。 + +获取配置项: + +```javascript +// 从配置存储中获取配置项 +//... + const config = await client.configuration.get(DAPR_CONFIGURATION_STORE, CONFIGURATION_ITEMS); + Object.keys(config.items).forEach((key) => { + console.log("Configuration for " + key + ":", JSON.stringify(config.items[key])); + }); +``` + +订阅配置更新: + +```javascript +// 订阅配置更新 +try { + const stream = await client.configuration.subscribeWithKeys( + DAPR_CONFIGURATION_STORE, + CONFIGURATION_ITEMS, + (config) => { + console.log("Configuration update", JSON.stringify(config.items)); + } + ); +``` + +取消订阅配置更新并退出应用程序: + +```javascript +// 取消订阅配置更新并在 20 秒后退出应用程序 +setTimeout(() => { + stream.stop(); + console.log("App unsubscribed to config changes"); + process.exit(0); +}, +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前提条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + +- [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0)、[.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) 或 [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) 已安装 + +**注意:** .NET 6 是此版本中 Dapr .NET SDK 包的最低支持版本。仅 .NET 8 和 .NET 9 将在 Dapr v1.16 及更高版本中得到支持。 + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/configuration/csharp/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +克隆后,打开一个新终端并运行以下命令,为配置项 `orderId1` 和 `orderId2` 设置值。 + +```bash +docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102" +``` + +### 步骤 2:运行 `order-processor` 服务 + +从快速入门克隆目录的根目录,导航到 `order-processor` 目录。 + +```bash +cd configuration/csharp/sdk/order-processor +``` + +恢复 NuGet 包: + +```bash +dotnet restore +dotnet build +``` + +在 Dapr 边车环境中运行 `order-processor` 服务。 + +```bash +dapr run --app-id order-processor-http --resources-path ../../../components/ --app-port 7001 -- dotnet run --project . +``` + +预期输出: + +``` +== APP == Configuration for orderId1: {"Value":"101","Version":"","Metadata":{}} +== APP == Configuration for orderId2: {"Value":"102","Version":"","Metadata":{}} +== APP == App unsubscribed from config changes +``` + +### (可选)步骤 3:更新配置项值 + +应用程序取消订阅后,尝试更新配置项值。使用以下命令更改 `orderId1` 和 `orderId2` 的值: + +```bash +docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104" +``` + +再次运行 `order-processor` 服务: + +```bash +dapr run --app-id order-processor-http --resources-path ../../../components/ --app-port 7001 -- dotnet run --project . +``` + +应用程序将显示更新后的配置值: + +``` +== APP == Configuration for orderId1: {"Value":"103","Version":"","Metadata":{}} +== APP == Configuration for orderId2: {"Value":"104","Version":"","Metadata":{}} +``` + +### `order-processor` 服务 + +`order-processor` 服务包括以下代码: +- 从配置存储中获取配置项 +- 订阅配置更新(您之前在 CLI 中进行的操作) +- 取消订阅配置更新,并在 20 秒不活动后退出应用程序。 + +获取配置项: + +```csharp +// 从配置存储中获取配置 +GetConfigurationResponse config = await client.GetConfiguration(DAPR_CONFIGURATION_STORE, CONFIGURATION_ITEMS); +foreach (var item in config.Items) +{ + var cfg = System.Text.Json.JsonSerializer.Serialize(item.Value); + Console.WriteLine("Configuration for " + item.Key + ": " + cfg); +} +``` + +订阅配置更新: + +```csharp +// 订阅配置更新 +SubscribeConfigurationResponse subscribe = await client.SubscribeConfiguration(DAPR_CONFIGURATION_STORE, CONFIGURATION_ITEMS); +``` + +取消订阅配置更新并退出应用程序: + +```csharp +// 取消订阅配置更新并退出应用程序 +try +{ + client.UnsubscribeConfiguration(DAPR_CONFIGURATION_STORE, subscriptionId); + Console.WriteLine("App unsubscribed from config changes"); + Environment.Exit(0); +} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前提条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- Java JDK 17(或更高版本): + - [Oracle JDK](https://www.oracle.com/technetwork/java/javase/downloads/index.html#JDK11),或 + - OpenJDK +- [Apache Maven](https://maven.apache.org/install.html),版本 3.x。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/configuration/java/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +克隆后,打开一个新终端并运行以下命令,为配置项 `orderId1` 和 `orderId2` 设置值。 + +```bash +docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102" +``` + +### 步骤 2:运行 `order-processor` 服务 + +从快速入门克隆目录的根目录,导航到 `order-processor` 目录。 + +```bash +cd configuration/java/sdk/order-processor +``` + +安装依赖项: + +```bash +mvn clean install +``` + +在 Dapr 边车环境中运行 `order-processor` 服务。 + +```bash +dapr run --app-id order-processor --resources-path ../../../components -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar +``` + +预期输出: + +``` +== APP == Configuration for orderId1: {'value':'101'} +== APP == Configuration for orderId2: {'value':'102'} +== APP == App unsubscribed to config changes +``` + +### (可选)步骤 3:更新配置项值 + +应用程序取消订阅后,尝试更新配置项值。使用以下命令更改 `orderId1` 和 `orderId2` 的值: + +```bash +docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104" +``` + +再次运行 `order-processor` 服务: + +```bash +dapr run --app-id order-processor --resources-path ../../../components -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar +``` + +应用程序将显示更新后的配置值: + +``` +== APP == Configuration for orderId1: {'value':'103'} +== APP == Configuration for orderId2: {'value':'104'} +``` + +### `order-processor` 服务 + +`order-processor` 服务包括以下代码: +- 从配置存储中获取配置项 +- 订阅配置更新(您之前在 CLI 中进行的操作) +- 取消订阅配置更新,并在 20 秒不活动后退出应用程序。 + +获取配置项: + +```java +// 从配置存储中获取配置项 +try (DaprPreviewClient client = (new DaprClientBuilder()).buildPreviewClient()) { + for (String configurationItem : CONFIGURATION_ITEMS) { + ConfigurationItem item = client.getConfiguration(DAPR_CONFIGURATON_STORE, configurationItem).block(); + System.out.println("Configuration for " + configurationItem + ": {'value':'" + item.getValue() + "'}"); + } +``` + +订阅配置更新: + +```java +// 订阅配置更改 +Flux subscription = client.subscribeConfiguration(DAPR_CONFIGURATON_STORE, + CONFIGURATION_ITEMS.toArray(String[]::new)); +``` + +取消订阅配置更新并退出应用程序: + +```java +// 取消订阅配置更改 +UnsubscribeConfigurationResponse unsubscribe = client + .unsubscribeConfiguration(subscriptionId, DAPR_CONFIGURATON_STORE).block(); +if (unsubscribe.getIsUnsubscribed()) { + System.out.println("App unsubscribed to config changes"); +} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前提条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的 Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/configuration/go/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +克隆后,打开一个新终端并运行以下命令,为配置项 `orderId1` 和 `orderId2` 设置值。 + +```bash +docker exec dapr_redis redis-cli MSET orderId1 "101" orderId2 "102" +``` + +### 步骤 2:运行 `order-processor` 服务 + +从快速入门克隆目录的根目录,导航到 `order-processor` 目录。 + +```bash +cd configuration/go/sdk/order-processor +``` + +在 Dapr 边车环境中运行 `order-processor` 服务。 + +```bash +dapr run --app-id order-processor --app-port 6001 --resources-path ../../../components -- go run . +``` + +预期输出: + +``` +== APP == Configuration for orderId1: {"Value":"101","Version":"","Metadata":null} +== APP == Configuration for orderId2: {"Value":"102","Version":"","Metadata":null} +== APP == dapr configuration subscribe finished. +== APP == App unsubscribed to config changes +``` + +### (可选)步骤 3:更新配置项值 + +应用程序取消订阅后,尝试更新配置项值。使用以下命令更改 `orderId1` 和 `orderId2` 的值: + +```bash +docker exec dapr_redis redis-cli MSET orderId1 "103" orderId2 "104" +``` + +再次运行 `order-processor` 服务: + +```bash +dapr run --app-id order-processor --app-port 6001 --resources-path ../../../components -- go run . +``` + +应用程序将显示更新后的配置值: + +``` +== APP == Configuration for orderId1: {"Value":"103","Version":"","Metadata":null} +== APP == Configuration for orderId2: {"Value":"104","Version":"","Metadata":null} +``` + +### `order-processor` 服务 + +`order-processor` 服务包括以下代码: +- 从配置存储中获取配置项 +- 订阅配置更新(您之前在 CLI 中进行的操作) +- 取消订阅配置更新,并在 20 秒不活动后退出应用程序。 + +获取配置项: + +```go +// 从配置存储中获取配置项 +for _, item := range CONFIGURATION_ITEMS { + config, err := client.GetConfigurationItem(ctx, DAPR_CONFIGURATION_STORE, item) + //... + c, _ := json.Marshal(config) + fmt.Println("Configuration for " + item + ": " + string(c)) +} +``` + +订阅配置更新: + +```go +// 订阅配置更改 +err = client.SubscribeConfigurationItems(ctx, DAPR_CONFIGURATION_STORE, CONFIGURATION_ITEMS, func(id string, config map[string]*dapr.ConfigurationItem) { + // 应用程序首次订阅配置更改时仅返回订阅 ID + if len(config) == 0 { + fmt.Println("App subscribed to config changes with subscription id: " + id) + subscriptionId = id + return + } +}) +``` + +取消订阅配置更新并退出应用程序: + +```go +// 取消订阅配置更新并在 20 秒后退出应用程序 +select { +case <-ctx.Done(): + err = client.UnsubscribeConfigurationItems(context.Background(), DAPR_CONFIGURATION_STORE, subscriptionId) + //... + { + fmt.Println("App unsubscribed to config changes") + } +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 演示 + +观看此视频[演示配置 API 快速入门](https://youtu.be/EcE6IGuX9L8?t=94): + + + +## 告诉我们您的想法! + +我们正在不断改进我们的快速入门示例,并重视您的反馈。您觉得这个快速入门有帮助吗?您有改进建议吗? + +加入我们的[Discord 频道](https://discord.com/channels/778680217417809931/953427615916638238)讨论。 + +## 下一步 + +- 使用 HTTP 而不是 SDK 使用 Dapr 配置。 + - [Python](https://github.com/dapr/quickstarts/tree/master/configuration/python/http) + - [JavaScript](https://github.com/dapr/quickstarts/tree/master/configuration/javascript/http) + - [.NET](https://github.com/dapr/quickstarts/tree/master/configuration/csharp/http) + - [Java](https://github.com/dapr/quickstarts/tree/master/configuration/java/http) + - [Go](https://github.com/dapr/quickstarts/tree/master/configuration/go/http) +- 了解更多关于[配置模块]({{< ref configuration-api-overview >}})的信息 + +{{< button text="探索 Dapr 教程 >>" page="getting-started/tutorials/_index.md" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/cryptography-quickstart.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/cryptography-quickstart.md new file mode 100644 index 000000000..21688d02c --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/cryptography-quickstart.md @@ -0,0 +1,491 @@ +--- +type: docs +title: "快速入门:加密技术" +linkTitle: 加密技术 +weight: 79 +description: 开始使用 Dapr 加密构建块 +--- + +{{% alert title="Alpha" color="warning" %}} +加密构建块目前处于**初始阶段**。 +{{% /alert %}} + +我们来了解一下 Dapr 的[加密构建块]({{< ref cryptography >}})。在这个快速入门中,您将创建一个应用程序,使用 Dapr 加密 API 来加密和解密数据。您将: + +- 加密并解密一个短字符串(使用 RSA 密钥),在内存中读取结果,使用 Go 的字节切片格式。 +- 加密并解密一个大文件(使用 AES 密钥),通过流的方式将加密和解密的数据存储到文件中。 + + + +{{% alert title="注意" color="primary" %}} +此示例使用 Dapr SDK,该 SDK 利用 gRPC,并在使用加密 API 加密和解密消息时**强烈**推荐使用。 +{{% /alert %}} + +目前,您可以使用 Go SDK 体验加密 API。 + +{{< tabs "JavaScript" "Go" >}} + + +{{% codetab %}} + +> 此快速入门包括一个名为 `crypto-quickstart` 的 JavaScript 应用程序。 + +### 前置条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [安装最新的 Node.js](https://nodejs.org/download/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + +- 系统上可用的 [OpenSSL](https://www.openssl.org/source/) + +### 步骤 1:设置环境 + +克隆 [快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/cryptography/javascript/sdk) + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +在终端中,从根目录导航到加密示例。 + +```bash +cd cryptography/javascript/sdk +``` + +导航到包含源代码的文件夹: + +```bash +cd ./crypto-quickstart +``` + +安装依赖项: + +```bash +npm install +``` + +### 步骤 2:使用 Dapr 运行应用程序 + +应用程序代码定义了两个必需的密钥: + +- 私有 RSA 密钥 +- 一个 256 位对称(AES)密钥 + +使用 OpenSSL 生成两个密钥:一个 RSA 密钥和一个 AES 密钥,并将它们写入两个文件: + +```bash +mkdir -p keys +# 生成一个私有 RSA 密钥,4096 位密钥 +openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out keys/rsa-private-key.pem +# 为 AES 生成一个 256 位密钥 +openssl rand -out keys/symmetric-key-256 32 +``` + +使用 Dapr 运行 Go 服务应用程序: + +```bash +dapr run --app-id crypto-quickstart --resources-path ../../../components/ -- npm start +``` + +**预期输出** + +``` +== APP == 2023-10-25T14:30:50.435Z INFO [GRPCClient, GRPCClient] Opening connection to 127.0.0.1:58173 +== APP == == Encrypting message using buffers +== APP == Encrypted the message, got 856 bytes +== APP == == Decrypting message using buffers +== APP == Decrypted the message, got 24 bytes +== APP == The secret is "passw0rd" +== APP == == Encrypting message using streams +== APP == Encrypting federico-di-dio-photography-Q4g0Q-eVVEg-unsplash.jpg to encrypted.out +== APP == Encrypted the message to encrypted.out +== APP == == Decrypting message using streams +== APP == Decrypting encrypted.out to decrypted.out.jpg +== APP == Decrypted the message to decrypted.out.jpg +``` + +### 发生了什么? + +#### `local-storage.yaml` + +之前,您在 `crypto-quickstarts` 中创建了一个名为 `keys` 的目录。在 [`local-storage` 组件 YAML](https://github.com/dapr/quickstarts/tree/master/cryptography/components/local-storage.yaml) 中,`path` 元数据映射到新创建的 `keys` 目录。 + +```yml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: localstorage +spec: + type: crypto.dapr.localstorage + version: v1 + metadata: + - name: path + # 路径相对于示例所在的文件夹 + value: ./keys +``` + +#### `index.mjs` + +[应用程序文件](https://github.com/dapr/quickstarts/blob/master/cryptography/javascript/sdk/crypto-quickstart/index.mjs) 使用您生成的 RSA 和 AES 密钥加密和解密消息和文件。应用程序创建了一个新的 Dapr SDK 客户端: + +```javascript +async function start() { + const client = new DaprClient({ + daprHost, + daprPort, + communicationProtocol: CommunicationProtocolEnum.GRPC, + }); + + // 从缓冲区加密和解密消息 + await encryptDecryptBuffer(client); + + // 使用流加密和解密消息 + await encryptDecryptStream(client); +} +``` + +##### 使用 RSA 密钥加密和解密字符串 + +一旦创建了客户端,应用程序就会加密一条消息: + +```javascript +async function encryptDecryptBuffer(client) { + // 要加密的消息 + const plaintext = `The secret is "passw0rd"` + + // 首先,加密消息 + console.log("== Encrypting message using buffers"); + + const encrypted = await client.crypto.encrypt(plaintext, { + componentName: "localstorage", + keyName: "rsa-private-key.pem", + keyWrapAlgorithm: "RSA", + }); + + console.log("Encrypted the message, got", encrypted.length, "bytes"); +``` + +然后应用程序解密消息: + +```javascript + // 解密消息 + console.log("== Decrypting message using buffers"); + const decrypted = await client.crypto.decrypt(encrypted, { + componentName: "localstorage", + }); + + console.log("Decrypted the message, got", decrypted.length, "bytes"); + console.log(decrypted.toString("utf8")); + + // ... +} +``` + +##### 使用 AES 密钥加密和解密大文件 + +接下来,应用程序加密一个大图像文件: + +```javascript +async function encryptDecryptStream(client) { + // 首先,加密消息 + console.log("== Encrypting message using streams"); + console.log("Encrypting", testFileName, "to encrypted.out"); + + await pipeline( + createReadStream(testFileName), + await client.crypto.encrypt({ + componentName: "localstorage", + keyName: "symmetric-key-256", + keyWrapAlgorithm: "A256KW", + }), + createWriteStream("encrypted.out"), + ); + + console.log("Encrypted the message to encrypted.out"); +``` + +然后应用程序解密大图像文件: + +```javascript + // 解密消息 + console.log("== Decrypting message using streams"); + console.log("Decrypting encrypted.out to decrypted.out.jpg"); + await pipeline( + createReadStream("encrypted.out"), + await client.crypto.decrypt({ + componentName: "localstorage", + }), + createWriteStream("decrypted.out.jpg"), + ); + + console.log("Decrypted the message to decrypted.out.jpg"); +} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +> 此快速入门包括一个名为 `crypto-quickstart` 的 Go 应用程序。 + +### 前置条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的 Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + +- 系统上可用的 [OpenSSL](https://www.openssl.org/source/) + +### 步骤 1:设置环境 + +克隆 [快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/cryptography/go/sdk) + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +在终端中,从根目录导航到加密示例。 + +```bash +cd cryptography/go/sdk +``` + +### 步骤 2:使用 Dapr 运行应用程序 + +导航到包含源代码的文件夹: + +```bash +cd ./crypto-quickstart +``` + +应用程序代码定义了两个必需的密钥: + +- 私有 RSA 密钥 +- 一个 256 位对称(AES)密钥 + +使用 OpenSSL 生成两个密钥:一个 RSA 密钥和一个 AES 密钥,并将它们写入两个文件: + +```bash +mkdir -p keys +# 生成一个私有 RSA 密钥,4096 位密钥 +openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -out keys/rsa-private-key.pem +# 为 AES 生成一个 256 位密钥 +openssl rand -out keys/symmetric-key-256 32 +``` + +使用 Dapr 运行 Go 服务应用程序: + +```bash +dapr run --app-id crypto-quickstart --resources-path ../../../components/ -- go run . +``` + +**预期输出** + +``` +== APP == dapr client initializing for: 127.0.0.1:52407 +== APP == Encrypted the message, got 856 bytes +== APP == Decrypted the message, got 24 bytes +== APP == The secret is "passw0rd" +== APP == Wrote decrypted data to encrypted.out +== APP == Wrote decrypted data to decrypted.out.jpg +``` + +### 发生了什么? + +#### `local-storage.yaml` + +之前,您在 `crypto-quickstarts` 中创建了一个名为 `keys` 的目录。在 [`local-storage` 组件 YAML](https://github.com/dapr/quickstarts/tree/master/cryptography/components/local-storage.yaml) 中,`path` 元数据映射到新创建的 `keys` 目录。 + +```yml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: localstorage +spec: + type: crypto.dapr.localstorage + version: v1 + metadata: + - name: path + # 路径相对于示例所在的文件夹 + value: ./keys +``` + +#### `app.go` + +[应用程序文件](https://github.com/dapr/quickstarts/tree/master/cryptography/go/sdk/crypto-quickstart/app.go) 使用您生成的 RSA 和 AES 密钥加密和解密消息和文件。应用程序创建了一个新的 Dapr SDK 客户端: + +```go +func main() { + // 创建一个新的 Dapr SDK 客户端 + client, err := dapr.NewClient() + + //... + + // 步骤 1:使用 RSA 密钥加密字符串,然后解密并在终端中显示输出 + encryptDecryptString(client) + + // 步骤 2:加密大文件,然后使用 AES 密钥解密 + encryptDecryptFile(client) +} +``` + +##### 使用 RSA 密钥加密和解密字符串 + +一旦创建了客户端,应用程序就会加密一条消息: + +```go +func encryptDecryptString(client dapr.Client) { + // ... + + // 加密消息 + encStream, err := client.Encrypt(context.Background(), + strings.NewReader(message), + dapr.EncryptOptions{ + ComponentName: CryptoComponentName, + // 要使用的密钥名称 + // 由于这是一个 RSA 密钥,我们将其指定为密钥包装算法 + KeyName: RSAKeyName, + KeyWrapAlgorithm: "RSA", + }, + ) + + // ... + + // 该方法返回一个可读流,我们在内存中完整读取 + encBytes, err := io.ReadAll(encStream) + // ... + + fmt.Printf("Encrypted the message, got %d bytes\n", len(encBytes)) +``` + +然后应用程序解密消息: + +```go + // 现在,解密加密的数据 + decStream, err := client.Decrypt(context.Background(), + bytes.NewReader(encBytes), + dapr.DecryptOptions{ + // 我们只需要传递组件的名称 + ComponentName: CryptoComponentName, + // 传递密钥名称是可选的 + KeyName: RSAKeyName, + }, + ) + + // ... + + // 该方法返回一个可读流,我们在内存中完整读取 + decBytes, err := io.ReadAll(decStream) + + // ... + + // 在控制台上打印消息 + fmt.Printf("Decrypted the message, got %d bytes\n", len(decBytes)) + fmt.Println(string(decBytes)) +} +``` + +##### 使用 AES 密钥加密和解密大文件 + +接下来,应用程序加密一个大图像文件: + +```go +func encryptDecryptFile(client dapr.Client) { + const fileName = "liuguangxi-66ouBTTs_x0-unsplash.jpg" + + // 获取输入文件的可读流 + plaintextF, err := os.Open(fileName) + + // ... + + defer plaintextF.Close() + + // 加密文件 + encStream, err := client.Encrypt(context.Background(), + plaintextF, + dapr.EncryptOptions{ + ComponentName: CryptoComponentName, + // 要使用的密钥名称 + // 由于这是一个对称密钥,我们将 AES 指定为密钥包装算法 + KeyName: SymmetricKeyName, + KeyWrapAlgorithm: "AES", + }, + ) + + // ... + + // 将加密数据写入文件 "encrypted.out" + encryptedF, err := os.Create("encrypted.out") + + // ... + + encryptedF.Close() + + fmt.Println("Wrote decrypted data to encrypted.out") +``` + +然后应用程序解密大图像文件: + +```go + // 现在,解密加密的数据 + // 首先,再次打开文件 "encrypted.out",这次用于读取 + encryptedF, err = os.Open("encrypted.out") + + // ... + + defer encryptedF.Close() + + // 现在,解密加密的数据 + decStream, err := client.Decrypt(context.Background(), + encryptedF, + dapr.DecryptOptions{ + // 我们只需要传递组件的名称 + ComponentName: CryptoComponentName, + // 传递密钥名称是可选的 + KeyName: SymmetricKeyName, + }, + ) + + // ... + + // 将解密数据写入文件 "decrypted.out.jpg" + decryptedF, err := os.Create("decrypted.out.jpg") + + // ... + + decryptedF.Close() + + fmt.Println("Wrote decrypted data to decrypted.out.jpg") +} +``` + +{{% /codetab %}} + + +{{< /tabs >}} + +## 观看演示 + +观看此 [Dapr 社区电话 #83 中的加密 API 演示视频](https://youtu.be/PRWYX4lb2Sg?t=1148): + + + +## 告诉我们您的想法! + +我们正在不断努力改进我们的快速入门示例,并重视您的反馈。您觉得这个快速入门有帮助吗?您有改进建议吗? + +加入我们的 [discord 频道](https://discord.com/channels/778680217417809931/953427615916638238)进行讨论。 + +## 下一步 + +- 通过 [更多使用加密 API 加密和解密的示例]({{< ref howto-cryptography.md >}}) 进行学习 +- 了解更多关于 [作为 Dapr 构建块的加密技术]({{< ref cryptography-overview.md >}}) + +{{< button text="探索 Dapr 教程 >>" page="getting-started/tutorials/_index.md" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/jobs-quickstart.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/jobs-quickstart.md new file mode 100644 index 000000000..85a174752 --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/jobs-quickstart.md @@ -0,0 +1,528 @@ +--- +type: docs +title: "快速入门:作业" +linkTitle: 作业 +weight: 80 +description: 开始使用 Dapr 作业构建块 +--- + +{{% alert title="Alpha" color="warning" %}} +作业构建块目前处于 **alpha** 阶段。 +{{% /alert %}} + +[Dapr 作业构建块]({{< ref jobs-overview.md >}}) 允许您在特定时间或间隔调度和运行作业。在本快速入门中,您将学习如何使用 Dapr 的作业 API 来调度、获取和删除作业。 + +您可以通过以下两种方式来体验此作业快速入门: + +- [同时运行所有示例应用程序]({{< ref "#run-using-multi-app-run" >}}),或 +- [逐个运行应用程序]({{< ref "#run-one-job-application-at-a-time" >}}) + +## 同时运行多个应用 + +在开始之前,请选择您偏好的 Dapr SDK 语言。目前,您可以使用 Go SDK 来试验作业 API。 + +{{< tabs Go >}} + + +{{% codetab %}} + +本快速入门包含两个应用程序: + +- **`job-scheduler.go`:** 负责调度、检索和删除作业。 +- **`job-service.go`:** 负责处理已调度的作业。 + +### 步骤 1:准备工作 + +您需要以下工具: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的 Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆 [快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/jobs/go/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +从仓库根目录导航到作业目录: + +```bash +cd jobs/go/sdk +``` + +### 步骤 3:调度作业 + +运行应用程序并调度作业: + +```bash +dapr run -f . +``` + +**预期输出** + +```text +== APP - job-service == dapr 客户端初始化中:127.0.0.1:6281 +== APP - job-service == 已注册作业处理程序:R2-D2 +== APP - job-service == 已注册作业处理程序:C-3PO +== APP - job-service == 已注册作业处理程序:BB-8 +== APP - job-service == 在端口启动服务器:6200 +== APP - job-service == 作业已调度:R2-D2 +== APP - job-service == 作业已调度:C-3PO +== APP - job-service == 2024/07/17 18:09:59 作业:{name:"C-3PO" due_time:"10s" data:{value:"{\"droid\":\"C-3PO\",\"Task\":\"Memory Wipe\"}"}} +== APP - job-scheduler == 获取作业响应:{"droid":"C-3PO","Task":"Memory Wipe"} +== APP - job-service == 作业已调度:BB-8 +== APP - job-service == 2024/07/17 18:09:59 作业:{name:"BB-8" due_time:"15s" data:{value:"{\"droid\":\"BB-8\",\"Task\":\"Internal Gyroscope Check\"}"}} +== APP - job-scheduler == 获取作业响应:{"droid":"BB-8","Task":"Internal Gyroscope Check"} +== APP - job-scheduler == 已删除作业:BB-8 +``` + +5 秒后,终端输出应显示 `R2-D2` 作业正在处理: + +```text +== APP - job-service == 启动机器人:R2-D2 +== APP - job-service == 执行维护作业:Oil Change +``` + +10 秒后,终端输出应显示 `C3-PO` 作业正在处理: + +```text +== APP - job-service == 启动机器人:C-3PO +== APP - job-service == 执行维护作业:Memory Wipe +``` + +完成后,您可以使用以下命令停止并清理应用程序进程。 + +```bash +dapr stop -f . +``` + +### 发生了什么? + +在 Dapr 安装期间运行 `dapr init` 时: + +- `dapr_scheduler` 控制平面与其他 Dapr 服务一起启动。 +- [在 `.dapr/components` 目录中生成了 `dapr.yaml` 多应用运行模板文件]({{< ref "#dapryaml-multi-app-run-template-file" >}})。 + +在此快速入门中运行 `dapr run -f .` 启动了 `job-scheduler` 和 `job-service`。在终端输出中,您可以看到以下作业正在调度、检索和删除。 + +- `R2-D2` 作业正在调度。 +- `C-3PO` 作业正在调度。 +- `C-3PO` 作业正在检索。 +- `BB-8` 作业正在调度。 +- `BB-8` 作业正在检索。 +- `BB-8` 作业正在删除。 +- `R2-D2` 作业在 5 秒后执行。 +- `R2-D2` 作业在 10 秒后执行。 + +#### `dapr.yaml` 多应用运行模板文件 + +使用 `dapr run -f .` 运行 [多应用运行模板文件]({{< ref multi-app-dapr-run >}}) 启动项目中的所有应用程序。在此快速入门中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +apps: + - appDirPath: ./job-service/ + appID: job-service + appPort: 6200 + daprGRPCPort: 6281 + appProtocol: grpc + command: ["go", "run", "."] + - appDirPath: ./job-scheduler/ + appID: job-scheduler + appPort: 6300 + command: ["go", "run", "."] +``` + +#### `job-service` 应用 + +`job-service` 应用程序创建服务调用处理程序以管理作业的生命周期(`scheduleJob`、`getJob` 和 `deleteJob`)。 + +```go +if err := server.AddServiceInvocationHandler("scheduleJob", scheduleJob); err != nil { + log.Fatalf("error adding invocation handler: %v", err) +} + +if err := server.AddServiceInvocationHandler("getJob", getJob); err != nil { + log.Fatalf("error adding invocation handler: %v", err) +} + +if err := server.AddServiceInvocationHandler("deleteJob", deleteJob); err != nil { + log.Fatalf("error adding invocation handler: %v", err) +} +``` + +接下来,为所有机器人注册作业事件处理程序: + +```go +for _, jobName := range jobNames { + if err := server.AddJobEventHandler(jobName, handleJob); err != nil { + log.Fatalf("failed to register job event handler: %v", err) + } + fmt.Println("Registered job handler for: ", jobName) +} + +fmt.Println("Starting server on port: " + appPort) +if err = server.Start(); err != nil { + log.Fatalf("failed to start server: %v", err) +} +``` + +然后,`job-service` 调用处理调度、获取、删除和处理作业事件的函数。 + +```go +// 处理调度 DroidJob 的处理程序 +func scheduleJob(ctx context.Context, in *common.InvocationEvent) (out *common.Content, err error) { + + if in == nil { + err = errors.New("no invocation parameter") + return + } + + droidJob := DroidJob{} + err = json.Unmarshal(in.Data, &droidJob) + if err != nil { + fmt.Println("failed to unmarshal job: ", err) + return nil, err + } + + jobData := JobData{ + Droid: droidJob.Name, + Task: droidJob.Job, + } + + content, err := json.Marshal(jobData) + if err != nil { + fmt.Printf("Error marshalling job content") + return nil, err + } + + // 调度作业 + job := daprc.Job{ + Name: droidJob.Name, + DueTime: droidJob.DueTime, + Data: &anypb.Any{ + Value: content, + }, + } + + err = app.daprClient.ScheduleJobAlpha1(ctx, &job) + if err != nil { + fmt.Println("failed to schedule job. err: ", err) + return nil, err + } + + fmt.Println("Job scheduled: ", droidJob.Name) + + out = &common.Content{ + Data: in.Data, + ContentType: in.ContentType, + DataTypeURL: in.DataTypeURL, + } + + return out, err + +} + +// 处理按名称获取作业的处理程序 +func getJob(ctx context.Context, in *common.InvocationEvent) (out *common.Content, err error) { + + if in == nil { + err = errors.New("no invocation parameter") + return nil, err + } + + job, err := app.daprClient.GetJobAlpha1(ctx, string(in.Data)) + if err != nil { + fmt.Println("failed to get job. err: ", err) + } + + out = &common.Content{ + Data: job.Data.Value, + ContentType: in.ContentType, + DataTypeURL: in.DataTypeURL, + } + + return out, err +} + +// 处理按名称删除作业的处理程序 +func deleteJob(ctx context.Context, in *common.InvocationEvent) (out *common.Content, err error) { + if in == nil { + err = errors.New("no invocation parameter") + return nil, err + } + + err = app.daprClient.DeleteJobAlpha1(ctx, string(in.Data)) + if err != nil { + fmt.Println("failed to delete job. err: ", err) + } + + out = &common.Content{ + Data: in.Data, + ContentType: in.ContentType, + DataTypeURL: in.DataTypeURL, + } + + return out, err +} + +// 处理作业事件的处理程序 +func handleJob(ctx context.Context, job *common.JobEvent) error { + var jobData common.Job + if err := json.Unmarshal(job.Data, &jobData); err != nil { + return fmt.Errorf("failed to unmarshal job: %v", err) + } + + var jobPayload JobData + if err := json.Unmarshal(job.Data, &jobPayload); err != nil { + return fmt.Errorf("failed to unmarshal payload: %v", err) + } + + fmt.Println("Starting droid:", jobPayload.Droid) + fmt.Println("Executing maintenance job:", jobPayload.Task) + + return nil +} +``` + +#### `job-scheduler` 应用 + +在 `job-scheduler` 应用程序中,首先将 R2D2、C3PO 和 BB8 作业定义为 `[]DroidJob`: + +```go +droidJobs := []DroidJob{ + {Name: "R2-D2", Job: "Oil Change", DueTime: "5s"}, + {Name: "C-3PO", Job: "Memory Wipe", DueTime: "15s"}, + {Name: "BB-8", Job: "Internal Gyroscope Check", DueTime: "30s"}, +} +``` + +然后使用作业 API 调度、检索和删除作业。正如您从终端输出中看到的,首先调度 R2D2 作业: + +```go +// 调度 R2D2 作业 +err = schedule(droidJobs[0]) +if err != nil { + log.Fatalln("Error scheduling job: ", err) +} +``` + +然后调度 C3PO 作业,并返回作业数据: + +```go +// 调度 C-3PO 作业 +err = schedule(droidJobs[1]) +if err != nil { + log.Fatalln("Error scheduling job: ", err) +} + +// 获取 C-3PO 作业 +resp, err := get(droidJobs[1]) +if err != nil { + log.Fatalln("Error retrieving job: ", err) +} +fmt.Println("Get job response: ", resp) +``` + +然后调度、检索和删除 BB8 作业: + +```go +// 调度 BB-8 作业 +err = schedule(droidJobs[2]) +if err != nil { + log.Fatalln("Error scheduling job: ", err) +} + +// 获取 BB-8 作业 +resp, err = get(droidJobs[2]) +if err != nil { + log.Fatalln("Error retrieving job: ", err) +} +fmt.Println("Get job response: ", resp) + +// 删除 BB-8 作业 +err = delete(droidJobs[2]) +if err != nil { + log.Fatalln("Error deleting job: ", err) +} +fmt.Println("Job deleted: ", droidJobs[2].Name) +``` + +`job-scheduler.go` 还定义了 `schedule`、`get` 和 `delete` 函数,从 `job-service.go` 调用。 + +```go +// 通过从 job-service 调用 grpc 服务并传递 DroidJob 作为参数来调度作业 +func schedule(droidJob DroidJob) error { + jobData, err := json.Marshal(droidJob) + if err != nil { + fmt.Println("Error marshalling job content") + return err + } + + content := &daprc.DataContent{ + ContentType: "application/json", + Data: []byte(jobData), + } + + // 调度作业 + _, err = app.daprClient.InvokeMethodWithContent(context.Background(), "job-service", "scheduleJob", "POST", content) + if err != nil { + fmt.Println("Error invoking method: ", err) + return err + } + + return nil +} + +// 通过从 job-service 调用 grpc 服务并传递作业名称作为参数来获取作业 +func get(droidJob DroidJob) (string, error) { + content := &daprc.DataContent{ + ContentType: "text/plain", + Data: []byte(droidJob.Name), + } + + // 获取作业 + resp, err := app.daprClient.InvokeMethodWithContent(context.Background(), "job-service", "getJob", "GET", content) + if err != nil { + fmt.Println("Error invoking method: ", err) + return "", err + } + + return string(resp), nil +} + +// 通过从 job-service 调用 grpc 服务并传递作业名称作为参数来删除作业 +func delete(droidJob DroidJob) error { + content := &daprc.DataContent{ + ContentType: "text/plain", + Data: []byte(droidJob.Name), + } + + _, err := app.daprClient.InvokeMethodWithContent(context.Background(), "job-service", "deleteJob", "DELETE", content) + if err != nil { + fmt.Println("Error invoking method: ", err) + return err + } + + return nil +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 逐个运行作业应用程序 + +{{< tabs Go >}} + + +{{% codetab %}} + +本快速入门包含两个应用程序: + +- **`job-scheduler.go`:** 负责调度、检索和删除作业。 +- **`job-service.go`:** 负责处理已调度的作业。 + +### 步骤 1:准备工作 + +您需要以下工具: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的 Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆 [快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/jobs)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +从仓库根目录导航到作业目录: + +```bash +cd jobs/go/sdk +``` + +### 步骤 3:调度作业 + +在终端中运行 `job-service` 应用: + +```bash +dapr run --app-id job-service --app-port 6200 --dapr-grpc-port 6281 --app-protocol grpc -- go run . +``` + +**预期输出** + +```text +== APP == dapr 客户端初始化中:127.0.0.1:6281 +== APP == 已注册作业处理程序:R2-D2 +== APP == 已注册作业处理程序:C-3PO +== APP == 已注册作业处理程序:BB-8 +== APP == 在端口启动服务器:6200 +``` + +在新终端窗口中运行 `job-scheduler` 应用: + +```bash +dapr run --app-id job-scheduler --app-port 6300 -- go run . +``` + +**预期输出** + +```text +== APP == dapr 客户端初始化中: +== APP == 获取作业响应:{"droid":"C-3PO","Task":"Memory Wipe"} +== APP == 获取作业响应:{"droid":"BB-8","Task":"Internal Gyroscope Check"} +== APP == 作业已删除:BB-8 +``` + +返回到 `job-service` 应用的终端窗口。输出应为: + +```text +== APP == 作业已调度:R2-D2 +== APP == 作业已调度:C-3PO +== APP == 2024/07/17 18:25:36 作业:{name:"C-3PO" due_time:"10s" data:{value:"{\"droid\":\"C-3PO\",\"Task\":\"Memory Wipe\"}"}} +== APP == 作业已调度:BB-8 +== APP == 2024/07/17 18:25:36 作业:{name:"BB-8" due_time:"15s" data:{value:"{\"droid\":\"BB-8\",\"Task\":\"Internal Gyroscope Check\"}"}} +== APP == 启动机器人:R2-D2 +== APP == 执行维护作业:Oil Change +== APP == 启动机器人:C-3PO +== APP == 执行维护作业:Memory Wipe +``` + +解读当您运行 `dapr run` 时 [`job-service`]({{< ref "#job-service-app" >}}) 和 [`job-scheduler`]({{< ref "#job-scheduler-app" >}}) 应用程序中发生的事情。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 观看演示 + +观看使用 Go HTTP 示例的作业 API 演示,录制于 [Dapr 社区电话 #107](https://www.youtube.com/live/WHGOc7Ec_YQ?si=JlOlcJKkhRuhf5R1&t=849)。 + + + +## 告诉我们您的想法! + +我们正在不断努力改进我们的快速入门示例,并重视您的反馈。您觉得这个快速入门有帮助吗?您有改进建议吗? + +加入我们的 [discord 频道](https://discord.com/channels/778680217417809931/953427615916638238) 参与讨论。 + +## 下一步 + +- 本快速入门的 HTTP 示例: + - [Go](https://github.com/dapr/quickstarts/tree/master/jobs/go/http) +- 了解更多关于 [作业构建块]({{< ref jobs-overview.md >}}) +- 了解更多关于 [调度器控制平面]({{< ref scheduler.md >}}) + +{{< button text="探索 Dapr 教程 >>" page="getting-started/tutorials/_index.md" >}} diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/pubsub-quickstart.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/pubsub-quickstart.md new file mode 100644 index 000000000..4c91cc4c7 --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/pubsub-quickstart.md @@ -0,0 +1,1648 @@ +--- +type: docs +title: "快速入门:发布和订阅" +linkTitle: "发布和订阅" +weight: 72 +description: "开始使用 Dapr 的发布和订阅构建块" +--- + +我们来了解一下 Dapr 的[发布和订阅 (Pub/sub) 构建块]({{< ref pubsub >}})。在这个快速入门中,您将运行发布者和订阅者微服务,以演示 Dapr 如何实现 Pub/sub 模式。 + +1. 使用发布者服务,开发者可以不断地将消息发布到某个主题。 +1. [Pub/sub 组件](https://docs.dapr.io/concepts/components-concept/#pubsub-brokers) 会对这些消息进行排队或代理。我们下面的示例使用 Redis,您也可以使用 RabbitMQ、Kafka 等。 +1. 订阅该主题的订阅者会从队列中获取消息并进行处理。 + + + +您可以通过以下两种方式尝试此 Pub/sub 快速入门: + +- [使用多应用运行模板文件同时运行此示例中的所有应用程序]({{< ref "#run-using-multi-app-run" >}}),或 +- [一次运行一个应用程序]({{< ref "#run-one-application-at-a-time" >}}) + +## 使用多应用运行 + +在继续快速入门之前,请选择您偏好的 Dapr SDK 语言。 + +{{< tabs "Python" "JavaScript" ".NET" "Java" "Go" >}} + +{{% codetab %}} + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装 Python 3.8+](https://www.python.org/downloads/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/pub_sub/python/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +从快速入门目录的根目录,导航到 pub/sub 目录: + +```bash +cd pub_sub/python/sdk +``` + +为 `order-processor` 和 `checkout` 应用安装依赖项: + +```bash +cd ./checkout +pip3 install -r requirements.txt +cd .. +cd ./order-processor +pip3 install -r requirements.txt +cd .. +cd ./order-processor-fastapi +pip3 install -r requirements.txt +cd .. +``` + +### 步骤 3:运行发布者和订阅者 + +使用以下命令,同时运行以下服务及其各自的 Dapr sidecar: +- `order-processor` 订阅者 +- `checkout` 发布者 + +```bash +dapr run -f . +``` +> **注意**:由于 Windows 中未定义 Python3.exe,您可能需要在运行 `dapr run -f .` 之前将 [`dapr.yaml`]({{< ref "#dapryaml-multi-app-run-template-file" >}}) 文件中的 `python3` 更改为 `python`。 + +**预期输出** + +``` +== APP - checkout-sdk == Published data: Order { OrderId = 1 } +== APP - order-processor == Subscriber received : Order { OrderId = 1 } +== APP - checkout-sdk == Published data: Order { OrderId = 2 } +== APP - order-processor == Subscriber received : Order { OrderId = 2 } +== APP - checkout-sdk == Published data: Order { OrderId = 3 } +== APP - order-processor == Subscriber received : Order { OrderId = 3 } +== APP - checkout-sdk == Published data: Order { OrderId = 4 } +== APP - order-processor == Subscriber received : Order { OrderId = 4 } +== APP - checkout-sdk == Published data: Order { OrderId = 5 } +== APP - order-processor == Subscriber received : Order { OrderId = 5 } +== APP - checkout-sdk == Published data: Order { OrderId = 6 } +== APP - order-processor == Subscriber received : Order { OrderId = 6 } +== APP - checkout-sdk == Published data: Order { OrderId = 7 } +== APP - order-processor == Subscriber received : Order { OrderId = 7 } +== APP - checkout-sdk == Published data: Order { OrderId = 8 } +== APP - order-processor == Subscriber received : Order { OrderId = 8 } +== APP - checkout-sdk == Published data: Order { OrderId = 9 } +== APP - order-processor == Subscriber received : Order { OrderId = 9 } +== APP - checkout-sdk == Published data: Order { OrderId = 10 } +== APP - order-processor == Subscriber received : Order { OrderId = 10 } +Exited App successfully +``` + +### 发生了什么? + +当您在 Dapr 安装期间运行 `dapr init` 时,以下 YAML 文件已在 `.dapr/components` 目录中生成: +- [`dapr.yaml` 多应用运行模板文件]({{< ref "#dapryaml-multi-app-run-template-file" >}}) +- [`pubsub.yaml` 组件文件]({{< ref "#pubsubyaml-component-file" >}}) + +在此快速入门中运行 `dapr run -f .` 启动了 [订阅者]({{< ref "#order-processor-subscriber" >}}) 和 [发布者]({{< ref "#checkout-publisher" >}}) 应用程序。 + +##### `dapr.yaml` 多应用运行模板文件 + +使用 `dapr run -f .` 运行 [多应用运行模板文件]({{< ref multi-app-dapr-run >}}) 启动项目中的所有应用程序。在此快速入门中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +common: + resourcesPath: ../../components/ +apps: + - appID: order-processor-sdk + appDirPath: ./order-processor/ + appPort: 6001 + command: ["uvicorn", "app:app"] + - appID: checkout-sdk + appDirPath: ./checkout/ + command: ["python3", "app.py"] +``` + +##### `pubsub.yaml` 组件文件 + +使用 `pubsub.yaml` 组件,您可以轻松地更换底层组件而无需更改应用程序代码。 + +此快速入门中包含的 Redis `pubsub.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: orderpubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + value: "" +``` + +在组件 YAML 文件中: + +- `metadata/name` 是您的应用程序与组件通信的方式。 +- `spec/metadata` 定义了与组件实例的连接。 +- `scopes` 指定哪个应用程序可以使用该组件。 + +##### `order-processor` 订阅者 + +在 `order-processor` 订阅者中,您订阅了名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。这使您的应用程序代码能够通过 Dapr sidecar 与 Redis 组件实例通信。 + +```py +# 注册 Dapr pub/sub 订阅 +@app.route('/dapr/subscribe', methods=['GET']) +def subscribe(): + subscriptions = [{ + 'pubsubname': 'orderpubsub', + 'topic': 'orders', + 'route': 'orders' + }] + print('Dapr pub/sub 已订阅: ' + json.dumps(subscriptions)) + return jsonify(subscriptions) + + +# Dapr 订阅在 /dapr/subscribe 中设置此路由 +@app.route('/orders', methods=['POST']) +def orders_subscriber(): + event = from_http(request.headers, request.get_data()) + print('订阅者收到: ' + event.data['orderid'], flush=True) + return json.dumps({'success': True}), 200, { + 'ContentType': 'application/json'} + + +app.run(port=5001) +``` + +##### `checkout` 发布者 + +在 `checkout` 发布者中,您将 orderId 消息发布到名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。服务一启动,它就会在循环中发布: + +```python +with DaprClient() as client: + # 使用 Dapr PubSub 发布事件/消息 + result = client.publish_event( + pubsub_name='orderpubsub', + topic_name='orders', + data=json.dumps(order), + data_content_type='application/json', + ) +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装最新的 Node.js](https://nodejs.org/download/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/pub_sub/javascript/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +从快速入门目录的根目录,导航到 pub/sub 目录: + +```bash +cd pub_sub/javascript/sdk +``` + +为 `order-processor` 和 `checkout` 应用安装依赖项: + +```bash +cd ./order-processor +npm install +cd .. +cd ./checkout +npm install +cd .. +``` + +### 步骤 3:运行发布者和订阅者 + +使用以下命令,同时运行以下服务及其各自的 Dapr sidecar: +- `order-processor` 订阅者 +- `checkout` 发布者 + +```bash +dapr run -f . +``` + +**预期输出** + +``` +== APP - checkout-sdk == Published data: Order { OrderId = 1 } +== APP - order-processor == Subscriber received : Order { OrderId = 1 } +== APP - checkout-sdk == Published data: Order { OrderId = 2 } +== APP - order-processor == Subscriber received : Order { OrderId = 2 } +== APP - checkout-sdk == Published data: Order { OrderId = 3 } +== APP - order-processor == Subscriber received : Order { OrderId = 3 } +== APP - checkout-sdk == Published data: Order { OrderId = 4 } +== APP - order-processor == Subscriber received : Order { OrderId = 4 } +== APP - checkout-sdk == Published data: Order { OrderId = 5 } +== APP - order-processor == Subscriber received : Order { OrderId = 5 } +== APP - checkout-sdk == Published data: Order { OrderId = 6 } +== APP - order-processor == Subscriber received : Order { OrderId = 6 } +== APP - checkout-sdk == Published data: Order { OrderId = 7 } +== APP - order-processor == Subscriber received : Order { OrderId = 7 } +== APP - checkout-sdk == Published data: Order { OrderId = 8 } +== APP - order-processor == Subscriber received : Order { OrderId = 8 } +== APP - checkout-sdk == Published data: Order { OrderId = 9 } +== APP - order-processor == Subscriber received : Order { OrderId = 9 } +== APP - checkout-sdk == Published data: Order { OrderId = 10 } +== APP - order-processor == Subscriber received : Order { OrderId = 10 } +Exited App successfully +``` + +### 发生了什么? + +当您在 Dapr 安装期间运行 `dapr init` 时,以下 YAML 文件已在 `.dapr/components` 目录中生成: +- [`dapr.yaml` 多应用运行模板文件]({{< ref "#dapryaml-multi-app-run-template-file" >}}) +- [`pubsub.yaml` 组件文件]({{< ref "#pubsubyaml-component-file" >}}) + +在此快速入门中运行 `dapr run -f .` 启动了 [订阅者]({{< ref "#order-processor-subscriber" >}}) 和 [发布者]({{< ref "#checkout-publisher" >}}) 应用程序。 + +##### `dapr.yaml` 多应用运行模板文件 + +使用 `dapr run -f .` 运行 [多应用运行模板文件]({{< ref multi-app-dapr-run >}}) 启动项目中的所有应用程序。在此快速入门中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +common: + resourcesPath: ../../components/ +apps: + - appID: order-processor + appDirPath: ./order-processor/ + appPort: 5002 + command: ["npm", "run", "start"] + - appID: checkout-sdk + appDirPath: ./checkout/ + command: ["npm", "run", "start"] +``` + +##### `pubsub.yaml` 组件文件 + +使用 `pubsub.yaml` 组件,您可以轻松地更换底层组件而无需更改应用程序代码。 + +此快速入门中包含的 Redis `pubsub.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: orderpubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + value: "" +``` + +在组件 YAML 文件中: + +- `metadata/name` 是您的应用程序与组件通信的方式。 +- `spec/metadata` 定义了与组件实例的连接。 +- `scopes` 指定哪个应用程序可以使用该组件。 + +##### `order-processor` 订阅者 + +在 `order-processor` 订阅者中,您订阅了名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。这使您的应用程序代码能够通过 Dapr sidecar 与 Redis 组件实例通信。 + +```js +server.pubsub.subscribe("orderpubsub", "orders", (data) => console.log("Subscriber received: " + JSON.stringify(data))); +``` + +##### `checkout` 发布者 + +在 `checkout` 发布者服务中,您将 orderId 消息发布到名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。服务一启动,它就会在循环中发布: + +```js +const client = new DaprClient(); + +await client.pubsub.publish(PUBSUB_NAME, PUBSUB_TOPIC, order); +console.log("Published data: " + JSON.stringify(order)); +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + +- [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0)、[.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) 或 [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) 已安装 + +**注意:** .NET 6 是此版本中 Dapr .NET SDK 包的最低支持版本。仅 .NET 8 和 .NET 9 将在 Dapr v1.16 及更高版本中得到支持。 + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/pub_sub/csharp/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +从快速入门目录的根目录,导航到 pub/sub 目录: + +```bash +cd pub_sub/csharp/sdk +``` + +为 `order-processor` 和 `checkout` 应用安装依赖项: + +```bash +cd ./order-processor +dotnet restore +dotnet build +cd ../checkout +dotnet restore +dotnet build +cd .. +``` + +### 步骤 3:运行发布者和订阅者 + +使用以下命令,同时运行以下服务及其各自的 Dapr sidecar: +- `order-processor` 订阅者 +- `checkout` 发布者 + +```bash +dapr run -f . +``` + +**预期输出** + +``` +== APP - checkout-sdk == Published data: Order { OrderId = 1 } +== APP - order-processor == Subscriber received : Order { OrderId = 1 } +== APP - checkout-sdk == Published data: Order { OrderId = 2 } +== APP - order-processor == Subscriber received : Order { OrderId = 2 } +== APP - checkout-sdk == Published data: Order { OrderId = 3 } +== APP - order-processor == Subscriber received : Order { OrderId = 3 } +== APP - checkout-sdk == Published data: Order { OrderId = 4 } +== APP - order-processor == Subscriber received : Order { OrderId = 4 } +== APP - checkout-sdk == Published data: Order { OrderId = 5 } +== APP - order-processor == Subscriber received : Order { OrderId = 5 } +== APP - checkout-sdk == Published data: Order { OrderId = 6 } +== APP - order-processor == Subscriber received : Order { OrderId = 6 } +== APP - checkout-sdk == Published data: Order { OrderId = 7 } +== APP - order-processor == Subscriber received : Order { OrderId = 7 } +== APP - checkout-sdk == Published data: Order { OrderId = 8 } +== APP - order-processor == Subscriber received : Order { OrderId = 8 } +== APP - checkout-sdk == Published data: Order { OrderId = 9 } +== APP - order-processor == Subscriber received : Order { OrderId = 9 } +== APP - checkout-sdk == Published data: Order { OrderId = 10 } +== APP - order-processor == Subscriber received : Order { OrderId = 10 } +Exited App successfully +``` + +### 发生了什么? + +当您在 Dapr 安装期间运行 `dapr init` 时,以下 YAML 文件已在 `.dapr/components` 目录中生成: +- [`dapr.yaml` 多应用运行模板文件]({{< ref "#dapryaml-multi-app-run-template-file" >}}) +- [`pubsub.yaml` 组件文件]({{< ref "#pubsubyaml-component-file" >}}) + +在此快速入门中运行 `dapr run -f .` 启动了 [订阅者]({{< ref "#order-processor-subscriber" >}}) 和 [发布者]({{< ref "#checkout-publisher" >}}) 应用程序。 + +##### `dapr.yaml` 多应用运行模板文件 + +使用 `dapr run -f .` 运行 [多应用运行模板文件]({{< ref multi-app-dapr-run >}}) 启动项目中的所有应用程序。在此快速入门中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +common: + resourcesPath: ../../components/ +apps: + - appID: order-processor + appDirPath: ./order-processor/ + appPort: 7006 + command: ["dotnet", "run"] + - appID: checkout-sdk + appDirPath: ./checkout/ + command: ["dotnet", "run"] +``` + +##### `pubsub.yaml` 组件文件 + +使用 `pubsub.yaml` 组件,您可以轻松地更换底层组件而无需更改应用程序代码。 + +此快速入门中包含的 Redis `pubsub.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: orderpubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + value: "" +``` + +在组件 YAML 文件中: + +- `metadata/name` 是您的应用程序与组件通信的方式。 +- `spec/metadata` 定义了与组件实例的连接。 +- `scopes` 指定哪个应用程序可以使用该组件。 + +##### `order-processor` 订阅者 + +在 `order-processor` 订阅者中,您订阅了名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。这使您的应用程序代码能够通过 Dapr sidecar 与 Redis 组件实例通信。 + +```cs +// Dapr 订阅在 [Topic] 中将 orders 主题路由到此路由 +app.MapPost("/orders", [Topic("orderpubsub", "orders")] (Order order) => { + Console.WriteLine("订阅者收到: " + order); + return Results.Ok(order); +}); + +public record Order([property: JsonPropertyName("orderId")] int OrderId); +``` + +##### `checkout` 发布者 + +在 `checkout` 发布者中,您将 orderId 消息发布到名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。服务一启动,它就会在循环中发布: + +```cs +using var client = new DaprClientBuilder().Build(); +await client.PublishEventAsync("orderpubsub", "orders", order); +Console.WriteLine("Published data: " + order); +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- Java JDK 17(或更高版本): + - [Oracle JDK](https://www.oracle.com/java/technologies/downloads),或 + - OpenJDK +- [Apache Maven](https://maven.apache.org/install.html),版本 3.x。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/pub_sub/java/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +从快速入门目录的根目录,导航到 pub/sub 目录: + +```bash +cd pub_sub/java/sdk +``` + +为 `order-processor` 和 `checkout` 应用安装依赖项: + +```bash +cd ./order-processor +mvn clean install +cd .. +cd ./checkout +mvn clean install +cd .. +``` + +### 步骤 3:运行发布者和订阅者 + +使用以下命令,同时运行以下服务及其各自的 Dapr sidecar: +- `order-processor` 订阅者 +- `checkout` 发布者 + +```bash +dapr run -f . +``` + +**预期输出** + +``` +== APP - checkout-sdk == Published data: Order { OrderId = 1 } +== APP - order-processor == Subscriber received : Order { OrderId = 1 } +== APP - checkout-sdk == Published data: Order { OrderId = 2 } +== APP - order-processor == Subscriber received : Order { OrderId = 2 } +== APP - checkout-sdk == Published data: Order { OrderId = 3 } +== APP - order-processor == Subscriber received : Order { OrderId = 3 } +== APP - checkout-sdk == Published data: Order { OrderId = 4 } +== APP - order-processor == Subscriber received : Order { OrderId = 4 } +== APP - checkout-sdk == Published data: Order { OrderId = 5 } +== APP - order-processor == Subscriber received : Order { OrderId = 5 } +== APP - checkout-sdk == Published data: Order { OrderId = 6 } +== APP - order-processor == Subscriber received : Order { OrderId = 6 } +== APP - checkout-sdk == Published data: Order { OrderId = 7 } +== APP - order-processor == Subscriber received : Order { OrderId = 7 } +== APP - checkout-sdk == Published data: Order { OrderId = 8 } +== APP - order-processor == Subscriber received : Order { OrderId = 8 } +== APP - checkout-sdk == Published data: Order { OrderId = 9 } +== APP - order-processor == Subscriber received : Order { OrderId = 9 } +== APP - checkout-sdk == Published data: Order { OrderId = 10 } +== APP - order-processor == Subscriber received : Order { OrderId = 10 } +Exited App successfully +``` + +### 发生了什么? + +当您在 Dapr 安装期间运行 `dapr init` 时,以下 YAML 文件已在 `.dapr/components` 目录中生成: +- [`dapr.yaml` 多应用运行模板文件]({{< ref "#dapryaml-multi-app-run-template-file" >}}) +- [`pubsub.yaml` 组件文件]({{< ref "#pubsubyaml-component-file" >}}) + +在此快速入门中运行 `dapr run -f .` 启动了 [订阅者]({{< ref "#order-processor-subscriber" >}}) 和 [发布者]({{< ref "#checkout-publisher" >}}) 应用程序。 + +##### `dapr.yaml` 多应用运行模板文件 + +使用 `dapr run -f .` 运行 [多应用运行模板文件]({{< ref multi-app-dapr-run >}}) 启动项目中的所有应用程序。在此快速入门中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +common: + resourcesPath: ../../components/ +apps: + - appID: order-processor-sdk + appDirPath: ./order-processor/target/ + appPort: 8080 + command: ["java", "-jar", "OrderProcessingService-0.0.1-SNAPSHOT.jar"] + - appID: checkout-sdk + appDirPath: ./checkout/target/ + command: ["java", "-jar", "CheckoutService-0.0.1-SNAPSHOT.jar"] +``` + +##### `pubsub.yaml` 组件文件 + +使用 `pubsub.yaml` 组件,您可以轻松地更换底层组件而无需更改应用程序代码。 + +此快速入门中包含的 Redis `pubsub.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: orderpubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + value: "" +``` + +在组件 YAML 文件中: + +- `metadata/name` 是您的应用程序与组件通信的方式。 +- `spec/metadata` 定义了与组件实例的连接。 +- `scopes` 指定哪个应用程序可以使用该组件。 + +##### `order-processor` 订阅者 + +在 `order-processor` 订阅者中,您订阅了名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。这使您的应用程序代码能够通过 Dapr sidecar 与 Redis 组件实例通信。 + +```java +@Topic(name = "orders", pubsubName = "orderpubsub") +@PostMapping(path = "/orders", consumes = MediaType.ALL_VALUE) +public Mono getCheckout(@RequestBody(required = false) CloudEvent cloudEvent) { + return Mono.fromSupplier(() -> { + try { + logger.info("订阅者收到: " + cloudEvent.getData().getOrderId()); + return ResponseEntity.ok("SUCCESS"); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); +} +``` + +##### `checkout` 发布者 + +在 `checkout` 发布者中,您将 orderId 消息发布到名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。服务一启动,它就会在循环中发布: + +```java +DaprClient client = new DaprClientBuilder().build(); +client.publishEvent( + PUBSUB_NAME, + TOPIC_NAME, + order).block(); +logger.info("Published data: " + order.getOrderId()); +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的 Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/pub_sub/go/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +从快速入门目录的根目录,导航到 pub/sub 目录: + +```bash +cd pub_sub/go/sdk +``` + +为 `order-processor` 和 `checkout` 应用安装依赖项: + +```bash +cd ./order-processor +go build . +cd ../checkout +go build . +cd .. +``` + +### 步骤 3:运行发布者和订阅者 + +使用以下命令,同时运行以下服务及其各自的 Dapr sidecar: +- `order-processor` 订阅者 +- `checkout` 发布者 + +```bash +dapr run -f . +``` + +**预期输出** + +``` +== APP - checkout-sdk == Published data: Order { OrderId = 1 } +== APP - order-processor == Subscriber received : Order { OrderId = 1 } +== APP - checkout-sdk == Published data: Order { OrderId = 2 } +== APP - order-processor == Subscriber received : Order { OrderId = 2 } +== APP - checkout-sdk == Published data: Order { OrderId = 3 } +== APP - order-processor == Subscriber received : Order { OrderId = 3 } +== APP - checkout-sdk == Published data: Order { OrderId = 4 } +== APP - order-processor == Subscriber received : Order { OrderId = 4 } +== APP - checkout-sdk == Published data: Order { OrderId = 5 } +== APP - order-processor == Subscriber received : Order { OrderId = 5 } +== APP - checkout-sdk == Published data: Order { OrderId = 6 } +== APP - order-processor == Subscriber received : Order { OrderId = 6 } +== APP - checkout-sdk == Published data: Order { OrderId = 7 } +== APP - order-processor == Subscriber received : Order { OrderId = 7 } +== APP - checkout-sdk == Published data: Order { OrderId = 8 } +== APP - order-processor == Subscriber received : Order { OrderId = 8 } +== APP - checkout-sdk == Published data: Order { OrderId = 9 } +== APP - order-processor == Subscriber received : Order { OrderId = 9 } +== APP - checkout-sdk == Published data: Order { OrderId = 10 } +== APP - order-processor == Subscriber received : Order { OrderId = 10 } +Exited App successfully +``` + +### 发生了什么? + +当您在 Dapr 安装期间运行 `dapr init` 时,以下 YAML 文件已在 `.dapr/components` 目录中生成: +- [`dapr.yaml` 多应用运行模板文件]({{< ref "#dapryaml-multi-app-run-template-file" >}}) +- [`pubsub.yaml` 组件文件]({{< ref "#pubsubyaml-component-file" >}}) + +在此快速入门中运行 `dapr run -f .` 启动了 [订阅者]({{< ref "#order-processor-subscriber" >}}) 和 [发布者]({{< ref "#checkout-publisher" >}}) 应用程序。 + +##### `dapr.yaml` 多应用运行模板文件 + +使用 `dapr run -f .` 运行 [多应用运行模板文件]({{< ref multi-app-dapr-run >}}) 启动项目中的所有应用程序。在此快速入门中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +common: + resourcesPath: ../../components/ +apps: + - appID: order-processor + appDirPath: ./order-processor/ + appPort: 6005 + command: ["go", "run", "."] + - appID: checkout-sdk + appDirPath: ./checkout/ + command: ["go", "run", "."] +``` + +##### `pubsub.yaml` 组件文件 + +使用 `pubsub.yaml` 组件,您可以轻松地更换底层组件而无需更改应用程序代码。 + +此快速入门中包含的 Redis `pubsub.yaml` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: orderpubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + value: "" +``` + +在组件 YAML 文件中: + +- `metadata/name` 是您的应用程序与组件通信的方式。 +- `spec/metadata` 定义了与组件实例的连接。 +- `scopes` 指定哪个应用程序可以使用该组件。 + +##### `order-processor` 订阅者 + +在 `order-processor` 订阅者中,您订阅了名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。这使您的应用程序代码能够通过 Dapr sidecar 与 Redis 组件实例通信。 + +```go +func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool, err error) { + fmt.Println("订阅者收到: ", e.Data) + return false, nil +} +``` + +##### `checkout` 发布者 + +在 `checkout` 发布者中,您将 orderId 消息发布到名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。服务一启动,它就会在循环中发布: + +```go +client, err := dapr.NewClient() + +if err := client.PublishEvent(ctx, PUBSUB_NAME, PUBSUB_TOPIC, []byte(order)); err != nil { + panic(err) +} + +fmt.Println("Published data: ", order) +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 一次运行一个应用程序 + +在继续快速入门之前,请选择您偏好的 Dapr SDK 语言。 + +{{< tabs "Python" "JavaScript" ".NET" "Java" "Go" >}} + +{{% codetab %}} + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装 Python 3.7+](https://www.python.org/downloads/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/pub_sub/python/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 3:订阅主题 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `order-processor` 目录。 + +```bash +cd pub_sub/python/sdk/order-processor +``` + +安装依赖项: + +```bash +pip3 install -r requirements.txt +``` + +在 Dapr sidecar 的旁边运行 `order-processor` 订阅者服务。 + +```bash +dapr run --app-id order-processor --resources-path ../../../components/ --app-port 6002 -- python3 app.py +``` + +> **注意**:由于 Windows 中未定义 Python3.exe,您可能需要使用 `python app.py` 而不是 `python3 app.py`。 + +在 `order-processor` 订阅者中,我们订阅了名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。这使您的应用程序代码能够通过 Dapr sidecar 与 Redis 组件实例通信。 + +```py +# 注册 Dapr pub/sub 订阅 +@app.route('/dapr/subscribe', methods=['GET']) +def subscribe(): + subscriptions = [{ + 'pubsubname': 'orderpubsub', + 'topic': 'orders', + 'route': 'orders' + }] + print('Dapr pub/sub 已订阅: ' + json.dumps(subscriptions)) + return jsonify(subscriptions) + + +# Dapr 订阅在 /dapr/subscribe 中设置此路由 +@app.route('/orders', methods=['POST']) +def orders_subscriber(): + event = from_http(request.headers, request.get_data()) + print('订阅者收到: ' + event.data['orderid'], flush=True) + return json.dumps({'success': True}), 200, { + 'ContentType': 'application/json'} + + +app.run(port=5001) +``` + +### 步骤 4:发布主题 + +在新的终端窗口中,导航到 `checkout` 目录。 + +```bash +cd pub_sub/python/sdk/checkout +``` + +安装依赖项: + +```bash +pip3 install -r requirements.txt +``` + +在 Dapr sidecar 的旁边运行 `checkout` 发布者服务。 + +```bash +dapr run --app-id checkout --resources-path ../../../components/ -- python3 app.py +``` + +> **注意**:由于 Windows 中未定义 Python3.exe,您可能需要使用 `python app.py` 而不是 `python3 app.py`。 + +在 `checkout` 发布者中,我们将 orderId 消息发布到名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。服务一启动,它就会在循环中发布: + +```python +with DaprClient() as client: + # 使用 Dapr PubSub 发布事件/消息 + result = client.publish_event( + pubsub_name='orderpubsub', + topic_name='orders', + data=json.dumps(order), + data_content_type='application/json', + ) +``` + +### 步骤 5:查看 Pub/sub 输出 + +发布者将订单发送到 Dapr sidecar,而订阅者接收它们。 + +发布者输出: + +``` +== APP == INFO:root:Published data: {"orderId": 1} +== APP == INFO:root:Published data: {"orderId": 2} +== APP == INFO:root:Published data: {"orderId": 3} +== APP == INFO:root:Published data: {"orderId": 4} +== APP == INFO:root:Published data: {"orderId": 5} +== APP == INFO:root:Published data: {"orderId": 6} +== APP == INFO:root:Published data: {"orderId": 7} +== APP == INFO:root:Published data: {"orderId": 8} +== APP == INFO:root:Published data: {"orderId": 9} +== APP == INFO:root:Published data: {"orderId": 10} +``` + +订阅者输出: + +``` +== APP == INFO:root:Subscriber received: {"orderId": 1} +== APP == INFO:root:Subscriber received: {"orderId": 2} +== APP == INFO:root:Subscriber received: {"orderId": 3} +== APP == INFO:root:Subscriber received: {"orderId": 4} +== APP == INFO:root:Subscriber received: {"orderId": 5} +== APP == INFO:root:Subscriber received: {"orderId": 6} +== APP == INFO:root:Subscriber received: {"orderId": 7} +== APP == INFO:root:Subscriber received: {"orderId": 8} +== APP == INFO:root:Subscriber received: {"orderId": 9} +== APP == INFO:root:Subscriber received: {"orderId": 10} +``` + +##### `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` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: orderpubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + value: "" +``` + +在 YAML 文件中: + +- `metadata/name` 是您的应用程序与组件通信的方式。 +- `spec/metadata` 定义了与组件实例的连接。 +- `scopes` 指定哪个应用程序可以使用该组件。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装最新的 Node.js](https://nodejs.org/download/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/pub_sub/javascript/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 3:订阅主题 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `order-processor` 目录。 + +```bash +cd pub_sub/javascript/sdk/order-processor +``` + +安装依赖项,其中将包括来自 JavaScript SDK 的 `@dapr/dapr` 包: + +```bash +npm install +``` + +验证服务目录中包含以下文件: + +- `package.json` +- `package-lock.json` + +在 Dapr sidecar 的旁边运行 `order-processor` 订阅者服务。 + +```bash +dapr run --app-port 5002 --app-id order-processing --app-protocol http --dapr-http-port 3501 --resources-path ../../../components -- npm run start +``` + +在 `order-processor` 订阅者中,我们订阅了名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。这使您的应用程序代码能够通过 Dapr sidecar 与 Redis 组件实例通信。 + +```js +server.pubsub.subscribe("orderpubsub", "orders", (data) => console.log("Subscriber received: " + JSON.stringify(data))); +``` + +### 步骤 4:发布主题 + +在新的终端窗口中,从快速入门克隆目录的根目录导航到 `checkout` 目录。 + +```bash +cd pub_sub/javascript/sdk/checkout +``` + +安装依赖项,其中将包括来自 JavaScript SDK 的 `@dapr/dapr` 包: + +```bash +npm install +``` + +验证服务目录中包含以下文件: + +- `package.json` +- `package-lock.json` + +在 Dapr sidecar 的旁边运行 `checkout` 发布者服务。 + +```bash +dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 --resources-path ../../../components -- npm run start +``` + +在 `checkout` 发布者服务中,我们将 orderId 消息发布到名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。服务一启动,它就会在循环中发布: + +```js +const client = new DaprClient(); + +await client.pubsub.publish(PUBSUB_NAME, PUBSUB_TOPIC, order); +console.log("Published data: " + JSON.stringify(order)); +``` + +### 步骤 5:查看 Pub/sub 输出 + +请注意,如上代码中所指定,发布者将一个随机数推送到 Dapr sidecar,而订阅者接收它。 + +发布者输出: + +```cli +== APP == Published data: {"orderId":1} +== APP == Published data: {"orderId":2} +== APP == Published data: {"orderId":3} +== APP == Published data: {"orderId":4} +== APP == Published data: {"orderId":5} +== APP == Published data: {"orderId":6} +== APP == Published data: {"orderId":7} +== APP == Published data: {"orderId":8} +== APP == Published data: {"orderId":9} +== APP == Published data: {"orderId":10} + +``` + +订阅者输出: + +```cli +== APP == Subscriber received: {"orderId":1} +== APP == Subscriber received: {"orderId":2} +== APP == Subscriber received: {"orderId":3} +== APP == Subscriber received: {"orderId":4} +== APP == Subscriber received: {"orderId":5} +== APP == Subscriber received: {"orderId":6} +== APP == Subscriber received: {"orderId":7} +== APP == Subscriber received: {"orderId":8} +== APP == Subscriber received: {"orderId":9} +== APP == Subscriber received: {"orderId":10} + +``` + +##### `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` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: orderpubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + value: "" +``` + +在 YAML 文件中: + +- `metadata/name` 是您的应用程序与组件通信的方式。 +- `spec/metadata` 定义了与组件实例的连接。 +- `scopes` 指定哪个应用程序可以使用该组件。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [.NET SDK 或 .NET 6 SDK 已安装](https://dotnet.microsoft.com/download)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/pub_sub/csharp/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 3:订阅主题 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `order-processor` 目录。 + +```bash +cd pub_sub/csharp/sdk/order-processor +``` + +恢复 NuGet 包: + +```bash +dotnet restore +dotnet build +``` + +在 Dapr sidecar 的旁边运行 `order-processor` 订阅者服务。 + +```bash +dapr run --app-id order-processor --resources-path ../../../components --app-port 7006 -- dotnet run +``` + +在 `order-processor` 订阅者中,我们订阅了名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。这使您的应用程序代码能够通过 Dapr sidecar 与 Redis 组件实例通信。 + +```cs +// Dapr 订阅在 [Topic] 中将 orders 主题路由到此路由 +app.MapPost("/orders", [Topic("orderpubsub", "orders")] (Order order) => { + Console.WriteLine("订阅者收到: " + order); + return Results.Ok(order); +}); + +public record Order([property: JsonPropertyName("orderId")] int OrderId); +``` + +### 步骤 4:发布主题 + +在新的终端窗口中,从快速入门克隆目录的根目录导航到 `checkout` 目录。 + +```bash +cd pub_sub/csharp/sdk/checkout +``` + +恢复 NuGet 包: + +```bash +dotnet restore +dotnet build +``` + +在 Dapr sidecar 的旁边运行 `checkout` 发布者服务。 + +```bash +dapr run --app-id checkout --resources-path ../../../components -- dotnet run +``` + +在 `checkout` 发布者中,我们将 orderId 消息发布到名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。服务一启动,它就会在循环中发布: + +```cs +using var client = new DaprClientBuilder().Build(); +await client.PublishEventAsync("orderpubsub", "orders", order); +Console.WriteLine("Published data: " + order); +``` + +### 步骤 5:查看 Pub/sub 输出 + +请注意,如上代码中所指定,发布者将一个随机数推送到 Dapr sidecar,而订阅者接收它。 + +发布者输出: + +```dotnetcli +== APP == Published data: Order { OrderId = 1 } +== APP == Published data: Order { OrderId = 2 } +== APP == Published data: Order { OrderId = 3 } +== APP == Published data: Order { OrderId = 4 } +== APP == Published data: Order { OrderId = 5 } +== APP == Published data: Order { OrderId = 6 } +== APP == Published data: Order { OrderId = 7 } +== APP == Published data: Order { OrderId = 8 } +== APP == Published data: Order { OrderId = 9 } +== APP == Published data: Order { OrderId = 10 } +``` + +订阅者输出: + +```dotnetcli +== APP == Subscriber received: Order { OrderId = 1 } +== APP == Subscriber received: Order { OrderId = 2 } +== APP == Subscriber received: Order { OrderId = 3 } +== APP == Subscriber received: Order { OrderId = 4 } +== APP == Subscriber received: Order { OrderId = 5 } +== APP == Subscriber received: Order { OrderId = 6 } +== APP == Subscriber received: Order { OrderId = 7 } +== APP == Subscriber received: Order { OrderId = 8 } +== APP == Subscriber received: Order { OrderId = 9 } +== APP == Subscriber received: Order { OrderId = 10 } +``` + +##### `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` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: orderpubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + value: "" +``` + +在 YAML 文件中: + +- `metadata/name` 是您的应用程序与组件通信的方式。 +- `spec/metadata` 定义了与组件实例的连接。 +- `scopes` 指定哪个应用程序可以使用该组件。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- Java JDK 17(或更高版本): + - [Oracle JDK](https://www.oracle.com/java/technologies/downloads),或 + - OpenJDK +- [Apache Maven](https://maven.apache.org/install.html),版本 3.x。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/pub_sub/java/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 3:订阅主题 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `order-processor` 目录。 + +```bash +cd pub_sub/java/sdk/order-processor +``` + +安装依赖项: + +```bash +mvn clean install +``` + +在 Dapr sidecar 的旁边运行 `order-processor` 订阅者服务。 + +```bash +dapr run --app-port 8080 --app-id order-processor --resources-path ../../../components -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar +``` + +在 `order-processor` 订阅者中,我们订阅了名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。这使您的应用程序代码能够通过 Dapr sidecar 与 Redis 组件实例通信。 + +```java +@Topic(name = "orders", pubsubName = "orderpubsub") +@PostMapping(path = "/orders", consumes = MediaType.ALL_VALUE) +public Mono getCheckout(@RequestBody(required = false) CloudEvent cloudEvent) { + return Mono.fromSupplier(() -> { + try { + logger.info("订阅者收到: " + cloudEvent.getData().getOrderId()); + return ResponseEntity.ok("SUCCESS"); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); +} +``` + +### 步骤 4:发布主题 + +在新的终端窗口中,从快速入门克隆目录的根目录导航到 `checkout` 目录。 + +```bash +cd pub_sub/java/sdk/checkout +``` + +安装依赖项: + +```bash +mvn clean install +``` + +在 Dapr sidecar 的旁边运行 `checkout` 发布者服务。 + +```bash +dapr run --app-id checkout --resources-path ../../../components -- java -jar target/CheckoutService-0.0.1-SNAPSHOT.jar +``` + +在 `checkout` 发布者中,我们将 orderId 消息发布到名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。服务一启动,它就会在循环中发布: + +```java +DaprClient client = new DaprClientBuilder().build(); +client.publishEvent( + PUBSUB_NAME, + TOPIC_NAME, + order).block(); +logger.info("Published data: " + order.getOrderId()); +``` + +### 步骤 5:查看 Pub/sub 输出 + +请注意,如上代码中所指定,发布者将一个随机数推送到 Dapr sidecar,而订阅者接收它。 + +发布者输出: + +``` +== APP == 7194 [main] INFO com.service.CheckoutServiceApplication - Published data: 1 +== APP == 12213 [main] INFO com.service.CheckoutServiceApplication - Published data: 2 +== APP == 17233 [main] INFO com.service.CheckoutServiceApplication - Published data: 3 +== APP == 22252 [main] INFO com.service.CheckoutServiceApplication - Published data: 4 +== APP == 27276 [main] INFO com.service.CheckoutServiceApplication - Published data: 5 +== APP == 32320 [main] INFO com.service.CheckoutServiceApplication - Published data: 6 +== APP == 37340 [main] INFO com.service.CheckoutServiceApplication - Published data: 7 +== APP == 42356 [main] INFO com.service.CheckoutServiceApplication - Published data: 8 +== APP == 47386 [main] INFO com.service.CheckoutServiceApplication - Published data: 9 +== APP == 52410 [main] INFO com.service.CheckoutServiceApplication - Published data: 10 +``` + +订阅者输出: + +``` +== APP == 2022-03-07 13:31:19.551 INFO 43512 --- [nio-8080-exec-5] c.s.c.OrderProcessingServiceController : 订阅者收到: 1 +== APP == 2022-03-07 13:31:19.552 INFO 43512 --- [nio-8080-exec-9] c.s.c.OrderProcessingServiceController : 订阅者收到: 2 +== APP == 2022-03-07 13:31:19.551 INFO 43512 --- [nio-8080-exec-6] c.s.c.OrderProcessingServiceController : 订阅者收到: 3 +== APP == 2022-03-07 13:31:19.552 INFO 43512 --- [nio-8080-exec-2] c.s.c.OrderProcessingServiceController : 订阅者收到: 4 +== APP == 2022-03-07 13:31:19.553 INFO 43512 --- [nio-8080-exec-2] c.s.c.OrderProcessingServiceController : 订阅者收到: 5 +== APP == 2022-03-07 13:31:19.553 INFO 43512 --- [nio-8080-exec-9] c.s.c.OrderProcessingServiceController : 订阅者收到: 6 +== APP == 2022-03-07 13:31:22.849 INFO 43512 --- [nio-8080-exec-3] c.s.c.OrderProcessingServiceController : 订阅者收到: 7 +== APP == 2022-03-07 13:31:27.866 INFO 43512 --- [nio-8080-exec-6] c.s.c.OrderProcessingServiceController : 订阅者收到: 8 +== APP == 2022-03-07 13:31:32.895 INFO 43512 --- [nio-8080-exec-6] c.s.c.OrderProcessingServiceController : 订阅者收到: 9 +== APP == 2022-03-07 13:31:37.919 INFO 43512 --- [nio-8080-exec-2] c.s.c.OrderProcessingServiceController : 订阅者收到: 10 +``` + +##### `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` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: orderpubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + value: "" +scopes: + - orderprocessing + - checkout +``` + +在 YAML 文件中: + +- `metadata/name` 是您的应用程序与组件通信的方式。 +- `spec/metadata` 定义了与组件实例的连接。 +- `scopes` 指定哪个应用程序可以使用该组件。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的 Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/pub_sub/go/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 3:订阅主题 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `order-processor` 目录。 + +```bash +cd pub_sub/go/sdk/order-processor +``` + +安装依赖项并构建应用程序: + +```bash +go build . +``` + +在 Dapr sidecar 的旁边运行 `order-processor` 订阅者服务。 + +```bash +dapr run --app-port 6005 --app-id order-processor-sdk --app-protocol http --dapr-http-port 3501 --resources-path ../../../components -- go run . +``` + +在 `order-processor` 订阅者中,我们订阅了名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。这使您的应用程序代码能够通过 Dapr sidecar 与 Redis 组件实例通信。 + +```go +func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool, err error) { + fmt.Println("订阅者收到: ", e.Data) + return false, nil +} +``` + +### 步骤 4:发布主题 + +在新的终端窗口中,从快速入门克隆目录的根目录导航到 `checkout` 目录。 + +```bash +cd pub_sub/go/sdk/checkout +``` + +安装依赖项并构建应用程序: + +```bash +go build . +``` + +在 Dapr sidecar 的旁边运行 `checkout` 发布者服务。 + +```bash +dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 --resources-path ../../../components -- go run . +``` + +在 `checkout` 发布者中,我们将 orderId 消息发布到名为 `orderpubsub` 的 Redis 实例 [(如 `pubsub.yaml` 组件中定义的)]({{< ref "#pubsubyaml-component-file" >}}) 和主题 `orders`。服务一启动,它就会在循环中发布: + +```go +client, err := dapr.NewClient() + +if err := client.PublishEvent(ctx, PUBSUB_NAME, PUBSUB_TOPIC, []byte(order)); err != nil { + panic(err) +} + +fmt.Println("Published data: ", order) +``` + +### 步骤 5:查看 Pub/sub 输出 + +请注意,如上代码中所指定,发布者将一个编号消息推送到 Dapr sidecar,而订阅者接收它。 + +发布者输出: + +``` +== APP == dapr client initializing for: 127.0.0.1:63293 +== APP == Published data: {"orderId":1} +== APP == Published data: {"orderId":2} +== APP == Published data: {"orderId":3} +== APP == Published data: {"orderId":4} +== APP == Published data: {"orderId":5} +== APP == Published data: {"orderId":6} +== APP == Published data: {"orderId":7} +== APP == Published data: {"orderId":8} +== APP == Published data: {"orderId":9} +== APP == Published data: {"orderId":10} +``` + +订阅者输出: + +``` +== APP == 订阅者收到: {"orderId":1} +== APP == 订阅者收到: {"orderId":2} +== APP == 订阅者收到: {"orderId":3} +== APP == 订阅者收到: {"orderId":4} +== APP == 订阅者收到: {"orderId":5} +== APP == 订阅者收到: {"orderId":6} +== APP == 订阅者收到: {"orderId":7} +== APP == 订阅者收到: {"orderId":8} +== APP == 订阅者收到: {"orderId":9} +== APP == 订阅者收到: {"orderId":10} +``` + +注意:接收的顺序可能会有所不同。 + +##### `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` 文件包含以下内容: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: orderpubsub +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + value: "" +scopes: + - orderprocessing + - checkout +``` + +在 YAML 文件中: + +- `metadata/name` 是您的应用程序与组件通信的方式。 +- `spec/metadata` 定义了与组件实例的连接。 +- `scopes` 指定哪个应用程序可以使用该组件。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 告诉我们您的想法! +我们正在不断努力改进我们的快速入门示例,并重视您的反馈。您觉得这个快速入门有帮助吗?您有改进的建议吗? + +加入我们的 [discord 频道](https://discord.com/channels/778680217417809931/953427615916638238) 讨论。 + +## 下一步 + +- 使用 HTTP 而不是 SDK 设置 Pub/sub。 + - [Python](https://github.com/dapr/quickstarts/tree/master/pub_sub/python/http) + - [JavaScript](https://github.com/dapr/quickstarts/tree/master/pub_sub/javascript/http) + - [.NET](https://github.com/dapr/quickstarts/tree/master/pub_sub/csharp/http) + - [Java](https://github.com/dapr/quickstarts/tree/master/pub_sub/java/http) + - [Go](https://github.com/dapr/quickstarts/tree/master/pub_sub/go/http) +- 了解更多关于 [Pub/sub 作为 Dapr 构建块]({{< ref pubsub-overview >}}) + +{{< button text="探索 Dapr 教程 >>" page="getting-started/tutorials/_index.md" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/resiliency/_index.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/resiliency/_index.md new file mode 100644 index 000000000..1adde0ef5 --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/resiliency/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "可靠性快速入门" +linkTitle: "可靠性" +weight: 100 +description: "开始探索 Dapr 的可靠性组件" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/resiliency/resiliency-serviceinvo-quickstart.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/resiliency/resiliency-serviceinvo-quickstart.md new file mode 100644 index 000000000..01c35572f --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/resiliency/resiliency-serviceinvo-quickstart.md @@ -0,0 +1,1149 @@ +--- +type: docs +title: "入门指南:服务间的弹性" +linkTitle: "弹性:服务间" +weight: 120 +description: "通过服务调用API开始使用Dapr的弹性功能" +--- + +通过模拟系统故障来测试Dapr的弹性功能。在本入门指南中,您将会: + +- 运行两个微服务应用程序:`checkout`和`order-processor`。`checkout`将持续向`order-processor`发起Dapr服务调用请求。 +- 通过模拟系统故障来触发弹性机制。 +- 移除故障以让微服务应用程序恢复。 + +显示应用于Dapr API的弹性图示 + +在继续入门指南之前,选择您偏好的Dapr SDK语言版本。 + +{{< tabs "Python" "JavaScript" ".NET" "Java" "Go" >}} + +{{% codetab %}} + +### 前提条件 + +对于此示例,您将需要: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装Python 3.7+](https://www.python.org/downloads/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[入门指南仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation/python/http)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤2:运行`order-processor`服务 + +在终端窗口中,从入门指南目录的根目录导航到`order-processor`目录。 + +```bash +cd service_invocation/python/http/order-processor +``` + +安装依赖项: + +```bash +pip3 install -r requirements.txt +``` + +运行`order-processor`服务及其Dapr sidecar。 + +```bash +dapr run --app-port 8001 --app-id order-processor --resources-path ../../../resources/ --app-protocol http --dapr-http-port 3501 -- python3 app.py +``` + +### 步骤3:运行`checkout`服务应用程序 + +在新的终端窗口中,从入门指南目录的根目录导航到`checkout`目录。 + +```bash +cd service_invocation/python/http/checkout +``` + +安装依赖项: + +```bash +pip3 install -r requirements.txt +``` + +运行`checkout`服务及其Dapr sidecar。 + +```bash +dapr run --app-id checkout --resources-path ../../../resources/ --app-protocol http --dapr-http-port 3500 -- python3 app.py +``` + +Dapr sidecar随后加载位于资源目录中的弹性配置: + + ```yaml + apiVersion: dapr.io/v1alpha1 + kind: Resiliency + metadata: + name: myresiliency + scopes: + - checkout + + spec: + policies: + retries: + retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 + + circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 + + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB + ``` + +### 步骤4:查看服务调用输出 +当两个服务和sidecar都在运行时,注意订单如何通过Dapr服务调用从`checkout`服务传递到`order-processor`服务。 + +`checkout`服务输出: + +``` +== APP == Order passed: {"orderId": 1} +== APP == Order passed: {"orderId": 2} +== APP == Order passed: {"orderId": 3} +== APP == Order passed: {"orderId": 4} +``` + +`order-processor`服务输出: + +``` +== APP == Order received: {"orderId": 1} +== APP == Order received: {"orderId": 2} +== APP == Order received: {"orderId": 3} +== APP == Order received: {"orderId": 4} +``` + +### 步骤5:引入故障 +通过停止`order-processor`服务来模拟故障。一旦实例停止,来自`checkout`服务的服务调用操作将开始失败。 + +由于`resiliency.yaml`配置将`order-processor`服务定义为弹性目标,所有失败的请求将应用重试和断路器策略: + +```yaml + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB +``` + +在`order-processor`窗口中,停止服务: + +```script +CTRL + C +``` + +一旦第一个请求失败,名为`retryForever`的重试策略将被应用: + +```bash +INFO[0005] Error processing operation endpoint[order-processor, order-processor:orders]. Retrying... +``` + +重试将以5秒的间隔无限期地继续每个失败的请求。 + +```yaml +retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 +``` + +一旦连续5次重试失败,断路器策略`simpleCB`将被触发,断路器打开,停止所有请求: + +```bash +INFO[0025] Circuit breaker "order-processor:orders" changed state from closed to open +``` + +```yaml +circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 +``` + +经过5秒后,断路器将切换到半开状态,允许一个请求通过以验证故障是否已解决。如果请求继续失败,断路器将再次触发回到打开状态。 + +```bash +INFO[0030] Circuit breaker "order-processor:orders" changed state from open to half-open +INFO[0030] Circuit breaker "order-processor:orders" changed state from half-open to open +INFO[0030] Circuit breaker "order-processor:orders" changed state from open to half-open +INFO[0030] Circuit breaker "order-processor:orders" changed state from half-open to open +``` + +这种半开/打开行为将持续到`order-processor`服务停止为止。 + +### 步骤6:移除故障 + +一旦您重新启动`order-processor`服务,应用程序将无缝恢复,继续接受订单请求。 + +在`order-processor`服务终端中,重新启动应用程序: + +```bash +dapr run --app-port 8001 --app-id order-processor --app-protocol http --dapr-http-port 3501 -- python3 app.py +``` + +`checkout`服务输出: + +``` +== APP == Order passed: {"orderId": 5} +== APP == Order passed: {"orderId": 6} +== APP == Order passed: {"orderId": 7} +== APP == Order passed: {"orderId": 8} +== APP == Order passed: {"orderId": 9} +== APP == Order passed: {"orderId": 10} +``` + +`order-processor`服务输出: + +``` +== APP == Order received: {"orderId": 5} +== APP == Order received: {"orderId": 6} +== APP == Order received: {"orderId": 7} +== APP == Order received: {"orderId": 8} +== APP == Order received: {"orderId": 9} +== APP == Order received: {"orderId": 10} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前提条件 + +对于此示例,您将需要: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装最新的Node.js](https://nodejs.org/download/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[入门指南仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation/javascript/http)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤2:运行`order-processor`服务 + +在终端窗口中,从入门指南目录的根目录导航到`order-processor`目录。 + +```bash +cd service_invocation/javascript/http/order-processor +``` + +安装依赖项: + +```bash +npm install +``` + +运行`order-processor`服务及其Dapr sidecar。 + +```bash +dapr run --app-port 5001 --app-id order-processor --resources-path ../../../resources/ --app-protocol http --dapr-http-port 3501 -- npm start +``` + +### 步骤3:运行`checkout`服务应用程序 + +在新的终端窗口中,从入门指南目录的根目录导航到`checkout`目录。 + +```bash +cd service_invocation/javascript/http/checkout +``` + +安装依赖项: + +```bash +npm install +``` + +运行`checkout`服务及其Dapr sidecar。 + +```bash +dapr run --app-id checkout --resources-path ../../../resources/ --app-protocol http --dapr-http-port 3500 -- npm start +``` + +Dapr sidecar随后加载位于资源目录中的弹性配置: + + ```yaml + apiVersion: dapr.io/v1alpha1 + kind: Resiliency + metadata: + name: myresiliency + scopes: + - checkout + + spec: + policies: + retries: + retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 + + circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 + + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB + ``` + +### 步骤4:查看服务调用输出 +当两个服务和sidecar都在运行时,注意订单如何通过Dapr服务调用从`checkout`服务传递到`order-processor`服务。 + +`checkout`服务输出: + +``` +== APP == Order passed: {"orderId": 1} +== APP == Order passed: {"orderId": 2} +== APP == Order passed: {"orderId": 3} +== APP == Order passed: {"orderId": 4} +``` + +`order-processor`服务输出: + +``` +== APP == Order received: {"orderId": 1} +== APP == Order received: {"orderId": 2} +== APP == Order received: {"orderId": 3} +== APP == Order received: {"orderId": 4} +``` + +### 步骤5:引入故障 +通过停止`order-processor`服务来模拟故障。一旦实例停止,来自`checkout`服务的服务调用操作将开始失败。 + +由于`resiliency.yaml`配置将`order-processor`服务定义为弹性目标,所有失败的请求将应用重试和断路器策略: + +```yaml + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB +``` + +在`order-processor`窗口中,停止服务: + +{{< tabs "MacOs" "Windows" >}} + + + +{{% codetab %}} + +```script +CMD + C +``` + +{{% /codetab %}} + + + +{{% codetab %}} + +```script +CTRL + C +``` + +{{% /codetab %}} + +{{< /tabs >}} + + +一旦第一个请求失败,名为`retryForever`的重试策略将被应用: + +```bash +INFO[0005] Error processing operation endpoint[order-processor, order-processor:orders]. Retrying... +``` + +重试将以5秒的间隔无限期地继续每个失败的请求。 + +```yaml +retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 +``` + +一旦连续5次重试失败,断路器策略`simpleCB`将被触发,断路器打开,停止所有请求: + +```bash +INFO[0025] Circuit breaker "order-processor:orders" changed state from closed to open +``` + +```yaml +circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 +``` + +经过5秒后,断路器将切换到半开状态,允许一个请求通过以验证故障是否已解决。如果请求继续失败,断路器将再次触发回到打开状态。 + +```bash +INFO[0030] Circuit breaker "order-processor:orders" changed state from open to half-open +INFO[0030] Circuit breaker "order-processor:orders" changed state from half-open to open +INFO[0030] Circuit breaker "order-processor:orders" changed state from open to half-open +INFO[0030] Circuit breaker "order-processor:orders" changed state from half-open to open +``` + +这种半开/打开行为将持续到`order-processor`服务停止为止。 + +### 步骤6:移除故障 + +一旦您重新启动`order-processor`服务,应用程序将无缝恢复,继续接受订单请求。 + +在`order-processor`服务终端中,重新启动应用程序: + +```bash +dapr run --app-port 5001 --app-id order-processor --resources-path ../../../resources/ --app-protocol http --dapr-http-port 3501 -- npm start +``` + +`checkout`服务输出: + +``` +== APP == Order passed: {"orderId": 5} +== APP == Order passed: {"orderId": 6} +== APP == Order passed: {"orderId": 7} +== APP == Order passed: {"orderId": 8} +== APP == Order passed: {"orderId": 9} +== APP == Order passed: {"orderId": 10} +``` + +`order-processor`服务输出: + +``` +== APP == Order received: {"orderId": 5} +== APP == Order received: {"orderId": 6} +== APP == Order received: {"orderId": 7} +== APP == Order received: {"orderId": 8} +== APP == Order received: {"orderId": 9} +== APP == Order received: {"orderId": 10} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前提条件 + +对于此示例,您将需要: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [.NET SDK或.NET 6 SDK已安装](https://dotnet.microsoft.com/download)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[入门指南仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation/csharp/http)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤2:运行`order-processor`服务 + +在终端窗口中,从入门指南目录的根目录导航到`order-processor`目录。 + +```bash +cd service_invocation/csharp/http/order-processor +``` + +安装依赖项: + +```bash +dotnet restore +dotnet build +``` + +运行`order-processor`服务及其Dapr sidecar。 + +```bash +dapr run --app-port 7001 --app-id order-processor --resources-path ../../../resources/ --app-protocol http --dapr-http-port 3501 -- dotnet run +``` + +### 步骤3:运行`checkout`服务应用程序 + +在新的终端窗口中,从入门指南目录的根目录导航到`checkout`目录。 + +```bash +cd service_invocation/csharp/http/checkout +``` + +安装依赖项: + +```bash +dotnet restore +dotnet build +``` + +运行`checkout`服务及其Dapr sidecar。 + +```bash +dapr run --app-id checkout --resources-path ../../../resources/ --app-protocol http --dapr-http-port 3500 -- dotnet run +``` + +Dapr sidecar随后加载位于资源目录中的弹性配置: + + ```yaml + apiVersion: dapr.io/v1alpha1 + kind: Resiliency + metadata: + name: myresiliency + scopes: + - checkout + + spec: + policies: + retries: + retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 + + circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 + + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB + ``` + +### 步骤4:查看服务调用输出 +当两个服务和sidecar都在运行时,注意订单如何通过Dapr服务调用从`checkout`服务传递到`order-processor`服务。 + +`checkout`服务输出: + +``` +== APP == Order passed: {"orderId": 1} +== APP == Order passed: {"orderId": 2} +== APP == Order passed: {"orderId": 3} +== APP == Order passed: {"orderId": 4} +``` + +`order-processor`服务输出: + +``` +== APP == Order received: {"orderId": 1} +== APP == Order received: {"orderId": 2} +== APP == Order received: {"orderId": 3} +== APP == Order received: {"orderId": 4} +``` + +### 步骤5:引入故障 +通过停止`order-processor`服务来模拟故障。一旦实例停止,来自`checkout`服务的服务调用操作将开始失败。 + +由于`resiliency.yaml`配置将`order-processor`服务定义为弹性目标,所有失败的请求将应用重试和断路器策略: + +```yaml + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB +``` + +在`order-processor`窗口中,停止服务: + +{{< tabs "MacOs" "Windows" >}} + + + +{{% codetab %}} + +```script +CMD + C +``` + +{{% /codetab %}} + + + +{{% codetab %}} + +```script +CTRL + C +``` + +{{% /codetab %}} + +{{< /tabs >}} + + +一旦第一个请求失败,名为`retryForever`的重试策略将被应用: + +```bash +INFO[0005] Error processing operation endpoint[order-processor, order-processor:orders]. Retrying... +``` + +重试将以5秒的间隔无限期地继续每个失败的请求。 + +```yaml +retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 +``` + +一旦连续5次重试失败,断路器策略`simpleCB`将被触发,断路器打开,停止所有请求: + +```bash +INFO[0025] Circuit breaker "order-processor:orders" changed state from closed to open +``` + +```yaml +circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 +``` + +经过5秒后,断路器将切换到半开状态,允许一个请求通过以验证故障是否已解决。如果请求继续失败,断路器将再次触发回到打开状态。 + +```bash +INFO[0030] Circuit breaker "order-processor:orders" changed state from open to half-open +INFO[0030] Circuit breaker "order-processor:orders" changed state from half-open to open +INFO[0030] Circuit breaker "order-processor:orders" changed state from open to half-open +INFO[0030] Circuit breaker "order-processor:orders" changed state from half-open to open +``` + +这种半开/打开行为将持续到`order-processor`服务停止为止。 + +### 步骤6:移除故障 + +一旦您重新启动`order-processor`服务,应用程序将无缝恢复,继续接受订单请求。 + +在`order-processor`服务终端中,重新启动应用程序: + +```bash +dapr run --app-port 7001 --app-id order-processor --app-protocol http --dapr-http-port 3501 -- dotnet run +``` + +`checkout`服务输出: + +``` +== APP == Order passed: {"orderId": 5} +== APP == Order passed: {"orderId": 6} +== APP == Order passed: {"orderId": 7} +== APP == Order passed: {"orderId": 8} +== APP == Order passed: {"orderId": 9} +== APP == Order passed: {"orderId": 10} +``` + +`order-processor`服务输出: + +``` +== APP == Order received: {"orderId": 5} +== APP == Order received: {"orderId": 6} +== APP == Order received: {"orderId": 7} +== APP == Order received: {"orderId": 8} +== APP == Order received: {"orderId": 9} +== APP == Order received: {"orderId": 10} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前提条件 + +对于此示例,您将需要: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- Java JDK 17(或更高版本): + - [Oracle JDK](https://www.oracle.com/java/technologies/downloads),或 + - OpenJDK +- [Apache Maven](https://maven.apache.org/install.html),版本3.x。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[入门指南仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation/java/http)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤2:运行`order-processor`服务 + +在终端窗口中,从入门指南目录的根目录导航到`order-processor`目录。 + +```bash +cd service_invocation/java/http/order-processor +``` + +安装依赖项: + +```bash +mvn clean install +``` + +运行`order-processor`服务及其Dapr sidecar。 + +```bash +dapr run --app-id order-processor --resources-path ../../../resources/ --app-port 9001 --app-protocol http --dapr-http-port 3501 -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar +``` + +### 步骤3:运行`checkout`服务应用程序 + +在新的终端窗口中,从入门指南目录的根目录导航到`checkout`目录。 + +```bash +cd service_invocation/java/http/checkout +``` + +安装依赖项: + +```bash +mvn clean install +``` + +运行`checkout`服务及其Dapr sidecar。 + +```bash +dapr run --app-id checkout --resources-path ../../../resources/ --app-protocol http --dapr-http-port 3500 -- java -jar target/CheckoutService-0.0.1-SNAPSHOT.jar +``` + +Dapr sidecar随后加载位于资源目录中的弹性配置: + + ```yaml + apiVersion: dapr.io/v1alpha1 + kind: Resiliency + metadata: + name: myresiliency + scopes: + - checkout + + spec: + policies: + retries: + retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 + + circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 + + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB + ``` + +### 步骤4:查看服务调用输出 +当两个服务和sidecar都在运行时,注意订单如何通过Dapr服务调用从`checkout`服务传递到`order-processor`服务。 + +`checkout`服务输出: + +``` +== APP == Order passed: {"orderId": 1} +== APP == Order passed: {"orderId": 2} +== APP == Order passed: {"orderId": 3} +== APP == Order passed: {"orderId": 4} +``` + +`order-processor`服务输出: + +``` +== APP == Order received: {"orderId": 1} +== APP == Order received: {"orderId": 2} +== APP == Order received: {"orderId": 3} +== APP == Order received: {"orderId": 4} +``` + +### 步骤5:引入故障 +通过停止`order-processor`服务来模拟故障。一旦实例停止,来自`checkout`服务的服务调用操作将开始失败。 + +由于`resiliency.yaml`配置将`order-processor`服务定义为弹性目标,所有失败的请求将应用重试和断路器策略: + +```yaml + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB +``` + +在`order-processor`窗口中,停止服务: + +{{< tabs "MacOs" "Windows" >}} + + + +{{% codetab %}} + +```script +CMD + C +``` + +{{% /codetab %}} + + + +{{% codetab %}} + +```script +CTRL + C +``` + +{{% /codetab %}} + +{{< /tabs >}} + + +一旦第一个请求失败,名为`retryForever`的重试策略将被应用: + +```bash +INFO[0005] Error processing operation endpoint[order-processor, order-processor:orders]. Retrying... +``` + +重试将以5秒的间隔无限期地继续每个失败的请求。 + +```yaml +retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 +``` + +一旦连续5次重试失败,断路器策略`simpleCB`将被触发,断路器打开,停止所有请求: + +```bash +INFO[0025] Circuit breaker "order-processor:orders" changed state from closed to open +``` + +```yaml +circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 +``` + +经过5秒后,断路器将切换到半开状态,允许一个请求通过以验证故障是否已解决。如果请求继续失败,断路器将再次触发回到打开状态。 + +```bash +INFO[0030] Circuit breaker "order-processor:orders" changed state from open to half-open +INFO[0030] Circuit breaker "order-processor:orders" changed state from half-open to open +INFO[0030] Circuit breaker "order-processor:orders" changed state from open to half-open +INFO[0030] Circuit breaker "order-processor:orders" changed state from half-open to open +``` + +这种半开/打开行为将持续到`order-processor`服务停止为止。 + +### 步骤6:移除故障 + +一旦您重新启动`order-processor`服务,应用程序将无缝恢复,继续接受订单请求。 + +在`order-processor`服务终端中,重新启动应用程序: + +```bash +dapr run --app-id order-processor --resources-path ../../../resources/ --app-port 9001 --app-protocol http --dapr-http-port 3501 -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar +``` + +`checkout`服务输出: + +``` +== APP == Order passed: {"orderId": 5} +== APP == Order passed: {"orderId": 6} +== APP == Order passed: {"orderId": 7} +== APP == Order passed: {"orderId": 8} +== APP == Order passed: {"orderId": 9} +== APP == Order passed: {"orderId": 10} +``` + +`order-processor`服务输出: + +``` +== APP == Order received: {"orderId": 5} +== APP == Order received: {"orderId": 6} +== APP == Order received: {"orderId": 7} +== APP == Order received: {"orderId": 8} +== APP == Order received: {"orderId": 9} +== APP == Order received: {"orderId": 10} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前提条件 + +对于此示例,您将需要: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[入门指南仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation/go/http)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤2:运行`order-processor`服务 + +在终端窗口中,从入门指南目录的根目录导航到`order-processor`目录。 + +```bash +cd service_invocation/go/http/order-processor +``` + +安装依赖项: + +```bash +go build . +``` + +运行`order-processor`服务及其Dapr sidecar。 + +```bash +dapr run --app-port 6001 --app-id order-processor --resources-path ../../../resources/ --app-protocol http --dapr-http-port 3501 -- go run . +``` + +### 步骤3:运行`checkout`服务应用程序 + +在新的终端窗口中,从入门指南目录的根目录导航到`checkout`目录。 + +```bash +cd service_invocation/go/http/checkout +``` + +安装依赖项: + +```bash +go build . +``` + +运行`checkout`服务及其Dapr sidecar。 + +```bash +dapr run --app-id checkout --resources-path ../../../resources/ --app-protocol http --dapr-http-port 3500 -- go run . +``` + +Dapr sidecar随后加载位于资源目录中的弹性配置: + + ```yaml + apiVersion: dapr.io/v1alpha1 + kind: Resiliency + metadata: + name: myresiliency + scopes: + - checkout + + spec: + policies: + retries: + retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 + + circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 + + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB + ``` + +### 步骤4:查看服务调用输出 +当两个服务和sidecar都在运行时,注意订单如何通过Dapr服务调用从`checkout`服务传递到`order-processor`服务。 + +`checkout`服务输出: + +``` +== APP == Order passed: {"orderId": 1} +== APP == Order passed: {"orderId": 2} +== APP == Order passed: {"orderId": 3} +== APP == Order passed: {"orderId": 4} +``` + +`order-processor`服务输出: + +``` +== APP == Order received: {"orderId": 1} +== APP == Order received: {"orderId": 2} +== APP == Order received: {"orderId": 3} +== APP == Order received: {"orderId": 4} +``` + +### 步骤5:引入故障 +通过停止`order-processor`服务来模拟故障。一旦实例停止,来自`checkout`服务的服务调用操作将开始失败。 + +由于`resiliency.yaml`配置将`order-processor`服务定义为弹性目标,所有失败的请求将应用重试和断路器策略: + +```yaml + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB +``` + +在`order-processor`窗口中,停止服务: + +{{< tabs "MacOs" "Windows" >}} + + + +{{% codetab %}} + +```script +CMD + C +``` + +{{% /codetab %}} + + + +{{% codetab %}} + +```script +CTRL + C +``` + +{{% /codetab %}} + +{{< /tabs >}} + + +一旦第一个请求失败,名为`retryForever`的重试策略将被应用: + +```bash +INFO[0005] Error processing operation endpoint[order-processor, order-processor:orders]. Retrying... +``` + +重试将以5秒的间隔无限期地继续每个失败的请求。 + +```yaml +retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 +``` + +一旦连续5次重试失败,断路器策略`simpleCB`将被触发,断路器打开,停止所有请求: + +```bash +INFO[0025] Circuit breaker "order-processor:orders" changed state from closed to open +``` + +```yaml +circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 +``` + +经过5秒后,断路器将切换到半开状态,允许一个请求通过以验证故障是否已解决。如果请求继续失败,断路器将再次触发回到打开状态。 + +```bash +INFO[0030] Circuit breaker "order-processor:orders" changed state from open to half-open +INFO[0030] Circuit breaker "order-processor:orders" changed state from half-open to open +INFO[0030] Circuit breaker "order-processor:orders" changed state from open to half-open +INFO[0030] Circuit breaker "order-processor:orders" changed state from half-open to open +``` + +这种半开/打开行为将持续到`order-processor`服务停止为止。 + +### 步骤6:移除故障 + +一旦您重新启动`order-processor`服务,应用程序将无缝恢复,继续接受订单请求。 + +在`order-processor`服务终端中,重新启动应用程序: + +```bash +dapr run --app-port 6001 --app-id order-processor --resources-path ../../../resources/ --app-protocol http --dapr-http-port 3501 -- go run . +``` + +`checkout`服务输出: + +``` +== APP == Order passed: {"orderId": 5} +== APP == Order passed: {"orderId": 6} +== APP == Order passed: {"orderId": 7} +== APP == Order passed: {"orderId": 8} +== APP == Order passed: {"orderId": 9} +== APP == Order passed: {"orderId": 10} +``` + +`order-processor`服务输出: + +``` +== APP == Order received: {"orderId": 5} +== APP == Order received: {"orderId": 6} +== APP == Order received: {"orderId": 7} +== APP == Order received: {"orderId": 8} +== APP == Order received: {"orderId": 9} +== APP == Order received: {"orderId": 10} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 告诉我们您的想法! +我们正在不断努力改进我们的入门指南示例,重视您的反馈。您觉得这个入门指南有帮助吗?您有改进建议吗? + +加入我们的[discord频道](https://discord.com/channels/778680217417809931/953427615916638238)讨论。 + +## 下一步 +访问[此链接](https://docs.dapr.io/operations/resiliency/resiliency-overview//)以获取有关Dapr弹性的更多信息。 + +{{< button text="探索Dapr教程 >>" page="getting-started/tutorials/_index.md" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/resiliency/resiliency-state-quickstart.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/resiliency/resiliency-state-quickstart.md new file mode 100644 index 000000000..ea3441dc8 --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/resiliency/resiliency-state-quickstart.md @@ -0,0 +1,876 @@ +--- +type: docs +title: "快速入门:从服务到组件的弹性" +linkTitle: "弹性:从服务到组件" +weight: 110 +description: "通过Dapr的状态管理API来了解其弹性功能" +--- + +通过模拟系统故障来了解Dapr的弹性功能。在本快速入门中,您将: + +- 运行一个微服务应用程序,该应用程序通过Dapr的状态管理API持续保存和检索状态。 +- 通过模拟系统故障来触发弹性策略。 +- 解决故障后,微服务应用程序将恢复。 + +显示应用于Dapr API的弹性示意图 + +在继续快速入门之前,请选择您偏好的Dapr SDK语言。 + +{{< tabs "Python" "JavaScript" ".NET" "Java" "Go" >}} + +{{% codetab %}} + +### 前提条件 + +对于此示例,您将需要: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装Python 3.7+](https://www.python.org/downloads/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/state_management/python/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +在终端窗口中,导航到`order-processor`目录。 + +```bash +cd ../state_management/python/sdk/order-processor +``` + +安装依赖项 + +```bash +pip3 install -r requirements.txt +``` + +### 步骤2:运行应用程序 + +在Dapr边车的支持下运行`order-processor`服务。然后,Dapr边车会加载位于资源目录中的弹性规范: + + ```yaml + apiVersion: dapr.io/v1alpha1 + kind: Resiliency + metadata: + name: myresiliency + scopes: + - order-processor + + spec: + policies: + retries: + retryForever: + policy: constant + duration: 5s + maxRetries: -1 + + circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 + + targets: + components: + statestore: + outbound: + retry: retryForever + circuitBreaker: simpleCB + ``` + +```bash +dapr run --app-id order-processor --resources-path ../../../resources/ -- python3 +``` + +应用程序启动后,`order-processor`服务会将`orderId`键值对写入和读取到`statestore`的Redis实例中[在`statestore.yaml`组件中定义]({{< ref "statemanagement-quickstart.md#statestoreyaml-component-file" >}})。 + +```bash +== APP == Saving Order: { orderId: '1' } +== APP == Getting Order: { orderId: '1' } +== APP == Saving Order: { orderId: '2' } +== APP == Getting Order: { orderId: '2' } +== APP == Saving Order: { orderId: '3' } +== APP == Getting Order: { orderId: '3' } +== APP == Saving Order: { orderId: '4' } +== APP == Getting Order: { orderId: '4' } +``` + +### 步骤3:引入故障 + +通过停止在开发机器上执行`dapr init`时初始化的Redis容器实例来模拟故障。一旦实例停止,来自`order-processor`服务的写入和读取操作将开始失败。 + +由于`resiliency.yaml`规范将`statestore`定义为组件目标,所有失败的请求将自动应用重试和断路器策略: + +```yaml + targets: + components: + statestore: + outbound: + retry: retryForever + circuitBreaker: simpleCB +``` + +在新的终端窗口中,运行以下命令以停止Redis: + +```bash +docker stop dapr_redis +``` + +一旦Redis停止,请求开始失败,并应用名为`retryForever`的重试策略。以下输出显示了来自`order-processor`服务的日志: + +```bash +INFO[0006] Error processing operation component[statestore] output. Retrying... +``` + +根据`retryForever`策略,重试将以5秒间隔无限期地继续每个失败的请求。 + +```yaml +retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 +``` + +一旦5次连续重试失败,断路器策略`simpleCB`被触发,断路器打开,停止所有请求: + +```bash +INFO[0026] Circuit breaker "simpleCB-statestore" changed state from closed to open +``` + +```yaml +circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 +``` + +经过5秒后,断路器将切换到半开状态,允许一个请求通过以验证故障是否已解决。如果请求继续失败,断路器将再次触发回到打开状态。 + +```bash +INFO[0031] Circuit breaker "simpleCB-statestore" changed state from open to half-open +INFO[0031] Circuit breaker "simpleCB-statestore" changed state from half-open to open +INFO[0036] Circuit breaker "simpleCB-statestore" changed state from open to half-open +INFO[0036] Circuit breaker "simpleCB-statestore" changed state from half-open to closed +``` + +只要Redis容器停止,这种半开/打开行为将继续。 + +### 步骤3:移除故障 + +当您在机器上重新启动Redis容器后,应用程序将无缝恢复并继续之前的操作。 + +```bash +docker start dapr_redis +``` + +```bash +INFO[0036] Recovered processing operation component[statestore] output. +== APP == Saving Order: { orderId: '5' } +== APP == Getting Order: { orderId: '5' } +== APP == Saving Order: { orderId: '6' } +== APP == Getting Order: { orderId: '6' } +== APP == Saving Order: { orderId: '7' } +== APP == Getting Order: { orderId: '7' } +== APP == Saving Order: { orderId: '8' } +== APP == Getting Order: { orderId: '8' } +== APP == Saving Order: { orderId: '9' } +== APP == Getting Order: { orderId: '9' } +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前提条件 + +对于此示例,您将需要: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装最新的Node.js](https://nodejs.org/download/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/state_management/javascript/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +在终端窗口中,导航到`order-processor`目录。 + +```bash +cd ../state_management/javascript/sdk/order-processor +``` + +安装依赖项 + +```bash +npm install +``` + +### 步骤2:运行应用程序 + +在Dapr边车的支持下运行`order-processor`服务。然后,Dapr边车会加载位于资源目录中的弹性规范: + + ```yaml + apiVersion: dapr.io/v1alpha1 + kind: Resiliency + metadata: + name: myresiliency + scopes: + - checkout + + spec: + policies: + retries: + retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 + + circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 + + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB + ``` + +```bash +dapr run --app-id order-processor --resources-path ../../../resources/ -- npm start +``` + +应用程序启动后,`order-processor`服务会将`orderId`键值对写入和读取到`statestore`的Redis实例中[在`statestore.yaml`组件中定义]({{< ref "statemanagement-quickstart.md#statestoreyaml-component-file" >}})。 + +```bash +== APP == Saving Order: { orderId: '1' } +== APP == Getting Order: { orderId: '1' } +== APP == Saving Order: { orderId: '2' } +== APP == Getting Order: { orderId: '2' } +== APP == Saving Order: { orderId: '3' } +== APP == Getting Order: { orderId: '3' } +== APP == Saving Order: { orderId: '4' } +== APP == Getting Order: { orderId: '4' } +``` + +### 步骤3:引入故障 + +通过停止在开发机器上执行`dapr init`时初始化的Redis容器实例来模拟故障。一旦实例停止,来自`order-processor`服务的写入和读取操作将开始失败。 + +由于`resiliency.yaml`规范将`statestore`定义为组件目标,所有失败的请求将自动应用重试和断路器策略: + +```yaml + targets: + components: + statestore: + outbound: + retry: retryForever + circuitBreaker: simpleCB +``` + +在新的终端窗口中,运行以下命令以停止Redis: + +```bash +docker stop dapr_redis +``` + +一旦Redis停止,请求开始失败,并应用名为`retryForever`的重试策略。以下输出显示了来自`order-processor`服务的日志: + +```bash +INFO[0006] Error processing operation component[statestore] output. Retrying... +``` + +根据`retryForever`策略,重试将以5秒间隔无限期地继续每个失败的请求。 + +```yaml +retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 +``` + +一旦5次连续重试失败,断路器策略`simpleCB`被触发,断路器打开,停止所有请求: + +```bash +INFO[0026] Circuit breaker "simpleCB-statestore" changed state from closed to open +``` + +```yaml +circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 +``` + +经过5秒后,断路器将切换到半开状态,允许一个请求通过以验证故障是否已解决。如果请求继续失败,断路器将再次触发回到打开状态。 + +```bash +INFO[0031] Circuit breaker "simpleCB-statestore" changed state from open to half-open +INFO[0031] Circuit breaker "simpleCB-statestore" changed state from half-open to open +INFO[0036] Circuit breaker "simpleCB-statestore" changed state from open to half-open +INFO[0036] Circuit breaker "simpleCB-statestore" changed state from half-open to closed +``` + +只要Redis容器停止,这种半开/打开行为将继续。 + +### 步骤3:移除故障 + +当您在机器上重新启动Redis容器后,应用程序将无缝恢复并继续之前的操作。 + +```bash +docker start dapr_redis +``` + +```bash +INFO[0036] Recovered processing operation component[statestore] output. +== APP == Saving Order: { orderId: '5' } +== APP == Getting Order: { orderId: '5' } +== APP == Saving Order: { orderId: '6' } +== APP == Getting Order: { orderId: '6' } +== APP == Saving Order: { orderId: '7' } +== APP == Getting Order: { orderId: '7' } +== APP == Saving Order: { orderId: '8' } +== APP == Getting Order: { orderId: '8' } +== APP == Saving Order: { orderId: '9' } +== APP == Getting Order: { orderId: '9' } +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前提条件 + +对于此示例,您将需要: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [.NET SDK或.NET 6 SDK已安装](https://dotnet.microsoft.com/download)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/state_management/csharp/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +在终端窗口中,导航到`order-processor`目录。 + +```bash +cd ../state_management/csharp/sdk/order-processor +``` + +安装依赖项 + +```bash +dotnet restore +dotnet build +``` + +### 步骤2:运行应用程序 + +在Dapr边车的支持下运行`order-processor`服务。然后,Dapr边车会加载位于资源目录中的弹性规范: + + ```yaml + apiVersion: dapr.io/v1alpha1 + kind: Resiliency + metadata: + name: myresiliency + scopes: + - checkout + + spec: + policies: + retries: + retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 + + circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 + + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB + ``` + +```bash +dapr run --app-id order-processor --resources-path ../../../resources/ -- dotnet run +``` + +应用程序启动后,`order-processor`服务会将`orderId`键值对写入和读取到`statestore`的Redis实例中[在`statestore.yaml`组件中定义]({{< ref "statemanagement-quickstart.md#statestoreyaml-component-file" >}})。 + +```bash +== APP == Saving Order: { orderId: '1' } +== APP == Getting Order: { orderId: '1' } +== APP == Saving Order: { orderId: '2' } +== APP == Getting Order: { orderId: '2' } +== APP == Saving Order: { orderId: '3' } +== APP == Getting Order: { orderId: '3' } +== APP == Saving Order: { orderId: '4' } +== APP == Getting Order: { orderId: '4' } +``` + +### 步骤3:引入故障 + +通过停止在开发机器上执行`dapr init`时初始化的Redis容器实例来模拟故障。一旦实例停止,来自`order-processor`服务的写入和读取操作将开始失败。 + +由于`resiliency.yaml`规范将`statestore`定义为组件目标,所有失败的请求将自动应用重试和断路器策略: + +```yaml + targets: + components: + statestore: + outbound: + retry: retryForever + circuitBreaker: simpleCB +``` + +在新的终端窗口中,运行以下命令以停止Redis: + +```bash +docker stop dapr_redis +``` + +一旦Redis停止,请求开始失败,并应用名为`retryForever`的重试策略。以下输出显示了来自`order-processor`服务的日志: + +```bash +INFO[0006] Error processing operation component[statestore] output. Retrying... +``` + +根据`retryForever`策略,重试将以5秒间隔无限期地继续每个失败的请求。 + +```yaml +retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 +``` + +一旦5次连续重试失败,断路器策略`simpleCB`被触发,断路器打开,停止所有请求: + +```bash +INFO[0026] Circuit breaker "simpleCB-statestore" changed state from closed to open +``` + +```yaml +circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 +``` + +经过5秒后,断路器将切换到半开状态,允许一个请求通过以验证故障是否已解决。如果请求继续失败,断路器将再次触发回到打开状态。 + +```bash +INFO[0031] Circuit breaker "simpleCB-statestore" changed state from open to half-open +INFO[0031] Circuit breaker "simpleCB-statestore" changed state from half-open to open +INFO[0036] Circuit breaker "simpleCB-statestore" changed state from open to half-open +INFO[0036] Circuit breaker "simpleCB-statestore" changed state from half-open to closed +``` + +只要Redis容器停止,这种半开/打开行为将继续。 + +### 步骤3:移除故障 + +当您在机器上重新启动Redis容器后,应用程序将无缝恢复并继续之前的操作。 + +```bash +docker start dapr_redis +``` + +```bash +INFO[0036] Recovered processing operation component[statestore] output. +== APP == Saving Order: { orderId: '5' } +== APP == Getting Order: { orderId: '5' } +== APP == Saving Order: { orderId: '6' } +== APP == Getting Order: { orderId: '6' } +== APP == Saving Order: { orderId: '7' } +== APP == Getting Order: { orderId: '7' } +== APP == Saving Order: { orderId: '8' } +== APP == Getting Order: { orderId: '8' } +== APP == Saving Order: { orderId: '9' } +== APP == Getting Order: { orderId: '9' } +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前提条件 + +对于此示例,您将需要: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- Java JDK 17(或更高版本): + - [Oracle JDK](https://www.oracle.com/java/technologies/downloads),或 + - OpenJDK +- [Apache Maven](https://maven.apache.org/install.html),版本3.x。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/state_management/java/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +在终端窗口中,导航到`order-processor`目录。 + +```bash +cd ../state_management/java/sdk/order-processor +``` + +安装依赖项 + +```bash +mvn clean install +``` + +### 步骤2:运行应用程序 + +在Dapr边车的支持下运行`order-processor`服务。然后,Dapr边车会加载位于资源目录中的弹性规范: + + ```yaml + apiVersion: dapr.io/v1alpha1 + kind: Resiliency + metadata: + name: myresiliency + scopes: + - checkout + + spec: + policies: + retries: + retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 + + circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 + + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB + ``` + +```bash +dapr run --app-id order-processor --resources-path ../../../resources/ -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar +``` + +应用程序启动后,`order-processor`服务会将`orderId`键值对写入和读取到`statestore`的Redis实例中[在`statestore.yaml`组件中定义]({{< ref "statemanagement-quickstart.md#statestoreyaml-component-file" >}})。 + +```bash +== APP == Saving Order: { orderId: '1' } +== APP == Getting Order: { orderId: '1' } +== APP == Saving Order: { orderId: '2' } +== APP == Getting Order: { orderId: '2' } +== APP == Saving Order: { orderId: '3' } +== APP == Getting Order: { orderId: '3' } +== APP == Saving Order: { orderId: '4' } +== APP == Getting Order: { orderId: '4' } +``` + +### 步骤3:引入故障 + +通过停止在开发机器上执行`dapr init`时初始化的Redis容器实例来模拟故障。一旦实例停止,来自`order-processor`服务的写入和读取操作将开始失败。 + +由于`resiliency.yaml`规范将`statestore`定义为组件目标,所有失败的请求将自动应用重试和断路器策略: + +```yaml + targets: + components: + statestore: + outbound: + retry: retryForever + circuitBreaker: simpleCB +``` + +在新的终端窗口中,运行以下命令以停止Redis: + +```bash +docker stop dapr_redis +``` + +一旦Redis停止,请求开始失败,并应用名为`retryForever`的重试策略。以下输出显示了来自`order-processor`服务的日志: + +```bash +INFO[0006] Error processing operation component[statestore] output. Retrying... +``` + +根据`retryForever`策略,重试将以5秒间隔无限期地继续每个失败的请求。 + +```yaml +retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 +``` + +一旦5次连续重试失败,断路器策略`simpleCB`被触发,断路器打开,停止所有请求: + +```bash +INFO[0026] Circuit breaker "simpleCB-statestore" changed state from closed to open +``` + +```yaml +circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 +``` + +经过5秒后,断路器将切换到半开状态,允许一个请求通过以验证故障是否已解决。如果请求继续失败,断路器将再次触发回到打开状态。 + +```bash +INFO[0031] Circuit breaker "simpleCB-statestore" changed state from open to half-open +INFO[0031] Circuit breaker "simpleCB-statestore" changed state from half-open to open +INFO[0036] Circuit breaker "simpleCB-statestore" changed state from open to half-open +INFO[0036] Circuit breaker "simpleCB-statestore" changed state from half-open to closed +``` + +只要Redis容器停止,这种半开/打开行为将继续。 + +### 步骤3:移除故障 + +当您在机器上重新启动Redis容器后,应用程序将无缝恢复并继续之前的操作。 + +```bash +docker start dapr_redis +``` + +```bash +INFO[0036] Recovered processing operation component[statestore] output. +== APP == Saving Order: { orderId: '5' } +== APP == Getting Order: { orderId: '5' } +== APP == Saving Order: { orderId: '6' } +== APP == Getting Order: { orderId: '6' } +== APP == Saving Order: { orderId: '7' } +== APP == Getting Order: { orderId: '7' } +== APP == Saving Order: { orderId: '8' } +== APP == Getting Order: { orderId: '8' } +== APP == Saving Order: { orderId: '9' } +== APP == Getting Order: { orderId: '9' } +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前提条件 + +对于此示例,您将需要: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/state_management/go/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +在终端窗口中,导航到`order-processor`目录。 + +```bash +cd ../state_management/go/sdk/order-processor +``` + +安装依赖项 + +```bash +go build . +``` + +### 步骤2:运行应用程序 + +在Dapr边车的支持下运行`order-processor`服务。然后,Dapr边车会加载位于资源目录中的弹性规范: + + ```yaml + apiVersion: dapr.io/v1alpha1 + kind: Resiliency + metadata: + name: myresiliency + scopes: + - checkout + + spec: + policies: + retries: + retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 + + circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 + + targets: + apps: + order-processor: + retry: retryForever + circuitBreaker: simpleCB + ``` + +```bash +dapr run --app-id order-processor --resources-path ../../../resources -- go run . +``` + +应用程序启动后,`order-processor`服务会将`orderId`键值对写入和读取到`statestore`的Redis实例中[在`statestore.yaml`组件中定义]({{< ref "statemanagement-quickstart.md#statestoreyaml-component-file" >}})。 + +```bash +== APP == Saving Order: { orderId: '1' } +== APP == Getting Order: { orderId: '1' } +== APP == Saving Order: { orderId: '2' } +== APP == Getting Order: { orderId: '2' } +== APP == Saving Order: { orderId: '3' } +== APP == Getting Order: { orderId: '3' } +== APP == Saving Order: { orderId: '4' } +== APP == Getting Order: { orderId: '4' } +``` + +### 步骤3:引入故障 + +通过停止在开发机器上执行`dapr init`时初始化的Redis容器实例来模拟故障。一旦实例停止,来自`order-processor`服务的写入和读取操作将开始失败。 + +由于`resiliency.yaml`规范将`statestore`定义为组件目标,所有失败的请求将自动应用重试和断路器策略: + +```yaml + targets: + components: + statestore: + outbound: + retry: retryForever + circuitBreaker: simpleCB +``` + +在新的终端窗口中,运行以下命令以停止Redis: + +```bash +docker stop dapr_redis +``` + +一旦Redis停止,请求开始失败,并应用名为`retryForever`的重试策略。以下输出显示了来自`order-processor`服务的日志: + +```bash +INFO[0006] Error processing operation component[statestore] output. Retrying... +``` + +根据`retryForever`策略,重试将以5秒间隔无限期地继续每个失败的请求。 + +```yaml +retryForever: + policy: constant + maxInterval: 5s + maxRetries: -1 +``` + +一旦5次连续重试失败,断路器策略`simpleCB`被触发,断路器打开,停止所有请求: + +```bash +INFO[0026] Circuit breaker "simpleCB-statestore" changed state from closed to open +``` + +```yaml +circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 5s + trip: consecutiveFailures >= 5 +``` + +经过5秒后,断路器将切换到半开状态,允许一个请求通过以验证故障是否已解决。如果请求继续失败,断路器将再次触发回到打开状态。 + +```bash +INFO[0031] Circuit breaker "simpleCB-statestore" changed state from open to half-open +INFO[0031] Circuit breaker "simpleCB-statestore" changed state from half-open to open +INFO[0036] Circuit breaker "simpleCB-statestore" changed state from open to half-open +INFO[0036] Circuit breaker "simpleCB-statestore" changed state from half-open to closed +``` + +只要Redis容器停止,这种半开/打开行为将继续。 + +### 步骤3:移除故障 + +当您在机器上重新启动Redis容器后,应用程序将无缝恢复并继续之前的操作。 + +```bash +docker start dapr_redis +``` + +```bash +INFO[0036] Recovered processing operation component[statestore] output. +== APP == Saving Order: { orderId: '5' } +== APP == Getting Order: { orderId: '5' } +== APP == Saving Order: { orderId: '6' } +== APP == Getting Order: { orderId: '6' } +== APP == Saving Order: { orderId: '7' } +== APP == Getting Order: { orderId: '7' } +== APP == Saving Order: { orderId: '8' } +== APP == Getting Order: { orderId: '8' } +== APP == Saving Order: { orderId: '9' } +== APP == Getting Order: { orderId: '9' } +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 告诉我们您的想法! +我们正在不断努力改进我们的快速入门示例,并重视您的反馈。您觉得这个快速入门有帮助吗?您有改进建议吗? + +加入我们的[discord频道](https://discord.com/channels/778680217417809931/953427615916638238)讨论。 + +## 下一步 + +了解更多关于[弹性功能]({{< ref resiliency-overview.md >}})及其如何与Dapr的构建块API协作。 + +{{< button text="探索Dapr教程 >>" page="getting-started/tutorials/_index.md" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/secrets-quickstart.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/secrets-quickstart.md new file mode 100644 index 000000000..8738d9d6b --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/secrets-quickstart.md @@ -0,0 +1,584 @@ +--- +type: docs +title: "快速入门:机密管理" +linkTitle: "机密管理" +weight: 77 +description: "开始使用Dapr的机密管理构建块" +--- + +Dapr提供了一个专用的机密API,允许开发者从机密存储中检索机密。在本快速入门中,您将: + +1. 运行一个带有机密存储组件的微服务。 +2. 在应用程序代码中使用Dapr机密API检索机密。 + +示例服务的机密管理图示。 + +在继续快速入门之前,请选择您偏好的编程语言对应的Dapr SDK。 + +{{< tabs "Python" "JavaScript" ".NET" "Java" "Go" >}} + +{{% codetab %}} + +### 前置条件 + +您需要准备以下环境: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装Python 3.7+](https://www.python.org/downloads/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/secrets_management/python/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤2:检索机密 + +在终端窗口中,导航到`order-processor`目录。 + +```bash +cd secrets_management/python/sdk/order-processor +``` + +安装依赖项: + +```bash +pip3 install -r requirements.txt +``` + +运行`order-processor`服务及其Dapr sidecar。 + +```bash +dapr run --app-id order-processor --resources-path ../../../components/ -- python3 app.py +``` + +> **注意**:在Windows中,可能需要使用`python app.py`而不是`python3 app.py`。 + +#### 背后的原理 + +**`order-processor`服务** + +请注意,`order-processor`服务配置如下: + +- 使用在`local-secret-store.yaml`组件中定义的`DAPR_SECRET_STORE`。 +- 使用在`secrets.json`中定义的机密。 + +```python +# app.py +DAPR_SECRET_STORE = 'localsecretstore' +SECRET_NAME = 'secret' +with DaprClient() as client: + secret = client.get_secret(store_name=DAPR_SECRET_STORE, key=SECRET_NAME) + logging.info('Fetched Secret: %s', secret.secret) +``` + +**`local-secret-store.yaml`组件** + +`DAPR_SECRET_STORE`在`local-secret-store.yaml`组件文件中定义,位于[secrets_management/components](https://github.com/dapr/quickstarts/tree/master/secrets_management/components/local-secret-store.yaml): + +```yaml +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`定义了组件使用的机密的连接信息。 + +**`secrets.json`文件** + +`SECRET_NAME`在`secrets.json`文件中定义,位于[secrets_management/python/sdk/order-processor](https://github.com/dapr/quickstarts/tree/master/secrets_management/python/sdk/order-processor/secrets.json): + +```json +{ + "secret": "YourPasskeyHere" +} +``` + +### 步骤3:查看order-processor输出 + +如上面的应用程序代码中所示,`order-processor`服务通过Dapr机密存储检索机密并在控制台中显示。 + +Order-processor输出: + +``` +== APP == INFO:root:Fetched Secret: {'secret': 'YourPasskeyHere'} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前置条件 + +您需要准备以下环境: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装最新的Node.js](https://nodejs.org/download/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/secrets_management/javascript/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤2:检索机密 + +在终端窗口中,导航到`order-processor`目录。 + +```bash +cd secrets_management/javascript/sdk/order-processor +``` + +安装依赖项: + +```bash +npm install +``` + +运行`order-processor`服务及其Dapr sidecar。 + +```bash +dapr run --app-id order-processor --resources-path ../../../components/ -- npm start +``` + +#### 背后的原理 + +**`order-processor`服务** + +请注意,`order-processor`服务配置如下: + +- 使用在`local-secret-store.yaml`组件中定义的`DAPR_SECRET_STORE`。 +- 使用在`secrets.json`中定义的机密。 + +```javascript +// 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)); +} +``` + +**`local-secret-store.yaml`组件** + +`DAPR_SECRET_STORE`在`local-secret-store.yaml`组件文件中定义,位于[secrets_management/components](https://github.com/dapr/quickstarts/tree/master/secrets_management/components/local-secret-store.yaml): + +```yaml +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`定义了组件使用的机密的连接信息。 + +**`secrets.json`文件** + +`SECRET_NAME`在`secrets.json`文件中定义,位于[secrets_management/javascript/sdk/order-processor](https://github.com/dapr/quickstarts/tree/master/secrets_management/javascript/sdk/order-processor/secrets.json): + +```json +{ + "secret": "YourPasskeyHere" +} +``` + +### 步骤3:查看order-processor输出 + +如上面的应用程序代码中所示,`order-processor`服务通过Dapr机密存储检索机密并在控制台中显示。 + +Order-processor输出: + +``` +== APP == +== APP == > order-processor@1.0.0 start +== APP == > node index.js +== APP == +== APP == Fetched Secret: {"secret":"YourPasskeyHere"} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前置条件 + +您需要准备以下环境: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + +- [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0)、[.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0)或[.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0)已安装 + +**注意:** .NET 6是此版本中Dapr .NET SDK包的最低支持版本。只有.NET 8和.NET 9将在Dapr v1.16及以后版本中得到支持。 + +### 步骤1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/secrets_management/csharp/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤2:检索机密 + +在终端窗口中,导航到`order-processor`目录。 + +```bash +cd secrets_management/csharp/sdk/order-processor +``` + +安装依赖项: + +```bash +dotnet restore +dotnet build +``` + +运行`order-processor`服务及其Dapr sidecar。 + +```bash +dapr run --app-id order-processor --resources-path ../../../components/ -- dotnet run +``` + +#### 背后的原理 + +**`order-processor`服务** + +请注意,`order-processor`服务配置如下: + +- 使用在`local-secret-store.yaml`组件中定义的`DAPR_SECRET_STORE`。 +- 使用在`secrets.json`中定义的机密。 + +```csharp +// Program.cs +const string DAPR_SECRET_STORE = "localsecretstore"; +const string SECRET_NAME = "secret"; +var client = new DaprClientBuilder().Build(); + +var secret = await client.GetSecretAsync(DAPR_SECRET_STORE, SECRET_NAME); +var secretValue = string.Join(", ", secret); +Console.WriteLine($"Fetched Secret: {secretValue}"); +``` + +**`local-secret-store.yaml`组件** + +`DAPR_SECRET_STORE`在`local-secret-store.yaml`组件文件中定义,位于[secrets_management/components](https://github.com/dapr/quickstarts/tree/master/secrets_management/components/local-secret-store.yaml): + +```yaml +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`定义了组件使用的机密的连接信息。 + +**`secrets.json`文件** + +`SECRET_NAME`在`secrets.json`文件中定义,位于[secrets_management/csharp/sdk/order-processor](https://github.com/dapr/quickstarts/tree/master/secrets_management/csharp/sdk/order-processor/secrets.json): + +```json +{ + "secret": "YourPasskeyHere" +} +``` + +### 步骤3:查看order-processor输出 + +如上面的应用程序代码中所示,`order-processor`服务通过Dapr机密存储检索机密并在控制台中显示。 + +Order-processor输出: + +``` +== APP == Fetched Secret: [secret, YourPasskeyHere] +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前置条件 + +您需要准备以下环境: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- Java JDK 17(或更高版本): + - [Oracle JDK](https://www.oracle.com/java/technologies/downloads),或 + - OpenJDK +- [Apache Maven](https://maven.apache.org/install.html),版本3.x。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/secrets_management/java/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤2:检索机密 + +在终端窗口中,导航到`order-processor`目录。 + +```bash +cd secrets_management/java/sdk/order-processor +``` + +安装依赖项: + +```bash +mvn clean install +``` + +运行`order-processor`服务及其Dapr sidecar。 + +```bash +dapr run --app-id order-processor --resources-path ../../../components/ -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar +``` + +#### 背后的原理 + +**`order-processor`服务** + +请注意,`order-processor`服务配置如下: + +- 使用在`local-secret-store.yaml`组件中定义的`DAPR_SECRET_STORE`。 +- 使用在`secrets.json`中定义的机密。 + +```java +// OrderProcessingServiceApplication.java +private static final String SECRET_STORE_NAME = "localsecretstore"; +// ... + Map secret = client.getSecret(SECRET_STORE_NAME, "secret").block(); + System.out.println("Fetched Secret: " + secret); +``` + +**`local-secret-store.yaml`组件** + +`DAPR_SECRET_STORE`在`local-secret-store.yaml`组件文件中定义,位于[secrets_management/components](https://github.com/dapr/quickstarts/tree/master/secrets_management/components/local-secret-store.yaml): + +```yaml +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`定义了组件使用的机密的连接信息。 + +**`secrets.json`文件** + +`SECRET_NAME`在`secrets.json`文件中定义,位于[secrets_management/java/sdk/order-processor](https://github.com/dapr/quickstarts/tree/master/secrets_management/java/sdk/order-processor/secrets.json): + +```json +{ + "secret": "YourPasskeyHere" +} +``` + +### 步骤3:查看order-processor输出 + +如上面的应用程序代码中所示,`order-processor`服务通过Dapr机密存储检索机密并在控制台中显示。 + +Order-processor输出: + +``` +== APP == Fetched Secret: {secret=YourPasskeyHere} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 前置条件 + +您需要准备以下环境: + +- [Dapr CLI和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/secrets_management/go/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤2:检索机密 + +在终端窗口中,导航到`order-processor`目录。 + +```bash +cd secrets_management/go/sdk/order-processor +``` + +安装依赖项: + +```bash +go build . +``` + +运行`order-processor`服务及其Dapr sidecar。 + +```bash +dapr run --app-id order-processor --resources-path ../../../components/ -- go run . +``` + +#### 背后的原理 + +**`order-processor`服务** + +请注意,`order-processor`服务配置如下: + +- 使用在`local-secret-store.yaml`组件中定义的`DAPR_SECRET_STORE`。 +- 使用在`secrets.json`中定义的机密。 + +```go +const DAPR_SECRET_STORE = "localsecretstore" +const SECRET_NAME = "secret" +// ... +secret, err := client.GetSecret(ctx, DAPR_SECRET_STORE, SECRET_NAME, nil) +if secret != nil { + fmt.Println("Fetched Secret: ", secret[SECRET_NAME]) +} +``` + +**`local-secret-store.yaml`组件** + +`DAPR_SECRET_STORE`在`local-secret-store.yaml`组件文件中定义,位于[secrets_management/components](https://github.com/dapr/quickstarts/tree/master/secrets_management/components/local-secret-store.yaml): + +```yaml +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`定义了组件使用的机密的连接信息。 + +**`secrets.json`文件** + +`SECRET_NAME`在`secrets.json`文件中定义,位于[secrets_management/go/sdk/order-processor](https://github.com/dapr/quickstarts/tree/master/secrets_management/go/sdk/order-processor/secrets.json): + +```json +{ + "secret": "YourPasskeyHere" +} +``` + +### 步骤3:查看order-processor输出 + +如上面的应用程序代码中所示,`order-processor`服务通过Dapr机密存储检索机密并在控制台中显示。 + +Order-processor输出: + +``` +== APP == Fetched Secret: YourPasskeyHere +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 告诉我们您的想法! + +我们正在不断改进我们的快速入门示例,重视您的反馈。您觉得这个快速入门有帮助吗?您有改进建议吗? + +加入我们的[discord频道](https://discord.com/channels/778680217417809931/953427615916638238)讨论。 + +## 下一步 + +- 使用HTTP而不是SDK来使用Dapr机密管理。 + - [Python](https://github.com/dapr/quickstarts/tree/master/secrets_management/python/http) + - [JavaScript](https://github.com/dapr/quickstarts/tree/master/secrets_management/javascript/http) + - [.NET](https://github.com/dapr/quickstarts/tree/master/secrets_management/csharp/http) + - [Java](https://github.com/dapr/quickstarts/tree/master/secrets_management/java/http) + - [Go](https://github.com/dapr/quickstarts/tree/master/secrets_management/go/http) +- 了解更多关于[机密管理构建块]({{< ref secrets-overview >}}) + +{{< button text="探索Dapr教程 >>" page="getting-started/tutorials/_index.md" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/serviceinvocation-quickstart.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/serviceinvocation-quickstart.md new file mode 100644 index 000000000..839d32d5d --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/serviceinvocation-quickstart.md @@ -0,0 +1,1422 @@ +--- +type: docs +title: "快速入门:服务调用" +linkTitle: "服务调用" +weight: 71 +description: "开始使用 Dapr 的服务调用模块" +--- + +通过 [Dapr 的服务调用模块](https://docs.dapr.io/developing-applications/building-blocks/service-invocation),您的应用程序可以稳定且安全地与其他应用程序进行通信。 + +显示服务调用步骤的图示 + +Dapr 提供了多种服务调用的方法,您可以根据具体需求进行选择。在本教程中,您将启用结账服务,通过 HTTP 代理调用订单处理服务中的方法,具体步骤如下: +- [使用多应用程序运行模板文件同时运行本示例中的所有应用程序]({{< ref "#run-using-multi-app-run" >}}),或 +- [一次运行一个应用程序]({{< ref "#run-one-application-at-a-time" >}}) + +在[概述文章]({{< ref service-invocation-overview.md >}})中了解更多关于 Dapr 服务调用方法的信息。 + +## 使用多应用程序运行 + +在继续本教程之前,请选择您偏好的编程语言。 + +{{< tabs "Python" "JavaScript" ".NET" "Java" "Go" >}} + +{{% codetab %}} + +### 步骤 1:准备工作 + +在此示例中,您需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装 Python 3.7+](https://www.python.org/downloads/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆 [快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation/python/http)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +从快速入门克隆目录的根目录,导航到快速入门目录。 + +```bash +cd service_invocation/python/http +``` + +为 `order-processor` 和 `checkout` 应用安装依赖项: + +```bash +cd ./order-processor +pip3 install -r requirements.txt +cd ../checkout +pip3 install -r requirements.txt +cd .. +``` + +### 步骤 3:运行 `order-processor` 和 `checkout` 服务 + +使用以下命令,同时运行以下服务及其各自的 Dapr 边车: +- `order-processor` 服务 +- `checkout` 服务 + +```bash +dapr run -f . +``` +> **注意**:在 Windows 中,由于未定义 Python3.exe,您可能需要在运行 `dapr run -f .` 之前将 [`dapr.yaml`]({{< ref "#dapryaml-multi-app-run-template-file" >}}) 文件中的 `python3` 更改为 `python` + +**预期输出** + +``` +== APP - order-processor == Order received : Order { orderId = 1 } +== APP - checkout == Order passed: Order { OrderId = 1 } +== APP - order-processor == Order received : Order { orderId = 2 } +== APP - checkout == Order passed: Order { OrderId = 2 } +== APP - order-processor == Order received : Order { orderId = 3 } +== APP - checkout == Order passed: Order { OrderId = 3 } +== APP - order-processor == Order received : Order { orderId = 4 } +== APP - checkout == Order passed: Order { OrderId = 4 } +== APP - order-processor == Order received : Order { orderId = 5 } +== APP - checkout == Order passed: Order { OrderId = 5 } +== APP - order-processor == Order received : Order { orderId = 6 } +== APP - checkout == Order passed: Order { OrderId = 6 } +== APP - order-processor == Order received : Order { orderId = 7 } +== APP - checkout == Order passed: Order { OrderId = 7 } +== APP - order-processor == Order received : Order { orderId = 8 } +== APP - checkout == Order passed: Order { OrderId = 8 } +== APP - order-processor == Order received : Order { orderId = 9 } +== APP - checkout == Order passed: Order { OrderId = 9 } +== APP - order-processor == Order received : Order { orderId = 10 } +== APP - checkout == Order passed: Order { OrderId = 10 } +== APP - order-processor == Order received : Order { orderId = 11 } +== APP - checkout == Order passed: Order { OrderId = 11 } +== APP - order-processor == Order received : Order { orderId = 12 } +== APP - checkout == Order passed: Order { OrderId = 12 } +== APP - order-processor == Order received : Order { orderId = 13 } +== APP - checkout == Order passed: Order { OrderId = 13 } +== APP - order-processor == Order received : Order { orderId = 14 } +== APP - checkout == Order passed: Order { OrderId = 14 } +== APP - order-processor == Order received : Order { orderId = 15 } +== APP - checkout == Order passed: Order { OrderId = 15 } +== APP - order-processor == Order received : Order { orderId = 16 } +== APP - checkout == Order passed: Order { OrderId = 16 } +== APP - order-processor == Order received : Order { orderId = 17 } +== APP - checkout == Order passed: Order { OrderId = 17 } +== APP - order-processor == Order received : Order { orderId = 18 } +== APP - checkout == Order passed: Order { OrderId = 18 } +== APP - order-processor == Order received : Order { orderId = 19 } +== APP - checkout == Order passed: Order { OrderId = 19 } +== APP - order-processor == Order received : Order { orderId = 20 } +== APP - checkout == Order passed: Order { OrderId = 20 } +Exited App successfully +``` + +### 发生了什么? + +在本教程中运行 `dapr run -f .` 使用 `dapr.yaml` 多应用程序运行模板文件启动了 [订阅者]({{< ref "#order-processor-service" >}}) 和 [发布者]({{< ref "#checkout-service" >}}) 应用程序。 + +##### `dapr.yaml` 多应用程序运行模板文件 + +使用 `dapr run -f .` 运行 [多应用程序运行模板文件]({{< ref multi-app-dapr-run >}}) 将启动项目中的所有应用程序。在本教程中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +apps: + - appDirPath: ./order-processor/ + appID: order-processor + appPort: 8001 + command: ["python3", "app.py"] + - appID: checkout + appDirPath: ./checkout/ + command: ["python3", "app.py"] +``` + +##### `order-processor` 服务 + +`order-processor` 服务接收来自 `checkout` 服务的调用: + +```py +@app.route('/orders', methods=['POST']) +def getOrder(): + data = request.json + print('Order received : ' + json.dumps(data), flush=True) + return json.dumps({'success': True}), 200, { + 'ContentType': 'application/json'} + + +app.run(port=8001) +``` + +#### `checkout` 服务 + +在 `checkout` 服务中,您会注意到无需重写应用程序代码即可使用 Dapr 的服务调用。您只需添加 `dapr-app-id` 头,该头指定目标服务的 ID,即可启用服务调用。 + +```python +headers = {'dapr-app-id': 'order-processor'} + +result = requests.post( + url='%s/orders' % (base_url), + data=json.dumps(order), + headers=headers +) +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:准备工作 + +在此示例中,您需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装最新的 Node.js](https://nodejs.org/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆 [快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation/javascript/http)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +从快速入门克隆目录的根目录,导航到快速入门目录。 + +```bash +cd service_invocation/javascript/http +``` + +为 `order-processor` 和 `checkout` 应用安装依赖项: + +```bash +cd ./order-processor +npm install +cd ../checkout +npm install +cd .. +``` + +### 步骤 3:运行 `order-processor` 和 `checkout` 服务 + +使用以下命令,同时运行以下服务及其各自的 Dapr 边车: +- `order-processor` 服务 +- `checkout` 服务 + +```bash +dapr run -f . +``` + +**预期输出** + +``` +== APP - order-processor == Order received : Order { orderId = 1 } +== APP - checkout == Order passed: Order { OrderId = 1 } +== APP - order-processor == Order received : Order { orderId = 2 } +== APP - checkout == Order passed: Order { OrderId = 2 } +== APP - order-processor == Order received : Order { orderId = 3 } +== APP - checkout == Order passed: Order { OrderId = 3 } +== APP - order-processor == Order received : Order { orderId = 4 } +== APP - checkout == Order passed: Order { OrderId = 4 } +== APP - order-processor == Order received : Order { orderId = 5 } +== APP - checkout == Order passed: Order { OrderId = 5 } +== APP - order-processor == Order received : Order { orderId = 6 } +== APP - checkout == Order passed: Order { OrderId = 6 } +== APP - order-processor == Order received : Order { orderId = 7 } +== APP - checkout == Order passed: Order { OrderId = 7 } +== APP - order-processor == Order received : Order { orderId = 8 } +== APP - checkout == Order passed: Order { OrderId = 8 } +== APP - order-processor == Order received : Order { orderId = 9 } +== APP - checkout == Order passed: Order { OrderId = 9 } +== APP - order-processor == Order received : Order { orderId = 10 } +== APP - checkout == Order passed: Order { OrderId = 10 } +== APP - order-processor == Order received : Order { orderId = 11 } +== APP - checkout == Order passed: Order { OrderId = 11 } +== APP - order-processor == Order received : Order { orderId = 12 } +== APP - checkout == Order passed: Order { OrderId = 12 } +== APP - order-processor == Order received : Order { orderId = 13 } +== APP - checkout == Order passed: Order { OrderId = 13 } +== APP - order-processor == Order received : Order { orderId = 14 } +== APP - checkout == Order passed: Order { OrderId = 14 } +== APP - order-processor == Order received : Order { orderId = 15 } +== APP - checkout == Order passed: Order { OrderId = 15 } +== APP - order-processor == Order received : Order { orderId = 16 } +== APP - checkout == Order passed: Order { OrderId = 16 } +== APP - order-processor == Order received : Order { orderId = 17 } +== APP - checkout == Order passed: Order { OrderId = 17 } +== APP - order-processor == Order received : Order { orderId = 18 } +== APP - checkout == Order passed: Order { OrderId = 18 } +== APP - order-processor == Order received : Order { orderId = 19 } +== APP - checkout == Order passed: Order { OrderId = 19 } +== APP - order-processor == Order received : Order { orderId = 20 } +== APP - checkout == Order passed: Order { OrderId = 20 } +Exited App successfully +``` + +### 发生了什么? + +在本教程中运行 `dapr run -f .` 使用 `dapr.yaml` 多应用程序运行模板文件启动了 [订阅者]({{< ref "#order-processor-service" >}}) 和 [发布者]({{< ref "#checkout-service" >}}) 应用程序。 + +##### `dapr.yaml` 多应用程序运行模板文件 + +使用 `dapr run -f .` 运行 [多应用程序运行模板文件]({{< ref multi-app-dapr-run >}}) 将启动项目中的所有应用程序。在本教程中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +apps: + - appDirPath: ./order-processor/ + appID: order-processor + appPort: 5001 + command: ["npm", "start"] + - appID: checkout + appDirPath: ./checkout/ + command: ["npm", "start"] +``` + +##### `order-processor` 服务 + +`order-processor` 服务接收来自 `checkout` 服务的调用: + +```javascript +app.post('/orders', (req, res) => { + console.log("Order received:", req.body); + res.sendStatus(200); +}); +``` + +##### `checkout` 服务 + +在 `checkout` 服务中,您会注意到无需重写应用程序代码即可使用 Dapr 的服务调用。您只需添加 `dapr-app-id` 头,该头指定目标服务的 ID,即可启用服务调用。 + +```javascript +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); +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:准备工作 + +在此示例中,您需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + +- [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0)、[.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) 或 [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) 已安装 + +**注意:** .NET 6 是此版本中 Dapr .NET SDK 包的最低支持版本。仅 .NET 8 和 .NET 9 将在 Dapr v1.16 及更高版本中得到支持。 + +### 步骤 2:设置环境 + +克隆 [快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation/csharp/http)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +从快速入门克隆目录的根目录,导航到快速入门目录。 + +```bash +cd service_invocation/csharp/http +``` + +为 `order-processor` 和 `checkout` 应用安装依赖项: + +```bash +cd ./order-processor +dotnet restore +dotnet build +cd ../checkout +dotnet restore +dotnet build +cd .. +``` + +### 步骤 3:运行 `order-processor` 和 `checkout` 服务 + +使用以下命令,同时运行以下服务及其各自的 Dapr 边车: +- `order-processor` 服务 +- `checkout` 服务 + +```bash +dapr run -f . +``` + +**预期输出** + +``` +== APP - order-processor == Order received : Order { orderId = 1 } +== APP - checkout == Order passed: Order { OrderId = 1 } +== APP - order-processor == Order received : Order { orderId = 2 } +== APP - checkout == Order passed: Order { OrderId = 2 } +== APP - order-processor == Order received : Order { orderId = 3 } +== APP - checkout == Order passed: Order { OrderId = 3 } +== APP - order-processor == Order received : Order { orderId = 4 } +== APP - checkout == Order passed: Order { OrderId = 4 } +== APP - order-processor == Order received : Order { orderId = 5 } +== APP - checkout == Order passed: Order { OrderId = 5 } +== APP - order-processor == Order received : Order { orderId = 6 } +== APP - checkout == Order passed: Order { OrderId = 6 } +== APP - order-processor == Order received : Order { orderId = 7 } +== APP - checkout == Order passed: Order { OrderId = 7 } +== APP - order-processor == Order received : Order { orderId = 8 } +== APP - checkout == Order passed: Order { OrderId = 8 } +== APP - order-processor == Order received : Order { orderId = 9 } +== APP - checkout == Order passed: Order { OrderId = 9 } +== APP - order-processor == Order received : Order { orderId = 10 } +== APP - checkout == Order passed: Order { OrderId = 10 } +== APP - order-processor == Order received : Order { orderId = 11 } +== APP - checkout == Order passed: Order { OrderId = 11 } +== APP - order-processor == Order received : Order { orderId = 12 } +== APP - checkout == Order passed: Order { OrderId = 12 } +== APP - order-processor == Order received : Order { orderId = 13 } +== APP - checkout == Order passed: Order { OrderId = 13 } +== APP - order-processor == Order received : Order { orderId = 14 } +== APP - checkout == Order passed: Order { OrderId = 14 } +== APP - order-processor == Order received : Order { orderId = 15 } +== APP - checkout == Order passed: Order { OrderId = 15 } +== APP - order-processor == Order received : Order { orderId = 16 } +== APP - checkout == Order passed: Order { OrderId = 16 } +== APP - order-processor == Order received : Order { orderId = 17 } +== APP - checkout == Order passed: Order { OrderId = 17 } +== APP - order-processor == Order received : Order { orderId = 18 } +== APP - checkout == Order passed: Order { OrderId = 18 } +== APP - order-processor == Order received : Order { orderId = 19 } +== APP - checkout == Order passed: Order { OrderId = 19 } +== APP - order-processor == Order received : Order { orderId = 20 } +== APP - checkout == Order passed: Order { OrderId = 20 } +Exited App successfully +``` + +### 发生了什么? + +在本教程中运行 `dapr run -f .` 使用 `dapr.yaml` 多应用程序运行模板文件启动了 [订阅者]({{< ref "#order-processor-service" >}}) 和 [发布者]({{< ref "#checkout-service" >}}) 应用程序。 + +##### `dapr.yaml` 多应用程序运行模板文件 + +使用 `dapr run -f .` 运行 [多应用程序运行模板文件]({{< ref multi-app-dapr-run >}}) 将启动项目中的所有应用程序。在本教程中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +apps: + - appDirPath: ./order-processor/ + appID: order-processor + appPort: 7001 + command: ["dotnet", "run"] + - appID: checkout + appDirPath: ./checkout/ + command: ["dotnet", "run"] +``` + +##### `order-processor` 服务 + +`order-processor` 服务接收来自 `checkout` 服务的调用: + +```csharp +app.MapPost("/orders", (Order order) => +{ + Console.WriteLine("Order received : " + order); + return order.ToString(); +}); +``` + +##### `checkout` 服务 + +在 `checkout` 服务的 Program.cs 文件中,您会注意到无需重写应用程序代码即可使用 Dapr 的服务调用。您只需添加 `dapr-app-id` 头,该头指定目标服务的 ID,即可启用服务调用。 + +```csharp +var client = new HttpClient(); +client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); + +client.DefaultRequestHeaders.Add("dapr-app-id", "order-processor"); + +var response = await client.PostAsync($"{baseURL}/orders", content); + Console.WriteLine("Order passed: " + order); +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:准备工作 + +在此示例中,您需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- Java JDK 17(或更高版本): + - [Oracle JDK](https://www.oracle.com/java/technologies/downloads),或 + - OpenJDK +- [Apache Maven](https://maven.apache.org/install.html),版本 3.x。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆 [快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation/java/http)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +从快速入门克隆目录的根目录,导航到快速入门目录。 + +```bash +cd service_invocation/java/http +``` + +为 `order-processor` 和 `checkout` 应用安装依赖项: + +```bash +cd ./order-processor +mvn clean install +cd ../checkout +mvn clean install +cd .. +``` + +### 步骤 3:运行 `order-processor` 和 `checkout` 服务 + +使用以下命令,同时运行以下服务及其各自的 Dapr 边车: +- `order-processor` 服务 +- `checkout` 服务 + +```bash +dapr run -f . +``` + +**预期输出** + +``` +== APP - order-processor == Order received : Order { orderId = 1 } +== APP - checkout == Order passed: Order { OrderId = 1 } +== APP - order-processor == Order received : Order { orderId = 2 } +== APP - checkout == Order passed: Order { OrderId = 2 } +== APP - order-processor == Order received : Order { orderId = 3 } +== APP - checkout == Order passed: Order { OrderId = 3 } +== APP - order-processor == Order received : Order { orderId = 4 } +== APP - checkout == Order passed: Order { OrderId = 4 } +== APP - order-processor == Order received : Order { orderId = 5 } +== APP - checkout == Order passed: Order { OrderId = 5 } +== APP - order-processor == Order received : Order { orderId = 6 } +== APP - checkout == Order passed: Order { OrderId = 6 } +== APP - order-processor == Order received : Order { orderId = 7 } +== APP - checkout == Order passed: Order { OrderId = 7 } +== APP - order-processor == Order received : Order { orderId = 8 } +== APP - checkout == Order passed: Order { OrderId = 8 } +== APP - order-processor == Order received : Order { orderId = 9 } +== APP - checkout == Order passed: Order { OrderId = 9 } +== APP - order-processor == Order received : Order { orderId = 10 } +== APP - checkout == Order passed: Order { OrderId = 10 } +== APP - order-processor == Order received : Order { orderId = 11 } +== APP - checkout == Order passed: Order { OrderId = 11 } +== APP - order-processor == Order received : Order { orderId = 12 } +== APP - checkout == Order passed: Order { OrderId = 12 } +== APP - order-processor == Order received : Order { orderId = 13 } +== APP - checkout == Order passed: Order { OrderId = 13 } +== APP - order-processor == Order received : Order { orderId = 14 } +== APP - checkout == Order passed: Order { OrderId = 14 } +== APP - order-processor == Order received : Order { orderId = 15 } +== APP - checkout == Order passed: Order { OrderId = 15 } +== APP - order-processor == Order received : Order { orderId = 16 } +== APP - checkout == Order passed: Order { OrderId = 16 } +== APP - order-processor == Order received : Order { orderId = 17 } +== APP - checkout == Order passed: Order { OrderId = 17 } +== APP - order-processor == Order received : Order { orderId = 18 } +== APP - checkout == Order passed: Order { OrderId = 18 } +== APP - order-processor == Order received : Order { orderId = 19 } +== APP - checkout == Order passed: Order { OrderId = 19 } +== APP - order-processor == Order received : Order { orderId = 20 } +== APP - checkout == Order passed: Order { OrderId = 20 } +Exited App successfully +``` + +### 发生了什么? + +在本教程中运行 `dapr run -f .` 使用 `dapr.yaml` 多应用程序运行模板文件启动了 [订阅者]({{< ref "#order-processor-service" >}}) 和 [发布者]({{< ref "#checkout-service" >}}) 应用程序。 + +##### `dapr.yaml` 多应用程序运行模板文件 + +使用 `dapr run -f .` 运行 [多应用程序运行模板文件]({{< ref multi-app-dapr-run >}}) 将启动项目中的所有应用程序。在本教程中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +apps: + - appDirPath: ./order-processor/ + appID: order-processor + appPort: 9001 + command: ["java", "-jar", "target/OrderProcessingService-0.0.1-SNAPSHOT.jar"] + - appID: checkout + appDirPath: ./checkout/ + command: ["java", "-jar", "target/CheckoutService-0.0.1-SNAPSHOT.jar"] +``` + +##### `order-processor` 服务 + +`order-processor` 服务接收来自 `checkout` 服务的调用: + +```java +public String processOrders(@RequestBody Order body) { + System.out.println("Order received: "+ body.getOrderId()); + return "CID" + body.getOrderId(); + } +``` + +##### `checkout` 服务 + +在 `checkout` 服务中,您会注意到无需重写应用程序代码即可使用 Dapr 的服务调用。您只需添加 `dapr-app-id` 头,该头指定目标服务的 ID,即可启用服务调用。 + +```java +.header("Content-Type", "application/json") +.header("dapr-app-id", "order-processor") + +HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); +System.out.println("Order passed: "+ orderId) +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:准备工作 + +在此示例中,您需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的 Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆 [快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation/go/http)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +从快速入门克隆目录的根目录,导航到快速入门目录。 + +```bash +cd service_invocation/go/http +``` + +为 `order-processor` 和 `checkout` 应用安装依赖项: + +```bash +cd ./order-processor +go build . +cd ../checkout +go build . +cd .. +``` + +### 步骤 3:运行 `order-processor` 和 `checkout` 服务 + +使用以下命令,同时运行以下服务及其各自的 Dapr 边车: +- `order-processor` 服务 +- `checkout` 服务 + +```bash +dapr run -f . +``` + +**预期输出** + +``` +== APP - order-processor == Order received : Order { orderId = 1 } +== APP - checkout == Order passed: Order { OrderId = 1 } +== APP - order-processor == Order received : Order { orderId = 2 } +== APP - checkout == Order passed: Order { OrderId = 2 } +== APP - order-processor == Order received : Order { orderId = 3 } +== APP - checkout == Order passed: Order { OrderId = 3 } +== APP - order-processor == Order received : Order { orderId = 4 } +== APP - checkout == Order passed: Order { OrderId = 4 } +== APP - order-processor == Order received : Order { orderId = 5 } +== APP - checkout == Order passed: Order { OrderId = 5 } +== APP - order-processor == Order received : Order { orderId = 6 } +== APP - checkout == Order passed: Order { OrderId = 6 } +== APP - order-processor == Order received : Order { orderId = 7 } +== APP - checkout == Order passed: Order { OrderId = 7 } +== APP - order-processor == Order received : Order { orderId = 8 } +== APP - checkout == Order passed: Order { OrderId = 8 } +== APP - order-processor == Order received : Order { orderId = 9 } +== APP - checkout == Order passed: Order { OrderId = 9 } +== APP - order-processor == Order received : Order { orderId = 10 } +== APP - checkout == Order passed: Order { OrderId = 10 } +== APP - order-processor == Order received : Order { orderId = 11 } +== APP - checkout == Order passed: Order { OrderId = 11 } +== APP - order-processor == Order received : Order { orderId = 12 } +== APP - checkout == Order passed: Order { OrderId = 12 } +== APP - order-processor == Order received : Order { orderId = 13 } +== APP - checkout == Order passed: Order { OrderId = 13 } +== APP - order-processor == Order received : Order { orderId = 14 } +== APP - checkout == Order passed: Order { OrderId = 14 } +== APP - order-processor == Order received : Order { orderId = 15 } +== APP - checkout == Order passed: Order { OrderId = 15 } +== APP - order-processor == Order received : Order { orderId = 16 } +== APP - checkout == Order passed: Order { OrderId = 16 } +== APP - order-processor == Order received : Order { orderId = 17 } +== APP - checkout == Order passed: Order { OrderId = 17 } +== APP - order-processor == Order received : Order { orderId = 18 } +== APP - checkout == Order passed: Order { OrderId = 18 } +== APP - order-processor == Order received : Order { orderId = 19 } +== APP - checkout == Order passed: Order { OrderId = 19 } +== APP - order-processor == Order received : Order { orderId = 20 } +== APP - checkout == Order passed: Order { OrderId = 20 } +Exited App successfully +``` + +### 发生了什么? + +在本教程中运行 `dapr run -f .` 使用 `dapr.yaml` 多应用程序运行模板文件启动了 [订阅者]({{< ref "#order-processor-service" >}}) 和 [发布者]({{< ref "#checkout-service" >}}) 应用程序。 + +##### `dapr.yaml` 多应用程序运行模板文件 + +使用 `dapr run -f .` 运行 [多应用程序运行模板文件]({{< ref multi-app-dapr-run >}}) 将启动项目中的所有应用程序。在本教程中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +apps: + - appDirPath: ./order-processor/ + appID: order-processor + appPort: 6006 + command: ["go", "run", "."] + - appID: checkout + appDirPath: ./checkout/ + command: ["go", "run", "."] +``` + +##### `order-processor` 服务 + +在 `order-processor` 服务中,每个订单通过 HTTP POST 请求接收并由 `getOrder` 函数处理。 + +```go +func getOrder(w http.ResponseWriter, r *http.Request) { + data, err := ioutil.ReadAll(r.Body) + if err != nil { + log.Fatal(err) + } + log.Printf("Order received : %s", string(data)) +} +``` + +##### `checkout` 服务 + +在 `checkout` 服务中,您会注意到无需重写应用程序代码即可使用 Dapr 的服务调用。您只需添加 `dapr-app-id` 头,该头指定目标服务的 ID,即可启用服务调用。 + +```go +req.Header.Add("dapr-app-id", "order-processor") + +response, err := client.Do(req) +``` + +{{% /codetab %}} + +{{% /tabs %}} + +## 一次运行一个应用程序 + +在继续本教程之前,请选择您偏好的编程语言。 + +{{< tabs "Python" "JavaScript" ".NET" "Java" "Go" >}} + +{{% codetab %}} + +### 步骤 1:准备工作 + +在此示例中,您需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装 Python 3.7+](https://www.python.org/downloads/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆 [快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 3:运行 `order-processor` 服务 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `order-processor` 目录。 + +```bash +cd service_invocation/python/http/order-processor +``` + +安装依赖项并构建应用程序: + +```bash +pip3 install -r requirements.txt +``` + +在 Dapr 边车旁边运行 `order-processor` 服务。 + +```bash +dapr run --app-port 8001 --app-id order-processor --app-protocol http --dapr-http-port 3501 -- python3 app.py +``` + +> **注意**:在 Windows 中,由于未定义 Python3.exe,您可能需要使用 `python app.py` 而不是 `python3 app.py`。 + +```py +@app.route('/orders', methods=['POST']) +def getOrder(): + data = request.json + print('Order received : ' + json.dumps(data), flush=True) + return json.dumps({'success': True}), 200, { + 'ContentType': 'application/json'} + + +app.run(port=8001) +``` + +### 步骤 4:运行 `checkout` 服务 + +在新的终端窗口中,从快速入门克隆目录的根目录导航到 `checkout` 目录。 + +```bash +cd service_invocation/python/http/checkout +``` + +安装依赖项并构建应用程序: + +```bash +pip3 install -r requirements.txt +``` + +在 Dapr 边车旁边运行 `checkout` 服务。 + +```bash +dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- python3 app.py +``` + +> **注意**:在 Windows 中,由于未定义 Python3.exe,您可能需要使用 `python app.py` 而不是 `python3 app.py`。 + +在 `checkout` 服务中,您会注意到无需重写应用程序代码即可使用 Dapr 的服务调用。您只需添加 `dapr-app-id` 头,该头指定目标服务的 ID,即可启用服务调用。 + +```python +headers = {'dapr-app-id': 'order-processor'} + +result = requests.post( + url='%s/orders' % (base_url), + data=json.dumps(order), + headers=headers +) +``` + +### 步骤 5:使用多应用程序运行 + +您可以使用 [多应用程序运行模板]({{< ref multi-app-dapr-run >}}) 运行本教程中的 Dapr 应用程序。无需为 `order-processor` 和 `checkout` 应用程序运行两个单独的 `dapr run` 命令,只需运行以下命令: + +```sh +dapr run -f . +``` + +要停止所有应用程序,请运行: + +```sh +dapr stop -f . +``` + +### 步骤 6:查看服务调用输出 + +Dapr 在任何 Dapr 实例上调用应用程序。在代码中,边车编程模型鼓励每个应用程序与其自己的 Dapr 实例通信。然后,Dapr 实例发现并相互通信。 + +`checkout` 服务输出: + +``` +== APP == Order passed: {"orderId": 1} +== APP == Order passed: {"orderId": 2} +== APP == Order passed: {"orderId": 3} +== APP == Order passed: {"orderId": 4} +== APP == Order passed: {"orderId": 5} +== APP == Order passed: {"orderId": 6} +== APP == Order passed: {"orderId": 7} +== APP == Order passed: {"orderId": 8} +== APP == Order passed: {"orderId": 9} +== APP == Order passed: {"orderId": 10} +``` + +`order-processor` 服务输出: + +``` +== APP == Order received: {"orderId": 1} +== APP == Order received: {"orderId": 2} +== APP == Order received: {"orderId": 3} +== APP == Order received: {"orderId": 4} +== APP == Order received: {"orderId": 5} +== APP == Order received: {"orderId": 6} +== APP == Order received: {"orderId": 7} +== APP == Order received: {"orderId": 8} +== APP == Order received: {"orderId": 9} +== APP == Order received: {"orderId": 10} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:准备工作 + +在此示例中,您需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装最新的 Node.js](https://nodejs.org/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆 [快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 3:运行 `order-processor` 服务 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `order-processor` 目录。 + +```bash +cd service_invocation/javascript/http/order-processor +``` + +安装依赖项: + +```bash +npm install +``` + +在 Dapr 边车旁边运行 `order-processor` 服务。 + +```bash +dapr run --app-port 5001 --app-id order-processor --app-protocol http --dapr-http-port 3501 -- npm start +``` + +```javascript +app.post('/orders', (req, res) => { + console.log("Order received:", req.body); + res.sendStatus(200); +}); +``` + +### 步骤 4:运行 `checkout` 服务 + +在新的终端窗口中,从快速入门克隆目录的根目录导航到 `checkout` 目录。 + +```bash +cd service_invocation/javascript/http/checkout +``` + +安装依赖项: + +```bash +npm install +``` + +在 Dapr 边车旁边运行 `checkout` 服务。 + +```bash +dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- npm start +``` + +在 `checkout` 服务中,您会注意到无需重写应用程序代码即可使用 Dapr 的服务调用。您只需添加 `dapr-app-id` 头,该头指定目标服务的 ID,即可启用服务调用。 + +```javascript +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); +``` + +### 步骤 5:使用多应用程序运行 + +您可以使用 [多应用程序运行模板]({{< ref multi-app-dapr-run >}}) 运行本教程中的 Dapr 应用程序。无需为 `order-processor` 和 `checkout` 应用程序运行两个单独的 `dapr run` 命令,只需运行以下命令: + +```sh +dapr run -f . +``` + +要停止所有应用程序,请运行: + +```sh +dapr stop -f . +``` + +### 步骤 6:查看服务调用输出 + +Dapr 在任何 Dapr 实例上调用应用程序。在代码中,边车编程模型鼓励每个应用程序与其自己的 Dapr 实例通信。然后,Dapr 实例发现并相互通信。 + +`checkout` 服务输出: + +``` +== APP == Order passed: {"orderId": 1} +== APP == Order passed: {"orderId": 2} +== APP == Order passed: {"orderId": 3} +== APP == Order passed: {"orderId": 4} +== APP == Order passed: {"orderId": 5} +== APP == Order passed: {"orderId": 6} +== APP == Order passed: {"orderId": 7} +== APP == Order passed: {"orderId": 8} +== APP == Order passed: {"orderId": 9} +== APP == Order passed: {"orderId": 10} +``` + +`order-processor` 服务输出: + +``` +== APP == Order received: {"orderId": 1} +== APP == Order received: {"orderId": 2} +== APP == Order received: {"orderId": 3} +== APP == Order received: {"orderId": 4} +== APP == Order received: {"orderId": 5} +== APP == Order received: {"orderId": 6} +== APP == Order received: {"orderId": 7} +== APP == Order received: {"orderId": 8} +== APP == Order received: {"orderId": 9} +== APP == Order received: {"orderId": 10} +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:准备工作 + +在此示例中,您需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [.NET SDK 或 .NET 7 SDK 已安装](https://dotnet.microsoft.com/download)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆 [快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 3:运行 `order-processor` 服务 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `order-processor` 目录。 + +```bash +cd service_invocation/csharp/http/order-processor +``` + +安装依赖项: + +```bash +dotnet restore +dotnet build +``` + +在 Dapr 边车旁边运行 `order-processor` 服务。 + +```bash +dapr run --app-port 7001 --app-id order-processor --app-protocol http --dapr-http-port 3501 -- dotnet run +``` + +以下是订单处理器 `Program.cs` 文件中的工作代码块。 + +```csharp +app.MapPost("/orders", (Order order) => +{ + Console.WriteLine("Order received : " + order); + return order.ToString(); +}); +``` + +### 步骤 4:运行 `checkout` 服务 + +在新的终端窗口中,从快速入门克隆目录的根目录导航到 `checkout` 目录。 + +```bash +cd service_invocation/csharp/http/checkout +``` + +安装依赖项: + +```bash +dotnet restore +dotnet build +``` + +在 Dapr 边车旁边运行 `checkout` 服务。 + +```bash +dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- dotnet run +``` + +在 `checkout` 服务的 Program.cs 文件中,您会注意到无需重写应用程序代码即可使用 Dapr 的服务调用。您只需添加 `dapr-app-id` 头,该头指定目标服务的 ID,即可启用服务调用。 + +```csharp +var client = new HttpClient(); +client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); + +client.DefaultRequestHeaders.Add("dapr-app-id", "order-processor"); + +var response = await client.PostAsync($"{baseURL}/orders", content); + Console.WriteLine("Order passed: " + order); +``` + +### 步骤 5:使用多应用程序运行 + +您可以使用 [多应用程序运行模板]({{< ref multi-app-dapr-run >}}) 运行本教程中的 Dapr 应用程序。无需为 `order-processor` 和 `checkout` 应用程序运行两个单独的 `dapr run` 命令,只需运行以下命令: + +```sh +dapr run -f . +``` + +要停止所有应用程序,请运行: + +```sh +dapr stop -f . +``` + +### 步骤 6:查看服务调用输出 + +Dapr 在任何 Dapr 实例上调用应用程序。在代码中,边车编程模型鼓励每个应用程序与其自己的 Dapr 实例通信。然后,Dapr 实例发现并相互通信。 + +`checkout` 服务输出: + +``` +== APP == Order passed: Order { OrderId: 1 } +== APP == Order passed: Order { OrderId: 2 } +== APP == Order passed: Order { OrderId: 3 } +== APP == Order passed: Order { OrderId: 4 } +== APP == Order passed: Order { OrderId: 5 } +== APP == Order passed: Order { OrderId: 6 } +== APP == Order passed: Order { OrderId: 7 } +== APP == Order passed: Order { OrderId: 8 } +== APP == Order passed: Order { OrderId: 9 } +== APP == Order passed: Order { OrderId: 10 } +``` + +`order-processor` 服务输出: + +``` +== APP == Order received: Order { OrderId: 1 } +== APP == Order received: Order { OrderId: 2 } +== APP == Order received: Order { OrderId: 3 } +== APP == Order received: Order { OrderId: 4 } +== APP == Order received: Order { OrderId: 5 } +== APP == Order received: Order { OrderId: 6 } +== APP == Order received: Order { OrderId: 7 } +== APP == Order received: Order { OrderId: 8 } +== APP == Order received: Order { OrderId: 9 } +== APP == Order received: Order { OrderId: 10 } +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:准备工作 + +在此示例中,您需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- Java JDK 17(或更高版本): + - [Oracle JDK](https://www.oracle.com/java/technologies/downloads),或 + - OpenJDK +- [Apache Maven](https://maven.apache.org/install.html),版本 3.x。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆 [快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 3:运行 `order-processor` 服务 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `order-processor` 目录。 + +```bash +cd service_invocation/java/http/order-processor +``` + +安装依赖项: + +```bash +mvn clean install +``` + +在 Dapr 边车旁边运行 `order-processor` 服务。 + +```bash +dapr run --app-id order-processor --app-port 9001 --app-protocol http --dapr-http-port 3501 -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar +``` + +```java +public String processOrders(@RequestBody Order body) { + System.out.println("Order received: "+ body.getOrderId()); + return "CID" + body.getOrderId(); + } +``` + +### 步骤 4:运行 `checkout` 服务 + +在新的终端窗口中,从快速入门克隆目录的根目录导航到 `checkout` 目录。 + +```bash +cd service_invocation/java/http/checkout +``` + +安装依赖项: + +```bash +mvn clean install +``` + +在 Dapr 边车旁边运行 `checkout` 服务。 + +```bash +dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- java -jar target/CheckoutService-0.0.1-SNAPSHOT.jar +``` + +在 `checkout` 服务中,您会注意到无需重写应用程序代码即可使用 Dapr 的服务调用。您只需添加 `dapr-app-id` 头,该头指定目标服务的 ID,即可启用服务调用。 + +```java +.header("Content-Type", "application/json") +.header("dapr-app-id", "order-processor") + +HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); +System.out.println("Order passed: "+ orderId) +``` + +### 步骤 5:使用多应用程序运行 + +您可以使用 [多应用程序运行模板]({{< ref multi-app-dapr-run >}}) 运行本教程中的 Dapr 应用程序。无需为 `order-processor` 和 `checkout` 应用程序运行两个单独的 `dapr run` 命令,只需运行以下命令: + +```sh +dapr run -f . +``` + +要停止所有应用程序,请运行: + +```sh +dapr stop -f . +``` + +### 步骤 6:查看服务调用输出 + +Dapr 在任何 Dapr 实例上调用应用程序。在代码中,边车编程模型鼓励每个应用程序与其自己的 Dapr 实例通信。然后,Dapr 实例发现并相互通信。 + +`checkout` 服务输出: + +``` +== APP == Order passed: 1 +== APP == Order passed: 2 +== APP == Order passed: 3 +== APP == Order passed: 4 +== APP == Order passed: 5 +== APP == Order passed: 6 +== APP == Order passed: 7 +== APP == Order passed: 8 +== APP == Order passed: 9 +== APP == Order passed: 10 +``` + +`order-processor` 服务输出: + +``` +== APP == Order received: 1 +== APP == Order received: 2 +== APP == Order received: 3 +== APP == Order received: 4 +== APP == Order received: 5 +== APP == Order received: 6 +== APP == Order received: 7 +== APP == Order received: 8 +== APP == Order received: 9 +== APP == Order received: 10 +``` + +{{% /codetab %}} + + +{{% codetab %}} + +### 步骤 1:准备工作 + +在此示例中,您需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的 Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆 [快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/service_invocation)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 3:运行 `order-processor` 服务 + +在终端窗口中,从快速入门克隆目录的根目录导航到 `order-processor` 目录。 + +```bash +cd service_invocation/go/http/order-processor +``` + +安装依赖项: + +```bash +go build . +``` + +在 Dapr 边车旁边运行 `order-processor` 服务。 + +```bash +dapr run --app-port 6006 --app-id order-processor --app-protocol http --dapr-http-port 3501 -- go run . +``` + +每个订单通过 HTTP POST 请求接收并由 `getOrder` 函数处理。 + +```go +func getOrder(w http.ResponseWriter, r *http.Request) { + data, err := ioutil.ReadAll(r.Body) + if err != nil { + log.Fatal(err) + } + log.Printf("Order received : %s", string(data)) +} +``` + +### 步骤 4:运行 `checkout` 服务 + +在新的终端窗口中,从快速入门克隆目录的根目录导航到 `checkout` 目录。 + +```bash +cd service_invocation/go/http/checkout +``` + +安装依赖项: + +```bash +go build . +``` + +在 Dapr 边车旁边运行 `checkout` 服务。 + +```bash +dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- go run . +``` + +在 `checkout` 服务中,您会注意到无需重写应用程序代码即可使用 Dapr 的服务调用。您只需添加 `dapr-app-id` 头,该头指定目标服务的 ID,即可启用服务调用。 + +```go +req.Header.Add("dapr-app-id", "order-processor") + +response, err := client.Do(req) +``` + +### 步骤 5:使用多应用程序运行 + +您可以使用 [多应用程序运行模板]({{< ref multi-app-dapr-run >}}) 运行本教程中的 Dapr 应用程序。无需为 `order-processor` 和 `checkout` 应用程序运行两个单独的 `dapr run` 命令,只需运行以下命令: + +```sh +dapr run -f . +``` + +要停止所有应用程序,请运行: + +```sh +dapr stop -f . +``` + +### 步骤 6:查看服务调用输出 + +Dapr 在任何 Dapr 实例上调用应用程序。在代码中,边车编程模型鼓励每个应用程序与其自己的 Dapr 实例通信。然后,Dapr 实例发现并相互通信。 + +`checkout` 服务输出: + +``` +== APP == Order passed: {"orderId":1} +== APP == Order passed: {"orderId":2} +== APP == Order passed: {"orderId":3} +== APP == Order passed: {"orderId":4} +== APP == Order passed: {"orderId":5} +== APP == Order passed: {"orderId":6} +== APP == Order passed: {"orderId":7} +== APP == Order passed: {"orderId":8} +== APP == Order passed: {"orderId":9} +== APP == Order passed: {"orderId":10} +``` + +`order-processor` 服务输出: + +``` +== APP == Order received : {"orderId":1} +== APP == Order received : {"orderId":2} +== APP == Order received : {"orderId":3} +== APP == Order received : {"orderId":4} +== APP == Order received : {"orderId":5} +== APP == Order received : {"orderId":6} +== APP == Order received : {"orderId":7} +== APP == Order received : {"orderId":8} +== APP == Order received : {"orderId":9} +== APP == Order received : {"orderId":10} +``` + +{{% /codetab %}} + +{{% /tabs %}} + +## 告诉我们您的想法! +我们正在不断努力改进我们的快速入门示例,并重视您的反馈。您觉得这个快速入门有帮助吗?您有改进建议吗? + +加入我们的 [discord 频道](https://discord.com/channels/778680217417809931/953427615916638238)进行讨论。 + +## 下一步 + +- 了解有关 [作为 Dapr 构建块的服务调用]({{< ref service-invocation-overview.md >}}) 的更多信息 +- 了解更多关于如何使用以下方式调用 Dapr 的服务调用: + - [HTTP]({{< ref howto-invoke-discover-services.md >}}),或 + - [gRPC]({{< ref howto-invoke-services-grpc.md >}}) + +{{< button text="探索 Dapr 教程 >>" page="getting-started/tutorials/_index.md" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/statemanagement-quickstart.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/statemanagement-quickstart.md new file mode 100644 index 000000000..20209c9b8 --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/statemanagement-quickstart.md @@ -0,0 +1,1304 @@ +--- +type: docs +title: "快速入门:状态管理" +linkTitle: "状态管理" +weight: 74 +description: "开始使用 Dapr 的状态管理模块" +--- + +本文将介绍 Dapr 的[状态管理模块]({{< ref state-management >}})。在本快速入门指南中,您将学习如何使用 Redis 状态存储来保存、获取和删除状态。您可以选择以下两种方式之一: +- [使用多应用运行模板文件同时启动所有应用]({{< ref "#run-using-multi-app-run" >}}),或 +- [一次运行一个应用]({{< ref "#run-one-application-at-a-time" >}}) + + + +虽然本示例使用了 Redis,您也可以替换为其他[支持的状态存储]({{< ref supported-state-stores.md >}})。 + +## 使用多应用运行 + +在开始之前,请选择您偏好的编程语言对应的 Dapr SDK。 + +{{< tabs "Python" "JavaScript" ".NET" "Java" "Go" >}} + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装 Python 3.7+](https://www.python.org/downloads/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/state_management/python/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:操作服务状态 + +在终端中,进入 `order-processor` 目录。 + +```bash +cd state_management/python/sdk/order-processor +``` + +安装依赖项: + +```bash +pip3 install -r requirements.txt +``` + +使用 [多应用运行]({{< ref multi-app-dapr-run >}})在 Dapr sidecar 旁边启动 `order-processor` 服务。 + +```bash +dapr run -f . +``` +> **注意**:在 Windows 系统中,由于未定义 Python3.exe,您可能需要在运行 `dapr run -f .` 之前将 [`dapr.yaml`]({{< ref "#dapryaml-multi-app-run-template-file" >}}) 文件中的 `python3` 修改为 `python`。 + +`order-processor` 服务会将 `orderId` 键/值对写入、读取并删除到[在 `statestore.yaml` 组件中定义的]({{< ref "#statestoreyaml-component-file" >}}) `statestore` 实例中。服务启动后,会自动执行一个循环。 + +```python +with DaprClient() as client: + + # 将状态保存到状态存储中 + client.save_state(DAPR_STORE_NAME, orderId, str(order)) + logging.info('Saving Order: %s', order) + + # 从状态存储中获取状态 + result = client.get_state(DAPR_STORE_NAME, orderId) + logging.info('Result after get: ' + str(result.data)) + + # 从状态存储中删除状态 + client.delete_state(store_name=DAPR_STORE_NAME, key=orderId) + logging.info('Deleting Order: %s', order) +``` + +### 步骤 3:查看 order-processor 输出 + +如上代码所示,应用程序会将状态保存在 Dapr 状态存储中,读取后再删除。 + +Order-processor 输出: +``` +== APP == INFO:root:Saving Order: {'orderId': '1'} +== APP == INFO:root:Result after get: b"{'orderId': '1'}" +== APP == INFO:root:Deleting Order: {'orderId': '1'} +== APP == INFO:root:Saving Order: {'orderId': '2'} +== APP == INFO:root:Result after get: b"{'orderId': '2'}" +== APP == INFO:root:Deleting Order: {'orderId': '2'} +== APP == INFO:root:Saving Order: {'orderId': '3'} +== APP == INFO:root:Result after get: b"{'orderId': '3'}" +== APP == INFO:root:Deleting Order: {'orderId': '3'} +== APP == INFO:root:Saving Order: {'orderId': '4'} +== APP == INFO:root:Result after get: b"{'orderId': '4'}" +== APP == INFO:root:Deleting Order: {'orderId': '4'} +``` + +##### `dapr.yaml` 多应用运行模板文件 + +当您运行 `dapr init` 时,Dapr 会创建一个名为 `dapr.yaml` 的默认[多应用运行模板文件]({{< ref multi-app-dapr-run >}})。运行 `dapr run -f` 会启动项目中的所有应用程序。在此示例中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +common: + resourcesPath: ../../resources/ +apps: + - appID: order-processor + appDirPath: ./order-processor/ + command: ["python3" , "app.py"] +``` + +##### `statestore.yaml` 组件文件 + +当您运行 `dapr init` 时,Dapr 还会创建一个默认的 Redis `statestore.yaml` 并在本地机器上运行一个 Redis 容器,位置如下: + +- 在 Windows 上,位于 `%UserProfile%\.dapr\components\statestore.yaml` +- 在 Linux/MacOS 上,位于 `~/.dapr/components/statestore.yaml` + +使用 `statestore.yaml` 组件,您可以轻松地替换[状态存储](/reference/components-reference/supported-state-stores/)而无需进行代码更改。 + +此快速入门中包含的 Redis `statestore.yaml` 文件包含以下内容: + +```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 实例的连接。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装最新的 Node.js](https://nodejs.org/download/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/state_management/javascript/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:操作服务状态 + +在终端中,进入 `order-processor` 目录。 + +```bash +cd state_management/javascript/sdk/order-processor +``` + +安装依赖项: + +```bash +npm install +``` + +在 Dapr sidecar 旁边启动 `order-processor` 服务。 + +```bash +dapr run -f . +``` + +`order-processor` 服务会将 `orderId` 键/值对写入、读取并删除到[在 `statestore.yaml` 组件中定义的]({{< ref "#statestoreyaml-component-file" >}}) `statestore` 实例中。服务启动后,会自动执行一个循环。 + +```js +const client = new DaprClient() + +// 将状态保存到状态存储中 +await client.state.save(DAPR_STATE_STORE_NAME, order) +console.log("Saving Order: ", order) + +// 从状态存储中获取状态 +const savedOrder = await client.state.get(DAPR_STATE_STORE_NAME, order.orderId) +console.log("Getting Order: ", savedOrder) + +// 从状态存储中删除状态 +await client.state.delete(DAPR_STATE_STORE_NAME, order.orderId) +console.log("Deleting Order: ", order) +``` +### 步骤 3:查看 order-processor 输出 + +如上代码所示,应用程序会将状态保存在 Dapr 状态存储中,读取后再删除。 + +Order-processor 输出: +``` +== APP == > order-processor@1.0.0 start +== APP == > node index.js +== APP == Saving Order: { orderId: 1 } +== APP == Saving Order: { orderId: 2 } +== APP == Saving Order: { orderId: 3 } +== APP == Saving Order: { orderId: 4 } +== APP == Saving Order: { orderId: 5 } +== APP == Getting Order: { orderId: 1 } +== APP == Deleting Order: { orderId: 1 } +== APP == Getting Order: { orderId: 2 } +== APP == Deleting Order: { orderId: 2 } +== APP == Getting Order: { orderId: 3 } +== APP == Deleting Order: { orderId: 3 } +== APP == Getting Order: { orderId: 4 } +== APP == Deleting Order: { orderId: 4 } +== APP == Getting Order: { orderId: 5 } +== APP == Deleting Order: { orderId: 5 } +``` + +##### `dapr.yaml` 多应用运行模板文件 + +当您运行 `dapr init` 时,Dapr 会创建一个名为 `dapr.yaml` 的默认多应用运行模板文件。运行 `dapr run -f` 会启动项目中的所有应用程序。在此示例中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +common: + resourcesPath: ../../resources/ +apps: + - appID: order-processor + appDirPath: ./order-processor/ + command: ["npm", "run", "start"] +``` + +##### `statestore.yaml` 组件文件 + +当您运行 `dapr init` 时,Dapr 会创建一个默认的 Redis `statestore.yaml` 并在本地机器上运行一个 Redis 容器,位置如下: + +- 在 Windows 上,位于 `%UserProfile%\.dapr\components\statestore.yaml` +- 在 Linux/MacOS 上,位于 `~/.dapr/components/statestore.yaml` + +使用 `statestore.yaml` 组件,您可以轻松地替换[状态存储](/reference/components-reference/supported-state-stores/)而无需进行代码更改。 + +此快速入门中包含的 Redis `statestore.yaml` 文件包含以下内容: + +```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 实例的连接。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + +- [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0)、[.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) 或 [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) 已安装 + +**注意:** .NET 6 是此版本中 Dapr .NET SDK 包的最低支持版本。只有 .NET 8 和 .NET 9 将在 Dapr v1.16 及更高版本中得到支持。 + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/state_management/csharp/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:操作服务状态 + +在终端中,进入 `order-processor` 目录。 + +```bash +cd state_management/csharp/sdk/order-processor +``` + +安装依赖项: + +```bash +dotnet restore +dotnet build +``` + +在 Dapr sidecar 旁边启动 `order-processor` 服务。 + +```bash +dapr run -f . +``` + +`order-processor` 服务会将 `orderId` 键/值对写入、读取并删除到[在 `statestore.yaml` 组件中定义的]({{< ref "#statestoreyaml-component-file" >}}) `statestore` 实例中。服务启动后,会自动执行一个循环。 + +```cs +var client = new DaprClientBuilder().Build(); + +// 将状态保存到状态存储中 +await client.SaveStateAsync(DAPR_STORE_NAME, orderId.ToString(), order.ToString()); +Console.WriteLine("Saving Order: " + order); + +// 从状态存储中获取状态 +var result = await client.GetStateAsync(DAPR_STORE_NAME, orderId.ToString()); +Console.WriteLine("Getting Order: " + result); + +// 从状态存储中删除状态 +await client.DeleteStateAsync(DAPR_STORE_NAME, orderId.ToString()); +Console.WriteLine("Deleting Order: " + order); +``` +### 步骤 3:查看 order-processor 输出 + +如上代码所示,应用程序会将状态保存在 Dapr 状态存储中,读取后再删除。 + +Order-processor 输出: +``` +== APP == Saving Order: Order { orderId = 1 } +== APP == Getting Order: Order { orderId = 1 } +== APP == Deleting Order: Order { orderId = 1 } +== APP == Saving Order: Order { orderId = 2 } +== APP == Getting Order: Order { orderId = 2 } +== APP == Deleting Order: Order { orderId = 2 } +== APP == Saving Order: Order { orderId = 3 } +== APP == Getting Order: Order { orderId = 3 } +== APP == Deleting Order: Order { orderId = 3 } +== APP == Saving Order: Order { orderId = 4 } +== APP == Getting Order: Order { orderId = 4 } +== APP == Deleting Order: Order { orderId = 4 } +== APP == Saving Order: Order { orderId = 5 } +== APP == Getting Order: Order { orderId = 5 } +== APP == Deleting Order: Order { orderId = 5 } +``` + +##### `dapr.yaml` 多应用运行模板文件 + +当您运行 `dapr init` 时,Dapr 会创建一个名为 `dapr.yaml` 的默认多应用运行模板文件。运行 `dapr run -f` 会启动项目中的所有应用程序。在此示例中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +common: + resourcesPath: ../../../resources/ +apps: + - appID: order-processor + appDirPath: ./order-processor/ + command: ["dotnet", "run"] +``` + +##### `statestore.yaml` 组件文件 + +当您运行 `dapr init` 时,Dapr 会创建一个默认的 Redis `statestore.yaml` 并在本地机器上运行一个 Redis 容器,位置如下: + +- 在 Windows 上,位于 `%UserProfile%\.dapr\components\statestore.yaml` +- 在 Linux/MacOS 上,位于 `~/.dapr/components/statestore.yaml` + +使用 `statestore.yaml` 组件,您可以轻松地替换[状态存储](/reference/components-reference/supported-state-stores/)而无需进行代码更改。 + +此快速入门中包含的 Redis `statestore.yaml` 文件包含以下内容: + +```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 实例的连接。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- Java JDK 17(或更高版本): + - [Oracle JDK](https://www.oracle.com/java/technologies/downloads),或 + - OpenJDK +- [Apache Maven](https://maven.apache.org/install.html),版本 3.x。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/state_management/java/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:操作服务状态 + +在终端中,进入 `order-processor` 目录。 + +```bash +cd state_management/java/sdk/order-processor +``` + +安装依赖项: + +```bash +mvn clean install +``` + +在 Dapr sidecar 旁边启动 `order-processor` 服务。 + +```bash +dapr run -f . +``` + +`order-processor` 服务会将 `orderId` 键/值对写入、读取并删除到[在 `statestore.yaml` 组件中定义的]({{< ref "#statestoreyaml-component-file" >}}) `statestore` 实例中。服务启动后,会自动执行一个循环。 + +```java +try (DaprClient client = new DaprClientBuilder().build()) { + for (int i = 1; i <= 10; i++) { + int orderId = i; + Order order = new Order(); + order.setOrderId(orderId); + + // 将状态保存到状态存储中 + client.saveState(DAPR_STATE_STORE, String.valueOf(orderId), order).block(); + LOGGER.info("Saving Order: " + order.getOrderId()); + + // 从状态存储中获取状态 + State response = client.getState(DAPR_STATE_STORE, String.valueOf(orderId), Order.class).block(); + LOGGER.info("Getting Order: " + response.getValue().getOrderId()); + + // 从状态存储中删除状态 + client.deleteState(DAPR_STATE_STORE, String.valueOf(orderId)).block(); + LOGGER.info("Deleting Order: " + orderId); + TimeUnit.MILLISECONDS.sleep(1000); + } +``` +### 步骤 3:查看 order-processor 输出 + +如上代码所示,应用程序会将状态保存在 Dapr 状态存储中,读取后再删除。 + +Order-processor 输出: +``` +== APP == INFO:root:Saving Order: {'orderId': '1'} +== APP == INFO:root:Result after get: b"{'orderId': '1'}" +== APP == INFO:root:Deleting Order: {'orderId': '1'} +== APP == INFO:root:Saving Order: {'orderId': '2'} +== APP == INFO:root:Result after get: b"{'orderId': '2'}" +== APP == INFO:root:Deleting Order: {'orderId': '2'} +== APP == INFO:root:Saving Order: {'orderId': '3'} +== APP == INFO:root:Result after get: b"{'orderId': '3'}" +== APP == INFO:root:Deleting Order: {'orderId': '3'} +== APP == INFO:root:Saving Order: {'orderId': '4'} +== APP == INFO:root:Result after get: b"{'orderId': '4'}" +== APP == INFO:root:Deleting Order: {'orderId': '4'} +``` + +##### `dapr.yaml` 多应用运行模板文件 + +当您运行 `dapr init` 时,Dapr 会创建一个名为 `dapr.yaml` 的默认多应用运行模板文件。运行 `dapr run -f` 会启动项目中的所有应用程序。在此示例中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +common: + resourcesPath: ../../resources/ +apps: + - appID: order-processor + appDirPath: ./order-processor/ + command: ["java", "-jar", "target/OrderProcessingService-0.0.1-SNAPSHOT.jar"] +``` + +##### `statestore.yaml` 组件文件 + +当您运行 `dapr init` 时,Dapr 会创建一个默认的 Redis `statestore.yaml` 并在本地机器上运行一个 Redis 容器,位置如下: + +- 在 Windows 上,位于 `%UserProfile%\.dapr\components\statestore.yaml` +- 在 Linux/MacOS 上,位于 `~/.dapr/components/statestore.yaml` + +使用 `statestore.yaml` 组件,您可以轻松地替换[状态存储](/reference/components-reference/supported-state-stores/)而无需进行代码更改。 + +此快速入门中包含的 Redis `statestore.yaml` 文件包含以下内容: + +```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 实例的连接。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的 Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/state_management/go/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:操作服务状态 + +在终端中,进入 `order-processor` 目录。 + +```bash +cd state_management/go/sdk/order-processor +``` + +安装依赖项: + +```bash +go build . +``` + +在 Dapr sidecar 旁边启动 `order-processor` 服务。 + +```bash +dapr run -f . +``` + +`order-processor` 服务会将 `orderId` 键/值对写入、读取并删除到[在 `statestore.yaml` 组件中定义的]({{< ref "#statestoreyaml-component-file" >}}) `statestore` 实例中。服务启动后,会自动执行一个循环。 + +```go + client, err := dapr.NewClient() + + // 将状态保存到状态存储中 + _ = client.SaveState(ctx, STATE_STORE_NAME, strconv.Itoa(orderId), []byte(order)) + log.Print("Saving Order: " + string(order)) + + // 从状态存储中获取状态 + result, _ := client.GetState(ctx, STATE_STORE_NAME, strconv.Itoa(orderId)) + fmt.Println("Getting Order: " + string(result.Value)) + + // 从状态存储中删除状态 + _ = client.DeleteState(ctx, STATE_STORE_NAME, strconv.Itoa(orderId)) + log.Print("Deleting Order: " + string(order)) +``` + +### 步骤 3:查看 order-processor 输出 + +如上代码所示,应用程序会将状态保存在 Dapr 状态存储中,读取后再删除。 + +Order-processor 输出: +``` +== APP == dapr client initializing for: 127.0.0.1:53689 +== APP == 2022/04/01 09:16:03 Saving Order: {"orderId":1} +== APP == Getting Order: {"orderId":1} +== APP == 2022/04/01 09:16:03 Deleting Order: {"orderId":1} +== APP == 2022/04/01 09:16:03 Saving Order: {"orderId":2} +== APP == Getting Order: {"orderId":2} +== APP == 2022/04/01 09:16:03 Deleting Order: {"orderId":2} +== APP == 2022/04/01 09:16:03 Saving Order: {"orderId":3} +== APP == Getting Order: {"orderId":3} +== APP == 2022/04/01 09:16:03 Deleting Order: {"orderId":3} +== APP == 2022/04/01 09:16:03 Saving Order: {"orderId":4} +== APP == Getting Order: {"orderId":4} +== APP == 2022/04/01 09:16:03 Deleting Order: {"orderId":4} +== APP == 2022/04/01 09:16:03 Saving Order: {"orderId":5} +== APP == Getting Order: {"orderId":5} +== APP == 2022/04/01 09:16:03 Deleting Order: {"orderId":5} +``` + +##### `dapr.yaml` 多应用运行模板文件 + +当您运行 `dapr init` 时,Dapr 会创建一个名为 `dapr.yaml` 的默认多应用运行模板文件。运行 `dapr run -f` 会启动项目中的所有应用程序。在此示例中,`dapr.yaml` 文件包含以下内容: + +```yml +version: 1 +common: + resourcesPath: ../../resources/ +apps: + - appID: order-processor + appDirPath: ./order-processor/ + command: ["go", "run", "."] +``` + +##### `statestore.yaml` 组件文件 + +当您运行 `dapr init` 时,Dapr 会创建一个默认的 Redis `statestore.yaml` 并在本地机器上运行一个 Redis 容器,位置如下: + +- 在 Windows 上,位于 `%UserProfile%\.dapr\components\statestore.yaml` +- 在 Linux/MacOS 上,位于 `~/.dapr/components/statestore.yaml` + +使用 `statestore.yaml` 组件,您可以轻松地替换[状态存储](/reference/components-reference/supported-state-stores/)而无需进行代码更改。 + +此快速入门中包含的 Redis `statestore.yaml` 文件包含以下内容: + +```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 实例的连接。 + +{{% /codetab %}} + +{{< /tabs >}} + + +## 一次运行一个应用程序 + +在开始之前,请选择您偏好的编程语言对应的 Dapr SDK。 + +{{< tabs "Python" "JavaScript" ".NET" "Java" "Go" >}} + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装 Python 3.7+](https://www.python.org/downloads/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/state_management/python/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:操作服务状态 + +在终端中,进入 `order-processor` 目录。 + +```bash +cd state_management/python/sdk/order-processor +``` + +安装依赖项: + +```bash +pip3 install -r requirements.txt +``` + +在 Dapr sidecar 旁边启动 `order-processor` 服务。 + +```bash +dapr run --app-id order-processor --resources-path ../../../resources/ -- python3 app.py +``` + +> **注意**:在 Windows 系统中,由于未定义 Python3.exe,您可能需要使用 `python app.py` 而不是 `python3 app.py`。 + +`order-processor` 服务会将 `orderId` 键/值对写入、读取并删除到[在 `statestore.yaml` 组件中定义的]({{< ref "#statestoreyaml-component-file" >}}) `statestore` 实例中。服务启动后,会自动执行一个循环。 + +```python +with DaprClient() as client: + + # 将状态保存到状态存储中 + client.save_state(DAPR_STORE_NAME, orderId, str(order)) + logging.info('Saving Order: %s', order) + + # 从状态存储中获取状态 + result = client.get_state(DAPR_STORE_NAME, orderId) + logging.info('Result after get: ' + str(result.data)) + + # 从状态存储中删除状态 + client.delete_state(store_name=DAPR_STORE_NAME, key=orderId) + logging.info('Deleting Order: %s', order) +``` + +### 步骤 3:查看 order-processor 输出 + +如上代码所示,应用程序会将状态保存在 Dapr 状态存储中,读取后再删除。 + +Order-processor 输出: +``` +== APP == INFO:root:Saving Order: {'orderId': '1'} +== APP == INFO:root:Result after get: b"{'orderId': '1'}" +== APP == INFO:root:Deleting Order: {'orderId': '1'} +== APP == INFO:root:Saving Order: {'orderId': '2'} +== APP == INFO:root:Result after get: b"{'orderId': '2'}" +== APP == INFO:root:Deleting Order: {'orderId': '2'} +== APP == INFO:root:Saving Order: {'orderId': '3'} +== APP == INFO:root:Result after get: b"{'orderId': '3'}" +== APP == INFO:root:Deleting Order: {'orderId': '3'} +== APP == INFO:root:Saving Order: {'orderId': '4'} +== APP == INFO:root:Result after get: b"{'orderId': '4'}" +== APP == INFO:root:Deleting Order: {'orderId': '4'} +``` + +##### `statestore.yaml` 组件文件 + +当您运行 `dapr init` 时,Dapr 会创建一个默认的 Redis `statestore.yaml` 并在本地机器上运行一个 Redis 容器,位置如下: + +- 在 Windows 上,位于 `%UserProfile%\.dapr\components\statestore.yaml` +- 在 Linux/MacOS 上,位于 `~/.dapr/components/statestore.yaml` + +使用 `statestore.yaml` 组件,您可以轻松地替换[状态存储](/reference/components-reference/supported-state-stores/)而无需进行代码更改。 + +此快速入门中包含的 Redis `statestore.yaml` 文件包含以下内容: + +```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 实例的连接。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装最新的 Node.js](https://nodejs.org/download/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/state_management/javascript/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:操作服务状态 + +在终端中,进入 `order-processor` 目录。 + +```bash +cd state_management/javascript/sdk/order-processor +``` + +安装依赖项,其中将包括 JavaScript SDK 的 `@dapr/dapr` 包: + +```bash +npm install +``` + +验证服务目录中包含以下文件: + +- `package.json` +- `package-lock.json` + +在 Dapr sidecar 旁边启动 `order-processor` 服务。 + +```bash +dapr run --app-id order-processor --resources-path ../../../resources/ -- npm run start +``` +`order-processor` 服务会将 `orderId` 键/值对写入、读取并删除到[在 `statestore.yaml` 组件中定义的]({{< ref "#statestoreyaml-component-file" >}}) `statestore` 实例中。服务启动后,会自动执行一个循环。 + +```js +const client = new DaprClient() + +// 将状态保存到状态存储中 +await client.state.save(DAPR_STATE_STORE_NAME, order) +console.log("Saving Order: ", order) + +// 从状态存储中获取状态 +const savedOrder = await client.state.get(DAPR_STATE_STORE_NAME, order.orderId) +console.log("Getting Order: ", savedOrder) + +// 从状态存储中删除状态 +await client.state.delete(DAPR_STATE_STORE_NAME, order.orderId) +console.log("Deleting Order: ", order) +``` +### 步骤 3:查看 order-processor 输出 + +如上代码所示,应用程序会将状态保存在 Dapr 状态存储中,读取后再删除。 + +Order-processor 输出: +``` +== APP == > order-processor@1.0.0 start +== APP == > node index.js +== APP == Saving Order: { orderId: 1 } +== APP == Saving Order: { orderId: 2 } +== APP == Saving Order: { orderId: 3 } +== APP == Saving Order: { orderId: 4 } +== APP == Saving Order: { orderId: 5 } +== APP == Getting Order: { orderId: 1 } +== APP == Deleting Order: { orderId: 1 } +== APP == Getting Order: { orderId: 2 } +== APP == Deleting Order: { orderId: 2 } +== APP == Getting Order: { orderId: 3 } +== APP == Deleting Order: { orderId: 3 } +== APP == Getting Order: { orderId: 4 } +== APP == Deleting Order: { orderId: 4 } +== APP == Getting Order: { orderId: 5 } +== APP == Deleting Order: { orderId: 5 } +``` + +##### `statestore.yaml` 组件文件 + +当您运行 `dapr init` 时,Dapr 会创建一个默认的 Redis `statestore.yaml` 并在本地机器上运行一个 Redis 容器,位置如下: + +- 在 Windows 上,位于 `%UserProfile%\.dapr\components\statestore.yaml` +- 在 Linux/MacOS 上,位于 `~/.dapr/components/statestore.yaml` + +使用 `statestore.yaml` 组件,您可以轻松地替换[状态存储](/reference/components-reference/supported-state-stores/)而无需进行代码更改。 + +此快速入门中包含的 Redis `statestore.yaml` 文件包含以下内容: + +```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 实例的连接。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [.NET SDK 或 .NET 6 SDK 已安装](https://dotnet.microsoft.com/download)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/state_management/csharp/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:操作服务状态 + +在终端中,进入 `order-processor` 目录。 + +```bash +cd state_management/csharp/sdk/order-processor +``` + +回忆 NuGet 包: + +```bash +dotnet restore +dotnet build +``` + +在 Dapr sidecar 旁边启动 `order-processor` 服务。 + +```bash +dapr run --app-id order-processor --resources-path ../../../resources/ -- dotnet run +``` + +`order-processor` 服务会将 `orderId` 键/值对写入、读取并删除到[在 `statestore.yaml` 组件中定义的]({{< ref "#statestoreyaml-component-file" >}}) `statestore` 实例中。服务启动后,会自动执行一个循环。 + +```cs +var client = new DaprClientBuilder().Build(); + +// 将状态保存到状态存储中 +await client.SaveStateAsync(DAPR_STORE_NAME, orderId.ToString(), order.ToString()); +Console.WriteLine("Saving Order: " + order); + +// 从状态存储中获取状态 +var result = await client.GetStateAsync(DAPR_STORE_NAME, orderId.ToString()); +Console.WriteLine("Getting Order: " + result); + +// 从状态存储中删除状态 +await client.DeleteStateAsync(DAPR_STORE_NAME, orderId.ToString()); +Console.WriteLine("Deleting Order: " + order); +``` +### 步骤 3:查看 order-processor 输出 + +如上代码所示,应用程序会将状态保存在 Dapr 状态存储中,读取后再删除。 + +Order-processor 输出: +``` +== APP == Saving Order: Order { orderId = 1 } +== APP == Getting Order: Order { orderId = 1 } +== APP == Deleting Order: Order { orderId = 1 } +== APP == Saving Order: Order { orderId = 2 } +== APP == Getting Order: Order { orderId = 2 } +== APP == Deleting Order: Order { orderId = 2 } +== APP == Saving Order: Order { orderId = 3 } +== APP == Getting Order: Order { orderId = 3 } +== APP == Deleting Order: Order { orderId = 3 } +== APP == Saving Order: Order { orderId = 4 } +== APP == Getting Order: Order { orderId = 4 } +== APP == Deleting Order: Order { orderId = 4 } +== APP == Saving Order: Order { orderId = 5 } +== APP == Getting Order: Order { orderId = 5 } +== APP == Deleting Order: Order { orderId = 5 } +``` + +##### `statestore.yaml` 组件文件 + +当您运行 `dapr init` 时,Dapr 会创建一个默认的 Redis `statestore.yaml` 并在本地机器上运行一个 Redis 容器,位置如下: + +- 在 Windows 上,位于 `%UserProfile%\.dapr\components\statestore.yaml` +- 在 Linux/MacOS 上,位于 `~/.dapr/components/statestore.yaml` + +使用 `statestore.yaml` 组件,您可以轻松地替换[状态存储](/reference/components-reference/supported-state-stores/)而无需进行代码更改。 + +此快速入门中包含的 Redis `statestore.yaml` 文件包含以下内容: + +```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 实例的连接。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- Java JDK 17(或更高版本): + - [Oracle JDK](https://www.oracle.com/java/technologies/downloads),或 + - OpenJDK +- [Apache Maven](https://maven.apache.org/install.html),版本 3.x。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/state_management/java/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:操作服务状态 + +在终端中,进入 `order-processor` 目录。 + +```bash +cd state_management/java/sdk/order-processor +``` + +安装依赖项: + +```bash +mvn clean install +``` + +在 Dapr sidecar 旁边启动 `order-processor` 服务。 + +```bash +dapr run --app-id order-processor --resources-path ../../../resources -- java -jar target/OrderProcessingService-0.0.1-SNAPSHOT.jar +``` + +`order-processor` 服务会将 `orderId` 键/值对写入、读取并删除到[在 `statestore.yaml` 组件中定义的]({{< ref "#statestoreyaml-component-file" >}}) `statestore` 实例中。服务启动后,会自动执行一个循环。 + +```java +try (DaprClient client = new DaprClientBuilder().build()) { + for (int i = 1; i <= 10; i++) { + int orderId = i; + Order order = new Order(); + order.setOrderId(orderId); + + // 将状态保存到状态存储中 + client.saveState(DAPR_STATE_STORE, String.valueOf(orderId), order).block(); + LOGGER.info("Saving Order: " + order.getOrderId()); + + // 从状态存储中获取状态 + State response = client.getState(DAPR_STATE_STORE, String.valueOf(orderId), Order.class).block(); + LOGGER.info("Getting Order: " + response.getValue().getOrderId()); + + // 从状态存储中删除状态 + client.deleteState(DAPR_STATE_STORE, String.valueOf(orderId)).block(); + LOGGER.info("Deleting Order: " + orderId); + TimeUnit.MILLISECONDS.sleep(1000); + } +``` +### 步骤 3:查看 order-processor 输出 + +如上代码所示,应用程序会将状态保存在 Dapr 状态存储中,读取后再删除。 + +Order-processor 输出: +``` +== APP == INFO:root:Saving Order: {'orderId': '1'} +== APP == INFO:root:Result after get: b"{'orderId': '1'}" +== APP == INFO:root:Deleting Order: {'orderId': '1'} +== APP == INFO:root:Saving Order: {'orderId': '2'} +== APP == INFO:root:Result after get: b"{'orderId': '2'}" +== APP == INFO:root:Deleting Order: {'orderId': '2'} +== APP == INFO:root:Saving Order: {'orderId': '3'} +== APP == INFO:root:Result after get: b"{'orderId': '3'}" +== APP == INFO:root:Deleting Order: {'orderId': '3'} +== APP == INFO:root:Saving Order: {'orderId': '4'} +== APP == INFO:root:Result after get: b"{'orderId': '4'}" +== APP == INFO:root:Deleting Order: {'orderId': '4'} +``` + +##### `statestore.yaml` 组件文件 + +当您运行 `dapr init` 时,Dapr 会创建一个默认的 Redis `statestore.yaml` 并在本地机器上运行一个 Redis 容器,位置如下: + +- 在 Windows 上,位于 `%UserProfile%\.dapr\components\statestore.yaml` +- 在 Linux/MacOS 上,位于 `~/.dapr/components/statestore.yaml` + +使用 `statestore.yaml` 组件,您可以轻松地替换[状态存储](/reference/components-reference/supported-state-stores/)而无需进行代码更改。 + +此快速入门中包含的 Redis `statestore.yaml` 文件包含以下内容: + +```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 实例的连接。 + +{{% /codetab %}} + + +{{% codetab %}} + +### 先决条件 + +您需要准备以下环境: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的 Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 1:设置环境 + +克隆[快速入门仓库中的示例](https://github.com/dapr/quickstarts/tree/master/state_management/go/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +### 步骤 2:操作服务状态 + +在终端中,进入 `order-processor` 目录。 + +```bash +cd state_management/go/sdk/order-processor +``` + +安装依赖项并构建应用程序: + +```bash +go build . +``` + +在 Dapr sidecar 旁边启动 `order-processor` 服务。 + +```bash +dapr run --app-id order-processor --resources-path ../../../resources -- go run . +``` + +`order-processor` 服务会将 `orderId` 键/值对写入、读取并删除到[在 `statestore.yaml` 组件中定义的]({{< ref "#statestoreyaml-component-file" >}}) `statestore` 实例中。服务启动后,会自动执行一个循环。 + +```go + client, err := dapr.NewClient() + + // 将状态保存到状态存储中 + _ = client.SaveState(ctx, STATE_STORE_NAME, strconv.Itoa(orderId), []byte(order)) + log.Print("Saving Order: " + string(order)) + + // 从状态存储中获取状态 + result, _ := client.GetState(ctx, STATE_STORE_NAME, strconv.Itoa(orderId)) + fmt.Println("Getting Order: " + string(result.Value)) + + // 从状态存储中删除状态 + _ = client.DeleteState(ctx, STATE_STORE_NAME, strconv.Itoa(orderId)) + log.Print("Deleting Order: " + string(order)) +``` + +### 步骤 3:查看 order-processor 输出 + +如上代码所示,应用程序会将状态保存在 Dapr 状态存储中,读取后再删除。 + +Order-processor 输出: +``` +== APP == dapr client initializing for: 127.0.0.1:53689 +== APP == 2022/04/01 09:16:03 Saving Order: {"orderId":1} +== APP == Getting Order: {"orderId":1} +== APP == 2022/04/01 09:16:03 Deleting Order: {"orderId":1} +== APP == 2022/04/01 09:16:03 Saving Order: {"orderId":2} +== APP == Getting Order: {"orderId":2} +== APP == 2022/04/01 09:16:03 Deleting Order: {"orderId":2} +== APP == 2022/04/01 09:16:03 Saving Order: {"orderId":3} +== APP == Getting Order: {"orderId":3} +== APP == 2022/04/01 09:16:03 Deleting Order: {"orderId":3} +== APP == 2022/04/01 09:16:03 Saving Order: {"orderId":4} +== APP == Getting Order: {"orderId":4} +== APP == 2022/04/01 09:16:03 Deleting Order: {"orderId":4} +== APP == 2022/04/01 09:16:03 Saving Order: {"orderId":5} +== APP == Getting Order: {"orderId":5} +== APP == 2022/04/01 09:16:03 Deleting Order: {"orderId":5} +``` + +##### `statestore.yaml` 组件文件 + +当您运行 `dapr init` 时,Dapr 会创建一个默认的 Redis `statestore.yaml` 并在本地机器上运行一个 Redis 容器,位置如下: + +- 在 Windows 上,位于 `%UserProfile%\.dapr\components\statestore.yaml` +- 在 Linux/MacOS 上,位于 `~/.dapr/components/statestore.yaml` + +使用 `statestore.yaml` 组件,您可以轻松地替换[状态存储](/reference/components-reference/supported-state-stores/)而无需进行代码更改。 + +此快速入门中包含的 Redis `statestore.yaml` 文件包含以下内容: + +```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 实例的连接。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 告诉我们您的想法! +我们正在不断努力改进我们的快速入门示例,并重视您的反馈。您觉得这个快速入门有帮助吗?您有改进建议吗? + +加入我们的[discord 频道](https://discord.com/channels/778680217417809931/953427615916638238)进行讨论。 + +## 下一步 + +- 使用 HTTP 而不是 SDK 来使用 Dapr 状态管理。 + - [Python](https://github.com/dapr/quickstarts/tree/master/state_management/python/http) + - [JavaScript](https://github.com/dapr/quickstarts/tree/master/state_management/javascript/http) + - [.NET](https://github.com/dapr/quickstarts/tree/master/state_management/csharp/http) + - [Java](https://github.com/dapr/quickstarts/tree/master/state_management/java/http) + - [Go](https://github.com/dapr/quickstarts/tree/master/state_management/go/http) +- 了解更多关于[状态管理模块]({{< ref state-management >}})的信息 + +{{< button text="探索 Dapr 教程 >>" page="getting-started/tutorials/_index.md" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/getting-started/quickstarts/workflow-quickstart.md b/src/translated_content/zh_CN/docs/getting-started/quickstarts/workflow-quickstart.md new file mode 100644 index 000000000..72095208e --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/quickstarts/workflow-quickstart.md @@ -0,0 +1,1359 @@ +--- +type: docs +title: "快速入门:工作流" +linkTitle: 工作流 +weight: 73 +description: 开始使用 Dapr 工作流构建块 +--- + +{{% alert title="注意" color="primary" %}} +在快速入门中,Redis 目前用作工作流的状态存储组件。然而,Redis 不支持事务回滚,因此不建议在生产环境中用作 actor 状态存储。 +{{% /alert %}} + +让我们来了解一下 Dapr 的[工作流构建块]({{< ref workflow-overview.md >}})。在这个快速入门中,您将创建一个简单的控制台应用程序,演示 Dapr 的工作流编程模型和管理 API。 + +在本指南中,您将: + +- 运行 `order-processor` 应用程序。 +- 启动工作流并观察工作流活动/任务的执行。 +- 查看工作流逻辑和工作流活动,以及它们在代码中的表示。 + + + +在继续快速入门之前,请选择您偏好的 Dapr SDK 语言版本。 +{{< tabs "Python" "JavaScript" ".NET" "Java" Go >}} + + +{{% codetab %}} + +`order-processor` 控制台应用程序启动并管理 `order_processing_workflow`,该工作流模拟从商店购买商品。工作流由五个独特的工作流活动或任务组成: + +- `notify_activity`:使用记录器在整个工作流过程中打印消息。这些消息通知您: + - 您的库存不足 + - 您的付款无法处理,等等。 +- `process_payment_activity`:处理和授权付款。 +- `verify_inventory_activity`:检查状态存储以确保有足够的库存可供购买。 +- `update_inventory_activity`:从状态存储中移除请求的商品,并使用新的剩余库存值更新存储。 +- `request_approval_activity`:如果付款金额超过 50,000 美元,则寻求经理的批准。 + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装 Python 3.7+](https://www.python.org/downloads/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/workflows/python/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +在新的终端窗口中,导航到 `order-processor` 目录: + +```bash +cd workflows/python/sdk/order-processor +``` + +安装 Dapr Python SDK 包: + +```bash +pip3 install -r requirements.txt +``` + +返回到 `python/sdk` 目录: + +```bash +cd .. +``` + +### 步骤 3:运行订单处理器应用程序 + +在终端中,使用 [Multi-App Run]({{< ref multi-app-dapr-run >}}) 启动订单处理器应用程序及其 Dapr 边车。从 `python/sdk` 目录运行以下命令: + +```bash +dapr run -f . +``` + +这将启动具有唯一工作流 ID 的 `order-processor` 应用程序并运行工作流活动。 + +预期输出: + +```bash +== APP == Starting order workflow, purchasing 10 of cars +== APP == 2023-06-06 09:35:52.945 durabletask-worker INFO: Successfully connected to 127.0.0.1:65406. Waiting for work items... +== APP == INFO:NotifyActivity:Received order f4e1926e-3721-478d-be8a-f5bebd1995da for 10 cars at $150000 ! +== APP == INFO:VerifyInventoryActivity:Verifying inventory for order f4e1926e-3721-478d-be8a-f5bebd1995da of 10 cars +== APP == INFO:VerifyInventoryActivity:There are 100 Cars available for purchase +== APP == INFO:RequestApprovalActivity:Requesting approval for payment of 165000 USD for 10 cars +== APP == 2023-06-06 09:36:05.969 durabletask-worker INFO: f4e1926e-3721-478d-be8a-f5bebd1995da Event raised: manager_approval +== APP == INFO:NotifyActivity:Payment for order f4e1926e-3721-478d-be8a-f5bebd1995da has been approved! +== APP == INFO:ProcessPaymentActivity:Processing payment: f4e1926e-3721-478d-be8a-f5bebd1995da for 10 cars at 150000 USD +== APP == INFO:ProcessPaymentActivity:Payment for request ID f4e1926e-3721-478d-be8a-f5bebd1995da processed successfully +== APP == INFO:UpdateInventoryActivity:Checking inventory for order f4e1926e-3721-478d-be8a-f5bebd1995da for 10 cars +== APP == INFO:UpdateInventoryActivity:There are now 90 cars left in stock +== APP == INFO:NotifyActivity:Order f4e1926e-3721-478d-be8a-f5bebd1995da has completed! +== APP == 2023-06-06 09:36:06.106 durabletask-worker INFO: f4e1926e-3721-478d-be8a-f5bebd1995da: Orchestration completed with status: COMPLETED +== APP == Workflow completed! Result: Completed +== APP == Purchase of item is Completed +``` + +### (可选)步骤 4:在 Zipkin 中查看 + +运行 `dapr init` 会启动 [openzipkin/zipkin](https://hub.docker.com/r/openzipkin/zipkin/) Docker 容器。如果容器已停止运行,请使用以下命令启动 Zipkin Docker 容器: + +``` +docker run -d -p 9411:9411 openzipkin/zipkin +``` + +在 Zipkin Web UI 中查看工作流跟踪跨度(通常位于 `http://localhost:9411/zipkin/`)。 + + + +### 发生了什么? + +当您运行 `dapr run -f .` 时: + +1. 为工作流生成了一个唯一的订单 ID(在上面的示例中为 `f4e1926e-3721-478d-be8a-f5bebd1995da`),并调度了工作流。 +2. `NotifyActivity` 工作流活动发送通知,表示已收到 10 辆车的订单。 +3. `ReserveInventoryActivity` 工作流活动检查库存数据,确定您是否可以供应订购的商品,并响应库存中的汽车数量。 +4. 您的工作流启动并通知您其状态。 +5. `ProcessPaymentActivity` 工作流活动开始处理订单 `f4e1926e-3721-478d-be8a-f5bebd1995da` 的付款,并确认是否成功。 +6. `UpdateInventoryActivity` 工作流活动在订单处理后更新库存中的当前可用汽车。 +7. `NotifyActivity` 工作流活动发送通知,表示订单 `f4e1926e-3721-478d-be8a-f5bebd1995da` 已完成。 +8. 工作流终止为已完成。 + +#### `order-processor/app.py` + +在应用程序的程序文件中,您将会: + +- 生成唯一的工作流订单 ID +- 调度工作流 +- 检索工作流状态 +- 注册工作流及其调用的工作流活动 + +```python +class WorkflowConsoleApp: + def main(self): + # Register workflow and activities + workflowRuntime = WorkflowRuntime(settings.DAPR_RUNTIME_HOST, settings.DAPR_GRPC_PORT) + workflowRuntime.register_workflow(order_processing_workflow) + workflowRuntime.register_activity(notify_activity) + workflowRuntime.register_activity(requst_approval_activity) + workflowRuntime.register_activity(verify_inventory_activity) + workflowRuntime.register_activity(process_payment_activity) + workflowRuntime.register_activity(update_inventory_activity) + workflowRuntime.start() + + print("==========Begin the purchase of item:==========", flush=True) + item_name = default_item_name + order_quantity = 10 + + total_cost = int(order_quantity) * baseInventory[item_name].per_item_cost + order = OrderPayload(item_name=item_name, quantity=int(order_quantity), total_cost=total_cost) + + # Start Workflow + print(f'Starting order workflow, purchasing {order_quantity} of {item_name}', flush=True) + start_resp = daprClient.start_workflow(workflow_component=workflow_component, + workflow_name=workflow_name, + input=order) + _id = start_resp.instance_id + + def prompt_for_approval(daprClient: DaprClient): + daprClient.raise_workflow_event(instance_id=_id, workflow_component=workflow_component, + event_name="manager_approval", event_data={'approval': True}) + + approval_seeked = False + start_time = datetime.now() + while True: + time_delta = datetime.now() - start_time + state = daprClient.get_workflow(instance_id=_id, workflow_component=workflow_component) + if not state: + print("Workflow not found!") # not expected + elif state.runtime_status == "Completed" or\ + state.runtime_status == "Failed" or\ + state.runtime_status == "Terminated": + print(f'Workflow completed! Result: {state.runtime_status}', flush=True) + break + if time_delta.total_seconds() >= 10: + state = daprClient.get_workflow(instance_id=_id, workflow_component=workflow_component) + if total_cost > 50000 and ( + state.runtime_status != "Completed" or + state.runtime_status != "Failed" or + state.runtime_status != "Terminated" + ) and not approval_seeked: + approval_seeked = True + threading.Thread(target=prompt_for_approval(daprClient), daemon=True).start() + + print("Purchase of item is ", state.runtime_status, flush=True) + + def restock_inventory(self, daprClient: DaprClient, baseInventory): + for key, item in baseInventory.items(): + print(f'item: {item}') + item_str = f'{{"name": "{item.item_name}", "quantity": {item.quantity},\ + "per_item_cost": {item.per_item_cost}}}' + daprClient.save_state("statestore-actors", key, item_str) + +if __name__ == '__main__': + app = WorkflowConsoleApp() + app.main() +``` + +#### `order-processor/workflow.py` + +在 `workflow.py` 中,工作流被定义为一个类,包含其所有相关任务(由工作流活动确定)。 + +```python + def order_processing_workflow(ctx: DaprWorkflowContext, order_payload_str: OrderPayload): + """Defines the order processing workflow. + When the order is received, the inventory is checked to see if there is enough inventory to + fulfill the order. If there is enough inventory, the payment is processed and the inventory is + updated. If there is not enough inventory, the order is rejected. + If the total order is greater than $50,000, the order is sent to a manager for approval. + """ + order_id = ctx.instance_id + order_payload=json.loads(order_payload_str) + yield ctx.call_activity(notify_activity, + input=Notification(message=('Received order ' +order_id+ ' for ' + +f'{order_payload["quantity"]}' +' ' +f'{order_payload["item_name"]}' + +' at $'+f'{order_payload["total_cost"]}' +' !'))) + result = yield ctx.call_activity(verify_inventory_activity, + input=InventoryRequest(request_id=order_id, + item_name=order_payload["item_name"], + quantity=order_payload["quantity"])) + if not result.success: + yield ctx.call_activity(notify_activity, + input=Notification(message='Insufficient inventory for ' + +f'{order_payload["item_name"]}'+'!')) + return OrderResult(processed=False) + + if order_payload["total_cost"] > 50000: + yield ctx.call_activity(requst_approval_activity, input=order_payload) + approval_task = ctx.wait_for_external_event("manager_approval") + timeout_event = ctx.create_timer(timedelta(seconds=200)) + winner = yield when_any([approval_task, timeout_event]) + if winner == timeout_event: + yield ctx.call_activity(notify_activity, + input=Notification(message='Payment for order '+order_id + +' has been cancelled due to timeout!')) + return OrderResult(processed=False) + approval_result = yield approval_task + if approval_result["approval"]: + yield ctx.call_activity(notify_activity, input=Notification( + message=f'Payment for order {order_id} has been approved!')) + else: + yield ctx.call_activity(notify_activity, input=Notification( + message=f'Payment for order {order_id} has been rejected!')) + return OrderResult(processed=False) + + yield ctx.call_activity(process_payment_activity, input=PaymentRequest( + request_id=order_id, item_being_purchased=order_payload["item_name"], + amount=order_payload["total_cost"], quantity=order_payload["quantity"])) + + try: + yield ctx.call_activity(update_inventory_activity, + input=PaymentRequest(request_id=order_id, + item_being_purchased=order_payload["item_name"], + amount=order_payload["total_cost"], + quantity=order_payload["quantity"])) + except Exception: + yield ctx.call_activity(notify_activity, + input=Notification(message=f'Order {order_id} Failed!')) + return OrderResult(processed=False) + + yield ctx.call_activity(notify_activity, input=Notification( + message=f'Order {order_id} has completed!')) + return OrderResult(processed=True) +``` +{{% /codetab %}} + + +{{% codetab %}} + +`order-processor` 控制台应用程序启动并管理订单处理工作流的生命周期,该工作流在状态存储中存储和检索数据。工作流由四个工作流活动或任务组成: + +- `notifyActivity`:使用记录器在整个工作流过程中打印消息。这些消息通知用户库存不足、付款无法处理等。 +- `reserveInventoryActivity`:检查状态存储以确保有足够的库存可供购买。 +- `requestApprovalActivity`:请求超过某个阈值的订单的批准 +- `processPaymentActivity`:处理和授权付款。 +- `updateInventoryActivity`:使用新的剩余库存值更新状态存储。 + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [已安装最新的 Node.js](https://nodejs.org/download/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/workflows/javascript/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +在新的终端窗口中,导航到 `order-processor` 目录: + +```bash +cd workflows/javascript/sdk/order-processor +``` + +安装依赖项: + +```bash +cd ./javascript/sdk +npm install +npm run build +``` + +### 步骤 3:运行订单处理器应用程序 + +在终端中,使用 [Multi-App Run]({{< ref multi-app-dapr-run >}}) 启动订单处理器应用程序及其 Dapr 边车。从 `javascript/sdk` 目录运行以下命令: + +```bash +dapr run -f . +``` + +这将启动具有唯一工作流 ID 的 `order-processor` 应用程序并运行工作流活动。 + +预期输出: + +```log +== APP - workflowApp == == APP == Orchestration scheduled with ID: 0c332155-1e02-453a-a333-28cfc7777642 +== APP - workflowApp == == APP == Waiting 30 seconds for instance 0c332155-1e02-453a-a333-28cfc7777642 to complete... +== APP - workflowApp == == APP == Received "Orchestrator Request" work item with instance id '0c332155-1e02-453a-a333-28cfc7777642' +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Rebuilding local state with 0 history event... +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Processing 2 new history event(s): [ORCHESTRATORSTARTED=1, EXECUTIONSTARTED=1] +== APP - workflowApp == == APP == Processing order 0c332155-1e02-453a-a333-28cfc7777642... +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Waiting for 1 task(s) and 0 event(s) to complete... +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Returning 1 action(s) +== APP - workflowApp == == APP == Received "Activity Request" work item +== APP - workflowApp == == APP == Received order 0c332155-1e02-453a-a333-28cfc7777642 for 10 item1 at a total cost of 100 +== APP - workflowApp == == APP == Activity notifyActivity completed with output undefined (0 chars) +== APP - workflowApp == == APP == Received "Orchestrator Request" work item with instance id '0c332155-1e02-453a-a333-28cfc7777642' +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Rebuilding local state with 3 history event... +== APP - workflowApp == == APP == Processing order 0c332155-1e02-453a-a333-28cfc7777642... +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Processing 2 new history event(s): [ORCHESTRATORSTARTED=1, TASKCOMPLETED=1] +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Waiting for 1 task(s) and 0 event(s) to complete... +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Returning 1 action(s) +== APP - workflowApp == == APP == Received "Activity Request" work item +== APP - workflowApp == == APP == Reserving inventory for 0c332155-1e02-453a-a333-28cfc7777642 of 10 item1 +== APP - workflowApp == == APP == 2024-02-16T03:15:59.498Z INFO [HTTPClient, HTTPClient] Sidecar Started +== APP - workflowApp == == APP == There are 100 item1 in stock +== APP - workflowApp == == APP == Activity reserveInventoryActivity completed with output {"success":true,"inventoryItem":{"perItemCost":100,"quantity":100,"itemName":"item1"}} (86 chars) +== APP - workflowApp == == APP == Received "Orchestrator Request" work item with instance id '0c332155-1e02-453a-a333-28cfc7777642' +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Rebuilding local state with 6 history event... +== APP - workflowApp == == APP == Processing order 0c332155-1e02-453a-a333-28cfc7777642... +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Processing 2 new history event(s): [ORCHESTRATORSTARTED=1, TASKCOMPLETED=1] +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Waiting for 1 task(s) and 0 event(s) to complete... +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Returning 1 action(s) +== APP - workflowApp == == APP == Received "Activity Request" work item +== APP - workflowApp == == APP == Processing payment for order item1 +== APP - workflowApp == == APP == Payment of 100 for 10 item1 processed successfully +== APP - workflowApp == == APP == Activity processPaymentActivity completed with output true (4 chars) +== APP - workflowApp == == APP == Received "Orchestrator Request" work item with instance id '0c332155-1e02-453a-a333-28cfc7777642' +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Rebuilding local state with 9 history event... +== APP - workflowApp == == APP == Processing order 0c332155-1e02-453a-a333-28cfc7777642... +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Processing 2 new history event(s): [ORCHESTRATORSTARTED=1, TASKCOMPLETED=1] +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Waiting for 1 task(s) and 0 event(s) to complete... +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Returning 1 action(s) +== APP - workflowApp == == APP == Received "Activity Request" work item +== APP - workflowApp == == APP == Updating inventory for 0c332155-1e02-453a-a333-28cfc7777642 of 10 item1 +== APP - workflowApp == == APP == Inventory updated for 0c332155-1e02-453a-a333-28cfc7777642, there are now 90 item1 in stock +== APP - workflowApp == == APP == Activity updateInventoryActivity completed with output {"success":true,"inventoryItem":{"perItemCost":100,"quantity":90,"itemName":"item1"}} (85 chars) +== APP - workflowApp == == APP == Received "Orchestrator Request" work item with instance id '0c332155-1e02-453a-a333-28cfc7777642' +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Rebuilding local state with 12 history event... +== APP - workflowApp == == APP == Processing order 0c332155-1e02-453a-a333-28cfc7777642... +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Processing 2 new history event(s): [ORCHESTRATORSTARTED=1, TASKCOMPLETED=1] +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Waiting for 1 task(s) and 0 event(s) to complete... +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Returning 1 action(s) +== APP - workflowApp == == APP == Received "Activity Request" work item +== APP - workflowApp == == APP == order 0c332155-1e02-453a-a333-28cfc7777642 processed successfully! +== APP - workflowApp == == APP == Activity notifyActivity completed with output undefined (0 chars) +== APP - workflowApp == == APP == Received "Orchestrator Request" work item with instance id '0c332155-1e02-453a-a333-28cfc7777642' +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Rebuilding local state with 15 history event... +== APP - workflowApp == == APP == Processing order 0c332155-1e02-453a-a333-28cfc7777642... +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Processing 2 new history event(s): [ORCHESTRATORSTARTED=1, TASKCOMPLETED=1] +== APP - workflowApp == == APP == Order 0c332155-1e02-453a-a333-28cfc7777642 processed successfully! +== APP - workflowApp == == APP == 0c332155-1e02-453a-a333-28cfc7777642: Orchestration completed with status COMPLETED +== APP - workflowApp == time="2024-02-15T21:15:59.5589687-06:00" level=info msg="0c332155-1e02-453a-a333-28cfc7777642: 'orderProcessingWorkflow' completed with a COMPLETED status." app_id=activity-sequence-workflow instance=kaibocai-devbox scope=wfengine.backend type=log ver=1.12.4 +== APP - workflowApp == == APP == Instance 0c332155-1e02-453a-a333-28cfc7777642 completed +``` + +### (可选)步骤 4:在 Zipkin 中查看 + +运行 `dapr init` 会启动 [openzipkin/zipkin](https://hub.docker.com/r/openzipkin/zipkin/) Docker 容器。如果容器已停止运行,请使用以下命令启动 Zipkin Docker 容器: + +``` +docker run -d -p 9411:9411 openzipkin/zipkin +``` + +在 Zipkin Web UI 中查看工作流跟踪跨度(通常位于 `http://localhost:9411/zipkin/`)。 + + + +### 发生了什么? + +当您运行 `dapr run -f .` 时: + +1. 为工作流生成了一个唯一的订单 ID(在上面的示例中为 `0c332155-1e02-453a-a333-28cfc7777642`),并调度了工作流。 +2. `notifyActivity` 工作流活动发送通知,表示已收到 10 辆车的订单。 +3. `reserveInventoryActivity` 工作流活动检查库存数据,确定您是否可以供应订购的商品,并响应库存中的汽车数量。 +4. 您的工作流启动并通知您其状态。 +5. `processPaymentActivity` 工作流活动开始处理订单 `0c332155-1e02-453a-a333-28cfc7777642` 的付款,并确认是否成功。 +6. `updateInventoryActivity` 工作流活动在订单处理后更新库存中的当前可用汽车。 +7. `notifyActivity` 工作流活动发送通知,表示订单 `0c332155-1e02-453a-a333-28cfc7777642` 已完成。 +8. 工作流终止为已完成。 + +#### `order-processor/workflowApp.ts` + +在应用程序文件中,您将会: + +- 生成唯一的工作流订单 ID +- 调度工作流 +- 检索工作流状态 +- 注册工作流及其调用的工作流活动 + +```javascript +import { DaprWorkflowClient, WorkflowRuntime, DaprClient } from "@dapr/dapr-dev"; +import { InventoryItem, OrderPayload } from "./model"; +import { notifyActivity, orderProcessingWorkflow, processPaymentActivity, requestApprovalActivity, reserveInventoryActivity, updateInventoryActivity } from "./orderProcessingWorkflow"; + +async function start() { + // Update the gRPC client and worker to use a local address and port + const workflowClient = new DaprWorkflowClient(); + const workflowWorker = new WorkflowRuntime(); + + const daprClient = new DaprClient(); + const storeName = "statestore"; + + const inventory = new InventoryItem("item1", 100, 100); + const key = inventory.itemName; + + await daprClient.state.save(storeName, [ + { + key: key, + value: inventory, + } + ]); + + const order = new OrderPayload("item1", 100, 10); + + workflowWorker + .registerWorkflow(orderProcessingWorkflow) + .registerActivity(notifyActivity) + .registerActivity(reserveInventoryActivity) + .registerActivity(requestApprovalActivity) + .registerActivity(processPaymentActivity) + .registerActivity(updateInventoryActivity); + + // Wrap the worker startup in a try-catch block to handle any errors during startup + try { + await workflowWorker.start(); + console.log("Workflow runtime started successfully"); + } catch (error) { + console.error("Error starting workflow runtime:", error); + } + + // Schedule a new orchestration + try { + const id = await workflowClient.scheduleNewWorkflow(orderProcessingWorkflow, order); + console.log(`Orchestration scheduled with ID: ${id}`); + + // Wait for orchestration completion + const state = await workflowClient.waitForWorkflowCompletion(id, undefined, 30); + + console.log(`Orchestration completed! Result: ${state?.serializedOutput}`); + } catch (error) { + console.error("Error scheduling or waiting for orchestration:", error); + throw error; + } + + await workflowWorker.stop(); + await workflowClient.stop(); +} + +start().catch((e) => { + console.error(e); + process.exit(1); +}); +``` + +{{% /codetab %}} + + +{{% codetab %}} + +`order-processor` 控制台应用程序启动并管理订单处理工作流的生命周期,该工作流在状态存储中存储和检索数据。工作流由四个工作流活动或任务组成: + +- `NotifyActivity`:使用记录器在整个工作流过程中打印消息 +- `ReserveInventoryActivity`:检查状态存储以确保有足够的库存可供购买 +- `ProcessPaymentActivity`:处理和授权付款 +- `UpdateInventoryActivity`:从状态存储中移除请求的商品,并使用新的剩余库存值更新存储 + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + +- [.NET 7](https://dotnet.microsoft.com/download/dotnet/7.0)、[.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) 或 [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) 已安装 + +**注意:** .NET 7 是 Dapr v1.15 中 Dapr.Workflows 支持的最低版本。只有 .NET 8 和 .NET 9 将在 Dapr v1.16 及更高版本中得到支持。 + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/workflows/csharp/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +在新的终端窗口中,导航到 `order-processor` 目录: + +```bash +cd workflows/csharp/sdk/order-processor +``` + +安装依赖项: + +```bash +dotnet restore +dotnet build +``` + +返回到 `csharp/sdk` 目录: + +```bash +cd .. +``` + +### 步骤 3:运行订单处理器应用程序 + +在终端中,使用 [Multi-App Run]({{< ref multi-app-dapr-run >}}) 启动订单处理器应用程序及其 Dapr 边车。从 `csharp/sdk` 目录运行以下命令: + +```bash +dapr run -f . +``` + +这将启动具有唯一工作流 ID 的 `order-processor` 应用程序并运行工作流活动。 + +预期输出: + +``` +== APP == Starting workflow 6d2abcc9 purchasing 10 Cars + +== APP == info: Microsoft.DurableTask.Client.Grpc.GrpcDurableTaskClient[40] +== APP == Scheduling new OrderProcessingWorkflow orchestration with instance ID '6d2abcc9' and 47 bytes of input data. +== APP == info: WorkflowConsoleApp.Activities.NotifyActivity[0] +== APP == Received order 6d2abcc9 for 10 Cars at $15000 +== APP == info: WorkflowConsoleApp.Activities.ReserveInventoryActivity[0] +== APP == Reserving inventory for order 6d2abcc9 of 10 Cars +== APP == info: WorkflowConsoleApp.Activities.ReserveInventoryActivity[0] +== APP == There are: 100, Cars available for purchase + +== APP == Your workflow has started. Here is the status of the workflow: Dapr.Workflow.WorkflowState + +== APP == info: WorkflowConsoleApp.Activities.ProcessPaymentActivity[0] +== APP == Processing payment: 6d2abcc9 for 10 Cars at $15000 +== APP == info: WorkflowConsoleApp.Activities.ProcessPaymentActivity[0] +== APP == Payment for request ID '6d2abcc9' processed successfully +== APP == info: WorkflowConsoleApp.Activities.UpdateInventoryActivity[0] +== APP == Checking Inventory for: Order# 6d2abcc9 for 10 Cars +== APP == info: WorkflowConsoleApp.Activities.UpdateInventoryActivity[0] +== APP == There are now: 90 Cars left in stock +== APP == info: WorkflowConsoleApp.Activities.NotifyActivity[0] +== APP == Order 6d2abcc9 has completed! + +== APP == Workflow Status: Completed +``` + +### (可选)步骤 4:在 Zipkin 中查看 + +运行 `dapr init` 会启动 [openzipkin/zipkin](https://hub.docker.com/r/openzipkin/zipkin/) Docker 容器。如果容器已停止运行,请使用以下命令启动 Zipkin Docker 容器: + +``` +docker run -d -p 9411:9411 openzipkin/zipkin +``` + +在 Zipkin Web UI 中查看工作流跟踪跨度(通常位于 `http://localhost:9411/zipkin/`)。 + + + +### 发生了什么? + +当您运行 `dapr run -f .` 时: + +1. 为工作流生成了一个唯一的订单 ID(在上面的示例中为 `6d2abcc9`),并调度了工作流。 +2. `NotifyActivity` 工作流活动发送通知,表示已收到 10 辆车的订单。 +3. `ReserveInventoryActivity` 工作流活动检查库存数据,确定您是否可以供应订购的商品,并响应库存中的汽车数量。 +4. 您的工作流启动并通知您其状态。 +5. `ProcessPaymentActivity` 工作流活动开始处理订单 `6d2abcc9` 的付款,并确认是否成功。 +6. `UpdateInventoryActivity` 工作流活动在订单处理后更新库存中的当前可用汽车。 +7. `NotifyActivity` 工作流活动发送通知,表示订单 `6d2abcc9` 已完成。 +8. 工作流终止为已完成。 + +#### `order-processor/Program.cs` + +在应用程序的程序文件中,您将会: + +- 生成唯一的工作流订单 ID +- 调度工作流 +- 检索工作流状态 +- 注册工作流及其调用的工作流活动 + +```csharp +using Dapr.Client; +using Dapr.Workflow; +//... + +{ + services.AddDaprWorkflow(options => + { + // Note that it's also possible to register a lambda function as the workflow + // or activity implementation instead of a class. + options.RegisterWorkflow(); + + // These are the activities that get invoked by the workflow(s). + options.RegisterActivity(); + options.RegisterActivity(); + options.RegisterActivity(); + options.RegisterActivity(); + }); +}; + +//... + +// Generate a unique ID for the workflow +string orderId = Guid.NewGuid().ToString()[..8]; +string itemToPurchase = "Cars"; +int ammountToPurchase = 10; + +// Construct the order +OrderPayload orderInfo = new OrderPayload(itemToPurchase, 15000, ammountToPurchase); + +// Start the workflow +Console.WriteLine("Starting workflow {0} purchasing {1} {2}", orderId, ammountToPurchase, itemToPurchase); + +await daprWorkflowClient.ScheduleNewWorkflowAsync( + name: nameof(OrderProcessingWorkflow), + input: orderInfo, + instanceId: orderId); + +// Wait for the workflow to start and confirm the input +WorkflowState state = await daprWorkflowClient.WaitForWorkflowStartAsync( + instanceId: orderId); + +Console.WriteLine($"{nameof(OrderProcessingWorkflow)} (ID = {orderId}) started successfully with {state.ReadInputAs()}"); + +// Wait for the workflow to complete +using var ctx = new CancellationTokenSource(TimeSpan.FromSeconds(5)); +state = await daprClient.WaitForWorkflowCompletionAsync( + instanceId: orderId, + cancellation: ctx.Token); + +Console.WriteLine("Workflow Status: {0}", state.ReadCustomStatusAs()); +``` + +#### `order-processor/Workflows/OrderProcessingWorkflow.cs` + +在 `OrderProcessingWorkflow.cs` 中,工作流被定义为一个类,包含其所有相关任务(由工作流活动确定)。 + +```csharp +using Dapr.Workflow; +//... + +class OrderProcessingWorkflow : Workflow + { + public override async Task RunAsync(WorkflowContext context, OrderPayload order) + { + string orderId = context.InstanceId; + + // Notify the user that an order has come through + await context.CallActivityAsync( + nameof(NotifyActivity), + new Notification($"Received order {orderId} for {order.Quantity} {order.Name} at ${order.TotalCost}")); + + string requestId = context.InstanceId; + + // Determine if there is enough of the item available for purchase by checking the inventory + InventoryResult result = await context.CallActivityAsync( + nameof(ReserveInventoryActivity), + new InventoryRequest(RequestId: orderId, order.Name, order.Quantity)); + + // If there is insufficient inventory, fail and let the user know + if (!result.Success) + { + // End the workflow here since we don't have sufficient inventory + await context.CallActivityAsync( + nameof(NotifyActivity), + new Notification($"Insufficient inventory for {order.Name}")); + return new OrderResult(Processed: false); + } + + // There is enough inventory available so the user can purchase the item(s). Process their payment + await context.CallActivityAsync( + nameof(ProcessPaymentActivity), + new PaymentRequest(RequestId: orderId, order.Name, order.Quantity, order.TotalCost)); + + try + { + // There is enough inventory available so the user can purchase the item(s). Process their payment + await context.CallActivityAsync( + nameof(UpdateInventoryActivity), + new PaymentRequest(RequestId: orderId, order.Name, order.Quantity, order.TotalCost)); + } + catch (WorkflowTaskFailedException) + { + // Let them know their payment was processed + await context.CallActivityAsync( + nameof(NotifyActivity), + new Notification($"Order {orderId} Failed! You are now getting a refund")); + return new OrderResult(Processed: false); + } + + // Let them know their payment was processed + await context.CallActivityAsync( + nameof(NotifyActivity), + new Notification($"Order {orderId} has completed!")); + + // End the workflow with a success result + return new OrderResult(Processed: true); + } + } +``` + +#### `order-processor/Activities` 目录 + +`Activities` 目录包含工作流使用的四个工作流活动,定义在以下文件中: + +- `NotifyActivity.cs` +- `ReserveInventoryActivity.cs` +- `ProcessPaymentActivity.cs` +- `UpdateInventoryActivity.cs` + +## 观看演示 + +观看[此视频以了解 Dapr Workflow .NET 演示](https://youtu.be/BxiKpEmchgQ?t=2564): + + + +{{% /codetab %}} + + +{{% codetab %}} + +`order-processor` 控制台应用程序启动并管理订单处理工作流的生命周期,该工作流在状态存储中存储和检索数据。工作流由四个工作流活动或任务组成: + +- `NotifyActivity`:使用记录器在整个工作流过程中打印消息 +- `RequestApprovalActivity`:请求处理付款的批准 +- `ReserveInventoryActivity`:检查状态存储以确保有足够的库存可供购买 +- `ProcessPaymentActivity`:处理和授权付款 +- `UpdateInventoryActivity`:从状态存储中移除请求的商品,并使用新的剩余库存值更新存储 + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- Java JDK 17(或更高版本): + - [Microsoft JDK 17](https://docs.microsoft.com/java/openjdk/download#openjdk-17) + - [Oracle JDK 17](https://www.oracle.com/technetwork/java/javase/downloads/index.html#JDK17) + - [OpenJDK 17](https://jdk.java.net/17/) +- [Apache Maven](https://maven.apache.org/install.html) 版本 3.x。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/workflows/java/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +导航到 `order-processor` 目录: + +```bash +cd workflows/java/sdk/order-processor +``` + +安装依赖项: + +```bash +mvn clean install +``` + +返回到 `java/sdk` 目录: + +```bash +cd .. +``` + +### 步骤 3:运行订单处理器应用程序 + +在终端中,使用 [Multi-App Run]({{< ref multi-app-dapr-run >}}) 启动订单处理器应用程序及其 Dapr 边车。从 `java/sdk` 目录运行以下命令: + +```bash +cd workflows/java/sdk +dapr run -f . +``` + +这将启动具有唯一工作流 ID 的 `order-processor` 应用程序并运行工作流活动。 + +预期输出: + +``` +== APP == *** Welcome to the Dapr Workflow console app sample! +== APP == *** Using this app, you can place orders that start workflows. +== APP == Start workflow runtime +== APP == Sep 20, 2023 3:23:05 PM com.microsoft.durabletask.DurableTaskGrpcWorker startAndBlock +== APP == INFO: Durable Task worker is connecting to sidecar at 127.0.0.1:50001. + +== APP == ==========Begin the purchase of item:========== +== APP == Starting order workflow, purchasing 10 of cars + +== APP == scheduled new workflow instance of OrderProcessingWorkflow with instance ID: edceba90-9c45-4be8-ad40-60d16e060797 +== APP == [Thread-0] INFO io.dapr.workflows.WorkflowContext - Starting Workflow: io.dapr.quickstarts.workflows.OrderProcessingWorkflow +== APP == [Thread-0] INFO io.dapr.workflows.WorkflowContext - Instance ID(order ID): edceba90-9c45-4be8-ad40-60d16e060797 +== APP == [Thread-0] INFO io.dapr.workflows.WorkflowContext - Current Orchestration Time: 2023-09-20T19:23:09.755Z +== APP == [Thread-0] INFO io.dapr.workflows.WorkflowContext - Received Order: OrderPayload [itemName=cars, totalCost=150000, quantity=10] +== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.NotifyActivity - Received Order: OrderPayload [itemName=cars, totalCost=150000, quantity=10] +== APP == workflow instance edceba90-9c45-4be8-ad40-60d16e060797 started +== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.ReserveInventoryActivity - Reserving inventory for order 'edceba90-9c45-4be8-ad40-60d16e060797' of 10 cars +== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.ReserveInventoryActivity - There are 100 cars available for purchase +== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.ReserveInventoryActivity - Reserved inventory for order 'edceba90-9c45-4be8-ad40-60d16e060797' of 10 cars +== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.RequestApprovalActivity - Requesting approval for order: OrderPayload [itemName=cars, totalCost=150000, quantity=10] +== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.RequestApprovalActivity - Approved requesting approval for order: OrderPayload [itemName=cars, totalCost=150000, quantity=10] +== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.ProcessPaymentActivity - Processing payment: edceba90-9c45-4be8-ad40-60d16e060797 for 10 cars at $150000 +== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.ProcessPaymentActivity - Payment for request ID 'edceba90-9c45-4be8-ad40-60d16e060797' processed successfully +== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.UpdateInventoryActivity - Updating inventory for order 'edceba90-9c45-4be8-ad40-60d16e060797' of 10 cars +== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.UpdateInventoryActivity - Updated inventory for order 'edceba90-9c45-4be8-ad40-60d16e060797': there are now 90 cars left in stock +== APP == [Thread-0] INFO io.dapr.quickstarts.workflows.activities.NotifyActivity - Order completed! : edceba90-9c45-4be8-ad40-60d16e060797 + +== APP == workflow instance edceba90-9c45-4be8-ad40-60d16e060797 completed, out is: {"processed":true} +``` + +### (可选)步骤 4:在 Zipkin 中查看 + +运行 `dapr init` 会启动 [openzipkin/zipkin](https://hub.docker.com/r/openzipkin/zipkin/) Docker 容器。如果容器已停止运行,请使用以下命令启动 Zipkin Docker 容器: + +``` +docker run -d -p 9411:9411 openzipkin/zipkin +``` + +在 Zipkin Web UI 中查看工作流跟踪跨度(通常位于 `http://localhost:9411/zipkin/`)。 + + + +### 发生了什么? + +当您运行 `dapr run -f .` 时: + +1. 为工作流生成了一个唯一的订单 ID(在上面的示例中为 `edceba90-9c45-4be8-ad40-60d16e060797`),并调度了工作流。 +2. `NotifyActivity` 工作流活动发送通知,表示已收到 10 辆车的订单。 +3. `ReserveInventoryActivity` 工作流活动检查库存数据,确定您是否可以供应订购的商品,并响应库存中的汽车数量。 +4. 一旦获得批准,您的工作流启动并通知您其状态。 +5. `ProcessPaymentActivity` 工作流活动开始处理订单 `edceba90-9c45-4be8-ad40-60d16e060797` 的付款,并确认是否成功。 +6. `UpdateInventoryActivity` 工作流活动在订单处理后更新库存中的当前可用汽车。 +7. `NotifyActivity` 工作流活动发送通知,表示订单 `edceba90-9c45-4be8-ad40-60d16e060797` 已完成。 +8. 工作流终止为已完成。 + +#### `order-processor/WorkflowConsoleApp.java` + +在应用程序的程序文件中,您将会: +- 生成唯一的工作流订单 ID +- 调度工作流 +- 检索工作流状态 +- 注册工作流及其调用的工作流活动 + +```java +package io.dapr.quickstarts.workflows; +import io.dapr.client.DaprClient; +import io.dapr.client.DaprClientBuilder; +import io.dapr.workflows.client.DaprWorkflowClient; + +public class WorkflowConsoleApp { + + private static final String STATE_STORE_NAME = "statestore-actors"; + + // ... + public static void main(String[] args) throws Exception { + System.out.println("*** Welcome to the Dapr Workflow console app sample!"); + System.out.println("*** Using this app, you can place orders that start workflows."); + // Wait for the sidecar to become available + Thread.sleep(5 * 1000); + + // Register the OrderProcessingWorkflow and its activities with the builder. + WorkflowRuntimeBuilder builder = new WorkflowRuntimeBuilder().registerWorkflow(OrderProcessingWorkflow.class); + builder.registerActivity(NotifyActivity.class); + builder.registerActivity(ProcessPaymentActivity.class); + builder.registerActivity(RequestApprovalActivity.class); + builder.registerActivity(ReserveInventoryActivity.class); + builder.registerActivity(UpdateInventoryActivity.class); + + // Build the workflow runtime + try (WorkflowRuntime runtime = builder.build()) { + System.out.println("Start workflow runtime"); + runtime.start(false); + } + + InventoryItem inventory = prepareInventoryAndOrder(); + + DaprWorkflowClient workflowClient = new DaprWorkflowClient(); + try (workflowClient) { + executeWorkflow(workflowClient, inventory); + } + + } + + // Start the workflow runtime, pulling and executing tasks + private static void executeWorkflow(DaprWorkflowClient workflowClient, InventoryItem inventory) { + System.out.println("==========Begin the purchase of item:=========="); + String itemName = inventory.getName(); + int orderQuantity = inventory.getQuantity(); + int totalcost = orderQuantity * inventory.getPerItemCost(); + OrderPayload order = new OrderPayload(); + order.setItemName(itemName); + order.setQuantity(orderQuantity); + order.setTotalCost(totalcost); + System.out.println("Starting order workflow, purchasing " + orderQuantity + " of " + itemName); + + String instanceId = workflowClient.scheduleNewWorkflow(OrderProcessingWorkflow.class, order); + System.out.printf("scheduled new workflow instance of OrderProcessingWorkflow with instance ID: %s%n", + instanceId); + + // Check workflow instance start status + try { + workflowClient.waitForInstanceStart(instanceId, Duration.ofSeconds(10), false); + System.out.printf("workflow instance %s started%n", instanceId); + } catch (TimeoutException e) { + System.out.printf("workflow instance %s did not start within 10 seconds%n", instanceId); + return; + } + + // Check workflow instance complete status + try { + WorkflowInstanceStatus workflowStatus = workflowClient.waitForInstanceCompletion(instanceId, + Duration.ofSeconds(30), + true); + if (workflowStatus != null) { + System.out.printf("workflow instance %s completed, out is: %s %n", instanceId, + workflowStatus.getSerializedOutput()); + } else { + System.out.printf("workflow instance %s not found%n", instanceId); + } + } catch (TimeoutException e) { + System.out.printf("workflow instance %s did not complete within 30 seconds%n", instanceId); + } + + } + + private static InventoryItem prepareInventoryAndOrder() { + // prepare 100 cars in inventory + InventoryItem inventory = new InventoryItem(); + inventory.setName("cars"); + inventory.setPerItemCost(15000); + inventory.setQuantity(100); + DaprClient daprClient = new DaprClientBuilder().build(); + restockInventory(daprClient, inventory); + + // prepare order for 10 cars + InventoryItem order = new InventoryItem(); + order.setName("cars"); + order.setPerItemCost(15000); + order.setQuantity(10); + return order; + } + + private static void restockInventory(DaprClient daprClient, InventoryItem inventory) { + String key = inventory.getName(); + daprClient.saveState(STATE_STORE_NAME, key, inventory).block(); + } +} +``` + +#### `OrderProcessingWorkflow.java` + +在 `OrderProcessingWorkflow.java` 中,工作流被定义为一个类,包含其所有相关任务(由工作流活动确定)。 + +```java +package io.dapr.quickstarts.workflows; +import io.dapr.workflows.Workflow; + +public class OrderProcessingWorkflow extends Workflow { + + @Override + public WorkflowStub create() { + return ctx -> { + Logger logger = ctx.getLogger(); + String orderId = ctx.getInstanceId(); + logger.info("Starting Workflow: " + ctx.getName()); + logger.info("Instance ID(order ID): " + orderId); + logger.info("Current Orchestration Time: " + ctx.getCurrentInstant()); + + OrderPayload order = ctx.getInput(OrderPayload.class); + logger.info("Received Order: " + order.toString()); + OrderResult orderResult = new OrderResult(); + orderResult.setProcessed(false); + + // Notify the user that an order has come through + Notification notification = new Notification(); + notification.setMessage("Received Order: " + order.toString()); + ctx.callActivity(NotifyActivity.class.getName(), notification).await(); + + // Determine if there is enough of the item available for purchase by checking + // the inventory + InventoryRequest inventoryRequest = new InventoryRequest(); + inventoryRequest.setRequestId(orderId); + inventoryRequest.setItemName(order.getItemName()); + inventoryRequest.setQuantity(order.getQuantity()); + InventoryResult inventoryResult = ctx.callActivity(ReserveInventoryActivity.class.getName(), + inventoryRequest, InventoryResult.class).await(); + + // If there is insufficient inventory, fail and let the user know + if (!inventoryResult.isSuccess()) { + notification.setMessage("Insufficient inventory for order : " + order.getItemName()); + ctx.callActivity(NotifyActivity.class.getName(), notification).await(); + ctx.complete(orderResult); + return; + } + + // Require orders over a certain threshold to be approved + if (order.getTotalCost() > 5000) { + ApprovalResult approvalResult = ctx.callActivity(RequestApprovalActivity.class.getName(), + order, ApprovalResult.class).await(); + if (approvalResult != ApprovalResult.Approved) { + notification.setMessage("Order " + order.getItemName() + " was not approved."); + ctx.callActivity(NotifyActivity.class.getName(), notification).await(); + ctx.complete(orderResult); + return; + } + } + + // There is enough inventory available so the user can purchase the item(s). + // Process their payment + PaymentRequest paymentRequest = new PaymentRequest(); + paymentRequest.setRequestId(orderId); + paymentRequest.setItemBeingPurchased(order.getItemName()); + paymentRequest.setQuantity(order.getQuantity()); + paymentRequest.setAmount(order.getTotalCost()); + boolean isOK = ctx.callActivity(ProcessPaymentActivity.class.getName(), + paymentRequest, boolean.class).await(); + if (!isOK) { + notification.setMessage("Payment failed for order : " + orderId); + ctx.callActivity(NotifyActivity.class.getName(), notification).await(); + ctx.complete(orderResult); + return; + } + + inventoryResult = ctx.callActivity(UpdateInventoryActivity.class.getName(), + inventoryRequest, InventoryResult.class).await(); + if (!inventoryResult.isSuccess()) { + // If there is an error updating the inventory, refund the user + // paymentRequest.setAmount(-1 * paymentRequest.getAmount()); + // ctx.callActivity(ProcessPaymentActivity.class.getName(), + // paymentRequest).await(); + + // Let users know their payment processing failed + notification.setMessage("Order failed to update inventory! : " + orderId); + ctx.callActivity(NotifyActivity.class.getName(), notification).await(); + ctx.complete(orderResult); + return; + } + + // Let user know their order was processed + notification.setMessage("Order completed! : " + orderId); + ctx.callActivity(NotifyActivity.class.getName(), notification).await(); + + // Complete the workflow with order result is processed + orderResult.setProcessed(true); + ctx.complete(orderResult); + }; + } + +} +``` + +#### `activities` 目录 + +`Activities` 目录包含工作流使用的四个工作流活动,定义在以下文件中: +- [`NotifyActivity.java`](https://github.com/dapr/quickstarts/tree/master/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/NotifyActivity.java) +- [`RequestApprovalActivity`](https://github.com/dapr/quickstarts/tree/master/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/RequestApprovalActivity.java) +- [`ReserveInventoryActivity`](https://github.com/dapr/quickstarts/tree/master/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/ReserveInventoryActivity.java) +- [`ProcessPaymentActivity`](https://github.com/dapr/quickstarts/tree/master/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/ProcessPaymentActivity.java) +- [`UpdateInventoryActivity`](https://github.com/dapr/quickstarts/tree/master/workflows/java/sdk/order-processor/src/main/java/io/dapr/quickstarts/workflows/activities/UpdateInventoryActivity.java) + +{{% /codetab %}} + + +{{% codetab %}} + +`order-processor` 控制台应用程序启动并管理 `OrderProcessingWorkflow` 工作流,该工作流模拟从商店购买商品。工作流由五个独特的工作流活动或任务组成: + +- `NotifyActivity`:使用记录器在整个工作流过程中打印消息。这些消息通知您: + - 您的库存不足 + - 您的付款无法处理,等等。 +- `ProcessPaymentActivity`:处理和授权付款。 +- `VerifyInventoryActivity`:检查状态存储以确保有足够的库存可供购买。 +- `UpdateInventoryActivity`:从状态存储中移除请求的商品,并使用新的剩余库存值更新存储。 +- `RequestApprovalActivity`:如果付款金额超过 50,000 美元,则寻求经理的批准。 + +### 步骤 1:先决条件 + +对于此示例,您将需要: + +- [Dapr CLI 和已初始化的环境](https://docs.dapr.io/getting-started)。 +- [最新版本的 Go](https://go.dev/dl/)。 + +- [Docker Desktop](https://www.docker.com/products/docker-desktop) + + +### 步骤 2:设置环境 + +克隆[快速入门仓库中提供的示例](https://github.com/dapr/quickstarts/tree/master/workflows/go/sdk)。 + +```bash +git clone https://github.com/dapr/quickstarts.git +``` + +在新的终端窗口中,导航到 `sdk` 目录: + +```bash +cd workflows/go/sdk +``` + +### 步骤 3:运行订单处理器应用程序 + +在终端中,使用 [Multi-App Run]({{< ref multi-app-dapr-run >}}) 启动订单处理器应用程序及其 Dapr 边车。从 `go/sdk` 目录运行以下命令: + +```bash +dapr run -f . +``` + +这将启动具有唯一工作流 ID 的 `order-processor` 应用程序并运行工作流活动。 + +预期输出: + +```bash +== APP - order-processor == *** Welcome to the Dapr Workflow console app sample! +== APP - order-processor == *** Using this app, you can place orders that start workflows. +== APP - order-processor == dapr client initializing for: 127.0.0.1:50056 +== APP - order-processor == adding base stock item: paperclip +== APP - order-processor == 2024/02/01 12:59:52 work item listener started +== APP - order-processor == INFO: 2024/02/01 12:59:52 starting background processor +== APP - order-processor == adding base stock item: cars +== APP - order-processor == adding base stock item: computers +== APP - order-processor == ==========Begin the purchase of item:========== +== APP - order-processor == NotifyActivity: Received order 48ee83b7-5d80-48d5-97f9-6b372f5480a5 for 10 cars - $150000 +== APP - order-processor == VerifyInventoryActivity: Verifying inventory for order 48ee83b7-5d80-48d5-97f9-6b372f5480a5 of 10 cars +== APP - order-processor == VerifyInventoryActivity: There are 100 cars available for purchase +== APP - order-processor == RequestApprovalActivity: Requesting approval for payment of 150000USD for 10 cars +== APP - order-processor == NotifyActivity: Payment for order 48ee83b7-5d80-48d5-97f9-6b372f5480a5 has been approved! +== APP - order-processor == ProcessPaymentActivity: 48ee83b7-5d80-48d5-97f9-6b372f5480a5 for 10 - cars (150000USD) +== APP - order-processor == UpdateInventoryActivity: Checking Inventory for order 48ee83b7-5d80-48d5-97f9-6b372f5480a5 for 10 * cars +== APP - order-processor == UpdateInventoryActivity: There are now 90 cars left in stock +== APP - order-processor == NotifyActivity: Order 48ee83b7-5d80-48d5-97f9-6b372f5480a5 has completed! +== APP - order-processor == Workflow completed - result: COMPLETED +== APP - order-processor == Purchase of item is complete +``` + +使用 `CTRL+C` 或以下命令停止 Dapr 工作流: + +```bash +dapr stop -f . +``` + +### (可选)步骤 4:在 Zipkin 中查看 + +运行 `dapr init` 会启动 [openzipkin/zipkin](https://hub.docker.com/r/openzipkin/zipkin/) Docker 容器。如果容器已停止运行,请使用以下命令启动 Zipkin Docker 容器: + +``` +docker run -d -p 9411:9411 openzipkin/zipkin +``` + +在 Zipkin Web UI 中查看工作流跟踪跨度(通常位于 `http://localhost:9411/zipkin/`)。 + + + +### 发生了什么? + +当您运行 `dapr run` 时: + +1. 为工作流生成了一个唯一的订单 ID(在上面的示例中为 `48ee83b7-5d80-48d5-97f9-6b372f5480a5`),并调度了工作流。 +2. `NotifyActivity` 工作流活动发送通知,表示已收到 10 辆车的订单。 +3. `ReserveInventoryActivity` 工作流活动检查库存数据,确定您是否可以供应订购的商品,并响应库存中的汽车数量。 +4. 您的工作流启动并通知您其状态。 +5. `ProcessPaymentActivity` 工作流活动开始处理订单 `48ee83b7-5d80-48d5-97f9-6b372f5480a5` 的付款,并确认是否成功。 +6. `UpdateInventoryActivity` 工作流活动在订单处理后更新库存中的当前可用汽车。 +7. `NotifyActivity` 工作流活动发送通知,表示订单 `48ee83b7-5d80-48d5-97f9-6b372f5480a5` 已完成。 +8. 工作流终止为已完成。 + +#### `order-processor/main.go` + +在应用程序的程序文件中,您将会: + +- 生成唯一的工作流订单 ID +- 调度工作流 +- 检索工作流状态 +- 注册工作流及其调用的工作流活动 + +```go +func main() { + fmt.Println("*** Welcome to the Dapr Workflow console app sample!") + fmt.Println("*** Using this app, you can place orders that start workflows.") + + // ... + + // Register workflow and activities + if err := w.RegisterWorkflow(OrderProcessingWorkflow); err != nil { + log.Fatal(err) + } + if err := w.RegisterActivity(NotifyActivity); err != nil { + log.Fatal(err) + } + if err := w.RegisterActivity(RequestApprovalActivity); err != nil { + log.Fatal(err) + } + if err := w.RegisterActivity(VerifyInventoryActivity); err != nil { + log.Fatal(err) + } + if err := w.RegisterActivity(ProcessPaymentActivity); err != nil { + log.Fatal(err) + } + if err := w.RegisterActivity(UpdateInventoryActivity); err != nil { + log.Fatal(err) + } + + // Build and start workflow runtime, pulling and executing tasks + if err := w.Start(); err != nil { + log.Fatal(err) + } + + daprClient, err := client.NewClient() + if err != nil { + log.Fatalf("failed to initialise dapr client: %v", err) + } + wfClient, err := workflow.NewClient(workflow.WithDaprClient(daprClient)) + if err != nil { + log.Fatalf("failed to initialise workflow client: %v", err) + } + + // Check inventory + inventory := []InventoryItem{ + {ItemName: "paperclip", PerItemCost: 5, Quantity: 100}, + {ItemName: "cars", PerItemCost: 15000, Quantity: 100}, + {ItemName: "computers", PerItemCost: 500, Quantity: 100}, + } + if err := restockInventory(daprClient, inventory); err != nil { + log.Fatalf("failed to restock: %v", err) + } + + fmt.Println("==========Begin the purchase of item:==========") + + itemName := defaultItemName + orderQuantity := 10 + + totalCost := inventory[1].PerItemCost * orderQuantity + + orderPayload := OrderPayload{ + ItemName: itemName, + Quantity: orderQuantity, + TotalCost: totalCost, + } + + // Start workflow events, like receiving order, verifying inventory, and processing payment + id, err := wfClient.ScheduleNewWorkflow(context.Background(), workflowName, workflow.WithInput(orderPayload)) + if err != nil { + log.Fatalf("failed to start workflow: %v", err) + } + + // ... + + // Notification that workflow has completed or failed + for { + timeDelta := time.Since(startTime) + metadata, err := wfClient.FetchWorkflowMetadata(context.Background(), id) + if err != nil { + log.Fatalf("failed to fetch workflow: %v", err) + } + if (metadata.RuntimeStatus == workflow.StatusCompleted) || (metadata.RuntimeStatus == workflow.StatusFailed) || (metadata.RuntimeStatus == workflow.StatusTerminated) { + fmt.Printf("Workflow completed - result: %v\n", metadata.RuntimeStatus.String()) + break + } + if timeDelta.Seconds() >= 10 { + metadata, err := wfClient.FetchWorkflowMetadata(context.Background(), id) + if err != nil { + log.Fatalf("failed to fetch workflow: %v", err) + } + if totalCost > 50000 && !approvalSought && ((metadata.RuntimeStatus != workflow.StatusCompleted) || (metadata.RuntimeStatus != workflow.StatusFailed) || (metadata.RuntimeStatus != workflow.StatusTerminated)) { + approvalSought = true + promptForApproval(id) + } + } + // Sleep to not DoS the dapr dev instance + time.Sleep(time.Second) + } + + fmt.Println("Purchase of item is complete") +} + +// Request approval (RequestApprovalActivity) +func promptForApproval(id string) { + wfClient, err := workflow.NewClient() + if err != nil { + log.Fatalf("failed to initialise wfClient: %v", err) + } + if err := wfClient.RaiseEvent(context.Background(), id, "manager_approval"); err != nil { + log.Fatal(err) + } +} + +// Update inventory for remaining stock (UpdateInventoryActivity) +func restockInventory(daprClient client.Client, inventory []InventoryItem) error { + for _, item := range inventory { + itemSerialized, err := json.Marshal(item) + if err != nil { + return err + } + fmt.Printf("adding base stock item: %s\n", item.ItemName) + if err := daprClient.SaveState(context.Background(), stateStoreName, item.ItemName, itemSerialized, nil); err != nil { + return err + } + } + return nil +} +``` + +同时,`OrderProcessingWorkflow` 及其活动在 [`workflow.go`](https://github.com/dapr/quickstarts/workflows/go/sdk/order-processor/workflow.go) 中定义为方法 + +{{% /codetab %}} + + +{{< /tabs >}} + +## 告诉我们您的想法! + +我们正在不断努力改进我们的快速入门示例,并重视您的反馈。您觉得这个快速入门有帮助吗?您有改进建议吗? + +加入我们的[Discord 频道](https://discord.com/channels/778680217417809931/953427615916638238)进行讨论。 + +## 下一步 + +- 使用任何编程语言设置 Dapr 工作流,使用 [HTTP 而不是 SDK]({{< ref howto-manage-workflow.md >}}) +- 通过更深入的 [.NET SDK 示例工作流](https://github.com/dapr/dotnet-sdk/tree/master/examples/Workflow) 进行学习 +- 了解有关 [工作流作为 Dapr 构建块]({{< ref workflow-overview >}}) 的更多信息 + +{{< button text="探索 Dapr 教程 >>" page="getting-started/tutorials/_index.md" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/getting-started/tutorials/_index.md b/src/translated_content/zh_CN/docs/getting-started/tutorials/_index.md new file mode 100644 index 000000000..eb49b266d --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/tutorials/_index.md @@ -0,0 +1,34 @@ +--- +type: docs +title: "Dapr 教程" +linkTitle: "Dapr 教程" +weight: 70 +description: "通过深入的示例学习如何使用 Dapr 概念" +no_list: true +--- + +您已经初始化了 Dapr 并尝试了一些构建块,现在可以浏览我们更详细的教程。 + +#### 在您开始之前 + +- [设置本地 Dapr 环境]({{< ref "install-dapr-cli.md" >}})。 +- [通过我们的快速入门探索 Dapr 的一个构建块]({{< ref "getting-started/quickstarts/_index.md" >}})。 + +## 教程 + +得益于我们庞大的 Dapr 社区,我们提供的教程既托管在 Dapr 文档上,也托管在我们的 [GitHub 仓库](https://github.com/dapr/quickstarts)上。 + +| Dapr 文档教程 | 描述 | +|--------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [定义一个组件]({{< ref get-started-component.md >}}) | 创建一个组件定义文件以与 Secrets 构建块交互。 | +| [配置 State & Pub/sub]({{< ref configure-state-pubsub.md >}}) | 为 Dapr 配置状态存储和发布/订阅消息代理组件。 | + +| GitHub 教程 | 描述 | +|--------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [Hello World](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-world) | *推荐*
演示如何在本地运行 Dapr,主要展示服务调用和状态管理。 | +| [Hello World Kubernetes](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-kubernetes) | *推荐*
演示如何在 Kubernetes 中运行 Dapr,主要展示服务调用和状态管理。 | +| [分布式计算器](https://github.com/dapr/quickstarts/tree/master/tutorials/distributed-calculator) | 演示一个分布式计算器应用,使用 Dapr 服务驱动 React Web 应用。主要展示多语言编程、服务调用和状态管理。 | +| [Pub/Sub](https://github.com/dapr/quickstarts/tree/master/tutorials/pub-sub) | 演示如何使用 Dapr 启用发布/订阅应用,使用 Redis 作为发布/订阅组件的实现。 | +| [Bindings](https://github.com/dapr/quickstarts/tree/master/tutorials/bindings) | 演示如何使用 Dapr 创建与其他组件的输入和输出绑定,使用 Kafka 作为绑定的实现。 | +| [可观测性](https://github.com/dapr/quickstarts/tree/master/tutorials/observability) | 演示 Dapr 的追踪能力,使用 Zipkin 作为追踪组件。 | +| [Secret Store](https://github.com/dapr/quickstarts/tree/master/tutorials/secretstore) | 演示使用 Dapr Secrets API 访问密钥存储。 | diff --git a/src/translated_content/zh_CN/docs/getting-started/tutorials/configure-state-pubsub.md b/src/translated_content/zh_CN/docs/getting-started/tutorials/configure-state-pubsub.md new file mode 100644 index 000000000..01f4322ca --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/tutorials/configure-state-pubsub.md @@ -0,0 +1,340 @@ +--- +type: docs +title: "教程:配置状态存储和发布/订阅消息代理" +linkTitle: "配置状态 & 发布/订阅" +weight: 80 +description: "为 Dapr 配置状态存储和发布/订阅消息代理组件" +aliases: + - /zh-hans/getting-started/tutorials/configure-redis/ +--- + +要使用状态和发布/订阅功能,您需要配置两个组件: + +- 用于数据持久化和恢复的状态存储组件。 +- 用于异步消息传递的发布/订阅消息代理组件。 + +您可以在以下链接找到支持的组件列表: +- [支持的状态存储]({{< ref supported-state-stores >}}) +- [支持的发布/订阅消息代理]({{< ref supported-pubsub >}}) + +本教程将介绍如何使用 Redis 进行配置。 + +### 步骤 1:创建 Redis 存储 + +Dapr 可以使用任何 Redis 实例,无论是: + +- 在本地开发环境中运行的容器化实例,还是 +- 托管在云服务上的实例。 + +如果您已经有一个 Redis 实例,请直接跳到[配置](#configure-dapr-components)部分。 + +{{< tabs "自托管" "Kubernetes" "Azure" "AWS" "GCP" >}} + +{{% codetab %}} +在自托管环境中,Dapr CLI 会在初始化过程中自动安装 Redis。您可以直接进行[下一步](#next-steps)。 +{{% /codetab %}} + +{{% codetab %}} +您可以使用 [Helm](https://helm.sh/) 在 Kubernetes 集群中创建 Redis 实例。在开始之前,请确保已[安装 Helm v3](https://github.com/helm/helm#install)。 + +在集群中安装 Redis: + +```bash +helm repo add bitnami https://charts.bitnami.com/bitnami +helm repo update +helm install redis bitnami/redis --set image.tag=6.2 +``` + +Dapr 的发布/订阅功能至少需要 Redis 版本 5。对于状态存储,您可以使用更低版本。 +如果您在本地环境中工作,可以在 `install` 命令中添加 `--set architecture=standalone`,以创建单副本 Redis 设置,从而节省内存和资源。 + +运行 `kubectl get pods` 查看集群中运行的 Redis 容器: + +```bash +$ kubectl get pods +NAME READY STATUS RESTARTS AGE +redis-master-0 1/1 Running 0 69s +redis-replicas-0 1/1 Running 0 69s +redis-replicas-1 1/1 Running 0 22s +``` + +在 Kubernetes 中: +- 主机名为 `redis-master.default.svc.cluster.local:6379` +- secret `redis` 会自动创建。 + +{{% /codetab %}} + +{{% codetab %}} +确保您拥有 Azure 订阅。 + +1. 打开并登录 [Azure 门户](https://ms.portal.azure.com/#create/Microsoft.Cache) 以创建 Azure Redis 缓存。 +1. 填写必要的信息。 + - Dapr 发布/订阅使用 Redis 5.0 引入的 [Redis 流](https://redis.io/topics/streams-intro)。要使用 Azure Redis 缓存进行发布/订阅,请将版本设置为 *(PREVIEW) 6*。 +1. 点击 **创建** 以启动 Redis 实例的部署。 +1. 从 Azure 门户的 **概览** 页面中记下 Redis 实例主机名以备后用。 + - 它应该看起来像 `xxxxxx.redis.cache.windows.net:6380`。 +1. 实例创建后,获取您的访问密钥: + 1. 导航到 **设置** 下的 **访问密钥**。 + 1. 创建一个 Kubernetes secret 来存储您的 Redis 密码: + + ```bash + kubectl create secret generic redis --from-literal=redis-password=********* + ``` + +{{% /codetab %}} + +{{% codetab %}} + +1. 从 [AWS Redis](https://aws.amazon.com/redis/) 部署一个 Redis 实例。 +1. 记下 AWS 门户中的 Redis 主机名以备后用。 +1. 创建一个 Kubernetes secret 来存储您的 Redis 密码: + + ```bash + kubectl create secret generic redis --from-literal=redis-password=********* + ``` + +{{% /codetab %}} + +{{% codetab %}} + +1. 从 [GCP Cloud MemoryStore](https://cloud.google.com/memorystore/) 部署一个 MemoryStore 实例。 +1. 记下 GCP 门户中的 Redis 主机名以备后用。 +1. 创建一个 Kubernetes secret 来存储您的 Redis 密码: + + ```bash + kubectl create secret generic redis --from-literal=redis-password=********* + ``` + +{{% /codetab %}} + +{{< /tabs >}} + +### 步骤 2:配置 Dapr 组件 + +Dapr 使用组件定义来管理构建块功能。以下步骤将指导您如何将上面创建的资源连接到 Dapr,以用于状态和发布/订阅。 + +#### 定位您的组件文件 + +{{< tabs "自托管" "Kubernetes" >}} + +{{% codetab %}} + +在自托管模式下,组件文件会自动创建在: +- **Windows**: `%USERPROFILE%\.dapr\components\` +- **Linux/MacOS**: `$HOME/.dapr/components` + +{{% /codetab %}} + +{{% codetab %}} + +由于 Kubernetes 文件是通过 `kubectl` 应用的,因此可以在任何目录中创建。 + +{{% /codetab %}} + +{{< /tabs >}} + +#### 创建状态存储组件 + +创建一个名为 `redis-state.yaml` 的文件,并粘贴以下内容: + +{{< tabs "自托管" "Kubernetes" >}} + +{{% codetab %}} + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: statestore + namespace: default +spec: + type: state.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + secretKeyRef: + name: redis + key: redis-password + # 取消注释以下内容以通过 TLS 连接到 redis 缓存实例(例如 - Azure Redis 缓存) + # - name: enableTLS + # value: true +``` + +{{% /codetab %}} + +{{% codetab %}} + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: statestore + namespace: default +spec: + type: state.redis + version: v1 + metadata: + - name: redisHost + value: + - name: redisPassword + secretKeyRef: + name: redis + key: redis-password + # 取消注释以下内容以通过 TLS 连接到 redis 缓存实例(例如 - Azure Redis 缓存) + # - name: enableTLS + # value: true +``` + +请注意,上述代码示例使用了您在设置集群时创建的 Kubernetes secret。 + +{{% /codetab %}} + +{{< /tabs >}} + +{{% alert title="其他存储" color="primary" %}} +如果使用的状态存储不是 Redis,请参考 [支持的状态存储]({{< ref supported-state-stores >}}) 以获取有关设置选项的信息。 +{{% /alert %}} + +#### 创建发布/订阅消息代理组件 + +创建一个名为 `redis-pubsub.yaml` 的文件,并粘贴以下内容: + +{{< tabs "自托管" "Kubernetes" >}} + +{{% codetab %}} + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: pubsub + namespace: default +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: localhost:6379 + - name: redisPassword + secretKeyRef: + name: redis + key: redis-password + # 取消注释以下内容以通过 TLS 连接到 redis 缓存实例(例如 - Azure Redis 缓存) + # - name: enableTLS + # value: true +``` + +{{% /codetab %}} + +{{% codetab %}} + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: pubsub + namespace: default +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: + - name: redisPassword + secretKeyRef: + name: redis + key: redis-password + # 取消注释以下内容以通过 TLS 连接到 redis 缓存实例(例如 - Azure Redis 缓存) + # - name: enableTLS + # value: true +``` + +请注意,上述代码示例使用了您在设置集群时创建的 Kubernetes secret。 + +{{% /codetab %}} + +{{< /tabs >}} + +{{% alert title="其他存储" color="primary" %}} +如果使用的发布/订阅消息代理不是 Redis,请参考 [支持的发布/订阅消息代理]({{< ref supported-pubsub >}}) 以获取有关设置选项的信息。 +{{% /alert %}} + +#### 硬编码密码(不推荐) + +仅用于开发目的,您可以跳过创建 Kubernetes secret 并将密码直接放入 Dapr 组件文件中: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: statestore + namespace: default +spec: + type: state.redis + version: v1 + metadata: + - name: redisHost + value: + - name: redisPassword + value: + # 取消注释以下内容以通过 TLS 连接到 redis 缓存实例(例如 - Azure Redis 缓存) + # - name: enableTLS + # value: true +``` + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: pubsub + namespace: default +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: + - name: redisPassword + value: + # 取消注释以下内容以通过 TLS 连接到 redis 缓存实例(例如 - Azure Redis 缓存) + # - name: enableTLS + # value: true +``` + +### 步骤 3:应用配置 + +{{< tabs "自托管" "Kubernetes">}} + +{{% codetab %}} + +当您运行 `dapr init` 时,Dapr 会在您的本地机器上创建一个默认的 redis `pubsub.yaml`。通过打开您的组件目录进行验证: + +- 在 Windows 上,位于 `%UserProfile%\.dapr\components\pubsub.yaml` +- 在 Linux/MacOS 上,位于 `~/.dapr/components/pubsub.yaml` + +对于新的组件文件: + +1. 在您的应用程序文件夹中创建一个包含 YAML 文件的 `components` 目录。 +1. 使用 `--resources-path` 标志为 `dapr run` 命令提供路径 + +如果您在[精简模式]({{< ref self-hosted-no-docker.md >}})(无 Docker)下初始化了 Dapr,您需要手动创建默认目录,或者始终使用 `--resources-path` 指定组件目录。 + +{{% /codetab %}} + +{{% codetab %}} + +运行 `kubectl apply -f ` 以应用状态和发布/订阅文件: + +```bash +kubectl apply -f redis-state.yaml +kubectl apply -f redis-pubsub.yaml +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 +[尝试 Dapr 快速入门]({{< ref quickstarts.md >}}) diff --git a/src/translated_content/zh_CN/docs/getting-started/tutorials/get-started-component.md b/src/translated_content/zh_CN/docs/getting-started/tutorials/get-started-component.md new file mode 100644 index 000000000..62440f4e1 --- /dev/null +++ b/src/translated_content/zh_CN/docs/getting-started/tutorials/get-started-component.md @@ -0,0 +1,112 @@ +--- +type: docs +title: "定义一个组件" +linkTitle: "定义一个组件" +weight: 70 +description: "创建一个组件定义文件以与secrets构建块交互" +--- + +在构建应用程序时,通常需要根据所需的构建块和特定组件创建组件文件定义。 + +在本教程中,您将创建一个组件定义文件以与[secrets构建块API]({{< ref secrets >}})交互: + +- 创建一个本地JSON密钥存储。 +- 使用组件定义文件向Dapr注册密钥存储。 +- 使用Dapr HTTP API获取密钥。 + +## 步骤1:创建一个JSON密钥存储 + +1. 创建一个名为`my-components`的新目录以保存新的密钥和组件文件: + + ```bash + mkdir my-components + ``` + +1. 进入此目录。 + + ```bash + cd my-components + ``` + +1. Dapr支持多种类型的密钥存储,但在本教程中,创建一个名为`mysecrets.json`的本地JSON文件,其中包含以下密钥: + +```json +{ + "my-secret" : "I'm Batman" +} +``` + +## 步骤2:创建一个密钥存储Dapr组件 + +1. 创建一个新文件`localSecretStore.yaml`,内容如下: + + ```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: ./mysecrets.json + - name: nestedSeparator + value: ":" + ``` + +在上述文件定义中: +- `type: secretstores.local.file` 指定Dapr使用本地文件组件作为密钥存储。 +- 元数据字段提供了与此组件一起使用所需的特定信息。在这种情况下,密钥存储JSON路径是相对于您执行`dapr run`命令的位置。 + +## 步骤3:运行Dapr sidecar + +启动一个Dapr sidecar,它将在端口3500上监听一个名为`myapp`的空应用程序: + +对于PowerShell环境: +```bash +dapr run --app-id myapp --dapr-http-port 3500 --resources-path ../ +``` +对于非PowerShell环境: +```bash +dapr run --app-id myapp --dapr-http-port 3500 --resources-path . +``` + +{{% alert title="提示" color="primary" %}} +如果出现错误消息提示`app-id`已被使用,您可能需要停止任何当前正在运行的Dapr sidecar。在运行下一个`dapr run`命令之前,可以通过以下方式停止sidecar: + +- 按Ctrl+C或Command+C。 +- 在终端中运行`dapr stop`命令。 + +{{% /alert %}} + +## 步骤4:获取一个密钥 + +在一个单独的终端中,运行: + +{{< tabs "HTTP API (Bash)" "HTTP API (PowerShell)">}} +{{% codetab %}} + +```bash +curl http://localhost:3500/v1.0/secrets/my-secret-store/my-secret +``` + +{{% /codetab %}} + +{{% codetab %}} + +```powershell +Invoke-RestMethod -Uri 'http://localhost:3500/v1.0/secrets/my-secret-store/my-secret' +``` + +{{% /codetab %}} +{{< /tabs >}} + +**输出:** + +```json +{"my-secret":"I'm Batman"} +``` + +{{< button text="下一步:设置一个Pub/sub代理 >>" page="pubsub-quickstart" >}} diff --git a/src/translated_content/zh_CN/docs/operations/_index.md b/src/translated_content/zh_CN/docs/operations/_index.md new file mode 100644 index 000000000..037cf0ec8 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "部署和配置Dapr" +linkTitle: "运维" +weight: 40 +description: "提供部署选项、最佳实践及其他指南,助您在Dapr上运行应用程序" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/components/_index.md b/src/translated_content/zh_CN/docs/operations/components/_index.md new file mode 100644 index 000000000..1e4809f2c --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/components/_index.md @@ -0,0 +1,36 @@ +--- +type: docs +title: "管理 Dapr 中的组件" +linkTitle: "组件" +weight: 300 +description: "如何在应用程序中管理 Dapr 组件" +--- + + +在 Dapr 中,组件是应用程序与外部资源交互的关键。它们可以是数据库、消息队列、秘密管理系统等。开发者可以通过配置这些组件,轻松地在应用程序中集成和使用这些外部资源。 + +Dapr 提供了一种声明式的方法来管理组件。每个组件都通过一个 YAML 文件定义,该文件描述了组件的类型、元数据和其他配置细节。以下是一个简单的组件定义示例: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: my-pubsub + namespace: default +spec: + type: pubsub.redis + version: v1 + metadata: + - name: redisHost + value: "localhost:6379" + - name: redisPassword + secretKeyRef: + name: redis-secret + key: password +``` + +在这个示例中,我们定义了一个名为 `my-pubsub` 的发布订阅组件,它使用 Redis 作为底层实现。组件的元数据部分指定了 Redis 主机和密码,其中密码是通过 secret 管理的。 + +要在应用程序中使用这些组件,开发者只需在应用程序代码中引用组件名称即可。Dapr 的 sidecar 会自动处理与组件的交互,使得开发者无需关心底层实现细节。 + +通过这种方式,Dapr 提供了一种灵活且可扩展的方式来管理应用程序中的外部资源,使得开发者可以专注于业务逻辑,而不是基础设施管理。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/components/certification-lifecycle.md b/src/translated_content/zh_CN/docs/operations/components/certification-lifecycle.md new file mode 100644 index 000000000..1892d0676 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/components/certification-lifecycle.md @@ -0,0 +1,135 @@ +--- +type: docs +title: "认证流程" +linkTitle: "认证流程" +weight: 200 +description: "组件从提交到生产就绪的认证流程" +--- + +{{% alert title="注意" color="primary" %}} +认证流程仅适用于内置组件,不适用于[可插拔组件]({{}})。 +{{% /alert %}} + +## 概述 + +Dapr 采用模块化设计,功能以组件形式提供。每个组件都有一个接口定义,所有组件都是可互换的,因此理想情况下,您可以用具有相同接口的另一个组件替换一个组件。每个用于生产的组件都需要满足一定的技术要求,以确保功能兼容性和稳健性。 + +一般来说,一个组件需要: + +- 符合定义的 Dapr 接口 +- 功能正确且稳健 +- 有良好的文档和维护 + +为了确保组件符合 Dapr 设定的标准,会在 Dapr 维护者管理的环境中对组件进行一系列测试。一旦测试持续通过,就可以确定组件的成熟度级别。 + +## 认证级别 + +级别如下: + +- [Alpha](#alpha) +- [Beta](#beta) +- [Stable](#stable) + +### Alpha + +- 组件实现了所需的接口,并按规范描述工作 +- 组件有文档 +- 组件可能存在漏洞,或在集成时暴露出漏洞 +- 组件可能无法通过所有一致性测试 +- 组件可能没有一致性测试 +- 由于后续版本中可能出现不兼容的更改,仅推荐用于非关键业务用途 + +所有组件都从 Alpha 阶段开始。 + +### Beta + +- 组件必须通过所有定义的组件一致性测试以满足组件规范 +- 组件一致性测试已在 Dapr 维护者管理的环境中运行 +- 组件包含由 Dapr 维护者审核和批准的特定 components-contrib 版本的一致性测试结果记录 +- 由于后续版本中可能出现不兼容的更改,仅推荐用于非关键业务用途 + +{{% alert title="注意" color="primary" %}} +如果满足以下条件,组件可以跳过 Beta 阶段和一致性测试要求,由维护者决定: +- 组件是一个绑定 +- 认证测试是全面的 +{{% /alert %}} + +### Stable + +- 组件必须有组件[认证测试](#certification-tests)以验证功能和弹性 +- 组件由 Dapr 维护者维护并由社区支持 +- 组件有良好的文档和测试 +- 组件在之前至少一个 Dapr 运行时的小版本发布中以 Alpha 或 Beta 形式存在 +- 维护者将根据 Dapr 支持政策解决组件安全性、核心功能和测试问题,并发布包含修补的稳定组件的补丁版本 + +{{% alert title="注意" color="primary" %}} +稳定的 Dapr 组件基于 Dapr 认证和一致性测试,并不保证由任何特定供应商支持,其中供应商的 SDK 作为组件的一部分使用。 + +Dapr 组件测试保证组件的稳定性,与第三方供应商为任何使用的 SDK 声明的稳定性状态无关。这是因为稳定的含义(例如 alpha、beta、stable)可能因供应商而异。 +{{% /alert %}} + +### 以前的正式发布 (GA) 组件 + +任何先前认证为 GA 的组件,即使不符合新要求,也允许进入 Stable。 + +## 一致性测试 + +[components-contrib](https://github.com/dapr/components-contrib) 仓库中的每个组件都需要遵循 Dapr 定义的一组接口。一致性测试是在这些组件定义及其相关支持服务上运行的测试,以确保组件符合 Dapr 接口规范和行为。 + +一致性测试为以下构建块定义: + +- 状态存储 +- secret 存储 +- 绑定 +- pubsub + +要了解更多信息,请参阅[此处](https://github.com/dapr/components-contrib/blob/master/tests/conformance/README.md)的自述文件。 + +### 测试要求 + +- 测试应根据组件规范验证组件的功能行为和稳健性 +- 作为组件一致性测试文档的一部分,添加所有重现测试所需的详细信息 + +## 认证测试 + +[components-contrib](https://github.com/dapr/components-contrib) 仓库中的每个稳定组件必须有一个认证测试计划和自动化认证测试,以验证组件通过 Dapr 支持的所有功能。 + +稳定组件的测试计划应包括以下场景: + +- 客户端重新连接:如果客户端库暂时无法连接到服务,一旦服务重新上线,Dapr sidecar 不应需要重启。 +- 认证选项:验证组件可以使用所有支持的选项进行认证。 +- 验证资源配置:验证组件在初始化时是否自动配置资源(如果适用)。 +- 所有与相应构建块和组件相关的场景。 + +测试计划必须由 Dapr 维护者批准,并与组件代码一起发布在 `README.md` 文件中。 + +### 测试要求 + +- 测试应根据组件规范验证组件的功能行为和稳健性,反映测试计划中的场景 +- 测试必须作为 [components-contrib](https://github.com/dapr/components-contrib) 仓库的持续集成的一部分成功运行 + +## 组件认证过程 + +为了使组件获得认证,测试在由 Dapr 项目维护的环境中运行。 + +### 新组件认证:Alpha->Beta + +对于需要从 Alpha 更改为 Beta 认证的新组件,组件认证请求遵循以下步骤: + +- 请求者在 [components-contrib](https://github.com/dapr/components-contrib) 仓库中创建一个问题,以认证组件的当前和新认证级别 +- 请求者提交一个 PR 以将组件与定义的一致性测试套件集成(如果尚未包含) + - 用户在创建的问题中详细说明环境设置,以便 Dapr 维护者可以在托管环境中设置服务 + - 环境设置完成后,Dapr 维护者审核 PR,如果批准则合并该 PR +- 请求者在 [docs](https://github.com/dapr/docs) 仓库中提交一个 PR,更新组件的认证级别 + +### 新组件认证:Beta->Stable + +对于需要从 Beta 更改为 Stable 认证的新组件,组件认证请求遵循以下步骤: + +- 请求者在 [components-contrib](https://github.com/dapr/components-contrib) 仓库中创建一个问题,以认证组件的当前和新认证级别 +- 请求者在组件的源代码目录中提交一个 PR,将测试计划作为 `README.md` 文件 + - 请求者在创建的 PR 中详细说明测试环境要求,包括任何手动步骤或凭据 + - Dapr 维护者审核测试计划,提供反馈或批准,并最终合并 PR +- 请求者提交一个 PR 用于自动化认证测试,包括在适用时配置资源的脚本 +- 在测试环境设置完成和凭据配置后,Dapr 维护者审核 PR,如果批准则合并 PR +- 请求者在 [docs](https://github.com/dapr/docs) 仓库中提交一个 PR,更新组件的认证级别 diff --git a/src/translated_content/zh_CN/docs/operations/components/component-scopes.md b/src/translated_content/zh_CN/docs/operations/components/component-scopes.md new file mode 100644 index 000000000..b31be675e --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/components/component-scopes.md @@ -0,0 +1,119 @@ +--- +type: docs +title: "操作指南:将组件限定于一个或多个应用程序" +linkTitle: "限定组件访问" +weight: 400 +description: "限制组件访问特定的Dapr实例" +--- + +Dapr组件具有命名空间(这与Kubernetes的命名空间概念不同),这意味着一个Dapr运行时实例只能访问部署在相同命名空间中的组件。 + +Dapr运行时,会将其配置的命名空间与加载的组件的命名空间进行匹配,并仅初始化与其命名空间匹配的组件。其他命名空间中的组件将不会被加载。 + +## 命名空间 +命名空间可以用来限制组件对特定Dapr实例的访问。 + +{{< tabs "Self-Hosted" "Kubernetes">}} + +{{% codetab %}} +在自托管模式下,开发者可以通过设置`NAMESPACE`环境变量来为Dapr实例指定命名空间。 +如果设置了`NAMESPACE`环境变量,Dapr将不会加载任何在其元数据中未指定相同命名空间的组件。 + +例如,假设在`production`命名空间中有以下组件: +```yaml +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: + +```bash +export NAMESPACE=production +# 像往常一样运行Dapr +``` +Windows: + +```powershell +setx NAMESPACE "production" +# 像往常一样运行Dapr +``` +{{% /codetab %}} + +{{% codetab %}} +让我们考虑以下在Kubernetes中的组件: + +```yaml +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实例可访问。 +{{% /codetab %}} + +{{< /tabs >}} + +{{% alert title="注意" color="primary" %}} +应用于命名空间"A"的组件YAML可以*引用*命名空间"B"中的实现。例如,命名空间"production-A"中的Redis组件YAML可以将Redis主机地址指向部署在命名空间"production-B"中的Redis实例。 + +参见[配置具有多个命名空间的Pub/Sub组件]({{< ref "pubsub-namespaces.md" >}})以获取示例。 +{{% /alert %}} + +## 应用程序对具有范围的组件的访问 +开发者和操作员可能希望限制某个应用程序或一组特定应用程序对一个数据库的访问。 +为实现这一点,Dapr允许您在组件YAML上指定`scopes`。添加到组件的应用程序范围仅限制具有特定ID的应用程序使用该组件。 + +以下示例展示了如何为两个启用Dapr的应用程序提供访问权限,这两个应用程序的ID分别为`app1`和`app2`,访问名为`statestore`的Redis组件,该组件本身位于`production`命名空间中 + +```yaml +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 +``` +### 社区电话演示 + +
+ +
+ +## 使用命名空间进行服务调用 +阅读[跨命名空间的服务调用]({{< ref "service-invocation-namespaces.md" >}})以获取有关在服务之间调用时使用命名空间的更多信息。 + +## 使用命名空间进行pub/sub +阅读[配置具有多个命名空间的Pub/Sub组件]({{< ref "pubsub-namespaces.md" >}})以获取有关在pub/sub中使用命名空间的更多信息。 + +## 相关链接 + +- [配置具有多个命名空间的Pub/Sub组件]({{< ref "pubsub-namespaces.md" >}}) +- [使用secret范围]({{< ref "secrets-scopes.md" >}}) +- [限制可以从secret存储中读取的secret]({{< ref "secret-scope.md" >}}) diff --git a/src/translated_content/zh_CN/docs/operations/components/component-secrets.md b/src/translated_content/zh_CN/docs/operations/components/component-secrets.md new file mode 100644 index 000000000..28dd3cca1 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/components/component-secrets.md @@ -0,0 +1,172 @@ +--- +type: docs +title: "操作指南:在组件中引用secret" +linkTitle: "在组件中引用secret" +weight: 500 +description: "如何在组件定义中安全地引用secret" +--- + +## 概述 + +在组件定义的`spec.metadata`部分中,可以引用secret。 + +要引用secret,你需要设置`auth.secretStore`字段来指定保存secret的secret存储的名称。 + +在Kubernetes中运行时,如果`auth.secretStore`为空,则默认使用Kubernetes secret存储。 + +### 支持的secret存储 + +访问[此链接]({{< ref "howto-secrets.md" >}})查看Dapr支持的所有secret存储,以及如何配置和使用它们的信息。 + +## 引用secret + +虽然你可以选择使用纯文本secret(如MyPassword),如下面yaml中`redisPassword`的`value`所示,但这不建议用于生产环境: + +```yml +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 +``` + +相反,建议在你的secret存储中创建secret并在组件定义中引用它。下面展示了两种情况——“secret包含嵌入的key”和“secret是一个字符串”。 + +“secret包含嵌入的key”适用于secret中嵌入了一个key的情况,即secret**不是**一个完整的连接字符串。这在以下组件定义yaml中展示。 + +```yml +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存储组件]({{< ref supported-secret-stores >}})的名称。在Kubernetes中运行并使用Kubernetes secret存储时,字段`auth.SecretStore`默认为`kubernetes`,可以留空。 + +上述组件定义告诉Dapr从定义的`secretStore`中提取名为`redis-secret`的secret,并将secret中嵌入的`redis-password` key关联的值分配给组件中的`redisPassword`字段。此情况的一个用途是当你的代码正在构建一个连接字符串时,例如将URL、secret以及其他必要信息组合成一个字符串。 + +另一方面,下面的“secret是一个字符串”适用于secret中没有嵌入key的情况。相反,secret只是一个字符串。因此,在`secretKeyRef`部分中,secret的`name`和secret的`key`将是相同的。这种情况是当secret本身是一个完整的连接字符串,没有需要提取值的嵌入key时。通常,连接字符串由连接信息、某种允许连接的secret以及可能的其他信息组成,不需要单独的“secret”。这种情况在下面的组件定义yaml中展示。 + +```yml +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是一个字符串”情况的yaml告诉Dapr从定义的`secretStore`中提取名为`asbNsConnstring`的连接字符串,并将值分配给组件中的`connectionString`字段,因为从`secretStore`中提取的“secret”是一个纯字符串,没有嵌入的key。这要求secret的`name`和secret的`key`相同。 + +## 示例 + +### 引用Kubernetes secret + +以下示例展示了如何创建一个Kubernetes secret来保存Event Hubs绑定的连接字符串。 + +1. 首先,创建Kubernetes secret: + ```bash + kubectl create secret generic eventhubs-secret --from-literal=connectionString=********* + ``` + +2. 接下来,在你的绑定中引用secret: + ```yaml + 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集群: + ```bash + kubectl apply -f ./eventhubs.yaml + ``` + +## 限制对secret的访问 + +Dapr可以使用其配置限制对secret存储中secret的访问。阅读[如何使用secret范围]({{< ref "secrets-scopes.md" >}})和[如何限制从secret存储中读取的secret]({{< ref "secret-scope.md" >}})以获取更多信息。这是使用Dapr限制对secret访问的推荐方法。 + +## Kubernetes权限 + +### 默认命名空间 + +在Kubernetes中运行时,Dapr在安装期间为从Kubernetes secret存储访问secret定义了默认的Role和RoleBinding在`default`命名空间中。对于从`default`命名空间获取secret的Dapr启用的应用程序,可以如上例所示定义和引用secret。 + +### 非默认命名空间 + +如果你的Dapr启用的应用程序使用从非默认命名空间获取secret的组件,请将以下资源应用到该命名空间: + +```yaml +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: secret-reader + namespace: +rules: +- apiGroups: [""] + resources: ["secrets"] + verbs: ["get", "list"] +--- + +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: dapr-secret-reader + namespace: +subjects: +- kind: ServiceAccount + name: default +roleRef: + kind: Role + name: secret-reader + apiGroup: rbac.authorization.k8s.io +``` + +这些资源授予Dapr从Role和RoleBinding中定义的命名空间的Kubernetes secret存储中获取secret的权限。 + +{{% alert title="注意" color="warning" %}} +在生产环境中,为了仅限制Dapr对某些secret资源的访问,你可以使用`resourceNames`字段。参见此[链接](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#referring-to-resources)以获取进一步的解释。 +{{% /alert %}} + +## 相关链接 + +- [使用secret范围]({{< ref "secrets-scopes.md" >}}) +- [限制从secret存储中读取的secret]({{< ref "secret-scope.md" >}}) diff --git a/src/translated_content/zh_CN/docs/operations/components/component-updates.md b/src/translated_content/zh_CN/docs/operations/components/component-updates.md new file mode 100644 index 000000000..6f7a9be40 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/components/component-updates.md @@ -0,0 +1,50 @@ +--- +type: docs +title: "更新组件" +linkTitle: "更新组件" +weight: 300 +description: "更新应用程序使用的已部署组件" +--- + +在更新应用程序使用的现有已部署组件时,除非启用了 [`HotReload`](#hot-reloading-preview-feature) 功能门控,否则 Dapr 不会自动更新组件。需要重启 Dapr sidecar 才能获取组件的最新版本。具体操作方式取决于托管环境。 + +### Kubernetes + +在 Kubernetes 中运行时,更新组件的过程包括以下两个步骤: + +1. 将新的组件 YAML 应用到所需的命名空间。 +2. 除非启用了 [`HotReload` 功能门控](#hot-reloading-preview-feature),否则需要对部署执行 [滚动重启操作](https://kubernetes.io/docs/reference/kubectl/cheatsheet/#updating-resources) 以获取最新组件。 + +### 自托管 + +除非启用了 [`HotReload` 功能门控](#hot-reloading-preview-feature),更新组件的过程包括停止和重启 `daprd` 进程以获取最新组件的单个步骤。 + +## 热重载(预览功能) + +> 此功能目前处于[预览]({{< ref "preview-features.md" >}})状态。 +> 热重载通过 [`HotReload` 功能门控]({{< ref "support-preview-features.md" >}}) 启用。 + +Dapr 可以实现“热重载”组件,从而在不需要重启 Dapr sidecar 进程或 Kubernetes pod 的情况下自动获取组件更新。这意味着创建、更新或删除组件清单将在运行时反映在 Dapr sidecar 中。 + +{{% alert title="更新组件" color="warning" %}} +当组件更新时,它首先被关闭,然后使用新配置重新初始化。这会导致组件在此过程中短时间内不可用。 +{{% /alert %}} + +{{% alert title="初始化错误" color="warning" %}} +如果通过热重载创建或更新组件时初始化过程出错,Dapr sidecar 会遵循组件字段 [`spec.ignoreErrors`]({{< ref component-schema.md>}}) 的设置。也就是说,行为与 sidecar 在启动时加载组件时相同。 +- `spec.ignoreErrors=false` (*默认*): sidecar 优雅地关闭。 +- `spec.ignoreErrors=true`: sidecar 继续运行,既没有注册旧的也没有注册新的组件配置。 +{{% /alert %}} + +除以下类型外,所有组件均支持热重载。这些组件类型的任何创建、更新或删除都将被 sidecar 忽略,需要重启以获取更改。 +- [actor 状态存储]({{< ref "state_api.md#configuring-state-store-for-actors" >}}) +- [workflow 后端]({{< ref "workflow-architecture.md#workflow-backend" >}}) + +## 进一步阅读 +- [组件概念]({{< ref components-concept.md >}}) +- [在组件定义中引用 secret]({{< ref component-secrets.md >}}) +- [支持的状态存储]({{< ref supported-state-stores >}}) +- [支持的 pub/sub 代理]({{< ref supported-pubsub >}}) +- [支持的 secret 存储]({{< ref supported-secret-stores >}}) +- [支持的 bindings]({{< ref supported-bindings >}}) +- [设置组件范围]({{< ref component-scopes.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/components/middleware.md b/src/translated_content/zh_CN/docs/operations/components/middleware.md new file mode 100644 index 000000000..b7b3ad309 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/components/middleware.md @@ -0,0 +1,73 @@ +--- +type: docs +title: "配置中间件组件" +linkTitle: "配置中间件" +weight: 2000 +description: "通过添加中间件组件自定义处理管道" +--- + +Dapr 允许通过串联一系列中间件组件来定义自定义处理管道。您可以在以下两种场景中使用中间件管道: + +1. 基础模块 API - 在调用任何 Dapr HTTP API 时执行 HTTP 中间件组件。 +2. 服务间调用 - HTTP 中间件组件应用于服务间调用。 + +## 配置 API 中间件管道 + +启动时,Dapr sidecar 会为传入的 HTTP 调用构建一个中间件处理管道。默认情况下,管道由[追踪]({{< ref tracing-overview.md >}})和 CORS 中间件组成。可以通过 Dapr [configuration]({{< ref configuration-concept.md >}}) 配置的其他中间件按定义顺序添加到管道中。该管道适用于所有 Dapr API 端点,包括 state、pubsub、service-invocation、bindings、secret、configuration、分布式锁等。 + +请求在路由到用户代码之前会依次经过所有定义的中间件组件,然后在返回给客户端之前以相反的顺序再次经过这些中间件,如下图所示。 + +图示请求和响应通过中间件的流程,如上段所述 + +在使用 `httpPipeline` 配置调用 Dapr HTTP API 时,HTTP 中间件组件会被执行。 + +以下配置示例定义了一个自定义管道,使用了 [OAuth 2.0 中间件]({{< ref middleware-oauth2.md >}}) 和 [大写中间件组件]({{< ref middleware-uppercase.md >}})。在这种情况下,所有请求在转发到用户代码之前都通过 OAuth 2.0 协议进行授权,并转换为大写文本。 + +```yaml +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 +``` + +与其他组件一样,中间件组件可以在[支持的中间件参考]({{< ref supported-middleware >}})和[`dapr/components-contrib` 仓库](https://github.com/dapr/components-contrib/tree/master/middleware/http)中找到。 + +{{< button page="supported-middleware" text="查看所有中间件组件">}} + +## 配置应用中间件管道 + +在进行服务间调用时,您也可以使用任何中间件组件。例如,在零信任环境中添加令牌验证,转换特定应用端点的请求,或应用 OAuth 策略。 + +服务间调用中间件组件适用于从 Dapr sidecar 到接收应用(服务)的所有**传出**调用,如下图所示。 + +图示服务调用请求的流程。从调用者 Dapr sidecar 到被调用应用的请求经过应用中间件管道,如上段所述。 + +任何可以用作 HTTP 中间件的中间件组件也可以通过 `appHttpPipeline` 配置应用于服务间调用。下面的示例为从 Dapr sidecar(服务调用的目标)到应用的所有传出调用添加了 `uppercase` 中间件组件。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: pipeline + namespace: default +spec: + appHttpPipeline: + handlers: + - name: uppercase + type: middleware.http.uppercase +``` + +## 相关链接 + +- [了解如何编写中间件组件]({{< ref develop-middleware.md >}}) +- [组件架构]({{< ref component-schema.md >}}) +- [配置概述]({{< ref configuration-overview.md >}}) +- [API 中间件示例](https://github.com/dapr/samples/tree/master/middleware-oauth-google) diff --git a/src/translated_content/zh_CN/docs/operations/components/pluggable-components-registration.md b/src/translated_content/zh_CN/docs/operations/components/pluggable-components-registration.md new file mode 100644 index 000000000..e511017c5 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/components/pluggable-components-registration.md @@ -0,0 +1,249 @@ +--- +type: docs +title: "如何:注册一个可插拔组件" +linkTitle: "注册一个可插拔组件" +weight: 1000 +description: "学习如何注册一个可插拔组件" +--- + +[uds]: https://en.wikipedia.org/wiki/Unix_domain_socket + +## 组件注册过程 + +[使用 gRPC 的可插拔组件]({{< ref pluggable-components-overview >}})通常作为容器或进程运行,需要通过[Unix 域套接字][uds](简称 UDS)与 Dapr 运行时通信。它们会通过以下步骤自动被发现并注册到运行时中: + +1. 组件监听放置在共享卷上的[Unix 域套接字][uds]。 +2. Dapr 运行时列出共享卷中的所有[Unix 域套接字][uds]。 +3. Dapr 运行时连接每个套接字,并使用 gRPC 反射从组件实现的给定构建块 API 中发现所有 proto 服务。 + +一个组件可以同时实现多个组件接口。 + + + +虽然 Dapr 的内置组件已经集成在运行时中,但可插拔组件在与 Dapr 一起使用之前需要进行一些设置步骤。 + +1. 可插拔组件需要在 Dapr 本身启动之前启动并准备好接收请求。 +2. 用于可插拔组件通信的[Unix 域套接字][uds]文件需要对 Dapr 和可插拔组件都可访问。 + +在独立模式下,可插拔组件可以作为进程或容器运行。在 Kubernetes 上,可插拔组件作为容器运行,并由 Dapr 的 sidecar 注入器自动注入到应用程序的 pod 中,允许通过标准的[Kubernetes 容器规范](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#container-v1-core)进行自定义。 + +这也改变了在 Dapr 和可插拔组件之间共享[Unix 域套接字][uds]文件的方法。 + +{{% alert title="注意" color="primary" %}} +作为前提条件,操作系统必须支持 Unix 域套接字,任何 UNIX 或类 UNIX 系统(Mac、Linux 或用于本地开发的 [WSL](https://learn.microsoft.com/windows/wsl/install) 对于 Windows 用户)都应该足够。 +{{% /alert %}} + +选择您的环境以开始使您的组件可被发现。 + +{{< tabs "Standalone" "Kubernetes" >}} + +{{% codetab %}} +[uds]: https://en.wikipedia.org/wiki/Unix_domain_socket + +## 运行组件 + +在 Dapr 启动之前,您的组件和 Unix 套接字必须正在运行。 + +默认情况下,Dapr sidecar 在 `/tmp/dapr-components-sockets` 中查找作为[Unix 域套接字][uds]文件的组件。 + +此文件夹中的文件名对于组件注册很重要。它们必须通过附加组件的**名称**和您选择的文件扩展名(通常为 `.sock`)来形成。例如,文件名 `my-component.sock` 是一个有效的 Unix 域套接字文件名,适用于名为 `my-component` 的组件。 + +由于您在与组件相同的主机上运行 Dapr,请验证此文件夹及其中的文件是否可被您的组件和 Dapr 访问和写入。如果您使用 Dapr 的 sidecar 注入器功能,则此卷会自动创建和挂载。 + +### 组件发现和多路复用 + +通过[Unix 域套接字][UDS](UDS)可访问的可插拔组件可以托管多个不同的组件 API。在组件的初始发现过程中,Dapr 使用反射枚举 UDS 后面的所有组件 API。上例中的 `my-component` 可插拔组件可以包含状态存储(`state`)和 pub/sub(`pubsub`)组件 API。 + +通常,可插拔组件实现单个组件 API 以进行打包和部署。然而,以增加其依赖性和扩大其安全攻击面为代价,可插拔组件可以实现多个组件 API。这可以减轻部署和监控负担。隔离、容错和安全的最佳实践是为每个可插拔组件实现单个组件 API。 + +## 定义组件 + +使用[组件规范]({{< ref component-schema.md >}})定义您的组件。组件的 `spec.type` 值是通过以下两个部分与 `.` 连接而成的: +1. 组件的 API(`state`、`pubsub`、`bindings` 等) +2. 组件的**名称**,它是从[Unix 域套接字][uds]文件名中派生的,不包括文件扩展名。 + +您需要为可插拔组件的[Unix 域套接字][uds]公开的每个 API 定义一个[组件规范]({{< ref component-schema.md >}})。前面示例中的 Unix 域套接字 `my-component.sock` 公开了一个名为 `my-component` 的可插拔组件,具有 `state` 和 `pubsub` API。需要两个组件规范,每个规范在其自己的 YAML 文件中,放置在 `resources-path` 中:一个用于 `state.my-component`,另一个用于 `pubsub.my-component`。 + +例如,`state.my-component` 的组件规范可以是: + +```yaml +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`,即此处定义的状态存储的名称,与可插拔组件名称无关。 + +将此文件保存为 Dapr 的组件配置文件夹中的 `component.yaml`。就像 `metadata.name` 字段的内容一样,此 YAML 文件的文件名没有影响,也不依赖于可插拔组件名称。 + +## 运行 Dapr + +[初始化 Dapr]({{< ref get-started-api.md >}}),并确保您的组件文件放置在正确的文件夹中。 + +{{% alert title="注意" color="primary" %}} +Dapr 1.9.0 是支持可插拔组件的最低版本。从 1.11.0 版本开始,支持可插拔组件的容器自动注入。 +{{% /alert %}} + + + +就是这样!现在您可以通过 Dapr API 调用状态存储 API。通过运行以下命令查看其运行情况。用 Dapr HTTP 端口替换 `$PORT`: + +```shell +curl -X POST -H "Content-Type: application/json" -d '[{ "key": "name", "value": "Bruce Wayne", "metadata": {}}]' http://localhost:$PORT/v1.0/state/prod-mystore +``` + +检索值,用 Dapr HTTP 端口替换 `$PORT`: + +```shell +curl http://localhost:$PORT/v1.0/state/prod-mystore/name +``` + +{{% /codetab %}} + +{{% codetab %}} + +[uds]: https://en.wikipedia.org/wiki/Unix_domain_socket + +## 为您的可插拔组件构建和发布容器 + +确保您的组件作为容器运行,首先发布并可被您的 Kubernetes 集群访问。 + +## 在 Kubernetes 集群上部署 Dapr + +按照[在 Kubernetes 集群上部署 Dapr]({{< ref kubernetes-deploy.md >}})文档中提供的步骤进行操作。 + +## 在您的部署中添加可插拔组件容器 + +可插拔组件作为容器**在与您的应用程序相同的 pod 中**部署。 + +由于可插拔组件由[Unix 域套接字][uds]支持,请使您的可插拔组件创建的套接字可被 Dapr 运行时访问。配置部署规范以: + +1. 挂载卷 +2. 提示 Dapr 挂载的 Unix 套接字卷位置 +3. 将卷附加到您的可插拔组件容器 + +在以下示例中,您配置的可插拔组件作为容器部署在与您的应用程序容器相同的 pod 中。 + +```yaml +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 的 sidecar 注入器该应用程序的 pod 将有额外的容器用于可插拔组件。 + +或者,您可以跳过 Dapr 的 sidecar 注入功能,手动添加可插拔组件的容器并注释您的 pod,告诉 Dapr 该 pod 中哪些容器是可插拔组件,如下例所示: + +```yaml +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 +``` + +在应用部署之前,让我们再添加一个配置:组件规范。 + +## 定义组件 + +可插拔组件使用[组件规范]({{< ref component-schema.md >}})定义。组件 `type` 是从套接字名称(不带文件扩展名)派生的。在以下示例 YAML 中,替换: + +- `your_socket_goes_here` 为您的组件套接字名称(无扩展名) +- `your_component_type` 为您的组件类型 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: prod-mystore + # 在 Kubernetes 上运行并自动容器注入时,添加以下注释: + annotations: + dapr.io/component-container: > + { + "name": "my-component", + "image": "/:" + } +spec: + type: your_component_type.your_socket_goes_here + version: v1 + metadata: +scopes: + - backend +``` +当您希望 Dapr 的 sidecar 注入器处理可插拔组件的容器和卷注入时,`dapr.io/component-container` 注释在 Kubernetes 上是必需的。至少,您需要 `name` 和 `image` 属性,以便 Dapr 的 sidecar 注入器成功将容器添加到应用程序的 pod 中。Unix 域套接字的卷由 Dapr 的 sidecar 注入器自动创建和挂载。 + +[范围]({{< ref component-scopes >}})您的组件,以确保只有目标应用程序可以连接到可插拔组件,因为它只会在其部署中运行。否则,运行时在初始化组件时会失败。 + +就是这样!**[将创建的清单应用到您的 Kubernetes 集群](https://kubernetes.io/docs/reference/kubectl/cheatsheet/#kubectl-apply)**,并通过 Dapr API 调用状态存储 API。 + +使用[Kubernetes pod 转发器](https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/)访问 `daprd` 运行时。 + +通过运行以下命令查看其运行情况。用 Dapr HTTP 端口替换 `$PORT`: + +```shell +curl -X POST -H "Content-Type: application/json" -d '[{ "key": "name", "value": "Bruce Wayne", "metadata": {}}]' http://localhost:$PORT/v1.0/state/prod-mystore +``` + +检索值,用 Dapr HTTP 端口替换 `$PORT`: + +```shell +curl http://localhost:$PORT/v1.0/state/prod-mystore/name +``` + +{{% /codetab %}} +{{< /tabs >}} + +## 下一步 + +使用此[示例代码](https://github.com/dapr/samples/tree/master/pluggable-components-dotnet-template)开始开发 .NET 可插拔组件 diff --git a/src/translated_content/zh_CN/docs/operations/components/setup-bindings.md b/src/translated_content/zh_CN/docs/operations/components/setup-bindings.md new file mode 100644 index 000000000..2800a2b2e --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/components/setup-bindings.md @@ -0,0 +1,83 @@ +--- +type: docs +title: "Bindings 组件" +linkTitle: "Bindings" +description: "关于设置 Dapr bindings 组件的指导" +weight: 900 +--- + +Dapr 可以与外部资源集成,使应用程序既能被外部事件触发,也能与资源进行交互。每个 bindings 组件都有一个名称,用于与资源进行交互时使用。 + +与其他构建块组件一样,bindings 组件是可扩展的,相关代码可以在 [components-contrib 仓库](https://github.com/dapr/components-contrib)中找到。 + +在 Dapr 中,bindings 使用一个 `Component` 文件描述,包含以下字段: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: + namespace: +spec: + type: bindings. + version: v1 + metadata: + - name: + value: + - name: + value: +... +``` + +bindings 的类型由 `type` 字段指定,连接字符串和其他元数据则在 `.metadata` 部分定义。 + +不同的[支持的 bindings]({{< ref supported-bindings >}})会有不同的特定字段需要配置。例如,当为 [Azure Blob Storage]({{< ref blobstorage>}}) 配置 bindings 时,文件看起来像这样: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.azure.blobstorage + version: v1 + metadata: + - name: storageAccount + value: myStorageAccountName + - name: storageAccessKey + value: *********** + - name: container + value: container1 + - name: decodeBase64 + value: + - name: getBlobRetryCount + value: +``` + +## 应用配置 + +一旦创建了组件的 YAML 文件,请根据您的托管环境按照以下步骤进行配置: + +{{< tabs "自托管" "Kubernetes" >}} + +{{% codetab %}} +对于自托管环境,创建一个包含 YAML 文件的 `components` 目录,并使用 `--resources-path` 标志将路径提供给 `dapr run` 命令。 +{{% /codetab %}} + +{{% codetab %}} +对于 Kubernetes 部署,假设您的组件文件名为 `mybinding.yaml`,运行以下命令: + +```bash +kubectl apply -f mybinding.yaml +``` +{{% /codetab %}} + +{{< /tabs >}} + +## 支持的 bindings + +访问 [bindings 参考]({{< ref supported-bindings >}}) 以获取支持资源的完整列表。 + +## 相关链接 +- [Bindings 构建块]({{< ref bindings >}}) +- [支持的 bindings]({{}}) diff --git a/src/translated_content/zh_CN/docs/operations/components/setup-pubsub/_index.md b/src/translated_content/zh_CN/docs/operations/components/setup-pubsub/_index.md new file mode 100644 index 000000000..5dc3b3284 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/components/setup-pubsub/_index.md @@ -0,0 +1,57 @@ +--- +type: docs +title: "发布/订阅代理" +linkTitle: "发布/订阅代理" +description: "关于为 Dapr 发布/订阅设置不同消息代理的指导" +weight: 700 +aliases: + - "/zh-hans/operations/components/setup-pubsub/setup-pubsub-overview/" +--- + +Dapr 支持与发布/订阅消息总线的集成,为应用程序提供创建事件驱动、松耦合架构的能力,生产者通过主题向消费者发送事件。 + +Dapr 允许为*每个应用程序*配置多个具名的发布/订阅组件。每个组件都有一个名称,用于在发布消息主题时识别。阅读 [API 参考]({{< ref pubsub_api.md >}}) 了解如何发布和订阅主题的详细信息。 + +发布/订阅组件是可扩展的。支持的组件列表在[这里]({{< ref supported-pubsub >}}),实现可以在 [components-contrib 仓库](https://github.com/dapr/components-contrib)中找到。 + +## 组件文件 + +发布/订阅通过 `Component` 文件描述: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: pubsub + namespace: default +spec: + type: pubsub. + version: v1 + metadata: + - name: + value: + - name: + value: +... +``` + +发布/订阅的类型由 `type` 字段指定,连接字符串和其他元数据等属性放在 `.metadata` 部分。尽管元数据值可以包含明文的 secret,建议您通过 `secretKeyRef` 使用 [secret 存储]({{< ref component-secrets.md >}}) 来管理这些 secret。 + +{{% alert title="主题创建" color="primary" %}} +根据您使用的发布/订阅消息总线及其配置,主题可能会自动创建。即使消息总线支持自动主题创建,在生产环境中禁用它是一种常见的治理实践。您可能仍需要使用 CLI、管理控制台或请求表单手动创建应用程序所需的主题。 +{{% /alert %}} + +虽然所有发布/订阅组件都支持 `consumerID` 元数据,但如果您未提供,运行时会自动生成一个消费者 ID。所有组件元数据字段值可以使用 [模板化元数据值]({{< ref "component-schema.md#templated-metadata-values" >}}),这些值在 Dapr sidecar 启动时解析。例如,您可以选择使用 `{namespace}` 作为 `consumerGroup`,以便在不同命名空间中使用相同的 `appId` 使用相同的主题,如[本文]({{< ref "howto-namespace.md#with-namespace-consumer-groups">}})所述。 + +访问[本指南]({{< ref "howto-publish-subscribe.md#step-3-publish-a-topic" >}})获取配置和使用发布/订阅组件的说明。 + +## 相关链接 + +- Dapr [发布/订阅构建块]({{< ref pubsub-overview.md >}})概述 +- 尝试 [发布/订阅快速入门示例](https://github.com/dapr/quickstarts/tree/master/tutorials/pub-sub) +- 阅读[发布和订阅指南]({{< ref howto-publish-subscribe.md >}}) +- 了解[主题范围]({{< ref pubsub-scopes.md >}}) +- 了解[消息生存时间]({{< ref pubsub-message-ttl.md >}}) +- 学习[如何配置具有多个命名空间的发布/订阅组件]({{< ref pubsub-namespaces.md >}}) +- [发布/订阅组件]({{< ref supported-pubsub >}})列表 +- 阅读 [API 参考]({{< ref pubsub_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/operations/components/setup-pubsub/pubsub-namespaces.md b/src/translated_content/zh_CN/docs/operations/components/setup-pubsub/pubsub-namespaces.md new file mode 100644 index 000000000..5f064b603 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/components/setup-pubsub/pubsub-namespaces.md @@ -0,0 +1,132 @@ +--- +type: docs +title: "HowTo: 配置具有多个命名空间的 Pub/Sub 组件" +linkTitle: "多个命名空间" +weight: 10000 +description: "使用 Dapr Pub/Sub 与多个命名空间" +--- + +在某些情况下,应用程序可能会跨多个命名空间分布,并通过 PubSub 共享队列或主题。在这种情况下,需要在每个命名空间中配置 PubSub 组件。 + +{{% alert title="注意" color="primary" %}} +命名空间是 Dapr 用于限定应用程序和组件范围的概念。本示例使用 Kubernetes 命名空间,但 Dapr 组件命名空间范围可以在任何支持的平台上使用。阅读 [How-To: 将组件限定到一个或多个应用程序]({{< ref "component-scopes.md" >}}) 以获取有关限定组件的更多信息。 +{{% /alert %}} + +本示例使用 [PubSub 示例](https://github.com/dapr/quickstarts/tree/master/tutorials/pub-sub)。Redis 安装和订阅者位于 `namespace-a`,而发布者 UI 位于 `namespace-b`。即使 Redis 安装在另一个命名空间,或者您使用托管云服务如 Azure ServiceBus、AWS SNS/SQS 或 GCP PubSub,该解决方案也同样适用。 + +以下是使用命名空间的示例图。 + + +

+ +下表显示了哪些资源部署到哪些命名空间: + +| 资源 | namespace-a | namespace-b | +|------------------------ |-------------|-------------| +| Redis 主节点 | ✅ | ❌ | +| Redis 副本 | ✅ | ❌ | +| Dapr 的 PubSub 组件 | ✅ | ✅ | +| Node 订阅者 | ✅ | ❌ | +| Python 订阅者 | ✅ | ❌ | +| React UI 发布者 | ❌ | ✅ | + +{{% alert title="注意" color="primary" %}} +所有 pub/sub 组件都支持通过 [命名空间或组件范围]({{< ref pubsub-scopes.md >}}) 将 pub/sub 主题限制到特定应用程序。 +{{% /alert %}} + +## 前提条件 + +* [在 Kubernetes 上安装 Dapr]({{< ref "kubernetes-deploy.md" >}}),因为 Dapr 在集群级别工作。 +* 检出并进入 [PubSub 快速入门](https://github.com/dapr/quickstarts/tree/master/tutorials/pub-sub) 的目录。 + +## 设置 `namespace-a` + +创建命名空间并切换 kubectl 使用它。 +``` +kubectl create namespace namespace-a +kubectl config set-context --current --namespace=namespace-a +``` + +在 `namespace-a` 上安装 Redis(主节点和从节点),按照[这些说明]({{< ref "getting-started/tutorials/configure-state-pubsub.md" >}})。 + +现在,配置 `deploy/redis.yaml`,确保主机名包含 `namespace-a`。 + +```yaml +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 +``` + +## 相关链接 + +- [将组件限定到一个或多个应用程序]({{< ref "component-scopes.md" >}}) +- [使用 secret 限定]({{< ref "secrets-scopes.md" >}}) +- [限制可以从 secret 存储中读取的 secret]({{< ref "secret-scope.md" >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/components/setup-secret-store.md b/src/translated_content/zh_CN/docs/operations/components/setup-secret-store.md new file mode 100644 index 000000000..dd4c57644 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/components/setup-secret-store.md @@ -0,0 +1,87 @@ +--- +type: docs +title: "Secret 存储组件" +linkTitle: "Secret 存储" +description: "关于设置不同 Secret 存储组件的指南" +weight: 800 +aliases: + - "/zh-hans/operations/components/setup-state-store/secret-stores-overview/" +--- + +Dapr 集成了 Secret 存储,为应用程序和其他组件提供安全的 Secret 存储和访问,例如访问密钥和密码。每个 Secret 存储组件都有一个名称,用于访问 Secret 时使用。 + +与其他构建块组件类似,Secret 存储组件是可扩展的,相关代码可以在 [components-contrib 仓库](https://github.com/dapr/components-contrib)中找到。 + +在 Dapr 中,Secret 存储通过一个 `Component` 文件进行描述,包含以下字段: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: secretstore +spec: + type: secretstores. + version: v1 + metadata: + - name: + value: + - name: + value: +... +``` + +Secret 存储的类型由 `type` 字段指定,连接字符串和其他元数据信息放在 `.metadata` 部分。 + +不同的[支持的 Secret 存储]({{< ref supported-secret-stores >}})会有不同的特定字段需要配置。例如,配置使用 AWS Secrets Manager 的 Secret 存储时,文件格式如下: + +```yaml +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]" +``` + +{{% alert title="重要" color="warning" %}} +在 EKS (AWS Kubernetes) 上运行 Dapr sidecar (daprd) 时,如果节点/Pod 已附加了允许访问 AWS 资源的 IAM 策略,则**不应**在组件配置中提供 AWS access-key、secret-key 和 tokens。 +{{% /alert %}} + +## 应用配置 + +创建组件的 YAML 文件后,请根据您的托管环境按照以下说明应用它: + +{{< tabs "Self-Hosted" "Kubernetes" >}} + +{{% codetab %}} +在本地运行时,创建一个包含 YAML 文件的 `components` 目录,并使用 `--resources-path` 标志提供给 `dapr run` 命令。 +{{% /codetab %}} + +{{% codetab %}} +在 Kubernetes 中部署时,假设您的组件文件名为 `secret-store.yaml`,运行: + +```bash +kubectl apply -f secret-store.yaml +``` +{{% /codetab %}} + +{{< /tabs >}} + +## 支持的 Secret 存储 + +访问 [Secret 存储参考]({{< ref supported-secret-stores >}}) 以获取支持的 Secret 存储的完整列表。 + +## 相关链接 + +- [支持的 Secret 存储组件]({{< ref supported-secret-stores >}}) +- [Secrets 构建块]({{< ref secrets >}}) diff --git a/src/translated_content/zh_CN/docs/operations/components/setup-state-store.md b/src/translated_content/zh_CN/docs/operations/components/setup-state-store.md new file mode 100644 index 000000000..5a5192f6b --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/components/setup-state-store.md @@ -0,0 +1,45 @@ +--- +type: docs +title: "状态存储组件" +linkTitle: "状态存储" +description: "关于为 Dapr 状态管理设置不同状态存储的指导" +weight: 600 +aliases: + - "/zh-hans/operations/components/setup-state-store/setup-state-store-overview/" +--- + +Dapr 集成现有数据库,为应用提供 CRUD 操作、事务等状态管理功能。它还支持为每个应用配置多个独立的状态存储组件。 + +状态存储具有可扩展性,可以在 [components-contrib 仓库](https://github.com/dapr/components-contrib)中找到。 + +在 Dapr 中,状态存储通过 `Component` 文件进行描述: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: statestore +spec: + type: state. + version: v1 + metadata: + - name: + value: + - name: + value: +... +``` + +数据库的类型由 `type` 字段决定,连接字符串和其他元数据信息放在 `.metadata` 部分。即使元数据值可以包含明文的密钥,仍建议使用 [密钥存储]({{< ref component-secrets.md >}})。 + +请参考[本指南]({{< ref "howto-get-save-state.md#step-1-setup-a-state-store" >}})了解如何配置状态存储组件。 + +## 支持的状态存储 + +请访问[此参考]({{< ref supported-state-stores >}})查看 Dapr 中支持的所有状态存储。 + +## 相关主题 +- [组件概念]({{< ref components-concept.md >}}) +- [状态管理概述]({{< ref state-management >}}) +- [状态管理 API 规范]({{< ref state_api.md >}}) +- [支持的状态存储]({{< ref supported-state-stores >}}) diff --git a/src/translated_content/zh_CN/docs/operations/configuration/_index.md b/src/translated_content/zh_CN/docs/operations/configuration/_index.md new file mode 100644 index 000000000..76a9377c2 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/configuration/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "Dapr 配置管理指南" +linkTitle: "配置管理" +weight: 200 +description: "了解如何设置 Dapr 配置并有效管理部署" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/configuration/api-allowlist.md b/src/translated_content/zh_CN/docs/operations/configuration/api-allowlist.md new file mode 100644 index 000000000..214248cb0 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/configuration/api-allowlist.md @@ -0,0 +1,136 @@ +--- +type: docs +title: "使用指南:选择性启用 Dapr Sidecar 的 API" +linkTitle: "Dapr API 白名单" +weight: 4500 +description: "选择应用程序可以使用的 Dapr Sidecar API" +--- + +在零信任网络环境中,或通过前端将 Dapr Sidecar 暴露给外部流量时,建议仅启用应用程序实际使用的 Dapr Sidecar API。这样可以减少潜在的攻击风险,并确保 Dapr API 仅限于应用程序的实际需求。 + +Dapr 允许您通过使用 [Dapr 配置]({{< ref "configuration-schema.md" >}}) 设置 API 白名单或黑名单来控制应用程序可以访问哪些 API。 + +### 默认设置 + +如果未指定 API 白名单或黑名单,默认情况下将允许访问所有 Dapr API。 + +- 如果只定义了黑名单,则除黑名单中定义的 API 外,所有 Dapr API 都被允许访问。 +- 如果只定义了白名单,则仅允许白名单中列出的 Dapr API。 +- 如果同时定义了白名单和黑名单,则黑名单中的 API 优先于白名单。 +- 如果两者都未定义,则允许访问所有 API。 + +例如,以下配置为 HTTP 和 gRPC 启用所有 API: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: myappconfig + namespace: default +spec: + tracing: + samplingRate: "1" +``` + +### 使用白名单 + +#### 启用特定的 HTTP API + +以下示例启用 state `v1.0` HTTP API,并禁用所有其他 HTTP API: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: myappconfig + namespace: default +spec: + api: + allowed: + - name: state + version: v1.0 + protocol: http +``` + +#### 启用特定的 gRPC API + +以下示例启用 state `v1` gRPC API,并禁用所有其他 gRPC API: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: myappconfig + namespace: default +spec: + api: + allowed: + - name: state + version: v1 + protocol: grpc +``` + +### 使用黑名单 + +#### 禁用特定的 HTTP API + +以下示例禁用 state `v1.0` HTTP API,允许所有其他 HTTP API: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: myappconfig + namespace: default +spec: + api: + denied: + - name: state + version: v1.0 + protocol: http +``` + +#### 禁用特定的 gRPC API + +以下示例禁用 state `v1` gRPC API,允许所有其他 gRPC API: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: myappconfig + namespace: default +spec: + api: + denied: + - name: state + version: v1 + protocol: grpc +``` + +### Dapr API 列表 + +`name` 字段用于指定您想启用的 Dapr API 名称。 + +请参考以下列表获取不同 Dapr API 的名称: + +| API 组 | HTTP API | [gRPC API](https://github.com/dapr/dapr/tree/master/pkg/api/grpc) | +| ----- | ----- | ----- | +| [服务调用]({{< ref service_invocation_api.md >}}) | `invoke` (`v1.0`) | `invoke` (`v1`) | +| [状态]({{< ref state_api.md>}})| `state` (`v1.0` 和 `v1.0-alpha1`) | `state` (`v1` 和 `v1alpha1`) | +| [发布/订阅]({{< ref pubsub.md >}}) | `publish` (`v1.0` 和 `v1.0-alpha1`) | `publish` (`v1` 和 `v1alpha1`) | +| [输出绑定]({{< ref bindings_api.md >}}) | `bindings` (`v1.0`) |`bindings` (`v1`) | +| 订阅 | n/a | `subscribe` (`v1alpha1`) | +| [秘密]({{< ref secrets_api.md >}})| `secrets` (`v1.0`) | `secrets` (`v1`) | +| [actor]({{< ref actors_api.md >}}) | `actors` (`v1.0`) |`actors` (`v1`) | +| [元数据]({{< ref metadata_api.md >}}) | `metadata` (`v1.0`) |`metadata` (`v1`) | +| [配置]({{< ref configuration_api.md >}}) | `configuration` (`v1.0` 和 `v1.0-alpha1`) | `configuration` (`v1` 和 `v1alpha1`) | +| [分布式锁]({{< ref distributed_lock_api.md >}}) | `lock` (`v1.0-alpha1`)
`unlock` (`v1.0-alpha1`) | `lock` (`v1alpha1`)
`unlock` (`v1alpha1`) | +| [加密]({{< ref cryptography_api.md >}}) | `crypto` (`v1.0-alpha1`) | `crypto` (`v1alpha1`) | +| [工作流]({{< ref workflow_api.md >}}) | `workflows` (`v1.0`) |`workflows` (`v1`) | +| [健康检查]({{< ref health_api.md >}}) | `healthz` (`v1.0`) | n/a | +| 关闭 | `shutdown` (`v1.0`) | `shutdown` (`v1`) | + +## 后续步骤 + +{{< button text="配置 Dapr 使用 gRPC" page="grpc" >}} diff --git a/src/translated_content/zh_CN/docs/operations/configuration/configuration-overview.md b/src/translated_content/zh_CN/docs/operations/configuration/configuration-overview.md new file mode 100644 index 000000000..9701d49ac --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/configuration/configuration-overview.md @@ -0,0 +1,397 @@ +--- +type: docs +title: "Dapr 配置" +linkTitle: "概述" +weight: 100 +description: "Dapr 配置概述" +--- + +Dapr 配置通过一系列设置和策略,允许您调整单个 Dapr 应用程序的行为,或控制平面系统服务的整体行为。 + +[欲了解更多信息,请阅读配置概念。]({{< ref configuration-concept.md >}}) + +## 应用程序配置 + +### 设置应用程序配置 + +您可以在自托管模式或 Kubernetes 模式下设置应用程序配置。 + +{{< tabs "Self-hosted" Kubernetes >}} + + +{{% codetab %}} + +在自托管模式下,Dapr 配置是一个[配置文件]({{< ref configuration-schema.md >}}),例如 `config.yaml`。默认情况下,Dapr sidecar 会在默认的 Dapr 文件夹中查找运行时配置: +- Linux/MacOs: `$HOME/.dapr/config.yaml` +- Windows: `%USERPROFILE%\.dapr\config.yaml` + +您还可以在 `dapr run` CLI 命令中使用 `--config` 标志指定文件路径来应用配置。 + +{{% /codetab %}} + + +{{% codetab %}} + +在 Kubernetes 模式下,Dapr 配置是一个应用于集群的配置资源。例如: + +```bash +kubectl apply -f myappconfig.yaml +``` + +您可以使用 Dapr CLI 列出应用程序的配置资源。 + +```bash +dapr configurations -k +``` + +Dapr sidecar 可以通过 `dapr.io/config` 注解来应用特定配置。例如: + +```yml + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "nodeapp" + dapr.io/app-port: "3000" + dapr.io/config: "myappconfig" +``` + +> **注意:** [查看所有 Kubernetes 注解]({{< ref "arguments-annotations-overview.md" >}}),以便在 sidecar 注入器系统服务激活时配置 Dapr sidecar。 + +{{% /codetab %}} + +{{< /tabs >}} + +### 应用程序配置选项 + +以下是您可以在 sidecar 上设置的所有配置选项。 + +- [跟踪](#tracing) +- [指标](#metrics) +- [日志](#logging) +- [中间件](#middleware) +- [名称解析](#name-resolution) +- [限制 secret 存储访问](#scope-secret-store-access) +- [构建块 API 的访问控制白名单](#access-control-allow-lists-for-building-block-apis) +- [服务调用 API 的访问控制白名单](#access-control-allow-lists-for-service-invocation-api) +- [禁止使用某些组件类型](#disallow-usage-of-certain-component-types) +- [启用预览功能](#turning-on-preview-features) +- [示例 sidecar 配置](#example-sidecar-configuration) + +#### 跟踪 + +跟踪配置用于启用应用程序的跟踪功能。 + +`Configuration` 规范下的 `tracing` 部分包含以下属性: + +```yml +tracing: + samplingRate: "1" + otel: + endpointAddress: "otelcollector.observability.svc.cluster.local:4317" + zipkin: + endpointAddress: "http://zipkin.default.svc.cluster.local:9411/api/v2/spans" +``` + +下表列出了跟踪的属性: + +| 属性 | 类型 | 描述 | +|--------------|--------|-------------| +| `samplingRate` | string | 设置跟踪的采样率以启用或禁用。 +| `stdout` | bool | 为跟踪写入更详细的信息 +| `otel.endpointAddress` | string | 设置 Open Telemetry (OTEL) 服务器地址以发送跟踪。这可能需要或不需要 https:// 或 http://,具体取决于您的 OTEL 提供商。 +| `otel.isSecure` | bool | 连接到端点地址是否加密 +| `otel.protocol` | string | 设置为 `http` 或 `grpc` 协议 +| `zipkin.endpointAddress` | string | 设置 Zipkin 服务器地址以发送跟踪。这应该在端点上包含协议 (http:// 或 https://)。 + +##### `samplingRate` + +`samplingRate` 用于启用或禁用跟踪。`samplingRate` 的有效范围是 `0` 到 `1`(含)。采样率决定了是否根据值对跟踪跨度进行采样。 + +`samplingRate : "1"` 采样所有跟踪。默认情况下,采样率为 (0.0001),即 1 万分之一。 + +要禁用采样率,请在配置中设置 `samplingRate : "0"`。 + +##### `otel` + +OpenTelemetry (`otel`) 端点也可以通过环境变量进行配置。`OTEL_EXPORTER_OTLP_ENDPOINT` 环境变量的存在会为 sidecar 启用跟踪。 + +| 环境变量 | 描述 | +|----------------------|-------------| +| `OTEL_EXPORTER_OTLP_ENDPOINT` | 设置 Open Telemetry (OTEL) 服务器地址,启用跟踪 | +| `OTEL_EXPORTER_OTLP_INSECURE` | 将连接到端点设置为未加密(true/false) | +| `OTEL_EXPORTER_OTLP_PROTOCOL` | 传输协议 (`grpc`, `http/protobuf`, `http/json`) | + +有关更多信息,请参阅 [可观察性分布式跟踪]({{< ref "tracing-overview.md" >}})。 + +#### 指标 + +`Configuration` 规范下的 `metrics` 部分可用于启用或禁用应用程序的指标。 + +`metrics` 部分包含以下属性: + +```yml +metrics: + enabled: true + rules: [] + latencyDistributionBuckets: [] + http: + increasedCardinality: true + pathMatching: + - /items + - /orders/{orderID} + - /orders/{orderID}/items/{itemID} + - /payments/{paymentID} + - /payments/{paymentID}/status + - /payments/{paymentID}/refund + - /payments/{paymentID}/details + excludeVerbs: false + recordErrorCodes: true +``` + +在上面的示例中,路径过滤器 `/orders/{orderID}/items/{itemID}` 将返回 _单个指标计数_,匹配所有 `orderID` 和所有 `itemID`,而不是为每个 `itemID` 返回多个指标。有关更多信息,请参阅 [HTTP 指标路径匹配]({{< ref "metrics-overview.md#http-metrics-path-matching" >}})。 + +上面的示例还启用了 [记录错误代码指标]({{< ref "metrics-overview.md#configuring-metrics-for-error-codes" >}}),默认情况下是禁用的。 + +下表列出了指标的属性: + +| 属性 | 类型 | 描述 | +|------------------------------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `enabled` | boolean | 当设置为 true 时,默认情况下,启用指标收集和指标端点。 | +| `rules` | array | 命名规则以过滤指标。每个规则包含一组 `labels` 以进行过滤和一个 `regex` 表达式以应用于指标路径。 | +| `latencyDistributionBuckets` | array | 延迟指标直方图的延迟分布桶的毫秒数组。 | +| `http.increasedCardinality` | boolean | 当设置为 `true`(默认)时,在 Dapr HTTP 服务器中,每个请求路径都会导致创建一个新的“桶”指标。这可能会导致问题,包括在请求的端点很多时(例如与 RESTful API 交互时)出现过多的内存消耗。
为了缓解与 HTTP 服务器相关的[高基数指标]({{< ref "metrics-overview.md#high-cardinality-metrics" >}})的高内存使用和出口成本,您应该将 `metrics.http.increasedCardinality` 属性设置为 `false`。 | +| `http.pathMatching` | array | 路径匹配的路径数组,允许用户定义匹配路径以管理基数。 | +| `http.excludeVerbs` | boolean | 当设置为 true 时(默认值为 false),Dapr HTTP 服务器在构建方法指标标签时忽略每个请求的 HTTP 动词。 | + +为了进一步帮助管理基数,路径匹配允许您根据定义的模式匹配指定的路径,减少唯一指标路径的数量,从而控制指标基数。此功能对于具有动态 URL 的应用程序特别有用,确保指标保持有意义且可管理,而不会消耗过多的内存。 + +使用规则,您可以为 Dapr sidecar 暴露的每个指标设置正则表达式。例如: + +```yml +metrics: + enabled: true + rules: + - name: dapr_runtime_service_invocation_req_sent_total + labels: + - name: method + regex: + "orders/": "orders/.+" +``` + +有关更多信息,请参阅 [指标文档]({{< ref "metrics-overview.md" >}})。 + +#### 日志 + +`Configuration` 规范下的 `logging` 部分用于配置 Dapr 运行时中的日志记录方式。 + +`logging` 部分包含以下属性: + +```yml +logging: + apiLogging: + enabled: false + obfuscateURLs: false + omitHealthChecks: false +``` + +下表列出了日志记录的属性: + +| 属性 | 类型 | 描述 | +|--------------|--------|-------------| +| `apiLogging.enabled` | boolean | `daprd` 的 `--enable-api-logging` 标志的默认值(以及相应的 `dapr.io/enable-api-logging` 注解):除非为每个 Dapr 运行时传递 `true` 或 `false` 值,否则使用配置规范中设置的值作为默认值。默认值:`false`。 +| `apiLogging.obfuscateURLs` | boolean | 启用时,会在 HTTP API 日志(如果启用)中模糊化 URL 的值,记录抽象路由名称而不是被调用的完整路径,该路径可能包含个人可识别信息(PII)。默认值:`false`。 +| `apiLogging.omitHealthChecks` | boolean | 如果为 `true`,则在启用 API 日志记录时,不会记录对健康检查端点(例如 `/v1.0/healthz`)的调用。这在这些调用在日志中添加了大量噪音时很有用。默认值:`false` + +有关更多信息,请参阅 [日志记录文档]({{< ref "logs.md" >}})。 + +#### 中间件 + +中间件配置设置命名的 HTTP 管道中间件处理程序。`Configuration` 规范下的 `httpPipeline` 和 `appHttpPipeline` 部分包含以下属性: + +```yml +httpPipeline: # 用于传入的 http 调用 + handlers: + - name: oauth2 + type: middleware.http.oauth2 + - name: uppercase + type: middleware.http.uppercase +appHttpPipeline: # 用于传出的 http 调用 + handlers: + - name: oauth2 + type: middleware.http.oauth2 + - name: uppercase + type: middleware.http.uppercase +``` + +下表列出了 HTTP 处理程序的属性: + +| 属性 | 类型 | 描述 | +|----------|--------|-------------| +| `name` | string | 中间件组件的名称 +| `type` | string | 中间件组件的类型 + +有关更多信息,请参阅 [中间件管道]({{< ref "middleware.md" >}})。 + +#### 名称解析组件 + +您可以在配置文件中设置要使用的名称解析组件。例如,要将 `spec.nameResolution.component` 属性设置为 `"sqlite"`,请在 `spec.nameResolution.configuration` 字典中传递配置选项,如下所示。 + +这是一个配置资源的基本示例: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: appconfig +spec: + nameResolution: + component: "sqlite" + version: "v1" + configuration: + connectionString: "/home/user/.dapr/nr.db" +``` + +有关更多信息,请参阅: +- [名称解析组件文档]({{< ref supported-name-resolution >}})以获取更多示例。 +- [配置文件文档]({{< ref configuration-schema.md >}})以了解如何为每个组件配置名称解析。 + +#### 限制 secret 存储访问 + +有关如何将 secret 范围限定到应用程序的信息和示例,请参阅 [范围 secret]({{< ref "secret-scope.md" >}}) 指南。 + +#### 构建块 API 的访问控制白名单 + +有关如何在构建块 API 列表上设置访问控制白名单(ACL)的信息和示例,请参阅 [在 Dapr sidecar 上选择性启用 Dapr API]({{< ref "api-allowlist.md" >}}) 指南。 + +#### 服务调用 API 的访问控制白名单 + +有关如何使用 ACL 设置白名单的服务调用 API 的信息和示例,请参阅 [服务调用的白名单]({{< ref "invoke-allowlist.md" >}}) 指南。 + +#### 禁止使用某些组件类型 + +使用 `Configuration` 规范中的 `components.deny` 属性,您可以指定不能初始化的组件类型的拒绝列表。 + +例如,下面的配置禁止初始化类型为 `bindings.smtp` 和 `secretstores.local.file` 的组件: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: myappconfig +spec: + components: + deny: + - bindings.smtp + - secretstores.local.file +``` + +可选地,您可以通过在组件名称末尾添加版本来指定要禁止的版本。例如,`state.in-memory/v1` 禁止初始化类型为 `state.in-memory` 且版本为 `v1` 的组件,但不禁止组件的(假设的)`v2` 版本。 + +{{% alert title="注意" color="primary" %}} + 当您将组件类型 `secretstores.kubernetes` 添加到拒绝列表时,Dapr 禁止创建 _额外的_ 类型为 `secretstores.kubernetes` 的组件。 + + 但是,它不会禁用内置的 Kubernetes secret 存储,该存储是: + - 由 Dapr 自动创建 + - 用于存储组件规范中指定的 secret + + 如果您想禁用内置的 Kubernetes secret 存储,您需要使用 `dapr.io/disable-builtin-k8s-secret-store` [注解]({{< ref arguments-annotations-overview.md >}})。 +{{% /alert %}} + +#### 启用预览功能 + +有关如何选择加入发布版的预览功能的信息和示例,请参阅 [预览功能]({{< ref "preview-features.md" >}}) 指南。 + +启用预览功能可以解锁新的功能,以便进行开发/测试,因为它们仍然需要更多时间才能在运行时中普遍可用(GA)。 + +### 示例 sidecar 配置 + +以下 YAML 显示了一个可以应用于应用程序的 Dapr sidecar 的示例配置文件。 + +```yml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: myappconfig + namespace: default +spec: + tracing: + samplingRate: "1" + stdout: true + otel: + endpointAddress: "localhost:4317" + isSecure: false + protocol: "grpc" + httpPipeline: + handlers: + - name: oauth2 + type: middleware.http.oauth2 + secrets: + scopes: + - storeName: localstore + defaultAccess: allow + deniedSecrets: ["redis-password"] + components: + deny: + - bindings.smtp + - secretstores.local.file + accessControl: + defaultAction: deny + trustDomain: "public" + policies: + - appId: app1 + defaultAction: deny + trustDomain: 'public' + namespace: "default" + operations: + - name: /op1 + httpVerb: ['POST', 'GET'] + action: deny + - name: /op2/* + httpVerb: ["*"] + action: allow +``` + +## 控制平面配置 + +一个名为 `daprsystem` 的单一配置文件与 Dapr 控制平面系统服务一起安装,应用全局设置。 + +> **仅在 Dapr 部署到 Kubernetes 时设置。** + +### 控制平面配置设置 + +Dapr 控制平面配置包含以下部分: + +- [`mtls`](#mtls-mutual-tls) 用于 mTLS(相互 TLS) + +### mTLS(相互 TLS) + +`mtls` 部分包含 mTLS 的属性。 + +| 属性 | 类型 | 描述 | +|------------------|--------|-------------| +| `enabled` | bool | 如果为 true,则启用集群中服务和应用程序之间通信的 mTLS。 +| `allowedClockSkew` | string | 检查 TLS 证书到期时允许的容差,以允许时钟偏差。遵循 [Go 的 time.ParseDuration](https://pkg.go.dev/time#ParseDuration) 使用的格式。默认值为 `15m`(15 分钟)。 +| `workloadCertTTL` | string | Dapr 签发的证书 TLS 的有效期。遵循 [Go 的 time.ParseDuration](https://pkg.go.dev/time#ParseDuration) 使用的格式。默认值为 `24h`(24 小时)。 +| `sentryAddress` | string | 连接到 Sentry 服务器的主机名端口地址。 | +| `controlPlaneTrustDomain` | string | 控制平面的信任域。用于验证与控制平面服务的连接。 | +| `tokenValidators` | array | 用于验证证书请求的其他 Sentry 令牌验证器。 | + +有关更多信息,请参阅 [mTLS 操作指南]({{< ref "mtls.md" >}}) 和 [安全概念]({{< ref "security-concept.md" >}})。 + +### 示例控制平面配置 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: daprsystem + namespace: default +spec: + mtls: + enabled: true + allowedClockSkew: 15m + workloadCertTTL: 24h +``` + +## 下一步 + +{{< button text="了解并发和速率限制" page="control-concurrency" >}} diff --git a/src/translated_content/zh_CN/docs/operations/configuration/control-concurrency.md b/src/translated_content/zh_CN/docs/operations/configuration/control-concurrency.md new file mode 100644 index 000000000..111338e89 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/configuration/control-concurrency.md @@ -0,0 +1,98 @@ +--- +type: docs +title: "操作指南:控制并发和限制应用程序的速率" +linkTitle: "并发与速率限制" +weight: 2000 +description: "了解如何控制同时调用您应用程序的请求和事件数量" +--- + +在分布式计算中,通常您可能只希望允许一定数量的请求同时执行。通过使用 Dapr 的 `app-max-concurrency`,您可以控制同时调用您应用程序的请求和事件数量。 + +默认情况下,`app-max-concurrency` 设置为 `-1`,表示不限制并发数量。 + +## 不同的方法 + +本指南主要介绍 `app-max-concurrency`,但您也可以使用 **`middleware.http.ratelimit`** 中间件来限制每秒的请求速率。理解这两种方法的区别非常重要: + +- `middleware.http.ratelimit`:限制每秒的请求数量 +- `app-max-concurrency`:限制在任意时间点的最大并发请求(和事件)数量。 + +有关该方法的更多信息,请参见[速率限制中间件]({{< ref middleware-rate-limit.md >}})。 + +## 演示 + +观看此[视频](https://youtu.be/yRI5g6o_jp8?t=1710)以了解如何控制并发和速率限制。 + +
+ +
+ +## 配置 `app-max-concurrency` + +如果不使用 Dapr,您需要在应用程序中创建某种信号量并负责获取和释放它。 + +使用 Dapr,您无需对应用程序进行任何代码更改。 + +选择您希望配置 `app-max-concurrency` 的方式。 + +{{< tabs "CLI" Kubernetes >}} + + +{{% codetab %}} + +要在本地开发环境中使用 Dapr CLI 设置并发限制,请添加 `app-max-concurrency` 标志: + +```bash +dapr run --app-max-concurrency 1 --app-port 5000 python ./app.py +``` + +上述示例将您的应用程序变成一个顺序处理服务。 + +{{% /codetab %}} + + +{{% codetab %}} + +要在 Kubernetes 中配置并发限制,请将以下注释添加到您的 pod: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nodesubscriber + namespace: default + labels: + app: nodesubscriber +spec: + replicas: 1 + selector: + matchLabels: + app: nodesubscriber + template: + metadata: + labels: + app: nodesubscriber + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "nodesubscriber" + dapr.io/app-port: "3000" + dapr.io/app-max-concurrency: "1" +#... +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 限制 + +### 控制外部请求的并发 +速率限制适用于来自 Dapr 的每个事件,包括 pub/sub 事件、来自其他服务的直接调用、bindings 事件等。然而,Dapr 无法对外部传入您应用程序的请求强制执行并发策略。 + +## 相关链接 + +[参数和注释]({{< ref arguments-annotations-overview.md >}}) + +## 下一步 + +{{< button text="限制 secret 存储访问" page="secret-scope" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/configuration/environment-variables-secrets.md b/src/translated_content/zh_CN/docs/operations/configuration/environment-variables-secrets.md new file mode 100644 index 000000000..c2aca8b69 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/configuration/environment-variables-secrets.md @@ -0,0 +1,129 @@ +--- +type: docs +title: "操作指南:为 Dapr sidecar 配置 Secret 环境变量" +linkTitle: "Secret 环境变量" +weight: 7500 +description: "将 Kubernetes Secret 中的环境变量注入到 Dapr sidecar" +--- + +在某些情况下,Dapr sidecar 需要注入环境变量。这可能是因为某个组件、第三方库或模块需要通过环境变量进行配置或自定义行为。这在生产和非生产环境中都很有用。 + +## 概述 + +在 Dapr 1.15 中,引入了新的 `dapr.io/env-from-secret` 注解,[类似于 `dapr.io/env`]({{< ref arguments-annotations-overview >}})。通过这个注解,你可以将环境变量注入到 Dapr sidecar 中,其值来自于一个 secret。 + +### 注解格式 + +注解的格式如下: + +- 单个键的 secret: `=` +- 多个键/值的 secret: `=:` + +`` 必须符合 `C_IDENTIFIER` 格式,遵循 `[A-Za-z_][A-Za-z0-9_]*` 的正则表达式: +- 必须以字母或下划线开头 +- 其余部分可以包含字母、数字或下划线 + +由于 `secretKeyRef` 的限制,`name` 字段是必需的,因此 `name` 和 `key` 必须同时设置。[从 Kubernetes 文档的 "env.valueFrom.secretKeyRef.name" 部分了解更多信息。](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables) 在这种情况下,Dapr 会将两者设置为相同的值。 + +## 配置单个键的 secret 环境变量 + +在以下示例中,`dapr.io/env-from-secret` 注解被添加到 Deployment 中。 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nodeapp +spec: + template: + metadata: + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "nodeapp" + dapr.io/app-port: "3000" + dapr.io/env-from-secret: "AUTH_TOKEN=auth-headers-secret" + spec: + containers: + - name: node + image: dapriosamples/hello-k8s-node:latest + ports: + - containerPort: 3000 + imagePullPolicy: Always +``` + +`dapr.io/env-from-secret` 注解的值为 `"AUTH_TOKEN=auth-headers-secret"` 被注入为: + +```yaml +env: +- name: AUTH_TOKEN + valueFrom: + secretKeyRef: + name: auth-headers-secret + key: auth-headers-secret +``` + +这要求 secret 的 `name` 和 `key` 字段具有相同的值,即 "auth-headers-secret"。 + +**示例 secret** + +> **注意:** 以下示例仅用于演示目的。不建议以明文存储 secret。 + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: auth-headers-secret +type: Opaque +stringData: + auth-headers-secret: "AUTH=mykey" +``` + +## 配置多个键的 secret 环境变量 + +在以下示例中,`dapr.io/env-from-secret` 注解被添加到 Deployment 中。 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nodeapp +spec: + template: + metadata: + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "nodeapp" + dapr.io/app-port: "3000" + dapr.io/env-from-secret: "AUTH_TOKEN=auth-headers-secret:auth-header-value" + spec: + containers: + - name: node + image: dapriosamples/hello-k8s-node:latest + ports: + - containerPort: 3000 + imagePullPolicy: Always +``` + +`dapr.io/env-from-secret` 注解的值为 `"AUTH_TOKEN=auth-headers-secret:auth-header-value"` 被注入为: + +```yaml +env: +- name: AUTH_TOKEN + valueFrom: + secretKeyRef: + name: auth-headers-secret + key: auth-header-value +``` + +**示例 secret** + +> **注意:** 以下示例仅用于演示目的。不建议以明文存储 secret。 + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: auth-headers-secret +type: Opaque +stringData: + auth-header-value: "AUTH=mykey" diff --git a/src/translated_content/zh_CN/docs/operations/configuration/grpc.md b/src/translated_content/zh_CN/docs/operations/configuration/grpc.md new file mode 100644 index 000000000..1140341af --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/configuration/grpc.md @@ -0,0 +1,67 @@ +--- +type: docs +title: "操作指南:配置 Dapr 使用 gRPC" +linkTitle: "使用 gRPC 接口" +weight: 5000 +description: "配置 Dapr 使用 gRPC 以实现低延迟、高性能场景" +--- + +Dapr 提供了用于本地调用的 HTTP 和 gRPC API。gRPC 适用于低延迟、高性能的场景,并支持通过 proto 客户端进行语言集成。[您可以查看自动生成的客户端(Dapr SDKs)的完整列表]({{< ref sdks >}})。 + +Dapr 运行时提供了一个 [proto 服务](https://github.com/dapr/dapr/blob/master/dapr/proto/runtime/v1/dapr.proto),应用程序可以通过 gRPC 与其进行通信。 + +Dapr 不仅可以通过 gRPC 被调用,还可以通过 gRPC 与应用程序通信。为此,应用程序需要托管一个 gRPC 服务器并实现 [Dapr `appcallback` 服务](https://github.com/dapr/dapr/blob/master/dapr/proto/runtime/v1/appcallback.proto)。 + +## 配置 Dapr 通过 gRPC 与应用程序通信 + +{{< tabs "Self-hosted" Kubernetes >}} + + +{{% codetab %}} + +在自托管模式下运行时,使用 `--app-protocol` 标志告诉 Dapr 使用 gRPC 与应用程序通信: + +```bash +dapr run --app-protocol grpc --app-port 5005 node app.js +``` +这告诉 Dapr 通过端口 `5005` 使用 gRPC 与您的应用程序通信。 + +{{% /codetab %}} + + +{{% codetab %}} + +在 Kubernetes 上,在您的部署 YAML 中设置以下注释: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myapp + namespace: default + labels: + app: myapp +spec: + replicas: 1 + selector: + matchLabels: + app: myapp + template: + metadata: + labels: + app: myapp + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "myapp" + dapr.io/app-protocol: "grpc" + dapr.io/app-port: "5005" +#... +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 + +{{< button text="处理大型 HTTP 头部大小" page="increase-read-buffer-size" >}} diff --git a/src/translated_content/zh_CN/docs/operations/configuration/increase-read-buffer-size.md b/src/translated_content/zh_CN/docs/operations/configuration/increase-read-buffer-size.md new file mode 100644 index 000000000..6c3bcff05 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/configuration/increase-read-buffer-size.md @@ -0,0 +1,68 @@ +--- +type: docs +title: "操作指南:处理大型HTTP头部大小" +linkTitle: "HTTP头部大小" +weight: 6000 +description: "配置更大的HTTP读取缓冲区大小" +--- + +Dapr的HTTP头部读取缓冲区大小默认限制为4KB。如果您发送的HTTP头部超过4KB,可能会遇到`请求头部过大`的服务调用错误。 + +您可以通过以下方法增加HTTP头部大小: +- 使用`dapr.io/http-read-buffer-size`注解,或 +- 在使用CLI时添加`--dapr-http-read-buffer-size`标志。 + +{{< tabs Self-hosted Kubernetes >}} + + +{{% codetab %}} + +在自托管模式下运行时,使用`--dapr-http-read-buffer-size`标志来配置Dapr,以便使用非默认的HTTP头部大小: + +```bash +dapr run --dapr-http-read-buffer-size 16 node app.js +``` +这会将Dapr的最大读取缓冲区大小设置为`16` KB。 + +{{% /codetab %}} + + +{{% codetab %}} + +在Kubernetes上,您可以在部署的YAML文件中设置以下注解: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myapp + namespace: default + labels: + app: myapp +spec: + replicas: 1 + selector: + matchLabels: + app: myapp + template: + metadata: + labels: + app: myapp + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "myapp" + dapr.io/app-port: "8000" + dapr.io/http-read-buffer-size: "16" +#... +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 相关链接 +[Dapr Kubernetes pod注解规范]({{< ref arguments-annotations-overview.md >}}) + +## 下一步 + +{{< button text="处理大型HTTP主体请求" page="increase-request-size" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/configuration/increase-request-size.md b/src/translated_content/zh_CN/docs/operations/configuration/increase-request-size.md new file mode 100644 index 000000000..248bd61a3 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/configuration/increase-request-size.md @@ -0,0 +1,67 @@ +--- +type: docs +title: "操作指南:如何处理大容量 HTTP 请求体" +linkTitle: "HTTP 请求体配置" +weight: 6000 +description: "如何配置超过 4 MB 的 HTTP 请求体" +--- + +Dapr 默认限制请求体大小为 4MB。您可以通过以下方法更改此限制: +- 使用 `dapr.io/http-max-request-size` 注解,或 +- 使用 `--dapr-http-max-request-size` 参数。 + +{{< tabs 自托管模式 Kubernetes 模式 >}} + + +{{% codetab %}} + +在自托管模式下运行时,使用 `--dapr-http-max-request-size` 参数来设置 Dapr 的请求体大小限制: + +```bash +dapr run --dapr-http-max-request-size 16 node app.js +``` +这将把 Dapr 的最大请求体大小设置为 `16` MB。 + +{{% /codetab %}} + + +{{% codetab %}} + +在 Kubernetes 中,您可以在部署的 YAML 文件中添加以下注解: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myapp + namespace: default + labels: + app: myapp +spec: + replicas: 1 + selector: + matchLabels: + app: myapp + template: + metadata: + labels: + app: myapp + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "myapp" + dapr.io/app-port: "8000" + dapr.io/http-max-request-size: "16" +#... +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 相关链接 + +[Dapr Kubernetes pod 注解规范]({{< ref arguments-annotations-overview.md >}}) + +## 下一步 + +{{< button text="安装 Sidecar 证书" page="install-certificates" >}} diff --git a/src/translated_content/zh_CN/docs/operations/configuration/install-certificates.md b/src/translated_content/zh_CN/docs/operations/configuration/install-certificates.md new file mode 100644 index 000000000..edadce5c1 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/configuration/install-certificates.md @@ -0,0 +1,121 @@ +--- +type: docs +title: "操作指南:在Dapr sidecar中安装证书" +linkTitle: "安装sidecar证书" +weight: 6500 +description: "配置Dapr sidecar容器以信任证书" +--- + +Dapr sidecar可以通过配置来信任与外部服务通信所需的证书。这在需要信任自签名证书的场景中非常有用,例如: +- 使用HTTP绑定 +- 为sidecar配置出站代理 + +支持信任证书颁发机构(CA)证书和叶子证书。 + +{{< tabs Self-hosted Kubernetes >}} + + +{{% codetab %}} + +当sidecar作为容器运行时,可以进行以下配置。 + +1. 使用卷挂载将证书配置为可用于sidecar容器。 +2. 将sidecar容器中的环境变量`SSL_CERT_DIR`指向包含证书的目录。 + +> **注意:** 对于Windows容器,请确保容器以管理员权限运行,以便可以安装证书。 + +以下示例展示了如何使用Docker Compose在sidecar容器中安装证书(证书位于本地的`./certificates`目录中): + +```yaml +version: '3' +services: + dapr-sidecar: + image: "daprio/daprd:edge" # dapr版本必须至少为v1.8 + command: [ + "./daprd", + "-app-id", "myapp", + "-app-port", "3000", + ] + volumes: + - "./components/:/components" + - "./certificates:/certificates" # (步骤1)将证书文件夹挂载到sidecar容器 + environment: + - "SSL_CERT_DIR=/certificates" # (步骤2)将环境变量设置为证书文件夹的路径 + # 对于Windows容器,取消注释下面的行 + # user: ContainerAdministrator +``` + +> **注意:** 当sidecar不在容器内运行时,证书必须直接安装在主机操作系统上。 + +{{% /codetab %}} + + +{{% codetab %}} + +在Kubernetes上: + +1. 使用卷挂载将证书配置为可用于sidecar容器。 +2. 将sidecar容器中的环境变量`SSL_CERT_DIR`指向包含证书的目录。 + +以下示例YAML展示了一个部署: +- 将pod卷附加到sidecar +- 设置`SSL_CERT_DIR`以安装证书 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myapp + namespace: default + labels: + app: myapp +spec: + replicas: 1 + selector: + matchLabels: + app: myapp + template: + metadata: + labels: + app: myapp + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "myapp" + dapr.io/app-port: "8000" + dapr.io/volume-mounts: "certificates-vol:/tmp/certificates" # (步骤1)将证书文件夹挂载到sidecar容器 + dapr.io/env: "SSL_CERT_DIR=/tmp/certificates" # (步骤2)将环境变量设置为证书文件夹的路径 + spec: + volumes: + - name: certificates-vol + hostPath: + path: /certificates +#... +``` + +> **注意:** 使用Windows容器时,sidecar容器以管理员权限启动,这是安装证书所需的。这不适用于Linux容器。 + +{{% /codetab %}} + +{{< /tabs >}} + +完成这些步骤后,`SSL_CERT_DIR`指向的目录中的所有证书都将被安装。 + +- **在Linux容器上:** 支持OpenSSL支持的所有证书扩展。[了解更多。](https://www.openssl.org/docs/man1.1.1/man1/openssl-rehash.html) +- **在Windows容器上:** 支持`certoc.exe`支持的所有证书扩展。[查看Windows Server Core中的certoc.exe](https://hub.docker.com/_/microsoft-windows-servercore)。 + +## 演示 + +观看在社区电话64中使用安装SSL证书和安全使用HTTP绑定的演示: + +
+ +
+ +## 相关链接 +- [HTTP绑定规范]({{< ref http.md >}}) +- [(Kubernetes) 操作指南:将Pod卷挂载到Dapr sidecar]({{< ref kubernetes-volume-mounts.md >}}) +- [Dapr Kubernetes pod注释规范]({{< ref arguments-annotations-overview.md >}}) + +## 下一步 + +{{< button text="启用预览功能" page="preview-features" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/configuration/invoke-allowlist.md b/src/translated_content/zh_CN/docs/operations/configuration/invoke-allowlist.md new file mode 100644 index 000000000..ca2ab854c --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/configuration/invoke-allowlist.md @@ -0,0 +1,441 @@ +--- +type: docs +title: "操作指南:为服务调用配置应用访问控制列表" +linkTitle: "服务调用访问控制" +weight: 4000 +description: "限制调用应用程序可以执行的操作" +--- + +通过访问控制,您可以配置策略,限制调用应用程序在被调用应用程序上通过服务调用可以执行的操作。您可以在配置模式中定义访问控制策略规范,以限制访问: +- 从特定操作到被调用应用程序,以及 +- 从调用应用程序到HTTP动词。 + +访问控制策略在配置中指定,并应用于被调用应用程序的Dapr sidecar。对被调用应用程序的访问基于匹配的策略操作。 + +您可以为所有调用应用程序提供一个默认的全局操作。如果未指定访问控制策略,默认行为是允许所有调用应用程序访问被调用应用程序。 + +[查看访问策略示例。](#example-scenarios) + +## 术语 + +### `trustDomain` + +“信任域”是用于管理信任关系的逻辑分组。每个应用程序都被分配一个信任域,可以在访问控制列表策略规范中指定。如果未定义策略规范或指定了空的信任域,则使用默认值“public”。信任域用于在TLS证书中生成应用程序的身份。 + +### 应用程序身份 + +Dapr请求sentry服务为所有应用程序生成一个[SPIFFE](https://spiffe.io/) ID。此ID附加在TLS证书中。 + +SPIFFE ID的格式为:`**spiffe://\/ns/\/\**`。 + +对于匹配策略,从调用应用程序的TLS证书中提取调用应用程序的信任域、命名空间和应用程序ID值。这些值与策略规范中指定的信任域、命名空间和应用程序ID值进行匹配。如果这三者都匹配,则进一步匹配更具体的策略。 + +## 配置属性 + +下表列出了访问控制、策略和操作的不同属性: + +### 访问控制 + +| 属性 | 类型 | 描述 | +|-----------------|--------|------| +| `defaultAction` | string | 当没有其他策略匹配时的全局默认操作 | +| `trustDomain` | string | 分配给应用程序的信任域。默认值为“public”。 | +| `policies` | string | 确定调用应用程序可以在被调用应用程序上执行哪些操作的策略 | + +### 策略 + +| 属性 | 类型 | 描述 | +|-----------------|--------|------| +| `app` | string | 允许/拒绝服务调用的调用应用程序的AppId | +| `namespace` | string | 需要与调用应用程序的命名空间匹配的命名空间值 | +| `trustDomain` | string | 需要与调用应用程序的信任域匹配的信任域。默认值为“public” | +| `defaultAction` | string | 如果找到应用程序但没有匹配的特定操作,则应用程序级别的默认操作 | +| `operations` | string | 允许从调用应用程序进行的操作 | + +### 操作 + +| 属性 | 类型 | 描述 | +|------------|--------|------| +| `name` | string | 允许在被调用应用程序上进行的操作的路径名称。通配符“\*”可以用于路径中进行匹配。通配符“\**”可以用于匹配多个路径下的内容。 | +| `httpVerb` | list | 调用应用程序可以使用的特定HTTP动词列表。通配符“\*”可以用于匹配任何HTTP动词。未用于grpc调用。 | +| `action` | string | 访问修饰符。接受的值为“allow”(默认)或“deny” | + +## 策略规则 + +1. 如果未指定访问策略,默认行为是允许所有应用程序访问被调用应用程序上的所有方法。 +1. 如果未指定全局默认操作且未定义特定应用程序策略,则空访问策略被视为未指定访问策略。默认行为是允许所有应用程序访问被调用应用程序上的所有方法。 +1. 如果未指定全局默认操作但已定义了一些特定应用程序策略,则我们采用更安全的选项,假设全局默认操作为拒绝访问被调用应用程序上的所有方法。 +1. 如果定义了访问策略且无法验证传入应用程序凭据,则全局默认操作生效。 +1. 如果传入应用程序的信任域或命名空间与应用程序策略中指定的值不匹配,则忽略应用程序策略,全局默认操作生效。 + +## 策略优先级 + +最具体的匹配策略对应的操作生效,按以下顺序排列: +1. 在HTTP的情况下为特定HTTP动词,或在GRPC的情况下为操作级别操作。 +1. 应用程序级别的默认操作 +1. 全局级别的默认操作 + +## 示例场景 + +以下是使用访问控制列表进行服务调用的一些示例场景。请参阅[配置指南]({{< ref "configuration-concept.md" >}})以了解应用程序sidecar的可用配置设置。 + +### 场景1: + +拒绝所有应用程序的访问,除非`trustDomain` = `public`,`namespace` = `default`,`appId` = `app1` + +通过此配置,所有调用方法的`appId` = `app1`被允许。来自其他应用程序的所有其他调用请求被拒绝。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: appconfig +spec: + accessControl: + defaultAction: deny + trustDomain: "public" + policies: + - appId: app1 + defaultAction: allow + trustDomain: 'public' + namespace: "default" +``` + +### 场景2: + +拒绝所有应用程序的访问,除非`trustDomain` = `public`,`namespace` = `default`,`appId` = `app1`,`operation` = `op1` + +通过此配置,只有来自`appId` = `app1`的方法`op1`被允许。来自所有其他应用程序的所有其他方法请求,包括`app1`上的其他方法,均被拒绝。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: appconfig +spec: + accessControl: + defaultAction: deny + trustDomain: "public" + policies: + - appId: app1 + defaultAction: deny + trustDomain: 'public' + namespace: "default" + operations: + - name: /op1 + httpVerb: ['*'] + action: allow +``` + +### 场景3: + +拒绝所有应用程序的访问,除非匹配特定的HTTP动词和GRPC操作 + +通过此配置,只有以下场景被允许访问。来自所有其他应用程序的所有其他方法请求,包括`app1`或`app2`上的其他方法,均被拒绝。 + +- `trustDomain` = `public`,`namespace` = `default`,`appID` = `app1`,`operation` = `op1`,`httpVerb` = `POST`/`PUT` +- `trustDomain` = `"myDomain"`,`namespace` = `"ns1"`,`appID` = `app2`,`operation` = `op2`且应用程序协议为GRPC + +只有来自`appId` = `app1`的方法`op1`上的`httpVerb` `POST`/`PUT`被允许。来自所有其他应用程序的所有其他方法请求,包括`app1`上的其他方法,均被拒绝。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: appconfig +spec: + accessControl: + defaultAction: deny + trustDomain: "public" + policies: + - appId: app1 + defaultAction: deny + trustDomain: 'public' + namespace: "default" + operations: + - name: /op1 + httpVerb: ['POST', 'PUT'] + action: allow + - appId: app2 + defaultAction: deny + trustDomain: 'myDomain' + namespace: "ns1" + operations: + - name: /op2 + action: allow +``` + +### 场景4: + +允许访问所有方法,除非`trustDomain` = `public`,`namespace` = `default`,`appId` = `app1`,`operation` = `/op1/*`,所有`httpVerb` + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: appconfig +spec: + accessControl: + defaultAction: allow + trustDomain: "public" + policies: + - appId: app1 + defaultAction: allow + trustDomain: 'public' + namespace: "default" + operations: + - name: /op1/* + httpVerb: ['*'] + action: deny +``` + +### 场景5: + +允许访问所有方法,`trustDomain` = `public`,`namespace` = `ns1`,`appId` = `app1`,并拒绝访问所有方法,`trustDomain` = `public`,`namespace` = `ns2`,`appId` = `app1` + +此场景展示了如何指定具有相同应用程序ID但属于不同命名空间的应用程序。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: appconfig +spec: + accessControl: + defaultAction: allow + trustDomain: "public" + policies: + - appId: app1 + defaultAction: allow + trustDomain: 'public' + namespace: "ns1" + - appId: app1 + defaultAction: deny + trustDomain: 'public' + namespace: "ns2" +``` + +### 场景6: + +允许访问所有方法,除非`trustDomain` = `public`,`namespace` = `default`,`appId` = `app1`,`operation` = `/op1/**/a`,所有`httpVerb` + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: appconfig +spec: + accessControl: + defaultAction: allow + trustDomain: "public" + policies: + - appId: app1 + defaultAction: allow + trustDomain: 'public' + namespace: "default" + operations: + - name: /op1/**/a + httpVerb: ['*'] + action: deny +``` + +## "hello world" 示例 + +在这些示例中,您将学习如何将访问控制应用于[hello world](https://github.com/dapr/quickstarts/tree/master/tutorials)教程。 + +访问控制列表依赖于Dapr [Sentry服务]({{< ref "security-concept.md" >}})生成带有SPIFFE ID的TLS证书进行身份验证。这意味着Sentry服务要么在本地运行,要么部署到您的托管环境中,例如Kubernetes集群。 + +下面的`nodeappconfig`示例展示了如何**拒绝**来自`pythonapp`的`neworder`方法的访问,其中Python应用程序位于`myDomain`信任域和`default`命名空间中。Node.js应用程序位于`public`信任域中。 + +### nodeappconfig.yaml + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: nodeappconfig +spec: + tracing: + samplingRate: "1" + accessControl: + defaultAction: allow + trustDomain: "public" + policies: + - appId: pythonapp + defaultAction: allow + trustDomain: 'myDomain' + namespace: "default" + operations: + - name: /neworder + httpVerb: ['POST'] + action: deny +``` + +### pythonappconfig.yaml + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: pythonappconfig +spec: + tracing: + samplingRate: "1" + accessControl: + defaultAction: allow + trustDomain: "myDomain" +``` + +### 自托管模式 + +在本教程中,您将: +- 在本地运行启用mTLS的Sentry服务 +- 设置访问证书所需的环境变量 +- 启动Node应用程序和Python应用程序,每个应用程序都引用Sentry服务以应用ACL + +#### 先决条件 + +- 熟悉在自托管模式下运行启用mTLS的[Sentry服务]({{< ref "mtls.md" >}}) +- 克隆[hello world](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-world/README.md)教程 + +#### 运行Node.js应用程序 + +1. 在命令提示符中,设置这些环境变量: + + {{< tabs "Linux/MacOS" Windows >}} + + {{% codetab %}} + + ```bash + export DAPR_TRUST_ANCHORS=`cat $HOME/.dapr/certs/ca.crt` + export DAPR_CERT_CHAIN=`cat $HOME/.dapr/certs/issuer.crt` + export DAPR_CERT_KEY=`cat $HOME/.dapr/certs/issuer.key` + export NAMESPACE=default + ``` + + {{% /codetab %}} + + {{% codetab %}} + + ```powershell + $env:DAPR_TRUST_ANCHORS=$(Get-Content -raw $env:USERPROFILE\.dapr\certs\ca.crt) + $env:DAPR_CERT_CHAIN=$(Get-Content -raw $env:USERPROFILE\.dapr\certs\issuer.crt) + $env:DAPR_CERT_KEY=$(Get-Content -raw $env:USERPROFILE\.dapr\certs\issuer.key) + $env:NAMESPACE="default" + ``` + + {{% /codetab %}} + + {{< /tabs >}} + +1. 运行daprd以启动Node.js应用程序的Dapr sidecar,启用mTLS,引用本地Sentry服务: + + ```bash + daprd --app-id nodeapp --dapr-grpc-port 50002 -dapr-http-port 3501 --log-level debug --app-port 3000 --enable-mtls --sentry-address localhost:50001 --config nodeappconfig.yaml + ``` + +1. 在另一个命令提示符中运行Node.js应用程序: + + ```bash + node app.js + ``` + +#### 运行Python应用程序 + +1. 在另一个命令提示符中,设置这些环境变量: + + {{< tabs "Linux/MacOS" Windows >}} + + {{% codetab %}} + + ```bash + export DAPR_TRUST_ANCHORS=`cat $HOME/.dapr/certs/ca.crt` + export DAPR_CERT_CHAIN=`cat $HOME/.dapr/certs/issuer.crt` + export DAPR_CERT_KEY=`cat $HOME/.dapr/certs/issuer.key` + export NAMESPACE=default + ``` + {{% /codetab %}} + + {{% codetab %}} + + ```powershell + $env:DAPR_TRUST_ANCHORS=$(Get-Content -raw $env:USERPROFILE\.dapr\certs\ca.crt) + $env:DAPR_CERT_CHAIN=$(Get-Content -raw $env:USERPROFILE\.dapr\certs\issuer.crt) + $env:DAPR_CERT_KEY=$(Get-Content -raw $env:USERPROFILE\.dapr\certs\issuer.key) + $env:NAMESPACE="default" + ``` + + {{% /codetab %}} + + {{< /tabs >}} + +1. 运行daprd以启动Python应用程序的Dapr sidecar,启用mTLS,引用本地Sentry服务: + + ```bash + daprd --app-id pythonapp --dapr-grpc-port 50003 --metrics-port 9092 --log-level debug --enable-mtls --sentry-address localhost:50001 --config pythonappconfig.yaml + ``` +1. 在另一个命令提示符中运行Python应用程序: + + ```bash + python app.py + ``` + +您应该在Python应用程序命令提示符中看到对Node.js应用程序的调用失败,这是由于`nodeappconfig`文件中的**拒绝**操作。将此操作更改为**允许**并重新运行应用程序以查看此调用成功。 + +### Kubernetes模式 + +#### 先决条件 + +- 熟悉在自托管模式下运行启用mTLS的[Sentry服务]({{< ref "mtls.md" >}}) +- 克隆[hello world](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-world/README.md)教程 + +#### 配置Node.js和Python应用程序 + +您可以创建并应用上述[`nodeappconfig.yaml`](#nodeappconfigyaml)和[`pythonappconfig.yaml`](#pythonappconfigyaml)配置文件,如[配置]({{< ref "configuration-concept.md" >}})中所述。 + +例如,下面的Kubernetes Deployment展示了Python应用程序如何在默认命名空间中使用此`pythonappconfig`配置文件部署到Kubernetes。 + +对Node.js部署执行相同操作,并查看Python应用程序的日志以查看由于`nodeappconfig`文件中设置的**拒绝**操作而导致的调用失败。 + +将此操作更改为**允许**并重新部署应用程序以查看此调用成功。 + +##### 部署YAML示例 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pythonapp + namespace: default + labels: + app: python +spec: + replicas: 1 + selector: + matchLabels: + app: python + template: + metadata: + labels: + app: python + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "pythonapp" + dapr.io/config: "pythonappconfig" + spec: + containers: + - name: python + image: dapriosamples/hello-k8s-python:edge +``` + +## 演示 + +观看此[视频](https://youtu.be/j99RN_nxExA?t=1108)了解如何为服务调用应用访问控制列表。 + +
+ +
+ +## 下一步 + +{{< button text="Dapr API允许列表" page="api-allowlist" >}} diff --git a/src/translated_content/zh_CN/docs/operations/configuration/preview-features.md b/src/translated_content/zh_CN/docs/operations/configuration/preview-features.md new file mode 100644 index 000000000..e9c30803e --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/configuration/preview-features.md @@ -0,0 +1,109 @@ +--- +type: docs +title: "操作指南:启用预览功能" +linkTitle: "预览功能" +weight: 7000 +description: "如何指定和启用预览功能" +--- + +在 Dapr 中,[预览功能]({{< ref support-preview-features >}})在首次发布时被视为实验功能。这些预览功能需要您明确选择启用才能使用。您需要在 Dapr 的配置文件中进行此选择。 + +预览功能是通过在运行应用程序实例时设置配置来启用的。 + +## 配置属性 + +`Configuration` 规范下的 `features` 部分包含以下属性: + +| 属性 | 类型 | 描述 | +|------------|--------|------| +|`name`|字符串|启用/禁用的预览功能的名称| +|`enabled`|布尔值|指定功能是否启用或禁用的布尔值| + +## 启用预览功能 + +预览功能需要在配置中指定。以下是一个包含多个功能的完整配置示例: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: featureconfig +spec: + tracing: + samplingRate: "1" + zipkin: + endpointAddress: "http://zipkin.default.svc.cluster.local:9411/api/v2/spans" + features: + - name: Feature1 + enabled: true + - name: Feature2 + enabled: true +``` + +{{< tabs Self-hosted Kubernetes >}} + + +{{% codetab %}} + +要在本地运行 Dapr 时启用预览功能,可以更新默认配置或使用 `dapr run` 指定单独的配置文件。 + +默认的 Dapr 配置是在您运行 `dapr init` 时创建的,位于: +- Windows: `%USERPROFILE%\.dapr\config.yaml` +- Linux/macOS: `~/.dapr/config.yaml` + +或者,您可以通过在 `dapr run` 中指定 `--config` 标志并指向单独的 Dapr 配置文件来更新本地运行的所有应用程序的预览功能: + +```bash +dapr run --app-id myApp --config ./previewConfig.yaml ./app +``` + +{{% /codetab %}} + + +{{% codetab %}} + +在 Kubernetes 模式下,必须通过配置组件来提供配置。使用与上面相同的配置,通过 `kubectl` 应用: + +```bash +kubectl apply -f previewConfig.yaml +``` + +然后可以通过修改应用程序的配置,使用 `dapr.io/config` 元素来引用该特定配置组件。例如: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nodeapp + labels: + app: node +spec: + replicas: 1 + selector: + matchLabels: + app: node + template: + metadata: + labels: + app: node + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "nodeapp" + dapr.io/app-port: "3000" + dapr.io/config: "featureconfig" + spec: + containers: + - name: node + image: dapriosamples/hello-k8s-node:latest + ports: + - containerPort: 3000 + imagePullPolicy: Always +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 下一步 + +{{< button text="配置模式" page="configuration-schema" >}} diff --git a/src/translated_content/zh_CN/docs/operations/configuration/secret-scope.md b/src/translated_content/zh_CN/docs/operations/configuration/secret-scope.md new file mode 100644 index 000000000..042c36479 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/configuration/secret-scope.md @@ -0,0 +1,128 @@ +--- +type: docs +title: "操作指南:限制从 secret 存储中读取的 secret" +linkTitle: "限制 secret 存储访问" +weight: 3000 +description: "通过在现有配置资源中增加限制性权限来定义 secret 范围。" +--- + +除了[定义哪些应用程序可以访问特定组件]({{< ref "component-scopes.md">}})之外,您还可以将命名的 secret 存储组件限制为应用程序的一个或多个 secret。通过定义 `allowedSecrets` 和/或 `deniedSecrets` 列表,可以限制应用程序仅访问特定的 secret。 + +有关配置资源的更多信息: +- [Configuration 概述]({{< ref configuration-overview.md >}}) +- [Configuration 模式]({{< ref configuration-schema.md >}}) + +## 配置 secret 访问 + +`Configuration` 规范下的 `secrets` 部分包含以下属性: + +```yml +secrets: + scopes: + - storeName: kubernetes + defaultAccess: allow + allowedSecrets: ["redis-password"] + - storeName: localstore + defaultAccess: allow + deniedSecrets: ["redis-password"] +``` + +下表列出了 secret 范围的属性: + +| 属性 | 类型 | 描述 | +|----------------|--------|-------------| +| storeName | string | secret 存储组件的名称。storeName 在列表中必须是唯一的 | +| defaultAccess | string | 访问修饰符。接受的值为 "allow"(默认)或 "deny" | +| allowedSecrets | list | 可以访问的 secret 键列表 | +| deniedSecrets | list | 不能访问的 secret 键列表 | + +当 `allowedSecrets` 列表中存在至少一个元素时,应用程序只能访问列表中定义的那些 secret。 + +## 权限优先级 + +`allowedSecrets` 和 `deniedSecrets` 列表的优先级高于 `defaultAccess`。请参阅以下示例场景了解其工作原理: + +| | 场景 | `defaultAccess` | `allowedSecrets` | `deniedSecrets` | `permission` +|--| ----- | ------- | -----------| ----------| ------------ +| 1 | 仅默认访问 | `deny`/`allow` | 空 | 空 | `deny`/`allow` +| 2 | 默认拒绝并允许列表 | `deny` | [`"s1"`] | 空 | 仅 `"s1"` 可以访问 +| 3 | 默认允许并拒绝列表 | `allow` | 空 | [`"s1"`] | 仅 `"s1"` 不能访问 +| 4 | 默认允许并允许列表 | `allow` | [`"s1"`] | 空 | 仅 `"s1"` 可以访问 +| 5 | 默认拒绝并拒绝列表 | `deny` | 空 | [`"s1"`] | `deny` +| 6 | 默认拒绝/允许并同时有列表 | `deny`/`allow` | [`"s1"`] | [`"s2"`] | 仅 `"s1"` 可以访问 + +## 示例 + +### 场景 1:拒绝对 secret 存储中所有 secret 的访问 + +在 Kubernetes 集群中,原生的 Kubernetes secret 存储默认会添加到您的 Dapr 应用程序中。在某些场景中,可能需要拒绝某个应用程序对 Dapr secret 的访问。要添加此配置: + +1. 定义以下 `appconfig.yaml`。 + + ```yaml + apiVersion: dapr.io/v1alpha1 + kind: Configuration + metadata: + name: appconfig + spec: + secrets: + scopes: + - storeName: kubernetes + defaultAccess: deny + ``` + +1. 使用以下命令将其应用到 Kubernetes 集群: + + ```bash + kubectl apply -f appconfig.yaml + ``` + +对于需要拒绝访问 Kubernetes secret 存储的应用程序,请按照[Kubernetes 指南]({{< ref kubernetes-overview >}}),在应用程序 pod 中添加以下注释。 + +```yaml +dapr.io/config: appconfig +``` + +定义此项后,应用程序将不再能访问 Kubernetes secret 存储。 + +### 场景 2:仅允许访问 secret 存储中的某些 secret + +要允许 Dapr 应用程序仅访问某些 secret,请定义以下 `config.yaml`: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: appconfig +spec: + secrets: + scopes: + - storeName: vault + defaultAccess: deny + allowedSecrets: ["secret1", "secret2"] +``` + +此示例为名为 `vault` 的 secret 存储定义了配置。对 secret 存储的默认访问为 `deny`。同时,应用程序可以根据 `allowedSecrets` 列表访问某些 secret。请按照[sidecar 配置指南]({{< ref "configuration-overview.md#sidecar-configuration" >}})将配置应用到 sidecar。 + +### 场景 3:拒绝访问 secret 存储中的某些敏感 secret + +定义以下 `config.yaml`: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: appconfig +spec: + secrets: + scopes: + - storeName: vault + defaultAccess: allow # 这是默认值,可以省略此行 + deniedSecrets: ["secret1", "secret2"] +``` + +此配置明确拒绝访问名为 `vault` 的 secret 存储中的 `secret1` 和 `secret2`,同时允许访问所有其他 secret。请按照[sidecar 配置指南]({{< ref "configuration-overview.md#sidecar-configuration" >}})将配置应用到 sidecar。 + +## 下一步 + +{{< button text="服务调用访问控制" page="invoke-allowlist" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/_index.md b/src/translated_content/zh_CN/docs/operations/hosting/_index.md new file mode 100644 index 000000000..5ec79029a --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "Dapr 的部署方式" +linkTitle: "部署方式" +weight: 100 +description: "了解如何在不同环境中部署 Dapr。" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/_index.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/_index.md new file mode 100644 index 000000000..6f739d289 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "在 Kubernetes 环境中部署和运行 Dapr" +linkTitle: "Kubernetes" +weight: 2000 +description: "如何在 Kubernetes 集群中运行 Dapr" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/_index.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/_index.md new file mode 100644 index 000000000..33f6c703d --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/_index.md @@ -0,0 +1,8 @@ +--- +type: docs +title: "Kubernetes 集群配置" +linkTitle: "如何设置集群" +weight: 15000 +description: > + 如何创建 Kubernetes 集群 +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-aks.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-aks.md new file mode 100644 index 000000000..1459130c2 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-aks.md @@ -0,0 +1,63 @@ +--- +type: docs +title: "配置 Azure Kubernetes 服务 (AKS) 集群" +linkTitle: "Azure Kubernetes 服务 (AKS)" +weight: 2000 +description: > + 学习如何配置 Azure Kubernetes 集群 +--- + +本指南将引导您安装 Azure Kubernetes 服务 (AKS) 集群。如果您需要更多信息,请参考 [快速入门:使用 Azure CLI 部署 AKS 集群](https://docs.microsoft.com/azure/aks/kubernetes-walkthrough) + +## 先决条件 + +- 安装: + - [Docker](https://docs.docker.com/install/) + - [kubectl](https://kubernetes.io/docs/tasks/tools/) + - [Azure CLI](https://docs.microsoft.com/cli/azure/install-azure-cli) + +## 部署 AKS 集群 + +1. 在终端中登录到 Azure。 + + ```bash + az login + ``` + +1. 设置您的默认订阅: + + ```bash + az account set -s [your_subscription_id] + ``` + +1. 创建资源组。 + + ```bash + az group create --name [your_resource_group] --location [region] + ``` + +1. 创建 AKS 集群。若需使用特定版本的 Kubernetes,请使用 `--kubernetes-version` 参数(需 1.13.x 或更高版本)。 + + ```bash + az aks create --resource-group [your_resource_group] --name [your_aks_cluster_name] --node-count 2 --enable-addons http_application_routing --generate-ssh-keys + ``` + +1. 获取 AKS 集群的访问凭据。 + + ```bash + az aks get-credentials -n [your_aks_cluster_name] -g [your_resource_group] + ``` + +## AKS Edge Essentials +要使用 Azure Kubernetes 服务 (AKS) Edge Essentials 创建单机 K8s/K3s Linux-only 集群,您可以按照 [AKS Edge Essentials 快速入门指南](https://learn.microsoft.com/azure/aks/hybrid/aks-edge-quickstart) 进行操作。 + +{{% alert title="注意" color="primary" %}} +AKS Edge Essentials 不自带默认存储类,这可能会导致在部署 Dapr 时出现问题。为避免此问题,请确保在部署 Dapr 之前在集群上启用 **local-path-provisioner** 存储类。有关更多信息,请参考 [AKS EE 上的 Local Path Provisioner](https://learn.microsoft.com/azure/aks/hybrid/aks-edge-howto-use-storage-local-path)。 +{{% /alert %}} + +## 相关链接 + +- 了解更多关于 [AKS 的 Dapr 扩展]({{< ref azure-kubernetes-service-extension >}}) + - [安装 AKS 的 Dapr 扩展](https://learn.microsoft.com/azure/aks/dapr) + - [配置 AKS 的 Dapr 扩展](https://learn.microsoft.com/azure/aks/dapr-settings) + - [使用 AKS 的 Dapr 扩展部署和运行工作流](https://learn.microsoft.com/azure/aks/dapr-workflow) diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-eks.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-eks.md new file mode 100644 index 000000000..12278852f --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-eks.md @@ -0,0 +1,132 @@ +--- +type: docs +title: "配置弹性Kubernetes服务(EKS)集群" +linkTitle: "弹性Kubernetes服务(EKS)" +weight: 4000 +description: > + 学习如何配置EKS集群 +--- + +本指南将引导您配置一个弹性Kubernetes服务(EKS)集群。如果您需要更多信息,请参考[创建一个Amazon EKS集群](https://docs.aws.amazon.com/eks/latest/userguide/create-cluster.html) + +## 前提条件 + +- 需要安装以下工具: + - [kubectl](https://kubernetes.io/docs/tasks/tools/) + - [AWS CLI](https://aws.amazon.com/cli/) + - [eksctl](https://eksctl.io/) + - [一个现有的VPC和子网](https://docs.aws.amazon.com/eks/latest/userguide/network_reqs.html) + - [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/) + +## 部署一个EKS集群 + +1. 在终端中配置AWS凭证。 + + ```bash + aws configure + ``` + +1. 创建一个名为`cluster-config.yaml`的新文件,并将以下内容添加到其中,将`[your_cluster_name]`、`[your_cluster_region]`和`[your_k8s_version]`替换为相应的值: + + ```yaml + apiVersion: eksctl.io/v1alpha5 + kind: ClusterConfig + + metadata: + name: [your_cluster_name] + region: [your_cluster_region] + version: [your_k8s_version] + tags: + karpenter.sh/discovery: [your_cluster_name] + + iam: + withOIDC: true + + managedNodeGroups: + - name: mng-od-4vcpu-8gb + desiredCapacity: 2 + minSize: 1 + maxSize: 5 + instanceType: c5.xlarge + privateNetworking: true + + addons: + - name: vpc-cni + attachPolicyARNs: + - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy + - name: coredns + version: latest + - name: kube-proxy + version: latest + - name: aws-ebs-csi-driver + wellKnownPolicies: + ebsCSIController: true + ``` + +1. 通过运行以下命令创建集群: + + ```bash + eksctl create cluster -f cluster.yaml + ``` + +1. 验证kubectl上下文: + + ```bash + kubectl config current-context + ``` + +## 为sidecar访问和默认存储类添加Dapr要求: + +1. 更新安全组规则,创建端口4000的入站规则,以允许EKS集群与Dapr sidecar通信。 + + ```bash + aws ec2 authorize-security-group-ingress --region [your_aws_region] \ + --group-id [your_security_group] \ + --protocol tcp \ + --port 4000 \ + --source-group [your_security_group] + ``` + +2. 如果没有默认存储类,请添加一个: + + ```bash + kubectl patch storageclass gp2 -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}' + ``` + +## 安装Dapr + +运行以下命令安装Dapr: + +```bash +dapr init -k +``` + +您应该看到以下响应: + +```bash +⌛ Making the jump to hyperspace... +ℹ️ Note: To install Dapr using Helm, see here: https://docs.dapr.io/getting-started/install-dapr-kubernetes/#install-with-helm-advanced + +ℹ️ Container images will be pulled from Docker Hub +✅ Deploying the Dapr control plane with latest version to your cluster... +✅ Deploying the Dapr dashboard with latest version to your cluster... +✅ Success! Dapr has been installed to namespace dapr-system. To verify, run `dapr status -k' in your terminal. To get started, go here: https://docs.dapr.io/getting-started +``` + +## 故障排除 + +### 访问权限 + +如果您遇到访问权限问题,请确保您使用的是创建集群时使用的相同AWS配置文件。如有需要,使用正确的配置文件更新kubectl配置。更多信息请参考[这里](https://repost.aws/knowledge-center/eks-api-server-unauthorized-error): + +```bash +aws eks --region [your_aws_region] update-kubeconfig --name [your_eks_cluster_name] --profile [your_profile_name] +``` + +## 相关链接 + +- [了解更多关于EKS集群的信息](https://docs.aws.amazon.com/eks/latest/userguide/clusters.html) +- [了解更多关于eksctl的信息](https://eksctl.io/getting-started/) +- [尝试一个Dapr快速入门]({{< ref quickstarts.md >}}) +- 了解如何[在您的集群上部署Dapr]({{< ref kubernetes-deploy.md >}}) +- [Kubernetes生产指南]({{< ref kubernetes-production.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-gke.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-gke.md new file mode 100644 index 000000000..f32168f91 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-gke.md @@ -0,0 +1,86 @@ +--- +type: docs +title: "设置 Google Kubernetes Engine (GKE) 集群" +linkTitle: "Google Kubernetes Engine (GKE)" +weight: 3000 +description: "设置 Google Kubernetes Engine 集群" +--- + +### 前提条件 + +- 安装: + - [kubectl](https://kubernetes.io/docs/tasks/tools/) + - [Google Cloud SDK](https://cloud.google.com/sdk) + +## 创建新集群 + +运行以下命令以创建 GKE 集群: + +```bash +$ gcloud services enable container.googleapis.com && \ + gcloud container clusters create $CLUSTER_NAME \ + --zone $ZONE \ + --project $PROJECT_ID +``` +更多选项请参阅: +- [Google Cloud SDK 文档](https://cloud.google.com/sdk/gcloud/reference/container/clusters/create)。 +- 通过 [Cloud Console](https://console.cloud.google.com/kubernetes) 创建集群以获得更具互动性的体验。 + +## 私有 GKE 集群的 Sidecar 注入 + +_**私有集群的 Sidecar 注入需要额外步骤。**_ + +在私有 GKE 集群中,自动创建的主访问防火墙规则未开放 Dapr 所需的 4000 端口用于 Sidecar 注入。 + +查看相关的防火墙规则: + +```bash +$ gcloud compute firewall-rules list --filter="name~gke-${CLUSTER_NAME}-[0-9a-z]*-master" +``` + +更新现有规则以允许 Kubernetes 主节点访问 4000 端口: + +```bash +$ gcloud compute firewall-rules update --allow tcp:10250,tcp:443,tcp:4000 +``` + +## 获取 `kubectl` 的凭据 + +运行以下命令以获取您的凭据: + +```bash +$ gcloud container clusters get-credentials $CLUSTER_NAME \ + --zone $ZONE \ + --project $PROJECT_ID +``` + +## 安装 Helm v3(可选) + +如果您使用 Helm,请安装 [Helm v3 客户端](https://helm.sh/docs/intro/install/)。 + +{{% alert title="重要" color="warning" %}} +最新的 Dapr Helm chart 不再支持 Helm v2。请参考 [从 Helm v2 迁移到 Helm v3](https://helm.sh/blog/migrate-from-helm-v2-to-helm-v3/)。 +{{% /alert %}} + +## 故障排除 + +### Kubernetes 仪表板权限 + +如果您收到类似以下的错误消息: + +``` +configmaps is forbidden: User "system:serviceaccount:kube-system:kubernetes-dashboard" cannot list configmaps in the namespace "default" +``` + +请执行此命令: + +```bash +kubectl create clusterrolebinding kubernetes-dashboard -n kube-system --clusterrole=cluster-admin --serviceaccount=kube-system:kubernetes-dashboard +``` + +## 相关链接 +- [了解更多关于 GKE 集群的信息](https://cloud.google.com/kubernetes-engine/docs) +- [尝试 Dapr 快速入门]({{< ref quickstarts.md >}}) +- 学习如何在您的集群上 [部署 Dapr]({{< ref kubernetes-deploy.md >}}) +- [在 Kubernetes 上升级 Dapr]({{< ref kubernetes-upgrade.md >}}) +- [Kubernetes 生产指南]({{< ref kubernetes-production.md >}}) diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-kind.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-kind.md new file mode 100644 index 000000000..084a1d0bf --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-kind.md @@ -0,0 +1,157 @@ +--- +type: docs +title: "设置 KiND 集群" +linkTitle: "KiND" +weight: 1100 +description: > + 如何设置 KiND 集群 +--- + +## 前提条件 + +- 安装: + - [Docker](https://docs.docker.com/install/) + - [kubectl](https://kubernetes.io/docs/tasks/tools/) +- 对于 Windows: + - 在 BIOS 中启用虚拟化 + - [安装 Hyper-V](https://docs.microsoft.com/virtualization/hyper-v-on-windows/quick-start/enable-hyper-v) + +## 安装和配置 KiND + +[参考 KiND 文档进行安装。](https://kind.sigs.k8s.io/docs/user/quick-start) + +使用 Docker Desktop 时,请确保您已进行[推荐的设置](https://kind.sigs.k8s.io/docs/user/quick-start#settings-for-docker-desktop)。 + +## 配置并创建 KiND 集群 + +1. 创建一个名为 `kind-cluster-config.yaml` 的文件,并粘贴以下内容: + + ```yaml + kind: Cluster + apiVersion: kind.x-k8s.io/v1alpha4 + nodes: + - role: control-plane + kubeadmConfigPatches: + - | + kind: InitConfiguration + nodeRegistration: + kubeletExtraArgs: + node-labels: "ingress-ready=true" + extraPortMappings: + - containerPort: 80 + hostPort: 8081 + protocol: TCP + - containerPort: 443 + hostPort: 8443 + protocol: TCP + - role: worker + - role: worker + ``` + + 此集群配置: + - 启动一个由控制平面和两个工作节点组成的 Kubernetes 集群。 + - 方便将来设置 Ingress。 + - 将容器端口映射到主机。 + +1. 运行 `kind create cluster` 命令,提供集群配置文件: + + ```bash + kind create cluster --config kind-cluster-config.yaml + ``` + + **预期输出** + + ```md + Creating cluster "kind" ... + ✓ Ensuring node image (kindest/node:v1.21.1) 🖼 + ✓ Preparing nodes 📦 📦 📦 + ✓ Writing configuration 📜 + ✓ Starting control-plane 🕹️ + ✓ Installing CNI 🔌 + ✓ Installing StorageClass 💾 + ✓ Joining worker nodes 🚜 + Set kubectl context to "kind-kind" + You can now use your cluster with: + + kubectl cluster-info --context kind-kind + + Thanks for using kind! 😊 + ``` + +## 初始化并运行 Dapr + +1. 在 Kubernetes 中初始化 Dapr。 + + ```bash + dapr init --kubernetes + ``` + + Dapr 初始化完成后,您可以在集群上使用其核心组件。 + +1. 验证 Dapr 组件的状态: + + ```bash + dapr status -k + ``` + + **预期输出** + + ```md + NAME NAMESPACE HEALTHY STATUS REPLICAS VERSION AGE CREATED + dapr-sentry dapr-system True Running 1 1.5.1 53s 2021-12-10 09:27.17 + dapr-operator dapr-system True Running 1 1.5.1 53s 2021-12-10 09:27.17 + dapr-sidecar-injector dapr-system True Running 1 1.5.1 53s 2021-12-10 09:27.17 + dapr-dashboard dapr-system True Running 1 0.9.0 53s 2021-12-10 09:27.17 + dapr-placement-server dapr-system True Running 1 1.5.1 52s 2021-12-10 09:27.18 + ``` + +1. 将端口转发到 [Dapr 仪表板](https://docs.dapr.io/reference/cli/dapr-dashboard/): + + ```bash + dapr dashboard -k -p 9999 + ``` + +1. 访问 `http://localhost:9999` 检查设置是否成功。 + +## 在 Kind Kubernetes 集群上安装 metrics-server + +1. 获取 metrics-server 清单 + + ```bash + wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml + ``` + +1. 向 components.yaml 文件添加不安全的 TLS 参数 + + ```yaml + metadata: + labels: + k8s-app: metrics-server + spec: + containers: + - args: + - --cert-dir=/tmp + - --secure-port=4443 + - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname + - --kubelet-use-node-status-port + - --kubelet-insecure-tls <==== 添加此项 + - --metric-resolution=15s + image: k8s.gcr.io/metrics-server/metrics-server:v0.6.2 + imagePullPolicy: IfNotPresent + livenessProbe: + failureThreshold: 3 + httpGet: + path: /livez + ``` + +1. 应用修改后的清单 + + ```bash + kubectl apply -f components.yaml + ``` + +## 相关链接 +- [尝试 Dapr 快速入门]({{< ref quickstarts.md >}}) +- 学习如何[在您的集群上部署 Dapr]({{< ref kubernetes-deploy.md >}}) +- [在 Kubernetes 上升级 Dapr]({{< ref kubernetes-upgrade.md >}}) +- [Kubernetes 生产指南]({{< ref kubernetes-production.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-minikube.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-minikube.md new file mode 100644 index 000000000..6f7dac878 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/cluster/setup-minikube.md @@ -0,0 +1,83 @@ +--- +type: docs +title: "设置 Minikube 集群" +linkTitle: "Minikube" +weight: 1000 +description: > + 如何设置 Minikube 集群 +--- + +## 前提条件 + +- 安装: + - [Docker](https://docs.docker.com/install/) + - [kubectl](https://kubernetes.io/docs/tasks/tools/) + - [Minikube](https://minikube.sigs.k8s.io/docs/start/) +- 对于 Windows: + - 在 BIOS 中启用虚拟化 + - [安装 Hyper-V](https://docs.microsoft.com/virtualization/hyper-v-on-windows/quick-start/enable-hyper-v) + +{{% alert title="注意" color="primary" %}} +查看 [Minikube 官方文档] 以了解有关驱动程序的详细信息和插件安装方法。 +{{% /alert %}} + +## 启动 Minikube 集群 + +1. 如果您的项目需要,设置默认的虚拟机。 + + ```bash + minikube config set vm-driver [driver_name] + ``` + +1. 启动集群。如果需要,使用 `--kubernetes-version` 指定 Kubernetes 1.13.x 或更新版本。 + + ```bash + minikube start --cpus=4 --memory=4096 + ``` + +1. 启用 Minikube 仪表板和 ingress 插件。 + + ```bash + # 启用仪表板 + minikube addons enable dashboard + + # 启用 ingress + minikube addons enable ingress + ``` + +## 安装 Helm v3(可选) + +如果您使用 Helm,安装 [Helm v3 客户端](https://helm.sh/docs/intro/install/)。 + +{{% alert title="重要" color="warning" %}} +最新的 Dapr Helm chart 不再支持 Helm v2。[从 Helm v2 迁移到 Helm v3](https://helm.sh/blog/migrate-from-helm-v2-to-helm-v3/)。 +{{% /alert %}} + +## 故障排除 + +负载均衡器的外部 IP 地址在 `kubectl get svc` 中未显示。 + +在 Minikube 中,`kubectl get svc` 中的 `EXTERNAL-IP` 显示为 `` 状态。此时,您可以运行 `minikube service [service_name]` 来打开服务,即使没有外部 IP 地址。 + +```bash +$ kubectl get svc +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +... +calculator-front-end LoadBalancer 10.103.98.37 80:30534/TCP 25h +calculator-front-end-dapr ClusterIP 10.107.128.226 80/TCP,50001/TCP 25h +... + +$ minikube service calculator-front-end +|-----------|----------------------|-------------|---------------------------| +| NAMESPACE | NAME | TARGET PORT | URL | +|-----------|----------------------|-------------|---------------------------| +| default | calculator-front-end | | http://192.168.64.7:30534 | +|-----------|----------------------|-------------|---------------------------| +🎉 正在默认浏览器中打开 Kubernetes 服务 default/calculator-front-end... +``` + +## 相关链接 +- [尝试 Dapr 快速入门]({{< ref quickstarts.md >}}) +- 学习如何在您的集群上 [部署 Dapr]({{< ref kubernetes-deploy.md >}}) +- [在 Kubernetes 上升级 Dapr]({{< ref kubernetes-upgrade.md >}}) +- [Kubernetes 生产指南]({{< ref kubernetes-production.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-dapr-shared.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-dapr-shared.md new file mode 100644 index 000000000..108bd9b52 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-dapr-shared.md @@ -0,0 +1,86 @@ +--- +type: docs +title: "使用 Dapr Shared 部署 Dapr 到每个节点或每个集群" +linkTitle: "Dapr Shared" +weight: 50000 +description: "了解如何使用 Dapr Shared 作为 sidecar 的替代部署方式" + +--- + +Dapr 会自动为您的应用程序注入一个 sidecar,以启用 Dapr API,从而实现最佳的可用性和可靠性。 + +Dapr Shared 提供了两种替代的部署策略:通过 Kubernetes 的 `DaemonSet` 实现每节点部署,或通过 `Deployment` 实现每集群部署。 + +- **`DaemonSet`:** 当以 Kubernetes 的 `DaemonSet` 资源运行 Dapr Shared 时,daprd 容器会在集群中的每个 Kubernetes 节点上运行。这可以减少应用程序与 Dapr 之间的网络延迟。 +- **`Deployment`:** 当以 Kubernetes 的 `Deployment` 运行 Dapr Shared 时,Kubernetes 调度器会决定 daprd 容器实例在集群中的哪个节点上运行。 + +{{% alert title="Dapr Shared 部署" color="primary" %}} +对于您部署的每个 Dapr 应用程序,您需要使用不同的 `shared.appId` 来部署 Dapr Shared Helm chart。 +{{% /alert %}} + + + +## 为什么选择 Dapr Shared? + +默认情况下,当 Dapr 安装到 Kubernetes 集群中时,Dapr 控制平面会将 Dapr 作为 sidecar 注入到带有 Dapr 注释(`dapr.io/enabled: "true"`)的应用程序中。sidecar 提供了许多优势,包括提高弹性,因为每个应用程序都有一个实例,并且应用程序与 sidecar 之间的所有通信都无需经过网络。 + + + +虽然 sidecar 是 Dapr 的默认部署方式,但某些用例需要其他方法。假设您希望将工作负载的生命周期与 Dapr API 解耦。一个典型的例子是函数或函数即服务(FaaS)运行时,它可能会自动缩减您的空闲工作负载以释放资源。在这种情况下,可能需要将 Dapr API 和所有 Dapr 异步功能(如订阅)分开。 + +Dapr Shared 是为这些场景而创建的,扩展了 Dapr sidecar 模型,提供了两种新的部署方法:`DaemonSet`(每节点)和 `Deployment`(每集群)。 + +{{% alert title="重要" color="primary" %}} +无论您选择哪种部署方法,重要的是要理解在大多数用例中,每个服务(app-id)都有一个 Dapr Shared 实例(Helm 发布)。这意味着如果您的应用程序由三个微服务组成,建议每个服务都有自己的 Dapr Shared 实例。您可以通过尝试 [Hello Kubernetes with Dapr Shared 教程](https://github.com/dapr/dapr-shared/blob/main/docs/tutorial/README.md) 来看到这一点。 +{{% /alert %}} + + +### `DeamonSet`(每节点) + +使用 Kubernetes `DaemonSet`,您可以定义需要在集群中每个节点上部署一次的应用程序。这使得在同一节点上运行的应用程序可以与本地 Dapr API 通信,无论 Kubernetes `Scheduler` 将您的工作负载调度到哪里。 + + + +{{% alert title="注意" color="primary" %}} +由于 `DaemonSet` 在每个节点上安装一个实例,与每集群部署的 `Deployment` 相比,它在集群中消耗更多资源,但具有提高弹性的优势。 +{{% /alert %}} + + +### `Deployment`(每集群) + +Kubernetes `Deployments` 每个集群安装一次。根据可用资源,Kubernetes `Scheduler` 决定工作负载在哪个节点上调度。对于 Dapr Shared,这意味着您的工作负载和 Dapr 实例可能位于不同的节点上,这可能会引入相当大的网络延迟,但资源使用减少。 + + + +## 开始使用 Dapr Shared + +{{% alert title="先决条件" color="primary" %}} +在安装 Dapr Shared 之前,请确保您已在集群中[安装 Dapr]({{< ref "kubernetes-deploy.md" >}})。 +{{% /alert %}} + +如果您想开始使用 Dapr Shared,可以通过安装官方 Helm Chart 创建一个新的 Dapr Shared 实例: + +``` +helm install my-shared-instance oci://registry-1.docker.io/daprio/dapr-shared-chart --set shared.appId= --set shared.remoteURL= --set shared.remotePort= --set shared.strategy=deployment +``` + +您的 Dapr 启用应用程序现在可以通过将 Dapr SDK 指向或发送请求到 Dapr Shared 实例暴露的 `my-shared-instance-dapr` Kubernetes 服务来使用 Dapr Shared 实例。 + +> 上述 `my-shared-instance` 是 Helm Chart 发布名称。 + +如果您使用 Dapr SDK,可以为您的应用程序设置以下环境变量以连接到 Dapr Shared 实例(在此情况下,运行在 `default` 命名空间中): + +``` + env: + - name: DAPR_HTTP_ENDPOINT + value: http://my-shared-instance-dapr.default.svc.cluster.local:3500 + - name: DAPR_GRPC_ENDPOINT + value: http://my-shared-instance-dapr.default.svc.cluster.local:50001 +``` + +如果您不使用 SDK,可以向这些端点发送 HTTP 或 gRPC 请求。 + +## 下一步 + +- 尝试 [Hello Kubernetes with Dapr Shared 教程](https://github.com/dapr/dapr-shared/blob/main/docs/tutorial/README.md)。 +- 在 [Dapr Shared 仓库](https://github.com/dapr/dapr-shared/blob/main/README.md)中阅读更多内容。 diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-deploy.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-deploy.md new file mode 100644 index 000000000..6f6c10a51 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-deploy.md @@ -0,0 +1,336 @@ +--- +type: docs +title: "在 Kubernetes 集群上部署 Dapr" +linkTitle: "部署 Dapr" +weight: 20000 +description: "按照这些步骤在 Kubernetes 上部署 Dapr。" +aliases: + - /zh-hans/getting-started/install-dapr-kubernetes/ +--- + +在 Kubernetes 上设置 Dapr 时,你可以使用 Dapr CLI 或 Helm。 + +{{% alert title="混合集群" color="primary" %}} +Dapr CLI 和 Dapr Helm chart 默认会部署到带有标签 `kubernetes.io/os=linux` 的节点上。如果你的应用程序需要,你也可以将 Dapr 部署到 Windows 节点。更多信息请参见[部署到混合 Linux/Windows Kubernetes 集群]({{< ref kubernetes-hybrid-clusters >}})。 +{{% /alert %}} + +{{< tabs "Dapr CLI" "Helm" >}} + +{{% codetab %}} +## 使用 Dapr CLI 安装 + +你可以使用 [Dapr CLI]({{< ref install-dapr-cli.md >}}) 在 Kubernetes 集群中安装 Dapr。 + +### 先决条件 + +- 安装: + - [Dapr CLI]({{< ref install-dapr-cli.md >}}) + - [kubectl](https://kubernetes.io/docs/tasks/tools/) +- 创建一个带有 Dapr 的 Kubernetes 集群。以下是一些有用的链接: + - [设置 KiNd 集群]({{< ref setup-kind.md >}}) + - [设置 Minikube 集群]({{< ref setup-minikube.md >}}) + - [设置 Azure Kubernetes 服务集群]({{< ref setup-aks.md >}}) + - [设置 GKE 集群]({{< ref setup-gke.md >}}) + - [设置 Amazon 弹性 Kubernetes 服务](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html) + +### 安装选项 + +你可以从官方 Helm chart 或私有 chart 安装 Dapr,并使用自定义命名空间等。 + +#### 从官方 Dapr Helm chart 安装 Dapr + +`-k` 标志用于在当前上下文的 Kubernetes 集群中初始化 Dapr。 + +1. 通过检查 `kubectl context (kubectl config get-contexts)` 来验证是否设置了正确的 "目标" 集群。 + - 你可以使用 `kubectl config use-context ` 设置不同的上下文。 + +1. 使用以下命令在集群中初始化 Dapr: + + ```bash + dapr init -k + ``` + + **预期输出** + + ```bash + ⌛ 正在初始化... + + ✅ 正在将 Dapr 控制平面部署到集群中... + ✅ 成功!Dapr 已安装到命名空间 dapr-system。要验证,请在终端中运行 "dapr status -k"。要开始,请访问此处:https://aka.ms/dapr-getting-started + ``` + +1. 运行仪表板: + + ```bash + dapr dashboard -k + ``` + + 如果你在**非默认命名空间**中安装了 Dapr,请运行: + + ```bash + dapr dashboard -k -n + ``` + +#### 从官方 Dapr Helm chart 安装 Dapr(带开发标志) + +添加 `--dev` 标志在当前上下文的 Kubernetes 集群中初始化 Dapr,并附加 Redis 和 Zipkin 部署。 + +步骤与[从 Dapr Helm chart 安装](#install-dapr-from-an-official-dapr-helm-chart)类似,只是需要在 `init` 命令后附加 `--dev` 标志: + + ```bash + dapr init -k --dev + ``` + +预期输出: + +```bash +⌛ 正在初始化... +ℹ️ 注意:要使用 Helm 安装 Dapr,请参见此处:https://docs.dapr.io/getting-started/install-dapr-kubernetes/#install-with-helm-advanced + +ℹ️ 容器镜像将从 Docker Hub 拉取 +✅ 正在将最新版本的 Dapr 控制平面部署到集群中... +✅ 正在将最新版本的 Dapr 仪表板部署到集群中... +✅ 正在将最新版本的 Dapr Redis 部署到集群中... +✅ 正在将最新版本的 Dapr Zipkin 部署到集群中... +ℹ️ 正在将 "statestore" 组件应用到 Kubernetes "default" 命名空间。 +ℹ️ 正在将 "pubsub" 组件应用到 Kubernetes "default" 命名空间。 +ℹ️ 正在将 "appconfig" zipkin 配置应用到 Kubernetes "default" 命名空间。 +✅ 成功!Dapr 已安装到命名空间 dapr-system。要验证,请在终端中运行 `dapr status -k`。要开始,请访问此处:https://aka.ms/dapr-getting-started + ``` + +经过一段时间(或使用 `--wait` 标志并指定等待时间),你可以检查 Redis 和 Zipkin 组件是否已部署到集群中。 + +```bash +kubectl get pods --namespace default +``` + +预期输出: + +```bash +NAME READY STATUS RESTARTS AGE +dapr-dev-zipkin-bfb4b45bb-sttz7 1/1 Running 0 159m +dapr-dev-redis-master-0 1/1 Running 0 159m +dapr-dev-redis-replicas-0 1/1 Running 0 159m +dapr-dev-redis-replicas-1 1/1 Running 0 159m +dapr-dev-redis-replicas-2 1/1 Running 0 158m + ``` + +#### 从私有 Dapr Helm chart 安装 Dapr + +从[私有 Helm chart 安装 Dapr](#install-dapr-from-an-official-dapr-helm-chart)在以下情况下可能有帮助: +- 需要对 Dapr Helm chart 进行更细粒度的控制 +- 有自定义的 Dapr 部署 +- 从由你的组织管理和维护的受信任注册表中拉取 Helm chart + +设置以下参数以允许 `dapr init -k` 从配置的 Helm 仓库安装 Dapr 镜像。 + +``` +export DAPR_HELM_REPO_URL="https://helm.custom-domain.com/dapr/dapr" +export DAPR_HELM_REPO_USERNAME="username_xxx" +export DAPR_HELM_REPO_PASSWORD="passwd_xxx" +``` +#### 在高可用模式下安装 + +你可以在 `dapr-system` 命名空间中运行每个控制平面 pod 的三个副本以用于[生产场景]({{< ref kubernetes-production.md >}})。 + +```bash +dapr init -k --enable-ha=true +``` + +#### 在自定义命名空间中安装 + +初始化 Dapr 时的默认命名空间是 `dapr-system`。你可以使用 `-n` 标志覆盖此设置。 + +```bash +dapr init -k -n mynamespace +``` + +#### 禁用 mTLS + +Dapr 默认使用 [mTLS]({{< ref "security-concept.md#sidecar-to-sidecar-communication" >}}) 初始化。你可以通过以下方式禁用它: + +```bash +dapr init -k --enable-mtls=false +``` + +#### 等待安装完成 + +你可以使用 `--wait` 标志等待安装完成其部署。默认超时时间为 300 秒(5 分钟),但可以使用 `--timeout` 标志自定义。 + +```bash +dapr init -k --wait --timeout 600 +``` + +### 使用 CLI 卸载 Kubernetes 上的 Dapr + +在本地机器上运行以下命令以卸载集群上的 Dapr: + +```bash +dapr uninstall -k +``` + +{{% /codetab %}} + + +{{% codetab %}} + +## 使用 Helm 安装 + +你可以使用 Helm v3 chart 在 Kubernetes 上安装 Dapr。 + +❗**重要:** 最新的 Dapr Helm chart 不再支持 Helm v2。[从 Helm v2 迁移到 Helm v3](https://helm.sh/blog/migrate-from-helm-v2-to-helm-v3/)。 + +### 先决条件 + +- 安装: + - [Helm v3](https://helm.sh/docs/intro/install/) + - [kubectl](https://kubernetes.io/docs/tasks/tools/) +- 创建一个带有 Dapr 的 Kubernetes 集群。以下是一些有用的链接: + - [设置 KiNd 集群]({{< ref setup-kind.md >}}) + - [设置 Minikube 集群]({{< ref setup-minikube.md >}}) + - [设置 Azure Kubernetes 服务集群]({{< ref setup-aks.md >}}) + - [设置 GKE 集群]({{< ref setup-gke.md >}}) + - [设置 Amazon 弹性 Kubernetes 服务](https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html) + +### 添加并安装 Dapr Helm chart + +1. 添加 Helm 仓库并更新: + + ```bash + // 添加官方 Dapr Helm chart。 + helm repo add dapr https://dapr.github.io/helm-charts/ + // 或者也可以添加私有 Dapr Helm chart。 + helm repo add dapr http://helm.custom-domain.com/dapr/dapr/ \ + --username=xxx --password=xxx + helm repo update + // 查看哪些 chart 版本可用 + helm search repo dapr --devel --versions + ``` + +1. 在 `dapr-system` 命名空间中安装 Dapr chart 到你的集群。 + + ```bash + helm upgrade --install dapr dapr/dapr \ + --version={{% dapr-latest-version short="true" %}} \ + --namespace dapr-system \ + --create-namespace \ + --wait + ``` + + 要在**高可用**模式下安装: + + ```bash + helm upgrade --install dapr dapr/dapr \ + --version={{% dapr-latest-version short="true" %}} \ + --namespace dapr-system \ + --create-namespace \ + --set global.ha.enabled=true \ + --wait + ``` + + 要在**高可用**模式下安装并独立于全局缩放选择服务: + + ```bash + helm upgrade --install dapr dapr/dapr \ + --version={{% dapr-latest-version short="true" %}} \ + --namespace dapr-system \ + --create-namespace \ + --set global.ha.enabled=false \ + --set dapr_scheduler.ha=true \ + --set dapr_placement.ha=true \ + --wait + ``` + +有关使用 Helm 安装和升级 Dapr 的更多信息,请参见[生产就绪部署的 Kubernetes 指南]({{< ref kubernetes-production.md >}})。 + +### (可选)将 Dapr 仪表板作为控制平面的一部分安装 + +如果你想安装 Dapr 仪表板,请使用此 Helm chart 并选择附加设置: + +`helm install dapr dapr/dapr-dashboard --namespace dapr-system` + +例如: + +```bash +helm repo add dapr https://dapr.github.io/helm-charts/ +helm repo update +kubectl create namespace dapr-system +# 安装 Dapr 仪表板 +helm install dapr-dashboard dapr/dapr-dashboard --namespace dapr-system +``` + +### 验证安装 + +安装完成后,验证 `dapr-operator`、`dapr-placement`、`dapr-sidecar-injector` 和 `dapr-sentry` pod 是否在 `dapr-system` 命名空间中运行: + +```bash +kubectl get pods --namespace dapr-system +``` + +```bash +NAME READY STATUS RESTARTS AGE +dapr-dashboard-7bd6cbf5bf-xglsr 1/1 Running 0 40s +dapr-operator-7bd6cbf5bf-xglsr 1/1 Running 0 40s +dapr-placement-7f8f76778f-6vhl2 1/1 Running 0 40s +dapr-sidecar-injector-8555576b6f-29cqm 1/1 Running 0 40s +dapr-sentry-9435776c7f-8f7yd 1/1 Running 0 40s +``` + +### 卸载 Kubernetes 上的 Dapr + +```bash +helm uninstall dapr --namespace dapr-system +``` + +### 更多信息 + +- 阅读[生产环境的 Kubernetes 指南]({{< ref kubernetes-production.md >}})以获取推荐的 Helm chart 值 +- [Dapr Helm chart 的更多细节](https://github.com/dapr/dapr/blob/master/charts/dapr/README.md) + +{{% /codetab %}} + +{{< /tabs >}} + +### 使用基于 Mariner 的镜像 + +在 Kubernetes 上默认拉取的容器镜像基于 [*distroless*](https://github.com/GoogleContainerTools/distroless)。 + +或者,你可以使用基于 Mariner 2(最小 distroless)的 Dapr 容器镜像。[Mariner](https://github.com/microsoft/CBL-Mariner/),官方称为 CBL-Mariner,是一个由微软维护的免费开源 Linux 发行版和容器基础镜像。对于一些 Dapr 用户,利用基于 Mariner 的容器镜像可以帮助你满足合规要求。 + +要使用基于 Mariner 的 Dapr 镜像,你需要在 Docker 标签中添加 `-mariner`。例如,`ghcr.io/dapr/dapr:latest` 是基于 *distroless* 的 Docker 镜像,而 `ghcr.io/dapr/dapr:latest-mariner` 是基于 Mariner 的。也有固定到特定版本的标签可用,例如 `{{% dapr-latest-version short="true" %}}-mariner`。 + +{{< tabs "Dapr CLI" "Helm" >}} + +{{% codetab %}} + +在 Dapr CLI 中,你可以使用 `--image-variant` 标志切换到使用基于 Mariner 的镜像。 + +```sh +dapr init -k --image-variant mariner +``` + +{{% /codetab %}} + + +{{% codetab %}} + +在 Kubernetes 和 Helm 中,你可以通过设置 `global.tag` 选项并添加 `-mariner` 来使用基于 Mariner 的镜像。例如: + +```sh +helm upgrade --install dapr dapr/dapr \ + --version={{% dapr-latest-version short="true" %}} \ + --namespace dapr-system \ + --create-namespace \ + --set global.tag={{% dapr-latest-version long="true" %}}-mariner \ + --wait +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 相关链接 +- [使用 Helm 参数和其他细节部署 Dapr]({{< ref "kubernetes-production.md#deploy-dapr-with-helm" >}}) +- [在 Kubernetes 上升级 Dapr]({{< ref kubernetes-upgrade.md >}}) +- [Kubernetes 生产指南]({{< ref kubernetes-production.md >}}) +- [配置 state 存储和 pubsub 消息代理]({{< ref "getting-started/tutorials/configure-state-pubsub.md" >}}) diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-hybrid-clusters.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-hybrid-clusters.md new file mode 100644 index 000000000..7ca7ae8db --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-hybrid-clusters.md @@ -0,0 +1,179 @@ +--- +type: docs +title: "部署到混合 Linux/Windows Kubernetes 集群" +linkTitle: "混合集群" +weight: 70000 +description: "如何在具有 Windows 节点的 Kubernetes 集群上运行 Dapr 应用" +--- + +Dapr 支持在以下类型的 Kubernetes 集群上运行您的微服务: +- Windows +- Linux +- 两者的组合 + +这在分阶段将遗留应用程序迁移到 Dapr Kubernetes 集群时特别有用。 + +Kubernetes 使用 **节点亲和性** 的概念来指定您的应用程序应在 Linux 节点还是 Windows 节点上启动。当部署到同时具有 Windows 和 Linux 节点的集群时,您必须为应用程序设置亲和性规则,否则 Kubernetes 调度器可能会将您的应用程序启动在错误类型的节点上。 + +## 先决条件 + +在开始之前,设置一个具有 Windows 节点的 Kubernetes 集群。许多 Kubernetes 提供商支持自动配置启用 Windows 的 Kubernetes 集群。 + +1. 按照您首选提供商的说明设置启用 Windows 的集群。 + + - [在 Azure AKS 上设置 Windows](https://docs.microsoft.com/azure/aks/windows-container-cli) + - [在 AWS EKS 上设置 Windows](https://docs.aws.amazon.com/eks/latest/userguide/windows-support.html) + - [在 Google Cloud GKE 上设置 Windows](https://cloud.google.com/kubernetes-engine/docs/how-to/creating-a-cluster-windows) + +1. 设置集群后,验证 Windows 和 Linux 节点是否可用。 + + ```bash + kubectl get nodes -o wide + + NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME + aks-nodepool1-11819434-vmss000000 Ready agent 6d v1.17.9 10.240.0.4 Ubuntu 16.04.6 LTS 4.15.0-1092-azure docker://3.0.10+azure + aks-nodepool1-11819434-vmss000001 Ready agent 6d v1.17.9 10.240.0.35 Ubuntu 16.04.6 LTS 4.15.0-1092-azure docker://3.0.10+azure + aks-nodepool1-11819434-vmss000002 Ready agent 5d10h v1.17.9 10.240.0.129 Ubuntu 16.04.6 LTS 4.15.0-1092-azure docker://3.0.10+azure + akswin000000 Ready agent 6d v1.17.9 10.240.0.66 Windows Server 2019 Datacenter 10.0.17763.1339 docker://19.3.5 + akswin000001 Ready agent 6d v1.17.9 10.240.0.97 Windows Server 2019 Datacenter 10.0.17763.1339 docker://19.3.5 + ``` + +## 安装 Dapr 控制平面 + +如果您使用 Dapr CLI 或通过 Helm chart 安装,只需按照正常的部署程序进行:[在 Kubernetes 集群上安装 Dapr]({{< ref "install-dapr-selfhost.md#installing-Dapr-on-a-kubernetes-cluster" >}}) + +亲和性将自动设置为 `kubernetes.io/os=linux`。这对于大多数用户来说是足够的,因为 Kubernetes 至少需要一个 Linux 节点池。 + +{{% alert title="注意" color="primary" %}} +Dapr 控制平面容器已为 Windows 和 Linux 构建和测试。然而,建议使用 Linux 控制平面容器,因为它们通常更小且拥有更大的用户基础。 + +如果您理解上述内容,但仍希望将 Dapr 控制平面部署到 Windows,可以通过设置以下命令实现: + +```sh +helm install dapr dapr/dapr --set global.daprControlPlaneOs=windows +``` +{{% /alert %}} + +## 安装 Dapr 应用 + +### Windows 应用 + +1. [按照 Microsoft 文档创建一个安装了您的应用的 Docker Windows 容器](https://learn.microsoft.com/virtualization/windowscontainers/quick-start/set-up-environment?tabs=dockerce)。 + +1. 创建一个带有节点亲和性设置为 `kubernetes.io/os: windows` 的部署 YAML 文件。在下面的 `deploy_windows.yaml` 部署文件示例中: + + ```yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: yourwinapp + labels: + app: applabel + spec: + replicas: 1 + selector: + matchLabels: + app: applablel + template: + metadata: + labels: + app: applabel + annotations: + dapr.io/enabled: "true" + dapr.io/id: "addapp" + dapr.io/port: "6000" + dapr.io/config: "appconfig" + spec: + containers: + - name: add + image: yourreponsitory/your-windows-dapr-container:your-tag + ports: + - containerPort: 6000 + imagePullPolicy: Always + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/os + operator: In + values: + - windows + ``` + +1. 将 YAML 文件部署到您的 Kubernetes 集群。 + + ```bash + kubectl apply -f deploy_windows.yaml + ``` + +### Linux 应用 + +如果您已经有一个在 Linux 上运行的 Dapr 应用,您仍然需要添加亲和性规则。 + +1. 创建一个带有节点亲和性设置为 `kubernetes.io/os: linux` 的部署 YAML 文件。在下面的 `deploy_linux.yaml` 部署文件示例中: + + ```yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: yourlinuxapp + labels: + app: yourlabel + spec: + replicas: 1 + selector: + matchLabels: + app: yourlabel + template: + metadata: + labels: + app: yourlabel + annotations: + dapr.io/enabled: "true" + dapr.io/id: "addapp" + dapr.io/port: "6000" + dapr.io/config: "appconfig" + spec: + containers: + - name: add + image: yourreponsitory/your-application:your-tag + ports: + - containerPort: 6000 + imagePullPolicy: Always + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/os + operator: In + values: + - linux + ``` + +1. 将 YAML 部署到您的 Kubernetes 集群。 + + ```bash + kubectl apply -f deploy_linux.yaml + ``` + +就是这样! + +## 清理 + +要从本指南中删除部署,请运行以下命令: + +```bash +kubectl delete -f deploy_linux.yaml +kubectl delete -f deploy_windows.yaml +helm uninstall dapr +``` + +## 相关链接 + +- 查看 [官方 Kubernetes 文档](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) 以获取通过节点亲和性进行更高级配置的示例 +- [入门:为容器准备 Windows](https://docs.microsoft.com/virtualization/windowscontainers/quick-start/set-up-environment) +- [在 Azure AKS 上设置启用 Windows 的 Kubernetes 集群](https://docs.microsoft.com/azure/aks/windows-container-cli) +- [在 AWS EKS 上设置启用 Windows 的 Kubernetes 集群](https://docs.aws.amazon.com/eks/latest/userguide/windows-support.html) +- [在 Google Cloud GKE 上设置 Windows](https://cloud.google.com/kubernetes-engine/docs/how-to/creating-a-cluster-windows) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-job.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-job.md new file mode 100644 index 000000000..516bee1db --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-job.md @@ -0,0 +1,69 @@ +--- +type: docs +title: "在 Kubernetes Job 中运行 Dapr" +linkTitle: "Kubernetes Jobs" +weight: 80000 +description: "在 Kubernetes Job 环境中使用 Dapr API" +--- + +Dapr sidecar 被设计为一个长期运行的进程。在 Kubernetes Job 的环境中,这种行为可能会阻碍作业的完成。 + +为了解决这个问题,Dapr sidecar 提供了一个 `Shutdown` 端点,用于关闭 sidecar。 + +在运行一个基本的 Kubernetes Job 时,你需要调用 sidecar 的 `/shutdown` 端点,以便优雅地停止 sidecar,并使作业被视为 `Completed`。 + +如果作业在没有调用 `Shutdown` 的情况下完成,作业会处于 `NotReady` 状态,而 `daprd` 容器会一直运行下去。 + +停止 Dapr sidecar 会导致容器中的就绪性和存活性探测失败。 + +为了防止 Kubernetes 尝试重启你的作业,请将作业的 `restartPolicy` 设置为 `Never`。 + +在调用 shutdown HTTP API 时,请确保使用 *POST* HTTP 动词。例如: + +```yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: job-with-shutdown +spec: + template: + metadata: + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "with-shutdown" + spec: + containers: + - name: job + image: alpine + command: ["/bin/sh", "-c", "apk --no-cache add curl && sleep 20 && curl -X POST localhost:3500/v1.0/shutdown"] + restartPolicy: Never +``` + +你也可以从任何 Dapr SDK 调用 `Shutdown`。例如,对于 Go SDK: + +```go +package main + +import ( + "context" + "log" + "os" + + dapr "github.com/dapr/go-sdk/client" +) + +func main() { + client, err := dapr.NewClient() + if err != nil { + log.Panic(err) + } + defer client.Close() + defer client.Shutdown() + // Job +} +``` + +## 相关链接 + +- [在 Kubernetes 上部署 Dapr]({{< ref kubernetes-deploy.md >}}) +- [在 Kubernetes 上升级 Dapr]({{< ref kubernetes-upgrade.md >}}) diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-overview.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-overview.md new file mode 100644 index 000000000..5c6b34449 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-overview.md @@ -0,0 +1,64 @@ +--- +type: docs +title: "Dapr 在 Kubernetes 上的概述" +linkTitle: "概述" +weight: 10000 +description: "如何在 Kubernetes 集群上运行 Dapr 的概述" +--- + +Dapr 可以在任何支持的 Kubernetes 版本上运行。为此,Dapr 部署了一些 Kubernetes 服务,这些服务提供了良好的集成,使得在 Kubernetes 上运行 Dapr 应用程序变得简单。 + +| Kubernetes 服务 | 描述 | +| ------------------- | ----------- | +| `dapr-operator` | 管理 Dapr 的[组件]({{< ref components >}})更新和 Kubernetes 服务端点(如状态存储、发布/订阅等) | +| `dapr-sidecar-injector` | 将 Dapr 注入到[已标注的](#adding-dapr-to-a-kubernetes-deployment)部署 pod 中,并添加环境变量 `DAPR_HTTP_PORT` 和 `DAPR_GRPC_PORT`,以便用户应用程序可以轻松与 Dapr 通信,而无需硬编码 Dapr 端口。 | +| `dapr-placement` | 专用于[actor]({{< ref actors >}})。创建映射表,将 actor 实例映射到 pod | +| `dapr-sentry` | 管理服务之间的 mTLS 并充当证书颁发机构。更多信息请参阅[安全概述]({{< ref "security-concept.md" >}}) | + + + +## 支持的版本 +Dapr 对 Kubernetes 的支持遵循 [Kubernetes 版本偏差政策](https://kubernetes.io/releases/version-skew-policy)。 + +## 将 Dapr 部署到 Kubernetes 集群 + +阅读[在 Kubernetes 集群上部署 Dapr]({{< ref kubernetes-deploy.md >}})以了解如何将 Dapr 部署到您的 Kubernetes 集群。 + +## 将 Dapr 添加到 Kubernetes 部署 + +要在 Kubernetes 集群中部署和运行启用 Dapr 的应用程序,只需在 pod 中添加一些注释即可。例如,在以下示例中,您的 Kubernetes pod 被标注为: +- 为您的服务提供 Dapr 识别的 `id` 和 `port` +- 配置追踪功能 +- 启动 Dapr sidecar 容器 + +```yml + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "nodeapp" + dapr.io/app-port: "3000" + dapr.io/config: "tracing" +``` + +有关更多信息,请查看 [Dapr 注释]({{< ref arguments-annotations-overview.md >}})。 + +## 从私有注册表拉取容器镜像 + +Dapr 可以与任何用户应用程序容器镜像无缝配合使用,无论其来源。只需[初始化 Dapr]({{< ref install-dapr-selfhost.md >}})并在 Kubernetes 定义中添加 [Dapr 注释]({{< ref arguments-annotations-overview.md >}}) 以添加 Dapr sidecar。 + +Dapr 控制平面和 sidecar 镜像来自 [daprio Docker Hub](https://hub.docker.com/u/daprio) 容器注册表,这是一个公共注册表。 + +有关以下内容的信息: +- 从私有注册表拉取您的应用程序镜像,请参考[官方 Kubernetes 文档](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/)。 +- 使用 Azure 容器注册表与 Azure Kubernetes 服务,请参考 [AKS 文档](https://docs.microsoft.com/azure/aks/cluster-container-registry-integration)。 + +## 教程 + +通过[Hello Kubernetes 教程](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-kubernetes)了解如何在您的 Kubernetes 集群上开始使用 Dapr。 + +## 相关链接 + +- [将 Dapr 部署到 Kubernetes 集群]({{< ref kubernetes-deploy >}}) +- [在 Kubernetes 集群上升级 Dapr]({{< ref kubernetes-upgrade >}}) +- [Kubernetes 上 Dapr 的生产指南]({{< ref kubernetes-production.md >}}) +- [Dapr Kubernetes 快速入门](https://github.com/dapr/quickstarts/tree/master/tutorials/hello-kubernetes) +- [使用 Bridge to Kubernetes 在本地调试 Dapr 应用程序,同时连接到您的 Kubernetes 集群]({{< ref bridge-to-kubernetes >}}) diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-persisting-scheduler.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-persisting-scheduler.md new file mode 100644 index 000000000..c22fbca34 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-persisting-scheduler.md @@ -0,0 +1,204 @@ +--- +type: docs +title: "操作指南:持久化调度器任务" +linkTitle: "操作指南:持久化调度器任务" +weight: 50000 +description: "配置调度器以持久化其数据库,使其在重启时具有弹性" +--- + +[调度器]({{< ref scheduler.md >}})服务负责将任务写入其嵌入的Etcd数据库并调度执行。 +默认情况下,调度器服务数据库会将数据写入大小为`1Gb`的持久卷声明(Persistent Volume Claim),使用集群的默认[存储类](https://kubernetes.io/docs/concepts/storage/storage-classes/)。 +这意味着在大多数Kubernetes部署中运行调度器服务不需要额外参数,但如果没有默认的StorageClass或在生产环境中运行时,您将需要进行[额外的配置](#storage-class)。 + +{{% alert title="警告" color="warning" %}} +调度器的默认存储大小为`1Gi`,这对于大多数生产部署来说可能不够。 +请注意,当启用[SchedulerReminders]({{< ref support-preview-features.md >}})预览功能时,调度器会用于[actor提醒]({{< ref actors-timers-reminders.md >}})、[工作流]({{< ref workflow-overview.md >}})以及[任务API]({{< ref jobs_api.md >}})。 +您可能需要考虑重新安装Dapr,并将调度器存储增加到至少`16Gi`或更多。 +有关更多信息,请参见下面的[ETCD存储磁盘大小](#etcd-storage-disk-size)部分。 +{{% /alert %}} + +## 生产环境设置 + +### ETCD存储磁盘大小 + +调度器的默认存储大小为`1Gb`。 +这个大小对于大多数生产部署来说可能不够。 +当存储大小超出时,调度器将记录类似以下的错误: + +``` +error running scheduler: etcdserver: mvcc: database space exceeded +``` + +确定存储大小的安全上限并不是一门精确的科学,主要取决于应用程序任务的数量、持久性和数据负载大小。 +[任务API]({{< ref jobs_api.md >}})和[actor提醒]({{< ref actors-timers-reminders.md >}})(启用[SchedulerReminders]({{< ref support-preview-features.md >}})预览功能时)会根据应用程序的使用情况进行映射。 +工作流(启用[SchedulerReminders]({{< ref support-preview-features.md >}})预览功能时)会创建大量的任务作为actor提醒,但这些任务是短暂的,与每个工作流执行的生命周期相匹配。 +工作流创建的任务的数据负载通常为空或很小。 + +调度器使用Etcd作为其存储后端数据库。 +根据设计,Etcd以[预写日志(WAL)和快照](https://etcd.io/docs/v3.5/learning/persistent-storage-files/)的形式持久化历史事务和数据。 +这意味着调度器的实际磁盘使用量将高于当前可观察的数据库状态,通常是多个倍数。 + +### 在安装时设置存储大小 + +如果您需要增加**现有**调度器的存储大小,请参见下面的[增加现有调度器存储大小](#increase-existing-scheduler-storage-size)部分。 +要增加**新**Dapr安装的存储大小(在此示例中为`16Gi`),您可以使用以下命令: + +{{< tabs "Dapr CLI" "Helm" >}} + +{{% codetab %}} + +```bash +dapr init -k --set dapr_scheduler.cluster.storageSize=16Gi --set dapr_scheduler.etcdSpaceQuota=16Gi +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```bash +helm upgrade --install dapr dapr/dapr \ +--version={{% dapr-latest-version short="true" %}} \ +--namespace dapr-system \ +--create-namespace \ +--set dapr_scheduler.cluster.storageSize=16Gi \ +--set dapr_scheduler.etcdSpaceQuota=16Gi \ +--wait +``` + +{{% /codetab %}} +{{< /tabs >}} + +#### 增加现有调度器存储大小 + +{{% alert title="警告" color="warning" %}} +并非所有存储提供商都支持动态卷扩展。 +请参阅您的存储提供商文档以确定是否支持此功能,以及如果不支持该怎么办。 +{{% /alert %}} + +默认情况下,每个调度器会为每个副本创建一个大小为`1Gi`的持久卷和持久卷声明,使用[默认的`standard`存储类](#storage-class)。 +这些将类似于以下内容,在此示例中我们以HA模式运行调度器。 + +``` +NAMESPACE NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE +dapr-system dapr-scheduler-data-dir-dapr-scheduler-server-0 Bound pvc-9f699d2e-f347-43b0-aa98-57dcf38229c5 1Gi RWO standard 3m25s +dapr-system dapr-scheduler-data-dir-dapr-scheduler-server-1 Bound pvc-f4c8be7b-ffbe-407b-954e-7688f2482caa 1Gi RWO standard 3m25s +dapr-system dapr-scheduler-data-dir-dapr-scheduler-server-2 Bound pvc-eaad5fb1-98e9-42a5-bcc8-d45dba1c4b9f 1Gi RWO standard 3m25s +``` + +``` +NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE +pvc-9f699d2e-f347-43b0-aa98-57dcf38229c5 1Gi RWO Delete Bound dapr-system/dapr-scheduler-data-dir-dapr-scheduler-server-0 standard 4m24s +pvc-eaad5fb1-98e9-42a5-bcc8-d45dba1c4b9f 1Gi RWO Delete Bound dapr-system/dapr-scheduler-data-dir-dapr-scheduler-server-2 standard 4m24s +pvc-f4c8be7b-ffbe-407b-954e-7688f2482caa 1Gi RWO Delete Bound dapr-system/dapr-scheduler-data-dir-dapr-scheduler-server-1 standard 4m24s +``` + +要扩展调度器的存储大小,请按照以下步骤操作: + +1. 首先,确保存储类支持卷扩展,并且`allowVolumeExpansion`字段设置为`true`,如果尚未设置。 + +```yaml +apiVersion: storage.k8s.io/v1 +kind: StorageClass +metadata: + name: standard +provisioner: my.driver +allowVolumeExpansion: true +... +``` + +2. 删除调度器StatefulSet,同时保留绑定的持久卷声明。 + +```bash +kubectl delete sts -n dapr-system dapr-scheduler-server --cascade=orphan +``` + +3. 通过编辑`spec.resources.requests.storage`字段,将持久卷声明的大小增加到所需大小。 + 在这种情况下,我们假设调度器以3个副本的HA模式运行。 + +```bash +kubectl edit pvc -n dapr-system dapr-scheduler-data-dir-dapr-scheduler-server-0 dapr-scheduler-data-dir-dapr-scheduler-server-1 dapr-scheduler-data-dir-dapr-scheduler-server-2 +``` + +4. 通过[安装具有所需存储大小的Dapr](#setting-the-storage-size-on-installation)重新创建调度器StatefulSet。 + +### 存储类 + +如果您的Kubernetes部署没有默认存储类或您正在配置生产集群,则需要定义存储类。 + +持久卷由托管的云提供商或Kubernetes基础设施平台提供的真实磁盘支持。 +磁盘大小由预计一次持久化的任务数量决定;然而,64Gb对于大多数生产场景来说应该绰绰有余。 +一些Kubernetes提供商建议使用[CSI驱动](https://kubernetes.io/docs/concepts/storage/volumes/#csi)来配置底层磁盘。 +以下是为主要云提供商创建持久磁盘的相关文档的有用链接列表: +- [Google Cloud Persistent Disk](https://cloud.google.com/compute/docs/disks) +- [Amazon EBS Volumes](https://aws.amazon.com/blogs/storage/persistent-storage-for-kubernetes/) +- [Azure AKS Storage Options](https://learn.microsoft.com/azure/aks/concepts-storage) +- [Digital Ocean Block Storage](https://www.digitalocean.com/docs/kubernetes/how-to/add-volumes/) +- [VMWare vSphere Storage](https://docs.vmware.com/VMware-vSphere/7.0/vmware-vsphere-with-tanzu/GUID-A19F6480-40DC-4343-A5A9-A5D3BFC0742E.html) +- [OpenShift Persistent Storage](https://docs.openshift.com/container-platform/4.6/storage/persistent_storage/persistent-storage-aws-efs.html) +- [Alibaba Cloud Disk Storage](https://www.alibabacloud.com/help/ack/ack-managed-and-ack-dedicated/user-guide/create-a-pvc) + +一旦存储类可用,您可以使用以下命令安装Dapr,并将调度器配置为使用存储类(将`my-storage-class`替换为存储类的名称): + +{{% alert title="注意" color="primary" %}} +如果Dapr已经安装,则需要完全[卸载]({{< ref dapr-uninstall.md >}})控制平面,以便调度器`StatefulSet`可以使用新的持久卷重新创建。 +{{% /alert %}} + +{{< tabs "Dapr CLI" "Helm" >}} + +{{% codetab %}} + +```bash +dapr init -k --set dapr_scheduler.cluster.storageClassName=my-storage-class +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```bash +helm upgrade --install dapr dapr/dapr \ +--version={{% dapr-latest-version short="true" %}} \ +--namespace dapr-system \ +--create-namespace \ +--set dapr_scheduler.cluster.storageClassName=my-storage-class \ +--wait +``` + +{{% /codetab %}} +{{< /tabs >}} + +## 临时存储 + +在非HA模式下运行时,调度器可以选择使用临时存储,即内存存储,这种存储在重启时**不**具有弹性。例如,调度器重启后,所有任务数据都会丢失。 +这在非生产部署或测试中很有用,在这些情况下存储不可用或不需要。 + +{{% alert title="注意" color="primary" %}} +如果Dapr已经安装,则需要完全[卸载]({{< ref dapr-uninstall.md >}})控制平面,以便调度器`StatefulSet`可以在没有持久卷的情况下重新创建。 +{{% /alert %}} + +{{< tabs "Dapr CLI" "Helm" >}} + +{{% codetab %}} + +```bash +dapr init -k --set dapr_scheduler.cluster.inMemoryStorage=true +``` + +{{% /codetab %}} + + +{{% codetab %}} + +```bash +helm upgrade --install dapr dapr/dapr \ +--version={{% dapr-latest-version short="true" %}} \ +--namespace dapr-system \ +--create-namespace \ +--set dapr_scheduler.cluster.inMemoryStorage=true \ +--wait +``` + +{{% /codetab %}} +{{< /tabs >}} diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-production.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-production.md new file mode 100644 index 000000000..9cddf8a4d --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-production.md @@ -0,0 +1,348 @@ +--- +type: docs +title: "Kubernetes 生产指南" +linkTitle: "生产指南" +weight: 40000 +description: "在 Kubernetes 集群中以生产就绪配置部署 Dapr 的最佳实践" +--- + +## 集群和容量要求 + +Dapr 对 Kubernetes 的支持遵循 [Kubernetes 版本偏差政策](https://kubernetes.io/releases/version-skew-policy/)。 + +以下资源配置可作为起始参考。具体要求会因集群规模、pod 数量及其他因素而有所不同。请根据您的环境进行测试以确定合适的配置值。在生产环境中,建议不要为 Dapr 控制平面组件设置内存限制,以避免出现 `OOMKilled` pod 状态。 + +| 部署 | CPU | 内存 +|-------------|-----|------- +| **Operator** | 限制: 1, 请求: 100m | 请求: 100Mi +| **Sidecar Injector** | 限制: 1, 请求: 100m | 请求: 30Mi +| **Sentry** | 限制: 1, 请求: 100m | 请求: 30Mi +| **Placement** | 限制: 1, 请求: 250m | 请求: 75Mi + +{{% alert title="注意" color="primary" %}} +有关更多信息,请参阅 Kubernetes 文档中的 [CPU 和内存资源单位及其含义](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-units-in-kubernetes)。 +{{% /alert %}} + +### Helm + +使用 Helm 安装 Dapr 时,默认未设置限制/请求值。每个组件都有一个 `resources` 选项(例如,`dapr_dashboard.resources`),您可以根据需要调整 Dapr 控制平面的资源配置。 + +[Helm chart 说明](https://github.com/dapr/dapr/blob/master/charts/dapr/README.md) 提供了详细信息和示例。 + +对于本地/开发安装,您可以选择不配置 `resources` 选项。 + +### 可选组件 + +以下 Dapr 控制平面部署是可选的: + +- **Placement**: 用于 Dapr actor +- **Sentry**: 用于服务到服务调用的 mTLS +- **Dashboard**: 用于集群的操作视图 + +## Sidecar 资源设置 + +[使用支持的注释设置 Dapr sidecar 的资源分配]({{< ref "arguments-annotations-overview.md" >}})。与 **资源约束** 相关的特定注释是: + +- `dapr.io/sidecar-cpu-limit` +- `dapr.io/sidecar-memory-limit` +- `dapr.io/sidecar-cpu-request` +- `dapr.io/sidecar-memory-request` + +如果未设置,Dapr sidecar 将在没有资源设置的情况下运行,这可能会导致问题。对于生产就绪的设置,强烈建议配置这些设置。 + +生产就绪设置中 Dapr sidecar 的示例设置: + +| CPU | 内存 | +|-----|--------| +| 限制: 300m, 请求: 100m | 限制: 1000Mi, 请求: 250Mi + +上述 CPU 和内存限制考虑了 Dapr 支持大量 I/O 绑定操作。使用 [监控工具]({{< ref observability >}}) 获取 sidecar(和应用程序)容器的基线,并根据这些基线调整这些设置。 + +有关在 Kubernetes 中配置资源的更多详细信息,请参阅以下 Kubernetes 指南: +- [为容器和 Pod 分配内存资源](https://kubernetes.io/docs/tasks/configure-pod-container/assign-memory-resource/) +- [为容器和 Pod 分配 CPU 资源](https://kubernetes.io/docs/tasks/configure-pod-container/assign-cpu-resource/) + +{{% alert title="注意" color="primary" %}} +由于 Dapr 旨在为您的应用程序完成大量 I/O 工作,分配给 Dapr 的资源会大大减少应用程序的资源分配。 +{{% /alert %}} + +### 在 Dapr sidecar 上设置软内存限制 + +当您设置了内存限制时,建议在 Dapr sidecar 上设置软内存限制。使用软内存限制时,sidecar 垃圾收集器在超过限制时释放内存,而不是等待其达到运行时堆中最后一次存在的内存量的两倍。Go 的 [垃圾收集器](https://tip.golang.org/doc/gc-guide#Memory_limit) 默认会等待,这可能导致 OOM Kill 事件。 + +例如,对于一个内存限制设置为 1000Mi 的应用程序,其 app-id 为 `nodeapp`,您可以在 pod 注释中使用以下内容: + +```yaml + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "nodeapp" + # 我们的 daprd 内存设置 + dapr.io/sidecar-memory-limit: "1000Mi" # 您的内存限制 + dapr.io/env: "GOMEMLIMIT=900MiB" # 您内存限制的 90%。还请注意后缀 "MiB" 而不是 "Mi" +``` + +在此示例中,软限制设置为 90%,以留出 5-10% 给其他服务,[如推荐](https://tip.golang.org/doc/gc-guide#Memory_limit)。 + +`GOMEMLIMIT` 环境变量 [允许某些内存大小的后缀:`B`、`KiB`、`MiB`、`GiB` 和 `TiB`。](https://pkg.go.dev/runtime) + +## 高可用模式 + +在生产就绪配置中部署 Dapr 时,最好以控制平面的高可用 (HA) 配置进行部署。这将在 `dapr-system` 命名空间中为每个控制平面 pod 创建三个副本,使 Dapr 控制平面能够保留三个运行实例并在单个节点故障和其他中断中幸存。 + +对于新的 Dapr 部署,可以通过以下两种方式设置 HA 模式: +- [Dapr CLI]({{< ref "kubernetes-deploy.md#install-in-highly-available-mode" >}}),和 +- [Helm charts]({{< ref "kubernetes-deploy.md#add-and-install-dapr-helm-chart" >}}) + +对于现有的 Dapr 部署,[您可以通过几个额外步骤启用 HA 模式]({{< ref "#enabling-high-availability-in-an-existing-dapr-deployment" >}})。 + +### 单个服务 HA Helm 配置 + +您可以通过将 `global.ha.enabled` 标志设置为 `true` 来跨所有服务配置 HA 模式。默认情况下,`--set global.ha.enabled=true` 完全被尊重且无法覆盖,因此不可能同时将 placement 或调度服务作为单个实例。 + +> **注意:** 调度和 placement 服务的 HA 不是默认设置。 + +要独立于 `global.ha.enabled` 标志将调度和 placement 扩展到三个实例,请将 `global.ha.enabled` 设置为 `false`,并将 `dapr_scheduler.ha` 和 `dapr_placement.ha` 设置为 `true`。例如: + + ```bash + helm upgrade --install dapr dapr/dapr \ + --version={{% dapr-latest-version short="true" %}} \ + --namespace dapr-system \ + --create-namespace \ + --set global.ha.enabled=false \ + --set dapr_scheduler.ha=true \ + --set dapr_placement.ha=true \ + --wait + ``` + +## 为控制平面服务设置集群关键优先级类名称 + +在某些情况下,节点可能会有内存和/或 CPU 压力,Dapr 控制平面 pod 可能会被选中进行驱逐。为防止这种情况,您可以为 Dapr 控制平面 pod 设置一个关键优先级类名称。这确保了 Dapr 控制平面 pod 不会被驱逐,除非所有其他优先级较低的 pod 都被驱逐。 + +了解更多关于 [保护关键任务 Pod](https://kubernetes.io/blog/2023/01/12/protect-mission-critical-pods-priorityclass/) 的信息。 + +Kubernetes 中有两个内置的关键优先级类: +- `system-cluster-critical` +- `system-node-critical`(最高优先级) + +建议将 `priorityClassName` 设置为 `system-cluster-critical` 用于 Dapr 控制平面 pod。 + +对于新的 Dapr 控制平面部署,可以通过 helm 值 `global.priorityClassName` 设置 `system-cluster-critical` 优先级类模式。 + +此优先级类可以通过 Dapr CLI 和 Helm charts 设置, +使用 helm `--set global.priorityClassName=system-cluster-critical` 参数。 + +#### Dapr 版本 < 1.14 + +对于低于 v1.14 的 Dapr 版本,建议您向 Dapr 控制平面命名空间添加 `ResourceQuota`。这可以防止与调度 pod 相关的问题 [集群可能被配置](https://kubernetes.io/docs/concepts/policy/resource-quotas/#limit-priority-class-consumption-by-default ) 限制哪些 pod 可以被分配高优先级类。对于 v1.14 及更高版本,Helm chart 会自动添加此项。 + +如果您在命名空间 `dapr-system` 中安装了 Dapr,您可以创建一个 `ResourceQuota`,内容如下: + +```yaml +apiVersion: v1 +kind: ResourceQuota +metadata: + name: dapr-system-critical-quota + namespace: dapr-system +spec: + scopeSelector: + matchExpressions: + - operator : In + scopeName: PriorityClass + values: [system-cluster-critical] +``` + +## 使用 Helm 部署 Dapr + +[访问使用 Helm 部署 Dapr 的完整指南]({{< ref "kubernetes-deploy.md#install-with-helm-advanced" >}})。 + +### 参数文件 + +建议创建一个 values 文件,而不是在命令中指定参数。将 values 文件检入源代码控制,以便您可以跟踪其更改。 + +[查看可用参数和设置的完整列表](https://github.com/dapr/dapr/blob/master/charts/dapr/README.md)。 + +以下命令在 `dapr-system` 命名空间中运行每个控制平面服务的三个副本。 + +```bash +# 添加/更新官方 Dapr Helm 仓库。 +helm repo add dapr https://dapr.github.io/helm-charts/ +# 或添加/更新私有 Dapr Helm 仓库。 +helm repo add dapr http://helm.custom-domain.com/dapr/dapr/ \ + --username=xxx --password=xxx +helm repo update + +# 查看哪些 chart 版本可用 +helm search repo dapr --devel --versions + +# 创建一个 values 文件来存储变量 +touch values.yml +cat << EOF >> values.yml +global: + ha: + enabled: true +EOF + +# 运行安装/升级 +helm install dapr dapr/dapr \ + --version= \ + --namespace dapr-system \ + --create-namespace \ + --values values.yml \ + --wait + +# 验证安装 +kubectl get pods --namespace dapr-system +``` + +{{% alert title="注意" color="primary" %}} +上面的示例使用 `helm install` 和 `helm upgrade`。您还可以运行 `helm upgrade --install` 来动态确定是安装还是升级。 +{{% /alert %}} + +Dapr Helm chart 自动部署具有 `kubernetes.io/os=linux` 标签的节点的亲和性。您可以将 Dapr 控制平面部署到 Windows 节点。有关更多信息,请参阅 [部署到混合 Linux/Windows K8s 集群]({{< ref "kubernetes-hybrid-clusters.md" >}})。 + +## 使用 Helm 升级 Dapr + +Dapr 支持以下步骤的零停机时间升级。 + +### 升级 CLI(推荐) + +升级 CLI 是可选的,但推荐。 + +1. [下载最新版本](https://github.com/dapr/cli/releases) 的 CLI。 +1. 验证 Dapr CLI 是否在您的路径中。 + +### 升级控制平面 + +[在 Kubernetes 集群上升级 Dapr]({{< ref "kubernetes-upgrade.md#helm" >}})。 + +### 更新数据平面(sidecars) + +更新运行 Dapr 的 pod 以获取 Dapr 运行时的新版本。 + +1. 对任何具有 `dapr.io/enabled` 注释的部署发出滚动重启命令: + + ```bash + kubectl rollout restart deploy/ + ``` + +1. 通过以下任一方式查看所有启用 Dapr 的部署列表: + - [Dapr Dashboard](https://github.com/dapr/dashboard) + - 使用 Dapr CLI 运行以下命令: + + ```bash + dapr list -k + + APP ID APP PORT AGE CREATED + nodeapp 3000 16h 2020-07-29 17:16.22 + ``` + +### 在现有 Dapr 部署中启用高可用性 + +为现有 Dapr 部署启用 HA 模式需要两个步骤: + +1. 删除现有的 placement 有状态集。 + + ```bash + kubectl delete statefulset.apps/dapr-placement-server -n dapr-system + ``` + + 您删除 placement 有状态集是因为在 HA 模式下,placement 服务添加了 [Raft](https://raft.github.io/) 用于领导者选举。然而,Kubernetes 仅允许有限的字段在有状态集中进行修补,随后会导致 placement 服务的升级失败。 + + 删除现有的 placement 有状态集是安全的。代理会重新连接并重新注册到新创建的 placement 服务,该服务在 Raft 中持久化其表。 + +1. 发出升级命令。 + + ```bash + helm upgrade dapr ./charts/dapr -n dapr-system --set global.ha.enabled=true + ``` + +## 推荐的安全配置 + +正确配置时,Dapr 确保安全通信,并可以通过许多内置功能使您的应用程序更安全。 + +验证您的生产就绪部署包括以下设置: + +1. **相互认证 (mTLS)** 已启用。Dapr 默认启用 mTLS。[了解更多关于如何使用您自己的证书]({{< ref "mtls.md#bringing-your-own-certificates" >}})。 + +1. **应用程序到 Dapr API 认证** 已启用。这是您的应用程序与 Dapr sidecar 之间的通信。为了保护 Dapr API 免受未经授权的应用程序访问,[启用 Dapr 的基于令牌的认证]({{< ref "api-token.md" >}})。 + +1. **Dapr 到应用程序 API 认证** 已启用。这是 Dapr 与您的应用程序之间的通信。[让 Dapr 知道它正在使用令牌认证与授权应用程序通信]({{< ref "app-api-token.md" >}})。 + +1. **组件 secret 数据配置在 secret 存储中**,而不是硬编码在组件 YAML 文件中。[了解如何使用 Dapr 组件的 secret]({{< ref "component-secrets.md" >}})。 + +1. Dapr **控制平面安装在专用命名空间中**,例如 `dapr-system`。 + +1. Dapr 支持并启用 **为某些应用程序设置组件范围**。这不是必需的实践。[了解更多关于组件范围]({{< ref "component-scopes.md" >}})。 + +## 推荐的 Placement 服务配置 + +[Placement 服务]({{< ref "placement.md" >}}) 是 Dapr 中的一个组件,负责通过 placement 表向所有 Dapr sidecar 传播 actor 地址信息(更多信息可以在 [这里]({{< ref "actors-features-concepts.md#actor-placement-service" >}}) 找到)。 + +在生产环境中运行时,建议使用以下值配置 Placement 服务: + +1. **高可用性**。确保 Placement 服务具有高可用性(三个副本)并能在单个节点故障中幸存。Helm chart 值:`dapr_placement.ha=true` +2. **内存日志**。使用内存 Raft 日志存储以加快写入速度。权衡是更多的 placement 表传播(因此,在最终的 Placement 服务 pod 故障中,网络流量会增加)。Helm chart 值:`dapr_placement.cluster.forceInMemoryLog=true` +3. **无元数据端点**。禁用未认证的 `/placement/state` 端点,该端点暴露了 Placement 服务的 placement 表信息。Helm chart 值:`dapr_placement.metadataEnabled=false` +4. **超时** 控制 Placement 服务与 sidecar 之间网络连接的敏感性,使用以下超时值。默认值已设置,但您可以根据网络条件调整这些值。 + 1. `dapr_placement.keepAliveTime` 设置 Placement 服务在 gRPC 流上向 Dapr sidecar 发送 [keep alive](https://grpc.io/docs/guides/keepalive/) ping 的间隔,以检查连接是否仍然存活。较低的值将在 pod 丢失/重启时导致较短的 actor 重新平衡时间,但在正常操作期间会增加网络流量。接受 `1s` 到 `10s` 之间的值。默认值为 `2s`。 + 2. `dapr_placement.keepAliveTimeout` 设置 Dapr sidecar 响应 Placement 服务的 [keep alive](https://grpc.io/docs/guides/keepalive/) ping 的超时时间,然后 Placement 服务关闭连接。较低的值将在 pod 丢失/重启时导致较短的 actor 重新平衡时间,但在正常操作期间会增加网络流量。接受 `1s` 到 `10s` 之间的值。默认值为 `3s`。 + 3. `dapr_placement.disseminateTimeout` 设置在 actor 成员更改(通常与 pod 重启相关)后传播延迟的超时时间,以避免在多个 pod 重启期间过度传播。较高的值将减少传播频率,但会延迟表传播。接受 `1s` 到 `3s` 之间的值。默认值为 `2s`。 + +## 服务账户令牌 + +默认情况下,Kubernetes 在每个容器中挂载一个包含 [服务账户令牌](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) 的卷。应用程序可以使用此令牌,其权限因集群和命名空间的配置等因素而异,以对 Kubernetes 控制平面执行 API 调用。 + +在创建新 Pod(或 Deployment、StatefulSet、Job 等)时,您可以通过在 pod 的 spec 中设置 `automountServiceAccountToken: false` 来禁用自动挂载服务账户令牌。 + +建议您考虑在不依赖服务账户令牌的情况下,将应用程序部署为 `automountServiceAccountToken: false`,以提高 pod 的安全性。例如,您可能需要服务账户令牌,如果: + +- 您的应用程序需要与 Kubernetes API 交互。 +- 您正在使用与 Kubernetes API 交互的 Dapr 组件;例如,[Kubernetes secret 存储]({{< ref "kubernetes-secret-store.md" >}}) 或 [Kubernetes 事件绑定]({{< ref "kubernetes-binding.md" >}})。 + +因此,Dapr 不会自动为您设置 `automountServiceAccountToken: false`。然而,在您的解决方案不需要服务账户的所有情况下,建议您在 pod 的 spec 中设置此选项。 + +{{% alert title="注意" color="primary" %}} +使用存储为 Kubernetes secret 的 [组件 secret]({{< ref "component-secrets.md" >}}) 初始化 Dapr 组件不需要服务账户令牌,因此在这种情况下您仍然可以设置 `automountServiceAccountToken: false`。只有在运行时调用 Kubernetes secret 存储,使用 [Secrets 管理]({{< ref "secrets-overview.md" >}}) 构建块时,才会受到影响。 +{{% /alert %}} + +## 跟踪和指标配置 + +Dapr 默认启用跟踪和指标。建议您为您的应用程序和 Dapr 控制平面在生产中设置分布式跟踪和指标。 + +如果您已经有自己的可观察性设置,您可以禁用 Dapr 的跟踪和指标。 + +### 跟踪 + +[为 Dapr 配置跟踪后端]({{< ref "setup-tracing.md" >}})。 + +### 指标 + +对于指标,Dapr 在端口 9090 上暴露了一个 Prometheus 端点,可以被 Prometheus 抓取。 + +[设置 Prometheus、Grafana 和其他监控工具与 Dapr]({{< ref "observability" >}})。 + +## 注入器看门狗 + +Dapr Operator 服务包括一个 **注入器看门狗**,可用于检测和修复您的应用程序的 pod 可能在没有 Dapr sidecar(`daprd` 容器)的情况下部署的情况。例如,它可以帮助在集群完全故障后恢复应用程序。 + +在 Kubernetes 模式下运行 Dapr 时,注入器看门狗默认禁用。然而,您应该考虑根据您的具体情况启用它并设置适当的值。 + +请参阅 [Dapr operator 服务文档]({{< ref operator >}}) 以获取有关注入器看门狗及其启用方法的更多详细信息。 + +## 为 sidecar 容器配置 `seccompProfile` + +默认情况下,Dapr sidecar 注入器注入一个没有任何 `seccompProfile` 的 sidecar。然而,为了使 Dapr sidecar 容器在具有 [受限](https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted) 配置文件的命名空间中成功运行,sidecar 容器需要 `securityContext.seccompProfile.Type` 不为 `nil`。 + +请参阅 [参数和注释概述]({{< ref "arguments-annotations-overview.md" >}}) 以在 sidecar 容器上设置适当的 `seccompProfile`。 + +## 最佳实践 + +观看此视频,深入了解在 Kubernetes 上运行 Dapr 的最佳实践。 + +
+ + +## 相关链接 + +- [在 Kubernetes 上部署 Dapr]({{< ref kubernetes-deploy.md >}}) +- [在 Kubernetes 上升级 Dapr]({{< ref kubernetes-upgrade.md >}}) diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-upgrade.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-upgrade.md new file mode 100644 index 000000000..653f06e26 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-upgrade.md @@ -0,0 +1,127 @@ +--- +type: docs +title: "在 Kubernetes 集群上升级 Dapr" +linkTitle: "升级 Dapr" +weight: 30000 +description: "按照这些步骤在 Kubernetes 上升级 Dapr,确保顺利升级。" +--- + +您可以通过 Dapr CLI 或 Helm 来升级 Kubernetes 集群上的 Dapr 控制平面。 + +{{% alert title="注意" color="primary" %}} +请参阅 [Dapr 版本政策]({{< ref "support-release-policy.md#upgrade-paths" >}}) 以获取 Dapr 升级路径的指导。 +{{% /alert %}} + +{{< tabs "Dapr CLI" "Helm" >}} + +{{% codetab %}} +## 使用 Dapr CLI 升级 + +您可以使用 [Dapr CLI]({{< ref install-dapr-cli.md >}}) 来升级 Dapr。 + +### 前提条件 + +- [安装 Dapr CLI]({{< ref install-dapr-cli.md >}}) +- 一个现有的 [运行 Dapr 的 Kubernetes 集群]({{< ref cluster >}}) + +### 将现有集群升级到 {{% dapr-latest-version long="true" %}} + +```bash +dapr upgrade -k --runtime-version={{% dapr-latest-version long="true" %}} +``` + +[您可以使用 Dapr CLI 提供所有可用的 Helm chart 配置。](https://github.com/dapr/cli#supplying-helm-values) + +### 通过 CLI 升级的故障排除 + +在集群上运行升级时,可能会遇到一个已知问题,即之前可能在集群上安装了 1.0.0-rc.2 之前的版本。 + +虽然这个问题不常见,但某些升级路径可能会在您的集群上留下不兼容的 `CustomResourceDefinition`。如果遇到这种情况,您可能会看到如下错误信息: + +``` +❌ 升级 Dapr 失败:警告:kubectl apply 应用于由 kubectl create --save-config 或 kubectl apply 创建的资源 +CustomResourceDefinition "configurations.dapr.io" 无效:spec.preserveUnknownFields: 无效值:true:必须为 false 以便在模式中使用默认值 +``` + +#### 解决方案 + +1. 运行以下命令将 `CustomResourceDefinition` 升级到兼容版本: + + ```sh + kubectl replace -f https://raw.githubusercontent.com/dapr/dapr/release-{{% dapr-latest-version short="true" %}}/charts/dapr/crds/configuration.yaml + ``` + +1. 继续执行 `dapr upgrade --runtime-version {{% dapr-latest-version long="true" %}} -k` 命令。 + +{{% /codetab %}} + + +{{% codetab %}} +## 使用 Helm 升级 + +您可以使用 Helm v3 chart 来升级 Dapr。 + +❗**重要:** 最新的 Dapr Helm chart 不再支持 Helm v2。[从 Helm v2 迁移到 Helm v3](https://helm.sh/blog/migrate-from-helm-v2-to-helm-v3/)。 + +### 前提条件 + +- [安装 Helm v3](https://github.com/helm/helm/releases) +- 一个现有的 [运行 Dapr 的 Kubernetes 集群]({{< ref cluster >}}) + +### 将现有集群升级到 {{% dapr-latest-version long="true" %}} + +从版本 1.0.0 开始,现有的证书值将在使用 Helm 升级 Dapr 时自动重用。 + +> **注意** Helm 不会自动处理资源的升级,因此您需要手动更新这些资源。资源是向后兼容的,只需向前安装即可。 + +1. 将 Dapr 升级到版本 {{% dapr-latest-version long="true" %}}: + + ```bash + kubectl replace -f https://raw.githubusercontent.com/dapr/dapr/v{{% dapr-latest-version long="true" %}}/charts/dapr/crds/components.yaml + kubectl replace -f https://raw.githubusercontent.com/dapr/dapr/v{{% dapr-latest-version long="true" %}}/charts/dapr/crds/configuration.yaml + kubectl replace -f https://raw.githubusercontent.com/dapr/dapr/v{{% dapr-latest-version long="true" %}}/charts/dapr/crds/subscription.yaml + kubectl apply -f https://raw.githubusercontent.com/dapr/dapr/v{{% dapr-latest-version long="true" %}}/charts/dapr/crds/resiliency.yaml + kubectl apply -f https://raw.githubusercontent.com/dapr/dapr/v{{% dapr-latest-version long="true" %}}/charts/dapr/crds/httpendpoints.yaml + ``` + + ```bash + helm repo update + ``` + + ```bash + helm upgrade dapr dapr/dapr --version {{% dapr-latest-version long="true" %}} --namespace dapr-system --wait + ``` + > 如果您使用的是 values 文件,请记得在运行升级命令时添加 `--values` 选项。* + +1. 确保所有 pod 正在运行: + + ```bash + kubectl get pods -n dapr-system -w + + NAME READY STATUS RESTARTS AGE + dapr-dashboard-69f5c5c867-mqhg4 1/1 Running 0 42s + dapr-operator-5cdd6b7f9c-9sl7g 1/1 Running 0 41s + dapr-placement-server-0 1/1 Running 0 41s + dapr-sentry-84565c747b-7bh8h 1/1 Running 0 35s + dapr-sidecar-injector-68f868668f-6xnbt 1/1 Running 0 41s + ``` + +1. 重启您的应用程序部署以更新 Dapr 运行时: + + ```bash + kubectl rollout restart deploy/ + ``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 升级现有 Dapr 部署以启用高可用模式 + +[通过一些额外步骤在现有 Dapr 部署中启用高可用模式。]({{< ref "kubernetes-production.md#enabling-high-availability-in-an-existing-dapr-deployment" >}}) + +## 相关链接 + +- [Kubernetes 上的 Dapr]({{< ref kubernetes-overview.md >}}) +- [更多关于使用 Helm 升级 Dapr 的信息]({{< ref "kubernetes-production.md#upgrade-dapr-with-helm" >}}) +- [Dapr 生产指南]({{< ref kubernetes-production.md >}}) diff --git a/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-volume-mounts.md b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-volume-mounts.md new file mode 100644 index 000000000..ff98824c7 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/kubernetes/kubernetes-volume-mounts.md @@ -0,0 +1,131 @@ +--- +type: docs +title: "操作指南:将 Pod 卷挂载到 Dapr sidecar" +linkTitle: "操作指南:挂载 Pod 卷" +weight: 90000 +description: "配置 Dapr sidecar 以挂载 Pod 卷" +--- + +Dapr sidecar 可以配置为挂载应用程序 Pod 上的任何 Kubernetes 卷。这些卷可以通过 `daprd` (sidecar) 容器以只读或读写模式访问。如果配置了一个卷进行挂载但在 Pod 中不存在,Dapr 会记录一个警告并忽略该卷。 + +有关不同类型卷的更多信息,请查看 [Kubernetes 文档](https://kubernetes.io/docs/concepts/storage/volumes/)。 + +## 配置 + +您可以在部署的 YAML 文件中设置以下注解: + +| 注解 | 描述 | +| ---------- | ----------- | +| `dapr.io/volume-mounts` | 用于只读卷挂载 | +| `dapr.io/volume-mounts-rw` | 用于读写卷挂载 | + +这些注解是以逗号分隔的 `volume-name:path/in/container` 对。请确保相应的卷在 Pod 规范中已定义。 + +在官方容器镜像中,Dapr 以用户 ID (UID) `65532` 运行。请确保挂载卷内的文件夹和文件对用户 `65532` 可读写。 + +虽然您可以在 Dapr sidecar 容器内的任何文件夹中挂载卷,但为了避免冲突并确保未来的兼容性,建议将所有挂载点放置在以下位置之一或其子文件夹中: + +| 位置 | 描述 | +| -------- | ----------- | +| `/mnt` | 推荐用于存储 Dapr sidecar 进程可读写的持久数据的卷。 | +| `/tmp` | 推荐用于存储临时数据的卷,例如临时磁盘。 | + +## 示例 + +### 基本部署资源示例 + +在下面的 Deployment 资源示例中: +- `my-volume1` 在 sidecar 容器内以只读模式挂载到 `/mnt/sample1` +- `my-volume2` 在 sidecar 容器内以只读模式挂载到 `/mnt/sample2` +- `my-volume3` 在 sidecar 容器内以读写模式挂载到 `/tmp/sample3` + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myapp + namespace: default + labels: + app: myapp +spec: + replicas: 1 + selector: + matchLabels: + app: myapp + template: + metadata: + labels: + app: myapp + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "myapp" + dapr.io/app-port: "8000" + dapr.io/volume-mounts: "my-volume1:/mnt/sample1,my-volume2:/mnt/sample2" + dapr.io/volume-mounts-rw: "my-volume3:/tmp/sample3" + spec: + volumes: + - name: my-volume1 + hostPath: + path: /sample + - name: my-volume2 + persistentVolumeClaim: + claimName: pv-sample + - name: my-volume3 + emptyDir: {} +... +``` + +### 使用本地文件 secret 存储自定义 secret 存储 + +由于任何类型的 Kubernetes 卷都可以附加到 sidecar,您可以使用本地文件 secret 存储从各种地方读取 secret。例如,如果您有一个运行在 `10.201.202.203` 的网络文件共享 (NFS) 服务器,secret 存储在 `/secrets/stage/secrets.json`,您可以将其用作 secret 存储。 + +1. 配置应用程序 pod 以挂载 NFS 并将其附加到 Dapr sidecar。 + + ```yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: myapp + ... + spec: + ... + template: + ... + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "myapp" + dapr.io/app-port: "8000" + dapr.io/volume-mounts: "nfs-secrets-vol:/mnt/secrets" + spec: + volumes: + - name: nfs-secrets-vol + nfs: + server: 10.201.202.203 + path: /secrets/stage + ... + ``` + +1. 将本地文件 secret 存储组件指向附加的文件。 + + ```yaml + apiVersion: dapr.io/v1alpha1 + kind: Component + metadata: + name: local-secret-store + spec: + type: secretstores.local.file + version: v1 + metadata: + - name: secretsFile + value: /mnt/secrets/secrets.json + ``` + +1. 使用 secret。 + + ``` + GET http://localhost:/v1.0/secrets/local-secret-store/my-secret + ``` + +## 相关链接 + +[Dapr Kubernetes pod 注解规范]({{< ref arguments-annotations-overview.md >}}) diff --git a/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/_index.md b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/_index.md new file mode 100644 index 000000000..500031780 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "在本地自托管模式下运行 Dapr" +linkTitle: "本地自托管" +weight: 1000 +description: "如何在本地环境中启动 Dapr" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-airgap.md b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-airgap.md new file mode 100644 index 000000000..eb12c6455 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-airgap.md @@ -0,0 +1,77 @@ +--- +type: docs +title: "操作指南:在离线或隔离环境中运行Dapr" +linkTitle: "离线或隔离运行" +weight: 30000 +description: "如何在隔离环境中以自托管模式部署和运行Dapr" +--- + +## 概述 + +通常情况下,Dapr初始化时会从网络下载二进制文件并拉取镜像来设置开发环境。然而,Dapr也支持使用预先下载的安装包进行离线或隔离安装,这可以通过Docker或精简模式来实现。每个Dapr版本的安装包都被构建成一个[Dapr安装包](https://github.com/dapr/installer-bundle),可以下载。通过使用这个安装包和Dapr CLI的`init`命令,你可以在没有网络访问的环境中安装Dapr。 + +## 设置 + +在进行隔离初始化之前,需要预先下载一个Dapr安装包,其中包含CLI、运行时和仪表板的内容。这避免了在本地初始化Dapr时需要下载二进制文件和Docker镜像。 + +1. 下载特定版本的[Dapr安装包](https://github.com/dapr/installer-bundle/releases)。例如,daprbundle_linux_amd64.tar.gz,daprbundle_windows_amd64.zip。 +2. 解压缩安装包。 +3. 要安装Dapr CLI,将`daprbundle/dapr (Windows为dapr.exe)`二进制文件复制到合适的位置: + * 对于Linux/MacOS - `/usr/local/bin` + * 对于Windows,创建一个目录并将其添加到系统PATH。例如,创建一个名为`c:\dapr`的目录,并通过编辑系统环境变量将此目录添加到路径中。 + + > 注意:如果Dapr CLI没有移动到合适的位置,你可以直接使用包中的本地`dapr` CLI二进制文件。上述步骤是为了将其移动到常用位置并添加到路径中。 + +## 初始化Dapr环境 + +Dapr可以在有或没有Docker容器的隔离环境中初始化。 + +### 使用Docker初始化Dapr + +([前提条件](#Prerequisites):环境中可用Docker) + +进入安装包目录并运行以下命令: +```bash +dapr init --from-dir . +``` +> 对于Linux用户,如果你使用sudo运行Docker命令,你需要使用“**sudo dapr init**” + +> 如果你不是在安装包目录下运行上述命令,请提供安装包目录的完整路径。例如,假设安装包目录路径是$HOME/daprbundle,运行`dapr init --from-dir $HOME/daprbundle`以获得相同的效果。 + +输出应类似于以下内容: +```bash + 正在进行超空间跳跃... +ℹ️ 正在安装最新的运行时版本 +↘ 正在提取二进制文件并设置组件... 已加载镜像:daprio/dapr:$version +✅ 提取二进制文件并设置组件完成。 +✅ 二进制文件提取和组件设置已完成。 +ℹ️ daprd二进制文件已安装到$HOME/.dapr/bin。 +ℹ️ dapr_placement容器正在运行。 +ℹ️ 使用`docker ps`检查正在运行的容器。 +✅ 成功!Dapr已启动并运行。要开始使用,请访问:https://aka.ms/dapr-getting-started +``` + +> 注意:要模拟*在线* Dapr初始化,使用`dapr init`,你也可以运行Redis和Zipkin容器,如下所示: +``` +1. docker run --name "dapr_zipkin" --restart always -d -p 9411:9411 openzipkin/zipkin +2. docker run --name "dapr_redis" --restart always -d -p 6379:6379 redislabs/rejson +``` + +### 不使用Docker初始化Dapr + +或者,为了让CLI不安装任何默认配置文件或运行任何Docker容器,可以使用`init`命令的`--slim`标志。这样只会安装Dapr的二进制文件。 + +```bash +dapr init --slim --from-dir . +``` + +输出应类似于以下内容: +```bash +⌛ 正在进行超空间跳跃... +ℹ️ 正在安装最新的运行时版本 +↙ 正在提取二进制文件并设置组件... +✅ 提取二进制文件并设置组件完成。 +✅ 二进制文件提取和组件设置已完成。 +ℹ️ daprd二进制文件已安装到$HOME/.dapr/bin。 +ℹ️ placement二进制文件已安装到$HOME/.dapr/bin。 +✅ 成功!Dapr已启动并运行。要开始使用,请访问:https://aka.ms/dapr-getting-started diff --git a/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-no-docker.md b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-no-docker.md new file mode 100644 index 000000000..0a3ee6a8b --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-no-docker.md @@ -0,0 +1,111 @@ +--- +type: docs +title: "如何在没有 Docker 的环境中以自托管模式运行 Dapr" +linkTitle: "无需 Docker 运行" +weight: 30000 +description: "在本地机器上未安装 Docker 的情况下部署和运行 Dapr 自托管模式" +--- + +## 前提条件 + +- [安装 Dapr CLI]({{< ref "install-dapr-selfhost.md#installing-dapr-cli" >}}) + +## 初始化无容器的 Dapr + +Dapr CLI 提供了一个选项,可以使用 slim init 初始化 Dapr,而无需依赖 Docker 来创建默认的开发环境。安装 Dapr CLI 后,使用以下命令进行 slim init 初始化: + +```bash +dapr init --slim +``` + +这将安装两个不同的二进制文件: +- `daprd` +- `placement` + +`placement` 二进制文件用于在 Dapr 自托管安装中启用 [actor]({{< ref "actors-overview.md" >}})。 + +在 slim init 模式下,不会安装用于状态管理或消息发布/订阅的默认组件(如 Redis)。这意味着,除了 [服务调用]({{< ref "service-invocation-overview.md" >}}) 外,安装时没有其他内置功能可用。您可以根据需要设置自己的环境和自定义组件。 + +如果配置了状态存储,则可以进行基于 actor 的服务调用,具体说明请参见以下章节。 + +## 执行服务调用 +请参阅 [Hello Dapr slim 示例](https://github.com/dapr/samples/tree/master/hello-dapr-slim),了解如何在 slim init 模式下执行服务调用。 + +## 启用状态管理或消息发布/订阅 + +请参阅 [在无 Docker 的自托管模式下配置 Redis](https://redis.io/topics/quickstart) 的文档,以启用本地状态存储或用于消息传递的发布/订阅代理。 + +## 启用 actor + +要启用 actor placement: +- 在本地运行 placement 服务。 +- 启用支持 ETags 的 [事务性状态存储]({{< ref "supported-state-stores.md" >}}) 以使用 actor。例如,[在自托管模式下配置的 Redis](https://redis.io/topics/quickstart)。 + +默认情况下,`placement` 二进制文件安装在: + +- 对于 Linux/MacOS: `/$HOME/.dapr/bin` +- 对于 Windows: `%USERPROFILE%\.dapr\bin` + +{{< tabs "Linux/MacOS" "Windows">}} + +{{% codetab %}} + +```bash +$ $HOME/.dapr/bin/placement + +INFO[0000] starting Dapr Placement Service -- version 1.0.0-rc.1 -- commit 13ae49d instance=Nicoletaz-L10.redmond.corp.microsoft.com scope=dapr.placement type=log ver=1.0.0-rc.1 +INFO[0000] log level set to: info instance=Nicoletaz-L10.redmond.corp.microsoft.com scope=dapr.placement type=log ver=1.0.0-rc.1 +INFO[0000] metrics server started on :9090/ instance=Nicoletaz-L10.redmond.corp.microsoft.com scope=dapr.metrics type=log ver=1.0.0-rc.1 +INFO[0000] Raft server is starting on 127.0.0.1:8201... instance=Nicoletaz-L10.redmond.corp.microsoft.com scope=dapr.placement.raft type=log ver=1.0.0-rc.1 +INFO[0000] placement service started on port 50005 instance=Nicoletaz-L10.redmond.corp.microsoft.com scope=dapr.placement type=log ver=1.0.0-rc.1 +INFO[0000] Healthz server is listening on :8080 instance=Nicoletaz-L10.redmond.corp.microsoft.com scope=dapr.placement type=log ver=1.0.0-rc.1 +INFO[0001] cluster leadership acquired instance=Nicoletaz-L10.redmond.corp.microsoft.com scope=dapr.placement type=log ver=1.0.0-rc.1 +INFO[0001] leader is established. instance=Nicoletaz-L10.redmond.corp.microsoft.com scope=dapr.placement type=log ver=1.0.0-rc.1 + +``` + +{{% /codetab %}} + +{{% codetab %}} + +在 Windows 上运行独立的 placement 时,指定端口 6050: + +```bash +%USERPROFILE%/.dapr/bin/placement.exe -port 6050 + +time="2022-10-17T14:56:55.4055836-05:00" level=info msg="starting Dapr Placement Service -- version 1.9.0 -- commit fdce5f1f1b76012291c888113169aee845f25ef8" instance=LAPTOP-OMK50S19 scope=dapr.placement type=log ver=1.9.0 +time="2022-10-17T14:56:55.4066226-05:00" level=info msg="log level set to: info" instance=LAPTOP-OMK50S19 scope=dapr.placement type=log ver=1.9.0 +time="2022-10-17T14:56:55.4067306-05:00" level=info msg="metrics server started on :9090/" instance=LAPTOP-OMK50S19 scope=dapr.metrics type=log ver=1.9.0 +time="2022-10-17T14:56:55.4077529-05:00" level=info msg="Raft server is starting on 127.0.0.1:8201..." instance=LAPTOP-OMK50S19 scope=dapr.placement.raft type=log ver=1.9.0 +time="2022-10-17T14:56:55.4077529-05:00" level=info msg="placement service started on port 6050" instance=LAPTOP-OMK50S19 scope=dapr.placement type=log ver=1.9.0 +time="2022-10-17T14:56:55.4082772-05:00" level=info msg="Healthz server is listening on :8080" instance=LAPTOP-OMK50S19 scope=dapr.placement type=log ver=1.9.0 +time="2022-10-17T14:56:56.8232286-05:00" level=info msg="cluster leadership acquired" instance=LAPTOP-OMK50S19 scope=dapr.placement type=log ver=1.9.0 +time="2022-10-17T14:56:56.8232286-05:00" level=info msg="leader is established." instance=LAPTOP-OMK50S19 scope=dapr.placement type=log ver=1.9.0 + +``` + +{{% /codetab %}} + +{{< /tabs >}} + +现在,要运行启用了 actor 的应用程序,您可以参考以下示例: +- [java-sdk](https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples/actors) +- [python-sdk](https://github.com/dapr/python-sdk/tree/master/examples/demo_actor) +- [dotnet-sdk]({{< ref "dotnet-actors-howto.md" >}}) + +更新状态存储配置文件以匹配您的 Redis 主机和密码设置。 + +通过将元数据部分设置为类似于 [示例 Java Redis 组件](https://github.com/dapr/java-sdk/blob/master/examples/components/state/redis.yaml) 的定义,将其启用为 actor 状态存储。 + +```yaml + - name: actorStateStore + value: "true" +``` + +## 清理 + +完成后,请按照 [在自托管环境中卸载 Dapr]({{< ref self-hosted-uninstall >}}) 的步骤移除二进制文件。 + +## 下一步 +- 使用默认的 [Docker]({{< ref install-dapr-selfhost.md >}}) 或在 [airgap 环境]({{< ref self-hosted-airgap.md >}}) 中运行 Dapr +- [在自托管模式下升级 Dapr]({{< ref self-hosted-upgrade >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-overview.md b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-overview.md new file mode 100644 index 000000000..61e3aedca --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-overview.md @@ -0,0 +1,38 @@ +--- +type: docs +title: "Dapr 自托管模式概述" +linkTitle: "概述" +weight: 10000 +description: "如何在 Windows/Linux/MacOS 机器上运行 Dapr 的概述" +--- + +## 概述 + +Dapr 可以配置为在本地开发者机器或生产环境的虚拟机上运行自托管模式。每个服务都会有一个 Dapr 运行时进程(或称为 sidecar),该进程配置为使用状态存储、发布/订阅、绑定组件和其他构建块。 + +## 初始化 + +Dapr 可以通过 [Docker]({{< ref self-hosted-with-docker.md >}})(默认)或 [slim-init 模式]({{< ref self-hosted-no-docker.md >}})进行初始化。它也可以在 [离线或隔离环境]({{< ref self-hosted-airgap.md >}})中初始化和运行。 + +{{% alert title="注意" color="warning" %}} +您也可以使用 [Podman](https://podman.io/) 代替 Docker 作为容器运行时。请参阅 [使用 Podman 初始化 Dapr]({{< ref self-hosted-with-podman.md >}}) 以获取更多详细信息。在由于各种网络限制无法安装 Docker 的情况下,这可能会很有用。 +{{% /alert %}} + +默认的 Docker 设置提供了即用的功能,包含以下容器和配置: +- 一个 Redis 容器,配置为同时用于状态管理和发布/订阅的默认组件。 +- 一个 Zipkin 容器,用于诊断和跟踪。 +- 默认的 Dapr 配置和组件安装在 `$HOME/.dapr/` (Mac/Linux) 或 `%USERPROFILE%\.dapr\` (Windows)。 + +`dapr-placement` 服务负责管理 actor 的分布方案和键范围设置。此服务不作为容器启动,仅在您使用 Dapr actor 时才需要。有关 actor `Placement` 服务的更多信息,请阅读 [actor 概述]({{< ref "actors-overview.md" >}})。 + +Dapr 自托管 Docker 模式的示意图 + +## 使用 Dapr 启动应用程序 + +您可以使用 [`dapr run` CLI 命令]({{< ref dapr-run.md >}}) 启动 Dapr sidecar 进程和您的应用程序。其他参数和标志可以在[这里]({{< ref arguments-annotations-overview.md >}})找到。 + +## 名称解析 + +Dapr 使用 [名称解析组件]({{< ref supported-name-resolution >}}) 在 [服务调用]({{< ref service-invocation >}}) 构建块中进行服务发现。默认情况下,Dapr 在自托管模式下使用 mDNS。 + +如果您在虚拟机上运行 Dapr 或 mDNS 不可用的情况下,可以使用 [HashiCorp Consul]({{< ref setup-nr-consul.md >}}) 组件进行名称解析。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-persisting-scheduler.md b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-persisting-scheduler.md new file mode 100644 index 000000000..02f2928b5 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-persisting-scheduler.md @@ -0,0 +1,27 @@ +--- +type: docs +title: "操作指南:持久化调度器作业" +linkTitle: "操作指南:持久化调度器作业" +weight: 50000 +description: "配置调度器以持久化其数据库,使其在重启时具有弹性" +--- + +[调度器]({{< ref scheduler.md >}})服务负责将作业写入嵌入式数据库并进行调度执行。 +默认情况下,调度器服务会将数据写入本地卷`dapr_scheduler`,这意味着**数据在重启时会被持久化**。 + +此本地卷的主机文件位置通常位于`/var/lib/docker/volumes/dapr_scheduler/_data`或`~/.local/share/containers/storage/volumes/dapr_scheduler/_data`,具体取决于您的容器运行时。 +请注意,如果您使用的是Docker Desktop,此卷位于Docker Desktop虚拟机的文件系统中,可以通过以下命令访问: + +```bash +docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh +``` + +调度器的持久卷可以通过使用预先存在的自定义卷进行修改,或者由Dapr自动创建。 + +{{% alert title="注意" color="primary" %}} +默认情况下,`dapr init`会在您的驱动器上创建一个名为`dapr_scheduler`的本地持久卷。如果Dapr已经安装,您需要完全[卸载]({{< ref dapr-uninstall.md >}})控制平面,然后才能使用新的持久卷重新创建调度器容器。 +{{% /alert %}} + +```bash +dapr init --scheduler-volume my-scheduler-volume +``` diff --git a/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-uninstall.md b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-uninstall.md new file mode 100644 index 000000000..25a401582 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-uninstall.md @@ -0,0 +1,22 @@ +--- +type: docs +title: "在自托管环境中卸载 Dapr" +linkTitle: "卸载 Dapr" +weight: 60000 +description: "从本地机器中移除 Dapr 的步骤" +--- + +以下 CLI 命令用于移除 Dapr sidecar 二进制文件和 placement 容器: + +```bash +dapr uninstall +``` +上述命令不会移除在 `dapr init` 时默认安装的 Redis 或 Zipkin 容器,以防您将它们用于其他用途。要移除 Redis、Zipkin、actor placement 容器,以及位于 `$HOME/.dapr` 或 `%USERPROFILE%\.dapr\` 的默认 Dapr 目录,请运行以下命令: + +```bash +dapr uninstall --all +``` + +{{% alert title="注意" color="primary" %}} +对于 Linux/MacOS 用户,如果您使用 sudo 运行 docker 命令,或者 Dapr 安装在 `/usr/local/bin`(默认安装路径),则需要使用 `sudo dapr uninstall` 来移除 Dapr 二进制文件和/或容器。 +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-upgrade.md b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-upgrade.md new file mode 100644 index 000000000..02df16917 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-upgrade.md @@ -0,0 +1,34 @@ +--- +type: docs +title: "在自托管环境中升级 Dapr 的步骤" +linkTitle: "升级 Dapr" +weight: 50000 +description: "按照这些步骤在自托管模式下升级 Dapr,确保升级过程顺利" +--- + +1. 卸载当前的 Dapr 部署: + + {{% alert title="注意" color="warning" %}} + 这将删除默认的 `$HOME/.dapr` 目录、二进制文件和所有容器(dapr_redis、dapr_placement 和 dapr_zipkin)。如果在 Linux 上运行 docker 命令需要使用 sudo,请使用 `sudo`。 + {{% /alert %}} + + ```bash + dapr uninstall --all + ``` + +1. 访问[本指南]({{< ref install-dapr-cli.md >}})以下载并安装最新版本的 CLI。 + +1. 初始化 Dapr 运行时: + + ```bash + dapr init + ``` + +1. 确认您正在使用最新版本的 Dapr (v{{% dapr-latest-version long="true" %}}): + + ```bash + $ dapr --version + + CLI version: {{% dapr-latest-version short="true" %}} + Runtime version: {{% dapr-latest-version short="true" %}} + \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-with-docker.md b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-with-docker.md new file mode 100644 index 000000000..a4c275c4e --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-with-docker.md @@ -0,0 +1,192 @@ +--- +type: docs +title: "如何使用 Docker 自托管 Dapr" +linkTitle: "使用 Docker 运行" +weight: 20000 +description: "在自托管模式下,如何通过 Docker 部署和运行 Dapr" +--- + +本文介绍如何在 Windows/Linux/macOS 机器或虚拟机上使用 Docker 运行 Dapr。 + +## 前提条件 + +- [Dapr CLI]({{< ref install-dapr-cli.md >}}) +- [Docker](https://docs.docker.com/get-docker/) +- [Docker-Compose](https://docs.docker.com/compose/install/)(可选) + +## 设置 Dapr 环境 + +运行以下命令以初始化 Dapr 控制平面并创建默认配置文件: + +```bash +dapr init +``` + +## 以进程形式运行应用和 sidecar + +使用 [`dapr run` CLI 命令]({{< ref dapr-run.md >}}) 启动 Dapr sidecar 和您的应用程序: + +```bash +dapr run --app-id myapp --app-port 5000 -- dotnet run +``` + +此命令将启动 daprd sidecar 并运行 `dotnet run`,从而启动您的应用程序。 + +## 应用以进程形式运行,sidecar 以 Docker 容器形式运行 + +如果您希望在 Docker 容器中运行 Dapr,而应用程序在主机上以进程形式运行,则需要配置 Docker 使用主机网络,以便 Dapr 和应用程序可以共享 localhost 网络接口。 + +{{% alert title="注意" color="warning" %}} +Docker 的 host 网络模式仅支持 Linux 主机。 +{{% /alert %}} + +在 Linux 主机上运行 Docker 守护进程时,可以使用以下命令启动 Dapr: + +```shell +docker run --net="host" --mount type=bind,source="$(pwd)"/components,target=/components daprio/daprd:edge ./daprd -app-id -app-port +``` + +然后,您可以在主机上运行您的应用程序,它们应通过 localhost 网络接口进行连接。 + +## 在单个 Docker 容器中运行应用和 Dapr +> 仅用于开发目的 + +不建议在同一个容器中同时运行 Dapr 运行时和应用程序。然而,在本地开发场景中可以这样做。 + +为此,您需要编写一个 Dockerfile 来安装 Dapr 运行时、Dapr CLI 和您的应用程序代码。然后您可以使用 Dapr CLI 调用 Dapr 运行时和您的应用程序代码。 + +下面是一个实现此目的的 Dockerfile 示例: + +```docker +FROM python:3.7.1 +# 安装 dapr CLI +RUN wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash + +# 安装 daprd +ARG DAPR_BUILD_DIR +COPY $DAPR_BUILD_DIR /opt/dapr +ENV PATH="/opt/dapr/:${PATH}" +RUN dapr init --slim + +# 安装您的应用 +WORKDIR /app +COPY python . +RUN pip install requests +ENTRYPOINT ["dapr"] +CMD ["run", "--app-id", "nodeapp", "--app-port", "3000", "node", "app.js"] +``` + +请记住,如果 Dapr 需要与其他组件通信,例如 Redis,这些也需要对其可访问。 + +## 在 Docker 网络上运行 + +如果您有多个 Dapr 实例在 Docker 容器中运行,并希望它们能够相互通信(例如用于服务调用),那么您需要创建一个共享的 Docker 网络,并确保这些 Dapr 容器连接到该网络。 + +您可以使用以下命令创建一个简单的 Docker 网络: +```bash +docker network create my-dapr-network +``` +在运行您的 Docker 容器时,您可以使用以下命令将它们连接到网络: +```bash +docker run --net=my-dapr-network ... +``` +每个容器将在该网络上接收一个唯一的 IP,并能够与该网络上的其他容器通信。 + +## 使用 Docker-Compose 运行 + +[Docker Compose](https://docs.docker.com/compose/) 可用于定义多容器应用程序配置。如果您希望在本地运行多个带有 Dapr sidecar 的应用程序而不使用 Kubernetes,建议使用 Docker Compose 定义(`docker-compose.yml`)。 + +Docker Compose 的语法和工具超出了本文的范围,建议您参考[官方 Docker 文档](https://docs.docker.com/compose/)以获取更多详细信息。 + +为了使用 Dapr 和 Docker Compose 运行您的应用程序,您需要在 `docker-compose.yml` 中定义 sidecar 模式。例如: + +```yaml +version: '3' +services: + nodeapp: + build: ./node + ports: + - "50001:50001" # Dapr 实例通过 gRPC 通信,因此我们需要暴露 gRPC 端口 + depends_on: + - redis + - placement + networks: + - hello-dapr + nodeapp-dapr: + image: "daprio/daprd:edge" + command: [ + "./daprd", + "--app-id", "nodeapp", + "--app-port", "3000", + "--placement-host-address", "placement:50006", # Dapr 的 placement 服务可以通过 docker DNS 条目访问 + "--resources-path", "./components" + ] + volumes: + - "./components/:/components" # 挂载我们的组件文件夹供运行时使用。挂载位置必须与 --resources-path 参数匹配。 + depends_on: + - nodeapp + network_mode: "service:nodeapp" # 将 nodeapp-dapr 服务附加到 nodeapp 网络命名空间 + + ... # 部署其他 daprized 服务和组件(例如 Redis) + + placement: + image: "daprio/dapr" + command: ["./placement", "--port", "50006"] + ports: + - "50006:50006" + + scheduler: + image: "daprio/dapr" + command: ["./scheduler", "--port", "50007"] + ports: + - "50007:50007" + # 警告 - 这是一个 tmpfs 卷,您的状态不会在重启后持久化 + volumes: + - type: tmpfs + target: /data + tmpfs: + size: "10000" + + networks: + hello-dapr: null +``` + +> 对于在 Linux 主机上运行 Docker 守护进程的用户,您还可以使用 `network_mode: host` 来利用主机网络(如果需要)。 + +要进一步了解如何使用 Docker Compose 运行 Dapr,请参阅 [Docker-Compose 示例](https://github.com/dapr/samples/tree/master/hello-docker-compose)。 + +上述示例还包括一个使用非持久性数据存储进行测试和开发目的的调度器定义。 + +## 在 Kubernetes 上运行 + +如果您的部署目标是 Kubernetes,请使用 Dapr 的一流集成。请参阅 +[Dapr 在 Kubernetes 上的文档]({{< ref "kubernetes-overview.md" >}})。 + +## 名称解析 + +Dapr 默认使用 mDNS 作为自托管模式下的名称解析组件进行服务调用。如果您在虚拟机上运行 Dapr 或 mDNS 不可用的地方运行 Dapr,则可以使用 [HashiCorp Consul]({{< ref setup-nr-consul.md >}}) 组件进行名称解析。 + +## Docker 镜像 + +Dapr 提供了多个不同组件的预构建 Docker 镜像,您应选择适合您所需二进制文件、架构和标签/版本的相关镜像。 + +### 镜像 +在 [Docker Hub](https://hub.docker.com/u/daprio) 上提供了每个 Dapr 组件的已发布 Docker 镜像。 +- [daprio/dapr](https://hub.docker.com/r/daprio/dapr)(包含所有 Dapr 二进制文件) +- [daprio/daprd](https://hub.docker.com/r/daprio/daprd) +- [daprio/placement](https://hub.docker.com/r/daprio/placement) +- [daprio/sentry](https://hub.docker.com/r/daprio/sentry) +- [daprio/dapr-dev](https://hub.docker.com/r/daprio/dapr-dev) + +### 标签 + +#### Linux/amd64 +- `latest`: 最新发布版本,**仅**用于开发目的。 +- `edge`: 最新的 edge 构建(master)。 +- `major.minor.patch`: 发布版本。 +- `major.minor.patch-rc.iteration`: 发布候选版本。 +#### Linux/arm/v7 +- `latest-arm`: ARM 的最新发布版本,**仅**用于开发目的。 +- `edge-arm`: ARM 的最新 edge 构建(master)。 +- `major.minor.patch-arm`: ARM 的发布版本。 +- `major.minor.patch-rc.iteration-arm`: ARM 的发布候选版本。 diff --git a/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-with-podman.md b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-with-podman.md new file mode 100644 index 000000000..3ce7363a1 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/self-hosted/self-hosted-with-podman.md @@ -0,0 +1,52 @@ +--- +type: docs +title: "如何使用 Podman 在自托管模式下运行 Dapr" +linkTitle: "Podman 自托管运行" +weight: 20000 +description: "使用 Podman 在自托管模式下部署和运行 Dapr 的方法" +--- + +本文介绍了如何在 Windows/Linux/macOS 机器或虚拟机上使用 Podman 运行 Dapr。 + +## 准备工作 + +- [Dapr CLI]({{< ref install-dapr-cli.md >}}) +- [Podman](https://podman-desktop.io/downloads) + +## 设置 Dapr 环境 + +要设置 Dapr 控制平面容器并创建默认配置文件,请执行以下命令: + +```bash +dapr init --container-runtime podman +``` + +## 以进程方式运行应用程序和 sidecar + +可以使用 [`dapr run` CLI 命令]({{< ref dapr-run.md >}}) 启动 Dapr sidecar 和您的应用程序: + +```bash +dapr run --app-id myapp --app-port 5000 -- dotnet run +``` + +此命令会启动 daprd sidecar 和您的应用程序。 + +## 以进程方式运行应用程序,sidecar 作为 Docker 容器运行 + +如果您希望在 Docker 容器中运行 Dapr,而应用程序在主机上以进程方式运行,则需要配置 Podman 使用主机网络,以便 Dapr 和应用程序可以共享 localhost 网络接口。 + +在 Linux 主机上运行 Podman 时,可以使用以下命令启动 Dapr: + +```shell +podman run --network="host" --mount type=bind,source="$(pwd)"/components,target=/components daprio/daprd:edge ./daprd -app-id -app-port +``` + +然后,您可以在主机上运行您的应用程序,它们可以通过 localhost 网络接口进行连接。 + +## 卸载 Dapr 环境 + +要卸载 Dapr,请运行: + +```bash +dapr uninstall --container-runtime podman --all +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/serverless/_index.md b/src/translated_content/zh_CN/docs/operations/hosting/serverless/_index.md new file mode 100644 index 000000000..c1abb29cf --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/serverless/_index.md @@ -0,0 +1,11 @@ +--- +type: docs +title: "在无服务器服务中运行 Dapr" +linkTitle: "无服务器服务" +weight: 3000 +description: "了解如何在无服务器云服务中运行您的 Dapr 应用程序" +--- + +如果您希望在无需管理底层基础设施(如虚拟机或 Kubernetes)的情况下运行 Dapr 应用程序,可以选择无服务器云服务。这些平台与 Dapr 集成,简化了应用程序的部署和管理。 + +## 服务提供 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/hosting/serverless/azure-container-apps/azure-container-apps-microservices-dapr.png b/src/translated_content/zh_CN/docs/operations/hosting/serverless/azure-container-apps/azure-container-apps-microservices-dapr.png new file mode 100644 index 000000000..ea12bf391 Binary files /dev/null and b/src/translated_content/zh_CN/docs/operations/hosting/serverless/azure-container-apps/azure-container-apps-microservices-dapr.png differ diff --git a/src/translated_content/zh_CN/docs/operations/hosting/serverless/azure-container-apps/index.md b/src/translated_content/zh_CN/docs/operations/hosting/serverless/azure-container-apps/index.md new file mode 100644 index 000000000..5bee3d9ef --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/hosting/serverless/azure-container-apps/index.md @@ -0,0 +1,20 @@ +--- +type: docs +title: "Azure 容器应用" +linkTitle: "Azure 容器应用" +description: "了解如何在 Azure 容器应用无服务器平台上运行您的 Dapr 应用程序" +--- + +[Azure 容器应用](https://docs.microsoft.com/azure/container-apps/overview) 是一种无服务器应用托管服务,用户无需管理底层的虚拟机、编排器或其他云基础设施。Azure 容器应用允许您运行打包在多个容器中的应用程序代码,并且对所使用的运行时或编程模型没有特定要求。 + +Dapr 已集成到容器应用中,您可以直接使用 Dapr API 的功能模块,而无需手动部署 Dapr 运行时。您只需将服务与其 Dapr 组件一起部署即可。 + +{{< button text="了解更多" link="https://docs.microsoft.com/azure/container-apps/overview" newtab="true" >}} + +## 教程 + +访问 [Azure 文档](https://docs.microsoft.com/azure/container-apps/microservices-dapr) 以尝试微服务教程,您将在其中将两个启用 Dapr 的应用程序部署到 Azure 容器应用。 + +包含两个 Dapr 服务的容器应用环境示意图 + +{{< button text="在容器应用上试用 Dapr" link="https://docs.microsoft.com/azure/container-apps/microservices-dapr" newtab="true" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/observability/_index.md b/src/translated_content/zh_CN/docs/operations/observability/_index.md new file mode 100644 index 000000000..d2feefd88 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/_index.md @@ -0,0 +1,18 @@ +--- +type: docs +title: "可观测性" +linkTitle: "可观测性" +weight: 60 +description: 观察和测量组件的消息调用以及网络服务之间的消息调用 +--- + +[下面的视频和演示概述了](https://www.youtube.com/watch?v=0y7ne6teHT4&t=12652s)Dapr中的可观测性是如何工作的。 + + + +{{% alert title="更多关于Dapr可观测性" color="primary" %}} +了解更多关于Dapr可观测性的使用方法: +- 通过支持的[Dapr SDKs]({{< ref sdks >}})来探索可观测性。 +- 查看[可观测性API参考文档]({{< ref health_api.md >}})。 +- 阅读关于Dapr中[可观测性概念的总体概述]({{< ref observability-concept >}})。 +{{% /alert %}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/observability/logging/_index.md b/src/translated_content/zh_CN/docs/operations/observability/logging/_index.md new file mode 100644 index 000000000..772ea6e37 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/logging/_index.md @@ -0,0 +1,23 @@ +--- +type: docs +title: "日志记录" +linkTitle: "日志记录" +weight: 400 +description: "如何为 Dapr sidecar 和您的应用程序设置日志记录" +--- + +在 Dapr 中,日志记录是一个关键功能,帮助开发者监控和调试应用程序。Dapr 提供了多种日志记录选项,您可以根据需求进行灵活配置。 + +### 配置 Dapr sidecar 日志 + +您可以通过设置环境变量来配置 Dapr sidecar 的日志记录。可以调整日志级别、输出格式等,以适应不同的需求。常见的日志级别包括 `Debug`、`Info`、`Warning` 和 `Error`。 + +### 应用程序日志记录 + +除了 Dapr sidecar,您还可以为您的应用程序设置日志记录。通过使用 Dapr 的日志记录功能,您可以更有效地监控应用程序的行为和性能。 + +### 日志输出 + +Dapr 支持将日志输出到多种目标,包括控制台、文件和远程日志服务。您可以根据应用程序的部署环境选择最合适的日志输出方式。 + +通过合理配置日志记录,您可以更好地了解应用程序的运行状况,快速发现和解决问题。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/observability/logging/fluentd.md b/src/translated_content/zh_CN/docs/operations/observability/logging/fluentd.md new file mode 100644 index 000000000..70707a57f --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/logging/fluentd.md @@ -0,0 +1,189 @@ +--- +type: docs +title: "操作指南:在 Kubernetes 中设置 Fluentd、Elastic search 和 Kibana" +linkTitle: "FluentD" +weight: 2000 +description: "如何在 Kubernetes 中安装 Fluentd、Elastic Search 和 Kibana 以搜索日志" +--- + +## 前提条件 + +- Kubernetes (> 1.14) +- [kubectl](https://kubernetes.io/docs/tasks/tools/) +- [Helm 3](https://helm.sh/) + +## 安装 Elastic search 和 Kibana + +1. 创建一个用于监控工具的 Kubernetes 命名空间 + + ```bash + kubectl create namespace dapr-monitoring + ``` + +2. 添加 Elastic Search 的 Helm 仓库 + + ```bash + helm repo add elastic https://helm.elastic.co + helm repo update + ``` + +3. 使用 Helm 安装 Elastic Search + + 默认情况下,chart 会创建 3 个副本,要求它们位于不同的节点上。如果您的集群少于 3 个节点,请指定较少的副本数。例如,将副本数设置为 1: + + ```bash + helm install elasticsearch elastic/elasticsearch --version 7.17.3 -n dapr-monitoring --set replicas=1 + ``` + + 否则: + + ```bash + helm install elasticsearch elastic/elasticsearch --version 7.17.3 -n dapr-monitoring + ``` + + 如果您使用 minikube 或仅在开发过程中想禁用持久卷,可以使用以下命令: + + ```bash + helm install elasticsearch elastic/elasticsearch --version 7.17.3 -n dapr-monitoring --set persistence.enabled=false,replicas=1 + ``` + +4. 安装 Kibana + + ```bash + helm install kibana elastic/kibana --version 7.17.3 -n dapr-monitoring + ``` + +5. 确保 Elastic Search 和 Kibana 在您的 Kubernetes 集群中正常运行 + + ```bash + $ kubectl get pods -n dapr-monitoring + NAME READY STATUS RESTARTS AGE + elasticsearch-master-0 1/1 Running 0 6m58s + kibana-kibana-95bc54b89-zqdrk 1/1 Running 0 4m21s + ``` + +## 安装 Fluentd + +1. 作为 daemonset 安装配置映射和 Fluentd + + 下载这些配置文件: + - [fluentd-config-map.yaml](/docs/fluentd-config-map.yaml) + - [fluentd-dapr-with-rbac.yaml](/docs/fluentd-dapr-with-rbac.yaml) + + > 注意:如果您的集群中已经运行了 Fluentd,请启用嵌套的 JSON 解析器,以便它可以解析来自 Dapr 的 JSON 格式日志。 + + 将配置应用到您的集群: + + ```bash + kubectl apply -f ./fluentd-config-map.yaml + kubectl apply -f ./fluentd-dapr-with-rbac.yaml + ``` + +2. 确保 Fluentd 作为 daemonset 运行。FluentD 实例的数量应与集群节点的数量相同。以下示例中,集群中只有一个节点: + + ```bash + $ kubectl get pods -n kube-system -w + NAME READY STATUS RESTARTS AGE + coredns-6955765f44-cxjxk 1/1 Running 0 4m41s + coredns-6955765f44-jlskv 1/1 Running 0 4m41s + etcd-m01 1/1 Running 0 4m48s + fluentd-sdrld 1/1 Running 0 14s + ``` + +## 安装 Dapr 并启用 JSON 格式日志 + +1. 安装 Dapr 并启用 JSON 格式日志 + + ```bash + helm repo add dapr https://dapr.github.io/helm-charts/ + helm repo update + helm install dapr dapr/dapr --namespace dapr-system --set global.logAsJson=true + ``` + +2. 在 Dapr sidecar 中启用 JSON 格式日志 + + 在您的部署 yaml 中添加 `dapr.io/log-as-json: "true"` 注解。例如: + + ```yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: pythonapp + namespace: default + labels: + app: python + spec: + replicas: 1 + selector: + matchLabels: + app: python + template: + metadata: + labels: + app: python + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "pythonapp" + dapr.io/log-as-json: "true" + ... + ``` + +## 搜索日志 + +> 注意:Elastic Search 需要一些时间来索引 Fluentd 发送的日志。 + +1. 从本地主机端口转发到 `svc/kibana-kibana` + + ```bash + $ kubectl port-forward svc/kibana-kibana 5601 -n dapr-monitoring + Forwarding from 127.0.0.1:5601 -> 5601 + Forwarding from [::1]:5601 -> 5601 + Handling connection for 5601 + Handling connection for 5601 + ``` + +2. 浏览到 `http://localhost:5601` + +3. 展开下拉菜单并点击 **Management → Stack Management** + + ![Kibana 管理菜单选项下的 Stack Management 项](/images/kibana-1.png) + +4. 在 Stack Management 页面上,选择 **Data → Index Management** 并等待 `dapr-*` 被索引。 + + ![Kibana Stack Management 页面上的 Index Management 视图](/images/kibana-2.png) + +5. 一旦 `dapr-*` 被索引,点击 **Kibana → Index Patterns** 然后点击 **Create index pattern** 按钮。 + + ![Kibana 创建索引模式按钮](/images/kibana-3.png) + +6. 通过在 **Index Pattern name** 字段中输入 `dapr*` 来定义一个新的索引模式,然后点击 **Next step** 按钮继续。 + + ![Kibana 定义索引模式页面](/images/kibana-4.png) + +7. 通过从 **Time field** 下拉菜单中选择 `@timestamp` 选项来配置新索引模式的主要时间字段。点击 **Create index pattern** 按钮完成索引模式的创建。 + + ![Kibana 创建索引模式的配置设置页面](/images/kibana-5.png) + +8. 应显示新创建的索引模式。通过在 **Fields** 标签中的搜索框中使用搜索,确认感兴趣的字段如 `scope`、`type`、`app_id`、`level` 等是否被索引。 + + > 注意:如果找不到索引字段,请稍等。搜索所有索引字段所需的时间取决于数据量和 Elastic Search 运行的资源大小。 + + ![查看创建的 Kibana 索引模式](/images/kibana-6.png) + +9. 要探索索引的数据,展开下拉菜单并点击 **Analytics → Discover**。 + + ![Kibana Analytics 菜单选项下的 Discover 项](/images/kibana-7.png) + +10. 在搜索框中输入查询字符串如 `scope:*` 并点击 **Refresh** 按钮查看结果。 + + > 注意:这可能需要很长时间。返回所有结果所需的时间取决于数据量和 Elastic Search 运行的资源大小。 + + ![在 Kibana Analytics Discover 页面中使用搜索框](/images/kibana-8.png) + +## 参考资料 + +* [Kubernetes 的 Fluentd](https://docs.fluentd.org/v/0.12/articles/kubernetes-fluentd) +* [Elastic search helm chart](https://github.com/elastic/helm-charts/tree/master/elasticsearch) +* [Kibana helm chart](https://github.com/elastic/helm-charts/tree/master/kibana) +* [Kibana 查询语言](https://www.elastic.co/guide/en/kibana/current/kuery-query.html) +* [使用日志进行故障排除]({{< ref "logs-troubleshooting.md" >}}) diff --git a/src/translated_content/zh_CN/docs/operations/observability/logging/logs.md b/src/translated_content/zh_CN/docs/operations/observability/logging/logs.md new file mode 100644 index 000000000..001af12d1 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/logging/logs.md @@ -0,0 +1,133 @@ +--- +type: docs +title: "日志" +linkTitle: "概述" +weight: 1000 +description: "了解 Dapr 日志" +--- + +Dapr 生成的结构化日志会输出到 stdout,可以选择纯文本或 JSON 格式。默认情况下,所有 Dapr 进程(包括运行时或 sidecar,以及所有控制平面服务)都会以纯文本形式将日志写入控制台(stdout)。若要启用 JSON 格式的日志记录,您需要在运行 Dapr 进程时添加 `--log-as-json` 命令标志。 + +{{% alert title="注意" color="primary" %}} +如果您希望使用 Elastic Search 或 Azure Monitor 等搜索引擎来搜索日志,强烈建议使用 JSON 格式的日志,因为日志收集器和搜索引擎可以利用内置的 JSON 解析器更好地解析这些日志。 +{{% /alert %}} + +## 日志模式 + +Dapr 生成的日志遵循以下模式: + +| 字段 | 描述 | 示例 | +|-------|-------------------|---------| +| time | ISO8601 时间戳 | `2011-10-05T14:48:00.000Z` | +| level | 日志级别 (info/warn/debug/error) | `info` | +| type | 日志类型 | `log` | +| msg | 日志消息 | `hello dapr!` | +| scope | 日志范围 | `dapr.runtime` | +| instance | 容器名称 | `dapr-pod-xxxxx` | +| app_id | Dapr 应用 ID | `dapr-app` | +| ver | Dapr 运行时版本 | `1.9.0` | + +API 日志可能会添加其他结构化字段,具体请参阅 [API 日志记录文档]({{< ref "api-logs-troubleshooting.md" >}})。 + +## 纯文本和 JSON 格式的日志 + +* 纯文本日志示例 + +```bash +time="2022-11-01T17:08:48.303776-07:00" level=info msg="starting Dapr Runtime -- version 1.9.0 -- commit v1.9.0-g5dfcf2e" instance=dapr-pod-xxxx scope=dapr.runtime type=log ver=1.9.0 +time="2022-11-01T17:08:48.303913-07:00" level=info msg="log level set to: info" instance=dapr-pod-xxxx scope=dapr.runtime type=log ver=1.9.0 +``` + +* JSON 格式日志示例 + +```json +{"instance":"dapr-pod-xxxx","level":"info","msg":"starting Dapr Runtime -- version 1.9.0 -- commit v1.9.0-g5dfcf2e","scope":"dapr.runtime","time":"2022-11-01T17:09:45.788005Z","type":"log","ver":"1.9.0"} +{"instance":"dapr-pod-xxxx","level":"info","msg":"log level set to: info","scope":"dapr.runtime","time":"2022-11-01T17:09:45.788075Z","type":"log","ver":"1.9.0"} +``` + +## 日志格式 + +Dapr 支持输出纯文本(默认)或 JSON 格式的日志。 + +若要使用 JSON 格式的日志,您需要在安装 Dapr 和部署应用时添加额外的配置选项。建议使用 JSON 格式的日志,因为大多数日志收集器和搜索引擎可以更容易地解析 JSON。 + +## 使用 Dapr CLI 启用 JSON 日志 + +使用 Dapr CLI 运行应用程序时,传递 `--log-as-json` 选项以启用 JSON 格式的日志,例如: + +```sh +dapr run \ + --app-id orderprocessing \ + --resources-path ./components/ \ + --log-as-json \ + -- python3 OrderProcessingService.py +``` + +## 在 Kubernetes 中启用 JSON 日志 + +以下步骤描述了如何为 Kubernetes 配置 JSON 格式的日志 + +### Dapr 控制平面 + +Dapr 控制平面中的所有服务(如 `operator`、`sentry` 等)支持 `--log-as-json` 选项以启用 JSON 格式的日志记录。 + +如果您使用 Helm chart 将 Dapr 部署到 Kubernetes,可以通过传递 `--set global.logAsJson=true` 选项为 Dapr 系统服务启用 JSON 格式的日志;例如: + +```bash +helm upgrade --install dapr \ + dapr/dapr \ + --namespace dapr-system \ + --set global.logAsJson=true +``` + +### 为 Dapr sidecar 启用 JSON 格式日志 + +您可以通过在部署中添加 `dapr.io/log-as-json: "true"` 注释来为 Dapr sidecar 启用 JSON 格式的日志,例如: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pythonapp + labels: + app: python +spec: + selector: + matchLabels: + app: python + template: + metadata: + labels: + app: python + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "pythonapp" + # 启用 JSON 格式的日志 + dapr.io/log-as-json: "true" +... +``` + +## API 日志 + +API 日志使您能够查看应用程序对 Dapr sidecar 的 API 调用,以调试问题或监控应用程序的行为。您可以将 Dapr API 日志与 Dapr 日志事件结合使用。 + +有关更多信息,请参阅 [配置和查看 Dapr 日志]({{< ref "logs-troubleshooting.md" >}}) 和 [配置和查看 Dapr API 日志]({{< ref "api-logs-troubleshooting.md" >}})。 + +## 日志收集器 + +如果您在 Kubernetes 集群中运行 Dapr,[Fluentd](https://www.fluentd.org/) 是一个流行的容器日志收集器。您可以使用带有 [JSON 解析器插件](https://docs.fluentd.org/parser/json) 的 Fluentd 来解析 Dapr JSON 格式的日志。这个 [操作指南]({{< ref fluentd.md >}}) 显示了如何在集群中配置 Fluentd。 + +如果您使用 Azure Kubernetes Service,您可以使用内置代理通过 Azure Monitor 收集日志,而无需安装 Fluentd。 + +## 搜索引擎 + +如果您使用 [Fluentd](https://www.fluentd.org/),我们建议使用 Elastic Search 和 Kibana。这个 [操作指南]({{< ref fluentd.md >}}) 显示了如何在 Kubernetes 集群中设置 Elastic Search 和 Kibana。 + +如果您使用 Azure Kubernetes Service,您可以使用 [Azure Monitor for containers](https://docs.microsoft.com/azure/azure-monitor/insights/container-insights-overview) 而无需安装任何额外的监控工具。另请阅读 [如何启用 Azure Monitor for containers](https://docs.microsoft.com/azure/azure-monitor/insights/container-insights-onboard) + +## 参考资料 + +- [操作指南:设置 Fluentd、Elastic search 和 Kibana]({{< ref fluentd.md >}}) +- [操作指南:在 Azure Kubernetes Service 中设置 Azure Monitor]({{< ref azure-monitor.md >}}) +- [配置和查看 Dapr 日志]({{< ref "logs-troubleshooting.md" >}}) +- [配置和查看 Dapr API 日志]({{< ref "api-logs-troubleshooting.md" >}}) diff --git a/src/translated_content/zh_CN/docs/operations/observability/logging/newrelic.md b/src/translated_content/zh_CN/docs/operations/observability/logging/newrelic.md new file mode 100644 index 000000000..9440d9296 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/logging/newrelic.md @@ -0,0 +1,78 @@ +--- +type: docs +title: "操作指南:为 Dapr 日志配置 New Relic" +linkTitle: "New Relic" +weight: 3000 +description: "为 Dapr 日志配置 New Relic" +--- + +## 前提条件 + +- 注册一个 [New Relic 账户](https://newrelic.com/signup?ref=dapr),享受每月 100 GB 的免费数据摄取、1 个免费完全访问用户和无限制的免费基本用户。 + +## 背景 + +New Relic 提供了一个 [Fluent Bit](https://fluentbit.io/) 输出 [插件](https://github.com/newrelic/newrelic-fluent-bit-output),可以轻松地将日志转发到 [New Relic Logs](https://github.com/newrelic/newrelic-fluent-bit-output)。该插件也可以作为独立的 Docker 镜像使用,并在 Kubernetes 集群中以 DaemonSet 的形式安装,我们称之为 Kubernetes 插件。 + +本文档将解释如何在集群中安装此插件,推荐使用 Helm chart,也可以通过应用 Kubernetes 清单手动安装。 + +## 安装 + +### 使用 Helm chart 安装(推荐) + +1. 按照官方说明安装 Helm。 + +2. 添加 New Relic 官方 Helm chart 仓库。 + +3. 运行以下命令通过 Helm 安装 New Relic Logging Kubernetes 插件,并将占位符 YOUR_LICENSE_KEY 替换为您的 [New Relic 许可证密钥](https://docs.newrelic.com/docs/accounts/accounts-billing/account-setup/new-relic-license-key/): + +- Helm 3 + ```bash + helm install newrelic-logging newrelic/newrelic-logging --set licenseKey=YOUR_LICENSE_KEY + ``` + +- Helm 2 + ```bash + helm install newrelic/newrelic-logging --name newrelic-logging --set licenseKey=YOUR_LICENSE_KEY + ``` + +对于欧盟用户,请在上述命令中添加 `--set endpoint=https://log-api.eu.newrelic.com/log/v1`。 + +默认情况下,日志跟踪路径设置为 /var/log/containers/*.log。要更改此设置,请在上述命令中添加 --set fluentBit.path=DESIRED_PATH,并提供您首选的路径。 + +### 安装 Kubernetes 清单 + +1. 下载以下 3 个清单文件到当前工作目录: + + ```bash + curl https://raw.githubusercontent.com/newrelic/helm-charts/master/charts/newrelic-logging/k8s/fluent-conf.yml > fluent-conf.yml + curl https://raw.githubusercontent.com/newrelic/helm-charts/master/charts/newrelic-logging/k8s/new-relic-fluent-plugin.yml > new-relic-fluent-plugin.yml + curl https://raw.githubusercontent.com/newrelic/helm-charts/master/charts/newrelic-logging/k8s/rbac.yml > rbac.yml + ``` + +2. 在下载的 new-relic-fluent-plugin.yml 文件中,将占位符 LICENSE_KEY 替换为您的 New Relic 许可证密钥。 + + 对于欧盟用户,将 ENDPOINT 环境变量替换为 https://log-api.eu.newrelic.com/log/v1。 + +3. 添加许可证密钥后,在终端或命令行界面中运行以下命令: + ```bash + kubectl apply -f . + ``` + +4. [可选] 您可以通过编辑 fluent-conf.yml 文件中的 parsers.conf 部分来配置插件如何解析数据。有关更多信息,请参阅 Fluent Bit 的 Parsers 配置文档。 + + 默认情况下,日志跟踪路径设置为 /var/log/containers/*.log。要更改此设置,请在 new-relic-fluent-plugin.yml 文件中将默认路径替换为您首选的路径。 + +## 查看日志 + +![Dapr 注释](/images/nr-logging-1.png) + +![搜索](/images/nr-logging-2.png) + +## 相关链接/参考 + +* [New Relic 账户注册](https://newrelic.com/signup) +* [遥测数据平台](https://newrelic.com/platform/telemetry-data-platform) +* [New Relic Logging](https://github.com/newrelic/helm-charts/tree/master/charts/newrelic-logging) +* [New Relic API 密钥类型](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/) +* [警报和应用智能](https://docs.newrelic.com/docs/alerts-applied-intelligence/overview/) diff --git a/src/translated_content/zh_CN/docs/operations/observability/metrics/_index.md b/src/translated_content/zh_CN/docs/operations/observability/metrics/_index.md new file mode 100644 index 000000000..506d68f7b --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/metrics/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "监控指标" +linkTitle: "监控指标" +weight: 300 +description: "如何查看和理解Dapr的监控指标" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/observability/metrics/azure-monitor.md b/src/translated_content/zh_CN/docs/operations/observability/metrics/azure-monitor.md new file mode 100644 index 000000000..1007af35a --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/metrics/azure-monitor.md @@ -0,0 +1,134 @@ +--- +type: docs +title: "操作指南:配置 Azure Monitor 以搜索日志和收集指标" +linkTitle: "Azure Monitor" +weight: 7000 +description: "为 Azure Kubernetes Service (AKS) 启用 Dapr 指标和日志的 Azure Monitor" +--- + +## 前提条件 + +- [Azure Kubernetes Service](https://docs.microsoft.com/azure/aks/) +- [在 AKS 中启用 Azure Monitor For 容器](https://docs.microsoft.com/azure/azure-monitor/insights/container-insights-overview) +- [kubectl](https://kubernetes.io/docs/tasks/tools/) +- [Helm 3](https://helm.sh/) + +## 使用配置映射启用 Prometheus 指标抓取 + +1. 确认 Azure Monitor Agents (AMA) 正在运行。 + + ```bash + $ kubectl get pods -n kube-system + NAME READY STATUS RESTARTS AGE + ... + ama-logs-48kpv 2/2 Running 0 2d13h + ama-logs-mx24c 2/2 Running 0 2d13h + ama-logs-rs-f9bbb9898-vbt6k 1/1 Running 0 30h + ama-logs-sm2mz 2/2 Running 0 2d13h + ama-logs-z7p4c 2/2 Running 0 2d13h + ... + ``` + +1. 使用配置映射启用 Prometheus 指标端点抓取。 + + 可以使用 [azm-config-map.yaml](/docs/azm-config-map.yaml) 来启用 Prometheus 指标端点抓取。 + + 如果 Dapr 安装在不同的命名空间,需要修改 `monitor_kubernetes_pod_namespaces` 数组的值。例如: + + ```yaml + ... + prometheus-data-collection-settings: |- + [prometheus_data_collection_settings.cluster] + interval = "1m" + monitor_kubernetes_pods = true + monitor_kubernetes_pods_namespaces = ["dapr-system", "default"] + [prometheus_data_collection_settings.node] + interval = "1m" + ... + ``` + + 应用配置映射: + + ```bash + kubectl apply -f ./azm-config.map.yaml + ``` + +## 安装带有 JSON 格式日志的 Dapr + +1. 安装 Dapr 并启用 JSON 格式日志。 + + ```bash + helm install dapr dapr/dapr --namespace dapr-system --set global.logAsJson=true + ``` + +1. 在 Dapr sidecar 中启用 JSON 格式日志并添加 Prometheus 注解。 + + > 注意:只有设置了 Prometheus 注解,Azure Monitor Agents (AMA) 才会发送指标。 + + 在部署的 YAML 文件中添加 `dapr.io/log-as-json: "true"` 注解。 + + 示例: + + ```yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + name: pythonapp + namespace: default + labels: + app: python + spec: + replicas: 1 + selector: + matchLabels: + app: python + template: + metadata: + labels: + app: python + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "pythonapp" + dapr.io/log-as-json: "true" + prometheus.io/scrape: "true" + prometheus.io/port: "9090" + prometheus.io/path: "/" + + ... + ``` + +## 使用 Azure Monitor 搜索指标和日志 + +1. 在 Azure 门户中进入 Azure Monitor。 + +1. 搜索 Dapr **日志**。 + + 下面是一个示例查询,用于解析 JSON 格式日志并查询来自 Dapr 系统进程的日志。 + + ``` + ContainerLog + | extend parsed=parse_json(LogEntry) + | project Time=todatetime(parsed['time']), app_id=parsed['app_id'], scope=parsed['scope'],level=parsed['level'], msg=parsed['msg'], type=parsed['type'], ver=parsed['ver'], instance=parsed['instance'] + | where level != "" + | sort by Time + ``` + +1. 搜索 **指标**。 + + 这个查询,查询 `process_resident_memory_bytes` Prometheus 指标用于 Dapr 系统进程并渲染时间图表。 + + ``` + InsightsMetrics + | where Namespace == "prometheus" and Name == "process_resident_memory_bytes" + | extend tags=parse_json(Tags) + | project TimeGenerated, Name, Val, app=tostring(tags['app']) + | summarize memInBytes=percentile(Val, 99) by bin(TimeGenerated, 1m), app + | where app startswith "dapr-" + | render timechart + ``` + +## 参考资料 + +- [使用 Azure Monitor for 容器配置 Prometheus 指标抓取](https://docs.microsoft.com/azure/azure-monitor/insights/container-insights-prometheus-integration) +- [为 Azure Monitor for 容器配置代理数据收集](https://docs.microsoft.com/azure/azure-monitor/insights/container-insights-agent-config) +- [Azure Monitor 查询](https://docs.microsoft.com/azure/azure-monitor/log-query/query-language) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/observability/metrics/grafana.md b/src/translated_content/zh_CN/docs/operations/observability/metrics/grafana.md new file mode 100644 index 000000000..1ff49b61b --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/metrics/grafana.md @@ -0,0 +1,180 @@ +--- +type: docs +title: "如何使用Grafana监控指标" +linkTitle: "Grafana仪表板" +weight: 5000 +description: "在Grafana仪表板中查看Dapr指标的方法。" +--- + +## 可用的仪表板 + +{{< tabs "系统服务" "sidecar" "actor" >}} + +{{% codetab %}} +`grafana-system-services-dashboard.json`模板展示了Dapr系统组件的状态,包括dapr-operator、dapr-sidecar-injector、dapr-sentry和dapr-placement: + +系统服务仪表板的截图 +{{% /codetab %}} + +{{% codetab %}} +`grafana-sidecar-dashboard.json`模板展示了Dapr sidecar 的状态,包括sidecar 的健康状况/资源使用情况、HTTP和gRPC的吞吐量/延迟、actor、mTLS等: + +sidecar仪表板的截图 +{{% /codetab %}} + +{{% codetab %}} +`grafana-actor-dashboard.json`模板展示了Dapr sidecar 的状态、actor 调用的吞吐量/延迟、timer/reminder触发器和基于回合的并发性: + +actor仪表板的截图 +{{% /codetab %}} + +{{< /tabs >}} + +## 前提条件 + +- [设置Prometheus]({{}}) + +## 在Kubernetes上设置 + +### 安装Grafana + +1. 添加Grafana Helm仓库: + + ```bash + helm repo add grafana https://grafana.github.io/helm-charts + helm repo update + ``` + +1. 安装图表: + + ```bash + helm install grafana grafana/grafana -n dapr-monitoring + ``` + + {{% alert title="注意" color="primary" %}} + 如果您使用Minikube或希望在开发中禁用持久卷,可以使用以下命令禁用: + + ```bash + helm install grafana grafana/grafana -n dapr-monitoring --set persistence.enabled=false + ``` + {{% /alert %}} + +1. 获取Grafana登录的管理员密码: + + ```bash + kubectl get secret --namespace dapr-monitoring grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo + ``` + + 您将看到一个类似于`cj3m0OfBNx8SLzUlTx91dEECgzRlYJb60D2evof1%`的密码。请去掉密码中的`%`字符,得到`cj3m0OfBNx8SLzUlTx91dEECgzRlYJb60D2evof1`作为管理员密码。 + +1. 检查Grafana是否在您的集群中运行: + + ```bash + kubectl get pods -n dapr-monitoring + + NAME READY STATUS RESTARTS AGE + dapr-prom-kube-state-metrics-9849d6cc6-t94p8 1/1 Running 0 4m58s + dapr-prom-prometheus-alertmanager-749cc46f6-9b5t8 2/2 Running 0 4m58s + dapr-prom-prometheus-node-exporter-5jh8p 1/1 Running 0 4m58s + dapr-prom-prometheus-node-exporter-88gbg 1/1 Running 0 4m58s + dapr-prom-prometheus-node-exporter-bjp9f 1/1 Running 0 4m58s + dapr-prom-prometheus-pushgateway-688665d597-h4xx2 1/1 Running 0 4m58s + dapr-prom-prometheus-server-694fd8d7c-q5d59 2/2 Running 0 4m58s + grafana-c49889cff-x56vj 1/1 Running 0 5m10s + ``` + +### 配置Prometheus作为数据源 +首先,您需要将Prometheus连接为Grafana的数据源。 + +1. 端口转发到svc/grafana: + + ```bash + kubectl port-forward svc/grafana 8080:80 -n dapr-monitoring + + Forwarding from 127.0.0.1:8080 -> 3000 + Forwarding from [::1]:8080 -> 3000 + Handling connection for 8080 + Handling connection for 8080 + ``` + +1. 打开浏览器访问`http://localhost:8080` + +1. 登录Grafana + - 用户名 = `admin` + - 密码 = 上述密码 + +1. 选择`Configuration`和`Data Sources` + + Grafana添加数据源菜单的截图 + +1. 添加Prometheus作为数据源。 + + Prometheus添加数据源的截图 + +1. 获取您的Prometheus HTTP URL + + Prometheus HTTP URL的格式为`http://.<命名空间>` + + 首先通过运行以下命令获取Prometheus服务器端点: + + ```bash + kubectl get svc -n dapr-monitoring + + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + dapr-prom-kube-state-metrics ClusterIP 10.0.174.177 8080/TCP 7d9h + dapr-prom-prometheus-alertmanager ClusterIP 10.0.255.199 80/TCP 7d9h + dapr-prom-prometheus-node-exporter ClusterIP None 9100/TCP 7d9h + dapr-prom-prometheus-pushgateway ClusterIP 10.0.190.59 9091/TCP 7d9h + dapr-prom-prometheus-server ClusterIP 10.0.172.191 80/TCP 7d9h + elasticsearch-master ClusterIP 10.0.36.146 9200/TCP,9300/TCP 7d10h + elasticsearch-master-headless ClusterIP None 9200/TCP,9300/TCP 7d10h + grafana ClusterIP 10.0.15.229 80/TCP 5d5h + kibana-kibana ClusterIP 10.0.188.224 5601/TCP 7d10h + + ``` + + 在本指南中,服务器名称为`dapr-prom-prometheus-server`,命名空间为`dapr-monitoring`,因此HTTP URL将是`http://dapr-prom-prometheus-server.dapr-monitoring`。 + +1. 填写以下设置: + + - 名称:`Dapr` + - HTTP URL:`http://dapr-prom-prometheus-server.dapr-monitoring` + - 默认:开启 + - 跳过TLS验证:开启 + - 这是保存和测试配置所必需的 + + Prometheus数据源配置的截图 + +1. 点击`Save & Test`按钮以验证连接是否成功。 + +## 在Grafana中导入仪表板 + +1. 在Grafana主屏幕的左上角,点击“+”选项,然后选择“Import”。 + + 现在,您可以从[发布资产](https://github.com/dapr/dapr/releases)中为您的Dapr版本导入[Grafana仪表板模板](https://github.com/dapr/dapr/tree/master/grafana): + + Grafana仪表板上传选项的截图 + +1. 找到您导入的仪表板并享受 + + Dapr服务仪表板的截图 + + {{% alert title="提示" color="primary" %}} + 将鼠标悬停在每个图表描述角落的`i`上: + + 图表工具提示的截图 + {{% /alert %}} + +## 参考资料 + +* [Dapr可观察性]({{}}) +* [Prometheus安装](https://github.com/prometheus-community/helm-charts) +* [Kubernetes上的Prometheus](https://github.com/coreos/kube-prometheus) +* [Prometheus查询语言](https://prometheus.io/docs/prometheus/latest/querying/basics/) +* [支持的Dapr指标](https://github.com/dapr/dapr/blob/master/docs/development/dapr-metrics.md) + +## 示例 + +
+ +
\ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/observability/metrics/metrics-overview.md b/src/translated_content/zh_CN/docs/operations/observability/metrics/metrics-overview.md new file mode 100644 index 000000000..d3cc38749 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/metrics/metrics-overview.md @@ -0,0 +1,314 @@ +--- +type: docs +title: "配置指标" +linkTitle: "概述" +weight: 4000 +description: "启用或禁用Dapr指标" +--- + +默认情况下,每个Dapr系统进程都会发出Go运行时和进程指标,并拥有自己的[Dapr指标](https://github.com/dapr/dapr/blob/master/docs/development/dapr-metrics.md)。 + +## Prometheus端点 + +Dapr sidecar提供了一个与[Prometheus](https://prometheus.io/)兼容的指标端点,您可以通过抓取该端点来更好地了解Dapr的运行状况。 + +## 使用CLI配置指标 + +指标应用程序端点默认是启用的。您可以通过传递命令行参数`--enable-metrics=false`来禁用它。 + +默认的指标端口是`9090`。您可以通过传递命令行参数`--metrics-port`给daprd来更改此设置。 + +## 在Kubernetes中配置指标 + +您还可以通过在应用程序部署上设置`dapr.io/enable-metrics: "false"`注解来启用或禁用特定应用程序的指标。禁用指标导出器后,daprd不会打开指标监听端口。 + +以下Kubernetes部署示例显示了如何显式启用指标,并将端口指定为"9090"。 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nodeapp + labels: + app: node +spec: + replicas: 1 + selector: + matchLabels: + app: node + template: + metadata: + labels: + app: node + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "nodeapp" + dapr.io/app-port: "3000" + dapr.io/enable-metrics: "true" + dapr.io/metrics-port: "9090" + spec: + containers: + - name: node + image: dapriosamples/hello-k8s-node:latest + ports: + - containerPort: 3000 + imagePullPolicy: Always +``` + +## 使用应用程序配置启用指标 + +您还可以通过应用程序配置启用指标。要默认禁用Dapr sidecar中的指标收集,请将`spec.metrics.enabled`设置为`false`。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: tracing + namespace: default +spec: + metrics: + enabled: false +``` + +## 为错误代码配置指标 + +您可以通过设置`spec.metrics.recordErrorCodes`为`true`来为[Dapr API错误代码](https://docs.dapr.io/reference/api/error_codes/)启用额外的指标。Dapr API可能会返回标准化的错误代码。[一个名为`error_code_total`的新指标被记录]({{< ref errors-overview.md >}}),它允许监控由应用程序、代码和类别触发的错误代码。有关特定代码和类别,请参见[`errorcodes`包](https://github.com/dapr/dapr/blob/master/pkg/messages/errorcodes/errorcodes.go)。 + +示例配置: +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: tracing + namespace: default +spec: + metrics: + enabled: true + recordErrorCodes: true +``` + +示例指标: +```json +{ + "app_id": "publisher-app", + "category": "state", + "dapr_io_enabled": "true", + "error_code": "ERR_STATE_STORE_NOT_CONFIGURED", + "instance": "10.244.1.64:9090", + "job": "kubernetes-service-endpoints", + "namespace": "my-app", + "node": "my-node", + "service": "publisher-app-dapr" +} +``` + +## 使用路径匹配优化HTTP指标报告 + +在使用HTTP调用Dapr时,默认情况下会为每个请求的方法创建指标。这可能导致大量指标,称为高基数,这可能会影响内存使用和CPU。 + +路径匹配允许您管理和控制Dapr中HTTP指标的基数。通过聚合指标,您可以减少指标事件的数量并报告一个总体数量。[了解更多关于如何在配置中设置基数]({{< ref "configuration-overview.md#metrics" >}})。 + +此配置是选择加入的,并通过Dapr配置`spec.metrics.http.pathMatching`启用。当定义时,它启用路径匹配,这将标准化指定路径的两个指标路径。这减少了唯一指标路径的数量,使指标更易于管理,并以受控方式减少资源消耗。 + +当`spec.metrics.http.pathMatching`与`increasedCardinality`标志设置为`false`结合使用时,未匹配的路径会被转换为一个通用桶,以控制和限制基数,防止路径无限增长。相反,当`increasedCardinality`为`true`(默认值)时,未匹配的路径会像通常一样传递,允许潜在的更高基数,但保留原始路径数据。 + +### HTTP指标中的路径匹配示例 + +以下示例演示了如何在Dapr中使用路径匹配API来管理HTTP指标。在每个示例中,指标是从5个HTTP请求到`/orders`端点收集的,具有不同的订单ID。通过调整基数和利用路径匹配,您可以微调指标粒度以平衡细节和资源效率。 + +这些示例说明了指标的基数,强调高基数配置会导致许多条目,这对应于处理指标的更高内存使用。为简单起见,以下示例专注于单个指标:`dapr_http_server_request_count`。 + +#### 低基数与路径匹配(推荐) + +配置: +```yaml +http: + increasedCardinality: false + pathMatching: + - /orders/{orderID} +``` + +生成的指标: +``` +# 匹配的路径 +dapr_http_server_request_count{app_id="order-service",method="GET",path="/orders/{orderID}",status="200"} 5 +# 未匹配的路径 +dapr_http_server_request_count{app_id="order-service",method="GET",path="",status="200"} 1 +``` + +通过配置低基数和路径匹配,您可以在不影响基数的情况下对重要端点的指标进行分组。这种方法有助于避免高内存使用和潜在的安全问题。 + +#### 无路径匹配的低基数 + +配置: + +```yaml +http: + increasedCardinality: false +``` +生成的指标: +``` +dapr_http_server_request_count{app_id="order-service",method="GET", path="",status="200"} 5 +``` + +在低基数模式下,路径是无限基数的主要来源,被丢弃。这导致的指标主要指示给定HTTP方法的服务请求数量,但没有关于调用路径的信息。 + +#### 高基数与路径匹配 + +配置: +```yaml +http: + increasedCardinality: true + pathMatching: + - /orders/{orderID} +``` + +生成的指标: +``` +dapr_http_server_request_count{app_id="order-service",method="GET",path="/orders/{orderID}",status="200"} 5 +``` + +此示例来自与上例相同的HTTP请求,但为路径`/orders/{orderID}`配置了路径匹配。通过使用路径匹配,您可以通过基于匹配路径分组指标来实现减少基数。 + +#### 无路径匹配的高基数 + +配置: +```yaml +http: + increasedCardinality: true +``` + +生成的指标: +``` +dapr_http_server_request_count{app_id="order-service",method="GET",path="/orders/1",status="200"} 1 +dapr_http_server_request_count{app_id="order-service",method="GET",path="/orders/2",status="200"} 1 +dapr_http_server_request_count{app_id="order-service",method="GET",path="/orders/3",status="200"} 1 +dapr_http_server_request_count{app_id="order-service",method="GET",path="/orders/4",status="200"} 1 +dapr_http_server_request_count{app_id="order-service",method="GET",path="/orders/5",status="200"} 1 +``` + +对于每个请求,都会创建一个带有请求路径的新指标。此过程会继续为每个新订单ID的请求创建新指标,导致基数无限增长,因为ID是不断增长的。 + +### HTTP指标排除动词 + +`excludeVerbs`选项允许您从指标中排除特定的HTTP动词。这在内存节省至关重要的高性能应用程序中非常有用。 + +### 在指标中排除HTTP动词的示例 + +以下示例演示了如何在Dapr中排除HTTP动词以管理HTTP指标。 + +#### 默认 - 包含HTTP动词 + +配置: +```yaml +http: + excludeVerbs: false +``` + +生成的指标: +``` +dapr_http_server_request_count{app_id="order-service",method="GET",path="/orders",status="200"} 1 +dapr_http_server_request_count{app_id="order-service",method="POST",path="/orders",status="200"} 1 +``` + +在此示例中,HTTP方法包含在指标中,导致每个请求到`/orders`端点的单独指标。 + +#### 排除HTTP动词 + +配置: +```yaml +http: + excludeVerbs: true +``` + +生成的指标: +``` +dapr_http_server_request_count{app_id="order-service",method="",path="/orders",status="200"} 2 +``` + +在此示例中,HTTP方法从指标中排除,导致所有请求到`/orders`端点的单个指标。 + +## 配置自定义延迟直方图桶 + +Dapr使用累积直方图指标将延迟值分组到桶中,其中每个桶包含: +- 具有该延迟的请求数量 +- 所有具有较低延迟的请求 + +### 使用默认延迟桶配置 + +默认情况下,Dapr将请求延迟指标分组到以下桶中: + +``` +1, 2, 3, 4, 5, 6, 8, 10, 13, 16, 20, 25, 30, 40, 50, 65, 80, 100, 130, 160, 200, 250, 300, 400, 500, 650, 800, 1000, 2000, 5000, 10000, 20000, 50000, 100000 +``` + +以累积方式分组延迟值允许根据需要使用或丢弃桶以增加或减少数据的粒度。 +例如,如果一个请求需要3ms,它会被计入3ms桶、4ms桶、5ms桶,依此类推。 +同样,如果一个请求需要10ms,它会被计入10ms桶、13ms桶、16ms桶,依此类推。 +在这两个请求完成后,3ms桶的计数为1,而10ms桶的计数为2,因为这两个请求都包含在这里。 + +这显示如下: + +|1|2|3|4|5|6|8|10|13|16|20|25|30|40|50|65|80|100|130|160| ..... | 100000 | +|-|-|-|-|-|-|-|--|--|--|--|--|--|--|--|--|--|---|---|---|-------|--------| +|0|0|1|1|1|1|1| 2| 2| 2| 2| 2| 2| 2| 2| 2| 2| 2 | 2 | 2 | ..... | 2 | + +默认的桶数量适用于大多数用例,但可以根据需要进行调整。每个请求创建34个不同的指标,这个值可能会随着大量应用程序而显著增长。 +通过增加桶的数量可以获得更准确的延迟百分位数。然而,更多的桶会增加存储指标所需的内存量,可能会对您的监控系统产生负面影响。 + +建议将延迟桶的数量设置为默认值,除非您在监控系统中看到不必要的内存压力。配置桶的数量允许您选择应用程序: +- 您希望通过更多的桶看到更多细节 +- 通过减少桶来获得更广泛的值 + +在配置桶的数量之前,请注意您的应用程序产生的默认延迟值。 +### 根据您的场景自定义延迟桶 + +通过修改应用程序的[Dapr配置规范]({{< ref configuration-schema.md >}})中的`spec.metrics.latencyDistributionBuckets`字段,定制延迟桶以满足您的需求。 + +例如,如果您对极低的延迟值(1-10ms)不感兴趣,可以将它们分组到一个10ms桶中。同样,您可以将高值分组到一个桶中(1000-5000ms),同时在您最感兴趣的中间范围内保持更多细节。 + +以下配置规范示例用11个桶替换了默认的34个桶,在中间范围内提供了更高的粒度: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: custom-metrics +spec: + metrics: + enabled: true + latencyDistributionBuckets: [10, 25, 40, 50, 70, 100, 150, 200, 500, 1000, 5000] +``` + +## 使用正则表达式转换指标 + +您可以为Dapr sidecar公开的每个指标设置正则表达式以“转换”其值。[查看所有Dapr指标的列表](https://github.com/dapr/dapr/blob/master/docs/development/dapr-metrics.md)。 + +规则的名称必须与被转换的指标名称匹配。以下示例显示了如何为指标`dapr_runtime_service_invocation_req_sent_total`中的标签`method`应用正则表达式: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: daprConfig +spec: + metrics: + enabled: true + http: + increasedCardinality: true + rules: + - name: dapr_runtime_service_invocation_req_sent_total + labels: + - name: method + regex: + "orders/": "orders/.+" +``` + +应用此配置后,记录的带有`method`标签的指标`orders/a746dhsk293972nz`将被替换为`orders/`。 + +使用正则表达式减少指标基数被认为是遗留的。我们鼓励所有用户将`spec.metrics.http.increasedCardinality`设置为`false`,这更易于配置并提供更好的性能。 + +## 参考 + +* [Howto: 本地运行Prometheus]({{< ref prometheus.md >}}) +* [Howto: 设置Prometheus和Grafana以获取指标]({{< ref grafana.md >}}) diff --git a/src/translated_content/zh_CN/docs/operations/observability/metrics/newrelic.md b/src/translated_content/zh_CN/docs/operations/observability/metrics/newrelic.md new file mode 100644 index 000000000..92aacde2b --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/metrics/newrelic.md @@ -0,0 +1,43 @@ +--- +type: docs +title: "操作指南:配置 New Relic 以收集和分析指标" +linkTitle: "New Relic" +weight: 6000 +description: "为 Dapr 指标配置 New Relic" +--- + +## 前提条件 + +- [New Relic 账户](https://newrelic.com/signup?ref=dapr),永久免费,每月提供 100 GB 的免费数据摄取,1 个免费完全访问用户,无限制的免费基本用户 + +## 背景信息 + +New Relic 支持 Prometheus 的 OpenMetrics 集成。 + +本文档将介绍如何在集群中安装该集成,建议使用 Helm chart 进行安装。 + +## 安装步骤 + +1. 根据官方说明安装 Helm。 + +2. 按照[这些说明](https://github.com/newrelic/helm-charts/blob/master/README.md#installing-charts)添加 New Relic 官方 Helm chart 仓库。 + +3. 运行以下命令通过 Helm 安装 New Relic Logging Kubernetes 插件,并将 YOUR_LICENSE_KEY 替换为您的 [New Relic 许可证密钥](https://docs.newrelic.com/docs/accounts/accounts-billing/account-setup/new-relic-license-key): + + ```bash + helm install nri-prometheus newrelic/nri-prometheus --set licenseKey=YOUR_LICENSE_KEY + ``` + +## 查看指标 + +![Dapr 指标](/images/nr-metrics-1.png) + +![仪表板](/images/nr-dashboard-dapr-metrics-1.png) + +## 相关链接/参考 + +* [New Relic 账户注册](https://newrelic.com/signup) +* [遥测数据平台](https://newrelic.com/platform/telemetry-data-platform) +* [New Relic Prometheus OpenMetrics 集成](https://github.com/newrelic/helm-charts/tree/master/charts/nri-prometheus) +* [New Relic API 密钥类型](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/) +* [警报和应用智能](https://docs.newrelic.com/docs/alerts-applied-intelligence/overview/) diff --git a/src/translated_content/zh_CN/docs/operations/observability/metrics/prometheus.md b/src/translated_content/zh_CN/docs/operations/observability/metrics/prometheus.md new file mode 100644 index 000000000..33e045d7c --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/metrics/prometheus.md @@ -0,0 +1,232 @@ +--- +type: docs +title: "操作指南:使用 Prometheus 监控指标" +linkTitle: "Prometheus" +weight: 4000 +description: "使用 Prometheus 收集与 Dapr 运行时执行相关的时间序列数据" +--- + +## 本地设置 Prometheus +在本地计算机上,您可以选择[安装并作为进程运行](#install) Prometheus,或者将其作为[Docker 容器运行](#Run-as-Container)。 + +### 安装 +{{% alert title="注意" color="warning" %}} +如果您计划将 Prometheus 作为 Docker 容器运行,则无需单独安装 Prometheus。请参阅[容器](#run-as-container)部分的说明。 +{{% /alert %}} + +请按照[此处](https://prometheus.io/docs/prometheus/latest/getting_started/)提供的步骤,根据您的操作系统安装 Prometheus。 + +### 配置 +安装完成后,您需要创建一个配置文件。 + +以下是一个示例 Prometheus 配置,请将其保存为文件,例如 `/tmp/prometheus.yml` 或 `C:\Temp\prometheus.yml`: +```yaml +global: + scrape_interval: 15s # 默认情况下,每 15 秒收集一次指标。 + +# 包含一个收集端点的配置: +# 这里是 Prometheus 自身。 +scrape_configs: + - job_name: 'dapr' + + # 覆盖全局默认值,每 5 秒从此 job 收集指标。 + scrape_interval: 5s + + static_configs: + - targets: ['localhost:9090'] # 如果不是默认值,请替换为 Dapr 指标端口 +``` + +### 作为进程运行 +使用您的配置文件运行 Prometheus,以开始从指定目标收集指标。 +```bash +./prometheus --config.file=/tmp/prometheus.yml --web.listen-address=:8080 +``` +> 我们更改了端口以避免与 Dapr 自身的指标端点冲突。 + +如果您当前没有运行 Dapr 应用程序,目标将显示为离线。要开始收集指标,您必须启动 Dapr,并确保其指标端口与配置中指定的目标一致。 + +一旦 Prometheus 运行,您可以通过访问 `http://localhost:8080` 来查看其仪表板。 + +### 作为容器运行 +要在本地计算机上将 Prometheus 作为 Docker 容器运行,首先确保已安装并运行 [Docker](https://docs.docker.com/install/)。 + +然后可以使用以下命令将 Prometheus 作为 Docker 容器运行: +```bash +docker run \ + --net=host \ + -v /tmp/prometheus.yml:/etc/prometheus/prometheus.yml \ + prom/prometheus --config.file=/etc/prometheus/prometheus.yml --web.listen-address=:8080 +``` +`--net=host` 确保 Prometheus 实例能够连接到在主机上运行的任何 Dapr 实例。如果您计划也在容器中运行 Dapr 应用程序,则需要在共享的 Docker 网络上运行它们,并使用正确的目标地址更新配置。 + +一旦 Prometheus 运行,您可以通过访问 `http://localhost:8080` 来查看其仪表板。 + +## 在 Kubernetes 上设置 Prometheus + +### 先决条件 + +- Kubernetes (> 1.14) +- [kubectl](https://kubernetes.io/docs/tasks/tools/) +- [Helm 3](https://helm.sh/) + +### 安装 Prometheus + +1. 首先创建一个命名空间,用于部署 Grafana 和 Prometheus 监控工具 + +```bash +kubectl create namespace dapr-monitoring +``` + +2. 安装 Prometheus + +```bash +helm repo add prometheus-community https://prometheus-community.github.io/helm-charts +helm repo update +helm install dapr-prom prometheus-community/prometheus -n dapr-monitoring +``` + +如果您是 Minikube 用户或想要禁用持久卷以进行开发,可以使用以下命令禁用它。 + +```bash +helm install dapr-prom prometheus-community/prometheus -n dapr-monitoring + --set alertmanager.persistence.enabled=false --set pushgateway.persistentVolume.enabled=false --set server.persistentVolume.enabled=false +``` + +要自动发现 Dapr 目标(服务发现),请使用: + +```bash + helm install dapr-prom prometheus-community/prometheus -f values.yaml -n dapr-monitoring --create-namespace +``` + +### `values.yaml` 文件 + +```yaml +alertmanager: + persistence: + enabled: false +pushgateway: + persistentVolume: + enabled: false +server: + persistentVolume: + enabled: false + +# 向 prometheus.yml 添加额外的收集配置 +# 使用服务发现找到 Dapr 和 Dapr sidecar 目标 +extraScrapeConfigs: |- + - job_name: dapr-sidecars + kubernetes_sd_configs: + - role: pod + relabel_configs: + - action: keep + regex: "true" + source_labels: + - __meta_kubernetes_pod_annotation_dapr_io_enabled + - action: keep + regex: "true" + source_labels: + - __meta_kubernetes_pod_annotation_dapr_io_enable_metrics + - action: replace + replacement: ${1} + source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - action: replace + replacement: ${1} + source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - action: replace + regex: (.*);daprd + replacement: ${1}-dapr + source_labels: + - __meta_kubernetes_pod_annotation_dapr_io_app_id + - __meta_kubernetes_pod_container_name + target_label: service + - action: replace + replacement: ${1}:9090 + source_labels: + - __meta_kubernetes_pod_ip + target_label: __address__ + + - job_name: dapr + kubernetes_sd_configs: + - role: pod + relabel_configs: + - action: keep + regex: dapr + source_labels: + - __meta_kubernetes_pod_label_app_kubernetes_io_name + - action: keep + regex: dapr + source_labels: + - __meta_kubernetes_pod_label_app_kubernetes_io_part_of + - action: replace + replacement: ${1} + source_labels: + - __meta_kubernetes_pod_label_app + target_label: app + - action: replace + replacement: ${1} + source_labels: + - __meta_kubernetes_namespace + target_label: namespace + - action: replace + replacement: ${1} + source_labels: + - __meta_kubernetes_pod_name + target_label: pod + - action: replace + replacement: ${1}:9090 + source_labels: + - __meta_kubernetes_pod_ip + target_label: __address__ +``` + +3. 验证 + +确保 Prometheus 在您的集群中运行。 + +```bash +kubectl get pods -n dapr-monitoring +``` + +预期输出: + +```bash +NAME READY STATUS RESTARTS AGE +dapr-prom-kube-state-metrics-9849d6cc6-t94p8 1/1 Running 0 4m58s +dapr-prom-prometheus-alertmanager-749cc46f6-9b5t8 2/2 Running 0 4m58s +dapr-prom-prometheus-node-exporter-5jh8p 1/1 Running 0 4m58s +dapr-prom-prometheus-node-exporter-88gbg 1/1 Running 0 4m58s +dapr-prom-prometheus-node-exporter-bjp9f 1/1 Running 0 4m58s +dapr-prom-prometheus-pushgateway-688665d597-h4xx2 1/1 Running 0 4m58s +dapr-prom-prometheus-server-694fd8d7c-q5d59 2/2 Running 0 4m58s +``` + +### 访问 Prometheus 仪表板 + +要查看 Prometheus 仪表板并检查服务发现: + +```bash +kubectl port-forward svc/dapr-prom-prometheus-server 9090:80 -n dapr-monitoring +``` + +打开浏览器并访问 `http://localhost:9090`。导航到 **Status** > **Service Discovery** 以验证 Dapr 目标是否被正确发现。 + +Prometheus Web UI + +您可以看到 `job_name` 及其发现的目标。 + +Prometheus Service Discovery + +## 示例 + +
+ +
+ +## 参考资料 + +* [Prometheus 安装](https://github.com/prometheus-community/helm-charts) +* [Prometheus 查询语言](https://prometheus.io/docs/prometheus/latest/querying/basics/) diff --git a/src/translated_content/zh_CN/docs/operations/observability/tracing/_index.md b/src/translated_content/zh_CN/docs/operations/observability/tracing/_index.md new file mode 100644 index 000000000..72e8d0b14 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/tracing/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "代码跟踪" +linkTitle: "代码跟踪" +weight: 200 +description: 了解代码跟踪的应用场景及如何利用其提升应用程序的监控能力 +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/observability/tracing/datadog.md b/src/translated_content/zh_CN/docs/operations/observability/tracing/datadog.md new file mode 100644 index 000000000..ce40ff642 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/tracing/datadog.md @@ -0,0 +1,56 @@ +--- +type: docs +title: "操作指南:为分布式追踪设置 Datadog" +linkTitle: "Datadog" +weight: 5000 +description: "为分布式追踪设置 Datadog" +--- + +Dapr 捕获的指标和追踪信息可以通过 OpenTelemetry Collector 的 Datadog 导出器直接发送到 Datadog。 + +## 使用 OpenTelemetry Collector 和 Datadog 配置 Dapr 追踪 + +您可以使用 OpenTelemetry Collector 的 Datadog 导出器来配置 Dapr,为 Kubernetes 集群中的每个应用程序创建追踪,并将这些追踪信息收集到 Datadog 中。 + +> 在开始之前,请先[设置 OpenTelemetry Collector]({{< ref "open-telemetry-collector.md#setting-opentelemetry-collector" >}})。 + +1. 在 `datadog` 导出器的配置部分,将您的 Datadog API 密钥添加到 `./deploy/opentelemetry-collector-generic-datadog.yaml` 文件中: + ```yaml + data: + otel-collector-config: + ... + exporters: + ... + datadog: + api: + key: + ``` + +1. 运行以下命令以应用 `opentelemetry-collector` 的配置。 + + ```sh + kubectl apply -f ./deploy/open-telemetry-collector-generic-datadog.yaml + ``` + +1. 设置一个 Dapr 配置文件以启用追踪,并部署一个使用 OpenTelemetry Collector 的追踪导出器组件。 + + ```sh + kubectl apply -f ./deploy/collector-config.yaml + ``` + +1. 在您希望参与分布式追踪的容器中添加 `dapr.io/config` 注解,以应用 `appconfig` 配置。 + + ```yml + annotations: + dapr.io/config: "appconfig" + ``` + +1. 创建并配置应用程序。应用程序运行后,遥测数据将被发送到 Datadog,并可以在 Datadog APM 中查看。 + +Datadog APM 显示遥测数据。 + +## 相关链接/参考 + +* [在 Kubernetes 集群上设置 Dapr 的完整示例](https://github.com/ericmustin/quickstarts/tree/master/hello-kubernetes) +* [关于 OpenTelemetry 支持的 Datadog 文档](https://docs.datadoghq.com/opentelemetry/) +* [Datadog 应用性能监控](https://docs.datadoghq.com/tracing/) diff --git a/src/translated_content/zh_CN/docs/operations/observability/tracing/newrelic.md b/src/translated_content/zh_CN/docs/operations/observability/tracing/newrelic.md new file mode 100644 index 000000000..3071e4167 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/tracing/newrelic.md @@ -0,0 +1,114 @@ +--- +type: docs +title: "操作指南:配置 New Relic 进行分布式追踪" +linkTitle: "New Relic" +weight: 2000 +description: "配置 New Relic 进行分布式追踪" +--- + +## 前提条件 + +- 需要一个 [New Relic 账户](https://newrelic.com/signup?ref=dapr),该账户永久免费,每月可免费处理 100 GB 的数据,包含 1 个完全访问用户和无限数量的基本用户。 + +## 配置 Dapr 追踪 + +Dapr 可以直接将其捕获的指标和追踪数据发送到 New Relic。最简单的方式是通过配置 Dapr,将追踪数据以 Zipkin 格式发送到 [New Relic 的 Trace API](https://docs.newrelic.com/docs/distributed-tracing/trace-api/report-zipkin-format-traces-trace-api/)。 + +为了将数据集成到 New Relic 的 [Telemetry Data Platform](https://newrelic.com/platform/telemetry-data-platform),您需要一个 [New Relic Insights Insert API key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#insights-insert-key)。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: appconfig + namespace: default +spec: + tracing: + samplingRate: "1" + zipkin: + endpointAddress: "https://trace-api.newrelic.com/trace/v1?Api-Key=&Data-Format=zipkin&Data-Format-Version=2" +``` + +### 查看追踪 + +New Relic 分布式追踪概览 +![New Relic Kubernetes Cluster Explorer App](/images/nr-distributed-tracing-overview.png) + +New Relic 分布式追踪详情 +![New Relic Kubernetes Cluster Explorer App](/images/nr-distributed-tracing-detail.png) + +## (选择性)New Relic 仪器化 + +为了将数据集成到 New Relic Telemetry Data Platform,您需要一个 [New Relic license key](https://docs.newrelic.com/docs/accounts/accounts-billing/account-setup/new-relic-license-key) 或 [New Relic Insights Insert API key](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/#insights-insert-key)。 + +### OpenTelemetry 仪器化 + +您可以使用不同语言的 OpenTelemetry 实现,例如 [New Relic Telemetry SDK 和 .NET 的 OpenTelemetry 支持](https://github.com/newrelic/newrelic-telemetry-sdk-dotnet)。在这种情况下,使用 [OpenTelemetry Trace Exporter](https://github.com/newrelic/newrelic-telemetry-sdk-dotnet/tree/main/src/NewRelic.OpenTelemetry)。示例请参见[此处](https://github.com/harrykimpel/quickstarts/blob/master/distributed-calculator/csharp-otel/Startup.cs)。 + +### New Relic 语言代理 + +类似于 OpenTelemetry 仪器化,您也可以使用 New Relic 语言代理。例如,.NET Core 的 [New Relic 代理仪器化](https://docs.newrelic.com/docs/agents/net-agent/other-installation/install-net-agent-docker-container) 是 Dockerfile 的一部分。示例请参见[此处](https://github.com/harrykimpel/quickstarts/blob/master/distributed-calculator/csharp/Dockerfile)。 + +## (选择性)启用 New Relic Kubernetes 集成 + +如果 Dapr 和您的应用程序在 Kubernetes 环境中运行,您可以启用额外的指标和日志。 + +安装 New Relic Kubernetes 集成的最简单方法是使用 [自动安装程序](https://one.newrelic.com/launcher/nr1-core.settings?pane=eyJuZXJkbGV0SWQiOiJrOHMtY2x1c3Rlci1leHBsb3Jlci1uZXJkbGV0Lms4cy1zZXR1cCJ9) 生成清单。它不仅包含集成 DaemonSets,还包括其他 New Relic Kubernetes 配置,如 [Kubernetes 事件](https://docs.newrelic.com/docs/integrations/kubernetes-integration/kubernetes-events/install-kubernetes-events-integration)、[Prometheus OpenMetrics](https://docs.newrelic.com/docs/integrations/prometheus-integrations/get-started/send-prometheus-metric-data-new-relic/) 和 [New Relic 日志监控](https://docs.newrelic.com/docs/logs/ui-data/use-logs-ui/)。 + +### New Relic Kubernetes 集群浏览器 + +[New Relic Kubernetes 集群浏览器](https://docs.newrelic.com/docs/integrations/kubernetes-integration/understand-use-data/kubernetes-cluster-explorer) 提供了一个独特的可视化界面,展示了 Kubernetes 集成收集的所有数据和部署。 + +这是观察所有数据并深入了解应用程序或微服务内部发生的任何性能问题或事件的良好起点。 + +![New Relic Kubernetes Cluster Explorer App](/images/nr-k8s-cluster-explorer-app.png) + +自动关联是 New Relic 可视化功能的一部分。 + +### Pod 级别详情 + +![New Relic K8s Pod Level Details](/images/nr-k8s-pod-level-details.png) + +### 上下文中的日志 + +![New Relic K8s Logs In Context](/images/nr-k8s-logs-in-context.png) + +## New Relic 仪表板 + +### Kubernetes 概览 + +![New Relic Dashboard Kubernetes Overview](/images/nr-dashboard-k8s-overview.png) + +### Dapr 系统服务 + +![New Relic Dashboard Dapr System Services](/images/nr-dashboard-dapr-system-services.png) + +### Dapr 指标 + +![New Relic Dashboard Dapr Metrics 1](/images/nr-dashboard-dapr-metrics-1.png) + +## New Relic Grafana 集成 + +New Relic 与 [Grafana Labs](https://grafana.com/) 合作,您可以使用 [Telemetry Data Platform](https://newrelic.com/platform/telemetry-data-platform) 作为 Prometheus 指标的数据源,并在现有仪表板中查看它们,轻松利用 New Relic 提供的可靠性、规模和安全性。 + +用于监控 Dapr 系统服务和 sidecar 的 [Grafana 仪表板模板](https://github.com/dapr/dapr/blob/227028e7b76b7256618cd3236d70c1d4a4392c9a/grafana/README.md) 可以轻松使用,无需任何更改。New Relic 提供了一个 [Prometheus 指标的本地端点](https://docs.newrelic.com/docs/integrations/grafana-integrations/set-configure/configure-new-relic-prometheus-data-source-grafana) 到 Grafana。可以轻松设置数据源: + +![New Relic Grafana Data Source](/images/nr-grafana-datasource.png) + +并且可以导入来自 Dapr 的完全相同的仪表板模板,以可视化 Dapr 系统服务和 sidecar。 + +![New Relic Grafana Dashboard](/images/nr-grafana-dashboard.png) + +## New Relic 警报 + +从 Dapr、Kubernetes 或任何在其上运行的服务收集的所有数据都可以用于设置警报和通知到您选择的首选渠道。请参见 [Alerts and Applied Intelligence](https://docs.newrelic.com/docs/alerts-applied-intelligence/overview/)。 + +## 相关链接/参考 + +* [New Relic 账户注册](https://newrelic.com/signup) +* [Telemetry Data Platform](https://newrelic.com/platform/telemetry-data-platform) +* [分布式追踪](https://docs.newrelic.com/docs/distributed-tracing/concepts/introduction-distributed-tracing/) +* [New Relic Trace API](https://docs.newrelic.com/docs/distributed-tracing/trace-api/introduction-trace-api/) +* [New Relic API 密钥类型](https://docs.newrelic.com/docs/apis/intro-apis/new-relic-api-keys/) +* [New Relic OpenTelemetry 用户体验](https://blog.newrelic.com/product-news/opentelemetry-user-experience/) +* [Alerts and Applied Intelligence](https://docs.newrelic.com/docs/alerts-applied-intelligence/overview/) diff --git a/src/translated_content/zh_CN/docs/operations/observability/tracing/otel-collector/_index.md b/src/translated_content/zh_CN/docs/operations/observability/tracing/otel-collector/_index.md new file mode 100644 index 000000000..8a6b69fdc --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/tracing/otel-collector/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "Open Telemetry Collector" +linkTitle: "Open Telemetry Collector" +weight: 700 +description: "如何配置您的监控工具以接收应用程序追踪数据" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/observability/tracing/otel-collector/open-telemetry-collector-appinsights.md b/src/translated_content/zh_CN/docs/operations/observability/tracing/otel-collector/open-telemetry-collector-appinsights.md new file mode 100644 index 000000000..c1d19857d --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/tracing/otel-collector/open-telemetry-collector-appinsights.md @@ -0,0 +1,83 @@ +--- +type: docs +title: "使用 OpenTelemetry Collector 将跟踪信息发送到应用程序洞察" +linkTitle: "通过 OpenTelemetry 连接 Azure 应用程序洞察" +weight: 1000 +description: "如何使用 OpenTelemetry Collector 将跟踪事件推送到 Azure 应用程序洞察。" +--- + +Dapr 使用 Zipkin API 集成了 [OpenTelemetry (OTEL) Collector](https://github.com/open-telemetry/opentelemetry-collector)。本指南演示了如何通过 Dapr 使用 OpenTelemetry Collector 将跟踪事件推送到 Azure 应用程序洞察。 + +## 前提条件 + +- [在 Kubernetes 上安装 Dapr]({{< ref kubernetes >}}) +- [设置一个应用程序洞察资源](https://docs.microsoft.com/azure/azure-monitor/app/create-new-resource)并记录下你的应用程序洞察仪器密钥。 + +## 配置 OTEL Collector 以推送数据到应用程序洞察 + +要将事件推送到你的应用程序洞察实例,请在 Kubernetes 集群中安装 OTEL Collector。 + +1. 查看 [`open-telemetry-collector-appinsights.yaml`](/docs/open-telemetry-collector/open-telemetry-collector-appinsights.yaml) 文件。 + +1. 用你的应用程序洞察仪器密钥替换 `` 占位符。 + +1. 使用以下命令应用配置: + + ```sh + kubectl apply -f open-telemetry-collector-appinsights.yaml + ``` + +## 配置 Dapr 以发送跟踪数据到 OTEL Collector + +创建一个 Dapr 配置文件以启用跟踪,并部署一个使用 OpenTelemetry Collector 的跟踪导出组件。 + +1. 使用此 [`collector-config.yaml`](/docs/open-telemetry-collector/collector-config.yaml) 文件创建你自己的配置。 + +1. 使用以下命令应用配置: + + ```sh + kubectl apply -f collector-config.yaml + ``` + +## 部署应用程序并启用跟踪 + +在你希望参与分布式跟踪的容器中添加 `dapr.io/config` 注解以应用 `appconfig` 配置,如下例所示: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + ... +spec: + ... + template: + metadata: + ... + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "MyApp" + dapr.io/app-port: "8080" + dapr.io/config: "appconfig" +``` + +{{% alert title="注意" color="primary" %}} +如果你正在使用 Dapr 教程之一,例如 [分布式计算器](https://github.com/dapr/quickstarts/tree/master/tutorials/distributed-calculator),`appconfig` 配置已经设置好,因此不需要额外的配置。 +{{% /alert %}} + +你可以同时注册多个跟踪导出器,跟踪日志会被转发到所有注册的导出器。 + +就是这样!无需包含任何 SDK 或对你的应用程序代码进行额外的修改。Dapr 会自动为你处理分布式跟踪。 + +## 查看跟踪 + +部署并运行一些应用程序。几分钟后,你应该会在你的应用程序洞察资源中看到跟踪日志。你还可以使用 **应用程序地图** 来检查你的服务拓扑,如下所示: + +![应用程序地图](/images/open-telemetry-app-insights.png) + +{{% alert title="注意" color="primary" %}} +只有通过 Dapr sidecar 暴露的 Dapr API(例如,服务调用或事件发布)的操作会显示在应用程序地图拓扑中。 +{{% /alert %}} + +## 相关链接 +- 尝试 [可观测性快速入门](https://github.com/dapr/quickstarts/tree/master/tutorials/observability/README.md) +- 了解如何设置 [跟踪配置选项]({{< ref "configuration-overview.md#tracing" >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/observability/tracing/otel-collector/open-telemetry-collector-jaeger.md b/src/translated_content/zh_CN/docs/operations/observability/tracing/otel-collector/open-telemetry-collector-jaeger.md new file mode 100644 index 000000000..e675b2d97 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/tracing/otel-collector/open-telemetry-collector-jaeger.md @@ -0,0 +1,140 @@ +--- +type: docs +title: "使用 OpenTelemetry Collector 收集追踪信息并发送到 Jaeger" +linkTitle: "使用 OpenTelemetry 发送到 Jaeger" +weight: 1200 +description: "如何使用 OpenTelemetry Collector 将追踪事件推送到 Jaeger 分布式追踪平台。" +--- + +Dapr 支持通过 OpenTelemetry (OTLP) 和 Zipkin 协议进行追踪信息的写入。然而,由于 Jaeger 对 Zipkin 的支持已被弃用,建议使用 OTLP。虽然 Jaeger 可以直接支持 OTLP,但在生产环境中,推荐使用 OpenTelemetry Collector 从 Dapr 收集追踪信息并发送到 Jaeger。这样可以让您的应用程序更高效地处理数据,并利用重试、批处理和加密等功能。更多信息请阅读 Open Telemetry Collector [文档](https://opentelemetry.io/docs/collector/#when-to-use-a-collector)。 +{{< tabs Self-hosted Kubernetes >}} + +{{% codetab %}} + +## 在自托管模式下配置 Jaeger + +### 本地设置 + +启动 Jaeger 的最简单方法是运行发布到 DockerHub 的预构建的 all-in-one Jaeger 镜像,并暴露 OTLP 端口: + +```bash +docker run -d --name jaeger \ + -p 4317:4317 \ + -p 16686:16686 \ + jaegertracing/all-in-one:1.49 +``` + +接下来,在本地创建以下 `config.yaml` 文件: + +> **注意:** 因为您使用 Open Telemetry 协议与 Jaeger 通信,您需要填写追踪配置的 `otel` 部分,并将 `endpointAddress` 设置为 Jaeger 容器的地址。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: tracing + namespace: default +spec: + tracing: + samplingRate: "1" + stdout: true + otel: + endpointAddress: "localhost:4317" + isSecure: false + protocol: grpc +``` + +要启动引用新 YAML 配置文件的应用程序,请使用 `--config` 选项。例如: + +```bash +dapr run --app-id myapp --app-port 3000 node app.js --config config.yaml +``` + +### 查看追踪信息 + +要在浏览器中查看追踪信息,请访问 `http://localhost:16686` 查看 Jaeger UI。 +{{% /codetab %}} + +{{% codetab %}} + +## 在 Kubernetes 上使用 OpenTelemetry Collector 配置 Jaeger + +以下步骤展示了如何配置 Dapr 以将分布式追踪数据发送到 OpenTelemetry Collector,然后将追踪信息发送到 Jaeger。 + +### 前提条件 + +- [在 Kubernetes 上安装 Dapr]({{< ref kubernetes >}}) +- 使用 Jaeger Kubernetes Operator [设置 Jaeger](https://www.jaegertracing.io/docs/1.49/operator/) + +### 设置 OpenTelemetry Collector 推送到 Jaeger + +要将追踪信息推送到您的 Jaeger 实例,请在您的 Kubernetes 集群上安装 OpenTelemetry Collector。 + +1. 下载并检查 [`open-telemetry-collector-jaeger.yaml`](/docs/open-telemetry-collector/open-telemetry-collector-jaeger.yaml) 文件。 + +1. 在 `otel-collector-conf` ConfigMap 的数据部分,更新 `otlp/jaeger.endpoint` 值以匹配您的 Jaeger collector Kubernetes 服务对象的端点。 + +1. 将 OpenTelemetry Collector 部署到运行 Dapr 应用程序的相同命名空间中: + + ```sh + kubectl apply -f open-telemetry-collector-jaeger.yaml + ``` + +### 设置 Dapr 发送追踪信息到 OpenTelemetryCollector + +创建一个 Dapr 配置文件以启用追踪,并将 sidecar 追踪信息导出到 OpenTelemetry Collector。 + +1. 使用 [`collector-config-otel.yaml`](/docs/open-telemetry-collector/collector-config-otel.yaml) 文件创建您自己的 Dapr 配置。 + +1. 更新 `namespace` 和 `otel.endpointAddress` 值以与部署 Dapr 应用程序和 OpenTelemetry Collector 的命名空间对齐。 + +1. 应用配置: + + ```sh + kubectl apply -f collector-config.yaml + ``` + +### 部署启用追踪的应用程序 + +通过在您希望启用分布式追踪的应用程序部署中添加 `dapr.io/config` 注释来应用 `tracing` Dapr 配置,如下例所示: + + ```yaml + apiVersion: apps/v1 + kind: Deployment + metadata: + ... + spec: + ... + template: + metadata: + ... + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "MyApp" + dapr.io/app-port: "8080" + dapr.io/config: "tracing" + ``` + +您可以同时注册多个追踪导出器,追踪日志将被转发到所有注册的导出器。 + +就是这样!无需包含 OpenTelemetry SDK 或对您的应用程序代码进行检测。Dapr 会自动为您处理分布式追踪。 + +### 查看追踪信息 + +要查看 Dapr sidecar 追踪信息,请端口转发 Jaeger 服务并打开 UI: + +```bash +kubectl port-forward svc/jaeger-query 16686 -n observability +``` + +在您的浏览器中,访问 `http://localhost:16686`,您将看到 Jaeger UI。 + +![jaeger](/images/jaeger_ui.png) +{{% /codetab %}} + +{{< /tabs >}} +## 参考资料 + +- [Jaeger 入门](https://www.jaegertracing.io/docs/1.49/getting-started/) +- [Jaeger Kubernetes Operator](https://www.jaegertracing.io/docs/1.49/operator/) +- [OpenTelemetry Collector 导出器](https://opentelemetry.io/docs/collector/configuration/#exporters) diff --git a/src/translated_content/zh_CN/docs/operations/observability/tracing/otel-collector/open-telemetry-collector.md b/src/translated_content/zh_CN/docs/operations/observability/tracing/otel-collector/open-telemetry-collector.md new file mode 100644 index 000000000..8d6d168c3 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/tracing/otel-collector/open-telemetry-collector.md @@ -0,0 +1,83 @@ +--- +type: docs +title: "使用 OpenTelemetry Collector 收集追踪" +linkTitle: "使用 OpenTelemetry Collector" +weight: 900 +description: "如何使用 Dapr 通过 OpenTelemetry Collector 推送追踪事件。" +--- + +Dapr 推荐使用 OpenTelemetry (OTLP) 协议来写入追踪数据。对于直接支持 OTLP 的可观测性工具,建议使用 [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector),因为它可以快速卸载数据,并提供重试、批处理和加密等功能。更多信息请参阅 Open Telemetry Collector 的[文档](https://opentelemetry.io/docs/collector/#when-to-use-a-collector)。 + +Dapr 也支持使用 Zipkin 协议来写入追踪数据。在 OTLP 协议支持之前,Zipkin 协议与 OpenTelemetry Collector 一起使用,以将追踪数据发送到 AWS X-Ray、Google Cloud Operations Suite 和 Azure Monitor 等可观测性工具。虽然两种协议都有效,但推荐使用 OpenTelemetry 协议。 + +![使用 OpenTelemetry Collector 集成多个后端](/images/open-telemetry-collector.png) + +## 先决条件 + +- [在 Kubernetes 上安装 Dapr]({{< ref kubernetes >}}) +- 确保您的追踪后端已准备好接收追踪数据 +- 查看 OTEL Collector 导出器所需的参数: + - [`opentelemetry-collector-contrib/exporter`](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter) + - [`opentelemetry-collector/exporter`](https://github.com/open-telemetry/opentelemetry-collector/tree/main/exporter) + +## 配置 OTEL Collector 推送追踪数据到您的后端 + +1. 查看 [`open-telemetry-collector-generic.yaml`](/docs/open-telemetry-collector/open-telemetry-collector-generic.yaml)。 + +1. 将 `` 替换为您的追踪导出器的实际配置。 + - 请参考[先决条件部分]({{< ref "#prerequisites.md" >}})中的 OTEL Collector 链接以获取正确的配置。 + +1. 使用以下命令应用配置: + + ```sh + kubectl apply -f open-telemetry-collector-generic.yaml + ``` + +## 配置 Dapr 发送追踪数据到 OTEL Collector + +创建一个 Dapr 配置文件以启用追踪,并部署一个使用 OpenTelemetry Collector 的追踪导出器组件。 + +1. 使用此 [`collector-config.yaml`](/docs/open-telemetry-collector/collector-config.yaml) 文件创建您的配置。 + +1. 使用以下命令应用配置: + + ```sh + kubectl apply -f collector-config.yaml + ``` + +## 部署应用程序并启用追踪 + +在需要参与分布式追踪的容器中添加 `dapr.io/config` 注解以应用 `appconfig` 配置,如下所示: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + ... +spec: + ... + template: + metadata: + ... + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "MyApp" + dapr.io/app-port: "8080" + dapr.io/config: "appconfig" +``` + +{{% alert title="注意" color="primary" %}} +如果您正在使用 Dapr 的教程,例如[分布式计算器](https://github.com/dapr/quickstarts/tree/master/tutorials/distributed-calculator),`appconfig` 配置已设置,无需额外操作。 +{{% /alert %}} + +您可以同时注册多个追踪导出器,追踪数据将被转发到所有注册的导出器。 + +就是这样!无需包含任何 SDK 或对您的应用程序代码进行修改。Dapr 会自动为您处理分布式追踪。 + +## 查看追踪 + +部署并运行一些应用程序。等待追踪数据传播到您的追踪后端并在那里查看它们。 + +## 相关链接 +- 尝试 [可观测性快速入门](https://github.com/dapr/quickstarts/tree/master/tutorials/observability/README.md) +- 了解如何设置[追踪配置选项]({{< ref "configuration-overview.md#tracing" >}}) diff --git a/src/translated_content/zh_CN/docs/operations/observability/tracing/setup-tracing.md b/src/translated_content/zh_CN/docs/operations/observability/tracing/setup-tracing.md new file mode 100644 index 000000000..221c7bc04 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/tracing/setup-tracing.md @@ -0,0 +1,77 @@ +--- +type: docs +title: "配置 Dapr 发送分布式追踪数据" +linkTitle: "配置追踪" +weight: 30 +description: "设置 Dapr 发送分布式追踪数据" +--- + +{{% alert title="注意" color="primary" %}} +建议在任何生产环境中启用 Dapr 的追踪功能。您可以根据运行环境配置 Dapr,将追踪和遥测数据发送到多种可观测性工具,无论是在云端还是本地。 +{{% /alert %}} + +## 配置 + +在 `Configuration` 规范中的 `tracing` 部分包含以下属性: + +```yml +spec: + tracing: + samplingRate: "1" + otel: + endpointAddress: "myendpoint.cluster.local:4317" + zipkin: + endpointAddress: "https://..." +``` + +下表列出了追踪的属性: + +| 属性 | 类型 | 描述 | +|---------------------|--------|------| +| `samplingRate` | string | 设置追踪的采样率来启用或禁用追踪。 | +| `stdout` | bool | 如果为真,则会将更详细的信息写入追踪。 | +| `otel.endpointAddress` | string | 设置 Open Telemetry (OTEL) 目标主机名和可选端口。如果使用此项,则无需指定 'zipkin' 部分。 | +| `otel.isSecure` | bool | 指定连接到端点地址的连接是否加密。 | +| `otel.protocol` | string | 设置为 `http` 或 `grpc` 协议。 | +| `zipkin.endpointAddress` | string | 设置 Zipkin 服务器 URL。如果使用此项,则无需指定 `otel` 部分。 | + +要启用追踪,请使用配置文件(在 selfhost 模式下)或 Kubernetes 配置对象(在 Kubernetes 模式下)。例如,以下配置对象将采样率设置为 1(每个 span 都被采样),并使用 OTEL 协议将追踪发送到本地的 OTEL 服务器 localhost:4317。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: tracing +spec: + tracing: + samplingRate: "1" + otel: + endpointAddress: "localhost:4317" + isSecure: false + protocol: grpc +``` + +## 采样率 + +Dapr 使用概率采样。采样率定义了追踪 span 被采样的概率,值可以在 0 到 1 之间(包括 0 和 1)。默认采样率为 0.0001(即每 10,000 个 span 中采样 1 个)。 + +将 `samplingRate` 设置为 0 将完全禁用追踪。 + +## 环境变量 + +OpenTelemetry (otel) 端点也可以通过环境变量进行配置。设置 OTEL_EXPORTER_OTLP_ENDPOINT 环境变量将为 sidecar 启用追踪。 + +| 环境变量 | 描述 | +|------------------------------|------| +| `OTEL_EXPORTER_OTLP_ENDPOINT` | 设置 Open Telemetry (OTEL) 服务器主机名和可选端口,启用追踪 | +| `OTEL_EXPORTER_OTLP_INSECURE` | 将连接设置为未加密(true/false) | +| `OTEL_EXPORTER_OTLP_PROTOCOL` | 传输协议(`grpc`、`http/protobuf`、`http/json`) | + +## 下一步 + +了解如何使用以下工具之一设置追踪: +- [OTEL Collector]({{< ref otel-collector >}}) +- [New Relic]({{< ref newrelic.md >}}) +- [Jaeger]({{< ref open-telemetry-collector-jaeger.md >}}) +- [Zipkin]({{< ref zipkin.md >}}) +- [Datadog]({{< ref datadog.md >}}) diff --git a/src/translated_content/zh_CN/docs/operations/observability/tracing/tracing-overview.md b/src/translated_content/zh_CN/docs/operations/observability/tracing/tracing-overview.md new file mode 100644 index 000000000..9d04086f4 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/tracing/tracing-overview.md @@ -0,0 +1,118 @@ +--- +type: docs +title: "分布式追踪概述" +linkTitle: "概述" +weight: 10 +description: "使用追踪技术获取应用程序可见性的概述" +--- + +Dapr 通过 Open Telemetry (OTEL) 和 Zipkin 协议来实现分布式追踪。OTEL 是行业标准,并且是推荐使用的追踪协议。 + +大多数可观测性工具支持 OTEL,包括: +- [Google Cloud Operations](https://cloud.google.com/products/operations) +- [AWS X-ray](https://aws.amazon.com/xray/) +- [New Relic](https://newrelic.com) +- [Azure Monitor](https://azure.microsoft.com/services/monitor/) +- [Datadog](https://www.datadoghq.com) +- [Zipkin](https://zipkin.io/) +- [Jaeger](https://www.jaegertracing.io/) +- [SignalFX](https://www.signalfx.com/) + +下图展示了 Dapr(使用 OTEL 和 Zipkin 协议)如何与多个可观测性工具集成。 + +Dapr 的分布式追踪 + +## 场景 + +追踪用于服务调用和发布/订阅(pubsub)API。您可以在使用这些 API 的服务之间传递追踪上下文。追踪的使用有两种场景: + +1. Dapr 生成追踪上下文,您将追踪上下文传递到另一个服务。 +2. 您生成追踪上下文,Dapr 将追踪上下文传递到服务。 + +### 场景 1:Dapr 生成追踪上下文头 + +#### 顺序服务调用的传递 + +Dapr 负责创建追踪头。然而,当有两个以上的服务时,您需要负责在它们之间传递追踪头。让我们通过示例来了解这些场景: + +##### 单一服务调用 + +例如,`服务 A -> 服务 B`。 + +Dapr 在 `服务 A` 中生成追踪头,然后从 `服务 A` 传递到 `服务 B`。不需要进一步的传递。 + +##### 多个顺序服务调用 + +例如,`服务 A -> 服务 B -> 传递追踪头到 -> 服务 C`,以及其他启用 Dapr 的服务。 + +Dapr 在请求开始时在 `服务 A` 中生成追踪头,然后传递到 `服务 B`。您现在需要负责获取头并将其传递到 `服务 C`,因为这与您的应用程序特定相关。 + +换句话说,如果应用程序调用 Dapr 并希望使用现有的追踪头(span)进行追踪,它必须始终传递到 Dapr(在此示例中,从 `服务 B` 到 `服务 C`)。Dapr 始终将追踪 span 传递到应用程序。 + +{{% alert title="注意" color="primary" %}} +Dapr SDK 中没有公开的辅助方法来传递和检索追踪上下文。您需要使用 HTTP/gRPC 客户端通过 HTTP 头和 gRPC 元数据传递和检索追踪头。 +{{% /alert %}} + +##### 请求来自外部端点 + +例如,`从网关服务到启用 Dapr 的服务 A`。 + +外部网关入口调用 Dapr,Dapr 生成追踪头并调用 `服务 A`。`服务 A` 然后调用 `服务 B` 和其他启用 Dapr 的服务。 + +您必须从 `服务 A` 传递头到 `服务 B`。例如:`入口 -> 服务 A -> 传递追踪头 -> 服务 B`。这类似于[案例 2]({{< ref "tracing-overview.md#multiple-sequential-service-invocation-calls" >}})。 + +##### 发布/订阅消息 + +Dapr 在发布的消息主题中生成追踪头。对于 `rawPayload` 消息,可以指定 `traceparent` 头以传递追踪信息。这些追踪头会传递到任何监听该主题的服务。 + +#### 多个不同服务调用的传递 + +在以下场景中,Dapr 为您完成了一些工作,您需要创建或传递追踪头。 + +##### 从单个服务调用多个不同的服务 + +当您从单个服务调用多个服务时,您需要传递追踪头。例如: + +``` +服务 A -> 服务 B +[ .. 一些代码逻辑 ..] +服务 A -> 服务 C +[ .. 一些代码逻辑 ..] +服务 A -> 服务 D +[ .. 一些代码逻辑 ..] +``` + +在这种情况下: +1. 当 `服务 A` 首次调用 `服务 B` 时,Dapr 在 `服务 A` 中生成追踪头。 +1. `服务 A` 中的追踪头被传递到 `服务 B`。 +1. 这些追踪头作为响应头的一部分在 `服务 B` 的响应中返回。 +1. 然后,您需要将返回的追踪上下文传递到下一个服务,如 `服务 C` 和 `服务 D`,因为 Dapr 不知道您想要重用相同的头。 + +### 场景 2:您从非 Dapr 化应用程序生成自己的追踪上下文头 + +生成您自己的追踪上下文头较为少见,并且在调用 Dapr 时通常不需要。 + +然而,在某些场景中,您可能会特别选择在服务调用中添加 W3C 追踪头。例如,您有一个不使用 Dapr 的现有应用程序。在这种情况下,Dapr 仍然为您传递追踪上下文头。 + +如果您决定自己生成追踪头,可以通过三种方式完成: + +1. 标准 OpenTelemetry SDK + + 您可以使用行业标准的 [OpenTelemetry SDKs](https://opentelemetry.io/docs/instrumentation/) 生成追踪头,并将这些追踪头传递到启用 Dapr 的服务。_这是首选方法_。 + +1. 供应商 SDK + + 您可以使用提供生成 W3C 追踪头的方法的供应商 SDK,并将其传递到启用 Dapr 的服务。 + +1. W3C 追踪上下文 + + 您可以根据 [W3C 追踪上下文规范](https://www.w3.org/TR/trace-context/) 手工制作追踪上下文,并将其传递到启用 Dapr 的服务。 + + 阅读 [追踪上下文概述]({{< ref w3c-tracing-overview >}}) 以获取有关 W3C 追踪上下文和头的更多背景和示例。 + +## 相关链接 + +- [可观测性概念]({{< ref observability-concept.md >}}) +- [用于分布式追踪的 W3C 追踪上下文]({{< ref w3c-tracing-overview >}}) +- [W3C 追踪上下文规范](https://www.w3.org/TR/trace-context/) +- [可观测性快速入门](https://github.com/dapr/quickstarts/tree/master/tutorials/observability) diff --git a/src/translated_content/zh_CN/docs/operations/observability/tracing/w3c-tracing-overview.md b/src/translated_content/zh_CN/docs/operations/observability/tracing/w3c-tracing-overview.md new file mode 100644 index 000000000..b03e457fc --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/tracing/w3c-tracing-overview.md @@ -0,0 +1,92 @@ +--- +type: docs +title: "W3C 跟踪上下文概述" +linkTitle: "W3C 跟踪上下文" +weight: 20 +description: 了解如何在 Dapr 中使用 W3C 跟踪上下文和头信息进行分布式跟踪 +--- + +Dapr 采用 [Open Telemetry 协议](https://opentelemetry.io/),该协议利用 [W3C 跟踪上下文](https://www.w3.org/TR/trace-context/) 来实现服务调用和发布/订阅消息的分布式跟踪。Dapr 生成并传播跟踪上下文信息,可以将其发送到可观测性工具进行可视化和查询。 + +## 背景 + +分布式跟踪是一种由跟踪工具实现的方法,用于跟踪、分析和调试跨多个软件组件的事务。 + +通常,分布式跟踪会跨越多个服务,因此需要一个唯一的标识符来标识每个事务。**跟踪上下文传播**就是传递这种唯一标识符的过程。 + +过去,不同的跟踪供应商各自实现自己的跟踪上下文传播方式。在多供应商环境中,这会导致互操作性的问题,例如: + +- 不同供应商收集的跟踪数据无法关联,因为没有共享的唯一标识符。 +- 跨越不同供应商边界的跟踪无法传播,因为没有统一的标识符集。 +- 中间商可能会丢弃供应商特定的元数据。 +- 云平台供应商、中间商和服务提供商无法保证支持跟踪上下文传播,因为没有标准可循。 + +以前,大多数应用程序由单一的跟踪供应商监控,并保持在单一平台提供商的边界内,因此这些问题没有显著影响。 + +如今,越来越多的应用程序是分布式的,并利用多个中间件服务和云平台。这种现代应用程序的转变需要一个分布式跟踪上下文传播标准。 + +[W3C 跟踪上下文规范](https://www.w3.org/TR/trace-context/) 定义了一种通用格式,用于交换跟踪上下文数据(称为跟踪上下文)。通过提供以下内容,跟踪上下文解决了上述问题: + +- 为单个跟踪和请求提供唯一标识符,允许将多个供应商的跟踪数据链接在一起。 +- 提供一种机制来转发供应商特定的跟踪数据,避免在单个事务中多个跟踪工具参与时出现断裂的跟踪。 +- 一个中间商、平台和硬件供应商可以支持的行业标准。 + +这种统一的跟踪数据传播方法提高了对分布式应用程序行为的可见性,促进了问题和性能分析。 + +## W3C 跟踪上下文和头格式 + +### W3C 跟踪上下文 + +Dapr 使用标准的 W3C 跟踪上下文头。 + +- 对于 HTTP 请求,Dapr 使用 `traceparent` 头。 +- 对于 gRPC 请求,Dapr 使用 `grpc-trace-bin` 头。 + +当请求到达时没有跟踪 ID,Dapr 会创建一个新的。否则,它会沿调用链传递跟踪 ID。 + +### W3C 跟踪头 + +这些是 Dapr 为 HTTP 和 gRPC 生成和传播的特定跟踪上下文头。 + +{{< tabs "HTTP" "gRPC" >}} + +{{% codetab %}} + +在从 HTTP 响应传播跟踪上下文头到 HTTP 请求时复制这些头: + +**Traceparent 头** + +Traceparent 头以所有供应商都能理解的通用格式表示跟踪系统中的传入请求: + +``` +traceparent: 00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01 +``` + +[了解更多关于 traceparent 字段的详细信息](https://www.w3.org/TR/trace-context/#traceparent-header)。 + +**Tracestate 头** + +Tracestate 头以可能是供应商特定的格式包含父级: + +``` +tracestate: congo=t61rcWkgMzE +``` + +[了解更多关于 tracestate 字段的详细信息](https://www.w3.org/TR/trace-context/#tracestate-header)。 + +{{% /codetab %}} + + + +{{% codetab %}} + +在 gRPC API 调用中,跟踪上下文通过 `grpc-trace-bin` 头传递。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 相关链接 + +- [了解更多关于 Dapr 中的分布式跟踪]({{< ref tracing-overview.md >}}) +- [W3C 跟踪上下文规范](https://www.w3.org/TR/trace-context/) diff --git a/src/translated_content/zh_CN/docs/operations/observability/tracing/zipkin.md b/src/translated_content/zh_CN/docs/operations/observability/tracing/zipkin.md new file mode 100644 index 000000000..f1a8b3b32 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/observability/tracing/zipkin.md @@ -0,0 +1,111 @@ +--- +type: docs +title: "操作指南:设置 Zipkin 进行分布式追踪" +linkTitle: "Zipkin" +weight: 4000 +description: "设置 Zipkin 进行分布式追踪" +--- + +## 配置自托管模式 + +在自托管模式下,运行 `dapr init` 时: + +1. 系统会默认创建一个 YAML 文件,路径为 `$HOME/.dapr/config.yaml`(Linux/Mac)或 `%USERPROFILE%\.dapr\config.yaml`(Windows)。在执行 `dapr run` 时,系统会默认引用该文件,除非您指定了其他配置: + +* config.yaml + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: daprConfig + namespace: default +spec: + tracing: + samplingRate: "1" + zipkin: + endpointAddress: "http://localhost:9411/api/v2/spans" +``` + +2. 运行 `dapr init` 时,[openzipkin/zipkin](https://hub.docker.com/r/openzipkin/zipkin/) 的 Docker 容器会自动启动。您也可以手动启动: + +使用 Docker 启动 Zipkin: + +```bash +docker run -d -p 9411:9411 openzipkin/zipkin +``` + +3. 使用 `dapr run` 启动应用程序时,默认会引用 `$HOME/.dapr/config.yaml` 或 `%USERPROFILE%\.dapr\config.yaml` 中的配置文件。您可以通过 Dapr CLI 的 `--config` 参数来指定其他配置: + +```bash +dapr run --app-id mynode --app-port 3000 node app.js +``` + +### 查看追踪 + +要查看追踪数据,请在浏览器中访问 http://localhost:9411,您将看到 Zipkin 的用户界面。 + +## 配置 Kubernetes + +以下步骤将指导您如何配置 Dapr,将分布式追踪数据发送到 Kubernetes 集群中的 Zipkin 容器,并查看这些数据。 + +### 设置 + +首先,部署 Zipkin: + +```bash +kubectl create deployment zipkin --image openzipkin/zipkin +``` + +为 Zipkin pod 创建一个 Kubernetes 服务: + +```bash +kubectl expose deployment zipkin --type ClusterIP --port 9411 +``` + +接下来,在本地创建以下 YAML 文件: + +* tracing.yaml 配置 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: tracing + namespace: default +spec: + tracing: + samplingRate: "1" + zipkin: + endpointAddress: "http://zipkin.default.svc.cluster.local:9411/api/v2/spans" +``` + +现在,部署 Dapr 配置文件: + +```bash +kubectl apply -f tracing.yaml +``` + +要在 Dapr sidecar 中启用此配置,请在 pod 规范模板中添加以下注释: + +```yml +annotations: + dapr.io/config: "tracing" +``` + +完成!您的 sidecar 现在已配置为将追踪数据发送到 Zipkin。 + +### 查看追踪数据 + +要查看追踪数据,请连接到 Zipkin 服务并打开用户界面: + +```bash +kubectl port-forward svc/zipkin 9411:9411 +``` + +在浏览器中,访问 `http://localhost:9411`,您将看到 Zipkin 的用户界面。 + +![zipkin](/images/zipkin_ui.png) + +## 参考资料 +- [Zipkin 用于分布式追踪](https://zipkin.io/) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/performance-and-scalability/_index.md b/src/translated_content/zh_CN/docs/operations/performance-and-scalability/_index.md new file mode 100644 index 000000000..3cb35a329 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/performance-and-scalability/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "Dapr 的性能与扩展性概述" +linkTitle: "性能与扩展性" +weight: 700 +description: "Dapr 组件的性能测试与使用指南" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/performance-and-scalability/perf-actors-activation.md b/src/translated_content/zh_CN/docs/operations/performance-and-scalability/perf-actors-activation.md new file mode 100644 index 000000000..39a69a270 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/performance-and-scalability/perf-actors-activation.md @@ -0,0 +1,58 @@ +--- +type: docs +title: "actor 性能激活" +linkTitle: "actor 性能激活" +weight: 20000 +description: "" +--- + +本文介绍了在 Kubernetes 上 Dapr 中 actor 的服务调用 API 的性能基准和资源使用情况。 + +## 系统概述 + +在 Dapr 中使用 actor 的应用程序需要考虑两个方面。首先,actor 调用的路由由 Dapr 的边车(sidecar)处理。其次,actor 的运行时在应用程序端实现和处理,这依赖于所使用的 SDK。目前,性能测试使用 Java SDK 在应用程序中提供 actor 运行时。 + +### Kubernetes 组件 + +* 边车(数据平面) +* Placement(actor 所需,控制平面将 actor 类型映射到主机) +* Operator(控制平面) +* 边车注入器(控制平面) +* Sentry(可选,控制平面) + +## Dapr v1.0 的性能总结 + +Dapr 边车中的 actor API 负责识别注册了特定 actor 类型的主机,并将请求路由到拥有该 actor ID 的合适主机。主机运行应用程序的一个实例,并使用 Dapr SDK(.Net、Java、Python 或 PHP)通过 HTTP 处理 actor 请求。 + +本次测试通过 Dapr 的 HTTP API 直接调用 actor。 + +有关更多信息,请参见 [actor 概述]({{< ref actors-overview.md >}})。 + +### Kubernetes 性能测试设置 + +测试在一个由 3 个节点组成的 Kubernetes 集群上进行,使用普通硬件,每个节点配备 4 核 CPU 和 8GB RAM,没有网络加速。 +设置包括一个负载测试器([Fortio](https://github.com/fortio/fortio))pod,其中注入了一个 Dapr 边车,调用服务 API 以访问不同节点上的 pod。 + +测试参数: + +* 每秒 500 个请求 +* 1 个副本 +* 持续 1 分钟 +* 边车限制为 0.5 vCPU +* 启用 mTLS +* 启用边车遥测(采样率为 0.1 的跟踪) +* 空 JSON 对象的负载:`{}` + +### 结果 + +* 实际吞吐量约为 500 qps。 +* tp90 延迟约为 3ms。 +* tp99 延迟约为 6.2ms。 +* Dapr 应用程序消耗约 523m CPU 和约 304.7Mb 内存 +* Dapr 边车消耗 2m CPU 和约 18.2Mb 内存 +* 无应用程序重启 +* 无边车重启 + +## 相关链接 + +* 有关更多信息,请参见 [Kubernetes 上的 Dapr 概述]({{< ref kubernetes-overview.md >}}) diff --git a/src/translated_content/zh_CN/docs/operations/performance-and-scalability/perf-service-invocation.md b/src/translated_content/zh_CN/docs/operations/performance-and-scalability/perf-service-invocation.md new file mode 100644 index 000000000..3b056adeb --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/performance-and-scalability/perf-service-invocation.md @@ -0,0 +1,93 @@ +--- +type: docs +title: "服务调用性能" +linkTitle: "服务调用性能" +weight: 10000 +description: "" +--- + +本文提供了在不同托管环境中运行Dapr所需组件的服务调用API性能基准和资源利用率。 + +## 系统概述 + +Dapr由两个主要部分组成:数据平面和控制平面。数据平面是运行在应用程序旁边的sidecar,而控制平面负责配置sidecar并提供证书和身份管理等功能。 + +### 自托管组件 + +* sidecar(数据平面) +* Sentry(可选,控制平面) +* Placement(可选,控制平面) + +更多信息请参见[Dapr自托管模式概述]({{< ref self-hosted-overview.md >}})。 + +### Kubernetes组件 + +* sidecar(数据平面) +* Sentry(可选,控制平面) +* Placement(可选,控制平面) +* Operator(控制平面) +* sidecar注入器(控制平面) + +更多信息请参见[Dapr在Kubernetes上的概述]({{< ref kubernetes-overview.md >}})。 + +## Dapr v1.0的性能总结 + +服务调用API是一个反向代理,内置了服务发现功能,用于连接其他服务。这包括跟踪、指标、用于流量传输加密的mTLS,以及通过重试网络分区和连接错误来实现的弹性。 + +通过服务调用,您可以实现从HTTP到HTTP、HTTP到gRPC、gRPC到HTTP和gRPC到gRPC的调用。Dapr在sidecar之间的通信中始终使用gRPC,但保留了应用程序调用时使用的协议语义。服务调用是与Dapr actor通信的底层机制。 + +更多信息请参见[服务调用概述]({{< ref service-invocation-overview.md >}})。 + +### Kubernetes性能测试设置 + +测试在一个3节点的Kubernetes集群上进行,使用普通硬件,每个节点配备4核CPU和8GB RAM,没有任何网络加速。 +设置包括一个负载测试器([Fortio](https://github.com/fortio/fortio))pod,其中注入了一个Dapr sidecar,调用服务调用API以到达不同节点上的pod。 + +测试参数: + +* 每秒1000个请求 +* sidecar限制为0.5 vCPU +* 启用sidecar mTLS +* 启用sidecar遥测(采样率为0.1的跟踪) +* 1KB的负载 + +基准测试包括直接、未加密的流量,没有遥测,直接从负载测试器到目标应用程序。 + +### 控制平面性能 + +Dapr控制平面在非高可用模式下运行时使用总共0.009 vCPU和61.6 Mb,这意味着每个系统组件只有一个副本。 +在高可用生产设置中运行时,Dapr控制平面消耗约0.02 vCPU和185 Mb。 + +| 组件 | vCPU | 内存 +| ------------- | ------------- | ------------- +| Operator | 0.001 | 12.5 Mb +| Sentry | 0.005 | 13.6 Mb +| sidecar注入器 | 0.002 | 14.6 Mb +| Placement | 0.001 | 20.9 Mb + +有许多因素会影响每个系统组件的CPU和内存消耗。这些因素在下表中显示。 + +| 组件 | vCPU | 内存 +| ------------- | ------------- | ------------------------ +| Operator | 请求组件、配置和订阅的pod数量 | +| Sentry | 证书请求数量 | +| sidecar注入器 | 准入请求数量 | +| Placement | actor重新平衡操作数量 | 连接的actor主机数量 + +### 数据平面性能 + +Dapr sidecar每秒处理1000个请求时使用0.48 vCPU和23Mb内存。 +在端到端的调用中,Dapr sidecar(客户端和服务器)在第90百分位延迟中增加约1.40 ms,在第99百分位延迟中增加约2.10 ms。端到端是指从一个应用程序发出请求到另一个应用程序接收响应的全过程。这在[此图]({{< ref service-invocation-overview.md >}})的步骤1-7中显示。 + +这种性能与常用的服务网格相当或更好。 + +### 延迟 + +在测试设置中,请求通过Dapr sidecar在客户端(从负载测试工具服务请求)和服务器端(目标应用程序)进行。 +在Dapr测试中启用了mTLS和遥测(采样率为0.1的跟踪)和指标,而在基准测试中禁用了这些功能。 + +第90百分位延迟 + +
+ +第99百分位延迟 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/resiliency/_index.md b/src/translated_content/zh_CN/docs/operations/resiliency/_index.md new file mode 100644 index 000000000..e142f1a07 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/resiliency/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "通过弹性策略实现错误恢复" +linkTitle: "系统弹性" +weight: 550 +description: "了解如何配置和定制 Dapr 的错误重试、超时设置和断路保护机制" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/resiliency/health-checks/_index.md b/src/translated_content/zh_CN/docs/operations/resiliency/health-checks/_index.md new file mode 100644 index 000000000..4132df3b4 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/resiliency/health-checks/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "健康检查" +linkTitle: "健康检查" +weight: 400 +description: "如何为Dapr sidecar及您的应用程序进行健康检查设置" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/resiliency/health-checks/app-health.md b/src/translated_content/zh_CN/docs/operations/resiliency/health-checks/app-health.md new file mode 100644 index 000000000..05b0d234a --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/resiliency/health-checks/app-health.md @@ -0,0 +1,169 @@ +--- +type: docs +title: "应用健康检查" +linkTitle: "应用健康检查" +weight: 100 +description: 响应应用健康状态的变化 +--- + +应用健康检查功能可以检测应用程序的健康状况,并对状态变化做出反应。 + +应用程序可能由于多种原因变得无响应。例如,您的应用程序: +- 可能太忙而无法接受新工作; +- 可能已崩溃;或 +- 可能处于死锁状态。 + +有时这种情况可能是暂时的,例如: +- 如果应用程序只是忙碌,最终会恢复接受新工作 +- 如果应用程序因某种原因正在重启并处于初始化阶段 + +应用健康检查默认情况下是禁用的。一旦启用,Dapr 运行时(sidecar)会通过 HTTP 或 gRPC 调用定期轮询您的应用程序。当检测到应用程序的健康状况出现问题时,Dapr 会通过以下方式暂停接受新工作: + +- 取消所有 pub/sub 订阅 +- 停止所有输入绑定 +- 短路所有服务调用请求,这些请求在 Dapr 运行时终止,不会转发到应用程序 + +这些变化是暂时的,一旦 Dapr 检测到应用程序恢复响应,它将恢复正常操作。 + +显示应用健康功能的图示。启用应用健康的 Dapr 运行时会定期探测应用程序的健康状况。 + +## 应用健康检查与平台级健康检查 + +Dapr 的应用健康检查旨在补充而不是替代任何平台级健康检查,例如在 Kubernetes 上运行时的[存活探针](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/)。 + +平台级健康检查(或存活探针)通常确保应用程序正在运行,并在出现故障时导致平台重启应用程序。 + +与平台级健康检查不同,Dapr 的应用健康检查专注于暂停当前无法接受工作的应用程序,但预计最终能够恢复接受工作。目标包括: + +- 不给已经超载的应用程序带来更多负担。 +- 当 Dapr 知道应用程序无法处理消息时,不从队列、绑定或 pub/sub 代理中获取消息。 + +在这方面,Dapr 的应用健康检查是“较软”的,等待应用程序能够处理工作,而不是以“硬”方式终止正在运行的进程。 + +{{% alert title="注意" color="primary" %}} +对于 Kubernetes,失败的应用健康检查不会将 pod 从服务发现中移除:这仍然是 Kubernetes 存活探针的责任,而不是 Dapr。 +{{% /alert %}} + +## 配置应用健康检查 + +应用健康检查默认情况下是禁用的,但可以通过以下方式启用: + +- `--enable-app-health-check` CLI 标志;或 +- 在 Kubernetes 上运行时使用 `dapr.io/enable-app-health-check: true` 注释。 + +添加此标志是启用应用健康检查的必要且充分条件,使用默认选项。 + +完整的选项列表如下表所示: + +| CLI 标志 | Kubernetes 部署注释 | 描述 | 默认值 | +| ----------------------------- | ----------------------------------- | ----------- | ------------- | +| `--enable-app-health-check` | `dapr.io/enable-app-health-check` | 启用健康检查的布尔值 | 禁用 | +| [`--app-health-check-path`]({{< ref "app-health.md#health-check-paths" >}}) | `dapr.io/app-health-check-path` | 当应用通道为 HTTP 时,Dapr 用于健康探测的路径(如果应用通道使用 gRPC,则忽略此值) | `/healthz` | +| [`--app-health-probe-interval`]({{< ref "app-health.md#intervals-timeouts-and-thresholds" >}}) | `dapr.io/app-health-probe-interval` | 每次健康探测之间的*秒数* | `5` | +| [`--app-health-probe-timeout`]({{< ref "app-health.md#intervals-timeouts-and-thresholds" >}}) | `dapr.io/app-health-probe-timeout` | 健康探测请求的超时时间(以*毫秒*为单位) | `500` | +| [`--app-health-threshold`]({{< ref "app-health.md#intervals-timeouts-and-thresholds" >}}) | `dapr.io/app-health-threshold` | 在应用被视为不健康之前的最大连续失败次数 | `3` | + +> 请参阅[完整的 Dapr 参数和注释参考]({{< ref arguments-annotations-overview >}})以获取所有选项及其启用方法。 + +此外,应用健康检查受应用通道使用的协议影响,该协议通过以下标志或注释进行配置: + +| CLI 标志 | Kubernetes 部署注释 | 描述 | 默认值 | +| ----------------------------- | ----------------------------------- | ----------- | ------------- | +| [`--app-protocol`]({{< ref "app-health.md#health-check-paths" >}}) | `dapr.io/app-protocol` | 应用通道使用的协议。支持的值有 `http`、`grpc`、`https`、`grpcs` 和 `h2c`(HTTP/2 明文)。 | `http` | + +{{% alert title="注意" color="primary" %}} +如果应用健康探测超时值过低,可能会在应用程序遇到突然高负载时将其分类为不健康,导致响应时间下降。如果发生这种情况,请增加 `dapr.io/app-health-probe-timeout` 值。 +{{% /alert %}} + +### 健康检查路径 + +#### HTTP +当使用 HTTP(包括 `http`、`https` 和 `h2c`)作为 `app-protocol` 时,Dapr 通过对 `app-health-check-path` 指定的路径进行 HTTP 调用来执行健康探测,默认路径为 `/health`。 + +为了使您的应用被视为健康,响应必须具有 200-299 范围内的 HTTP 状态码。任何其他状态码都被视为失败。Dapr 只关心响应的状态码,忽略任何响应头或正文。 + +#### gRPC +当使用 gRPC 作为应用通道(`app-protocol` 设置为 `grpc` 或 `grpcs`)时,Dapr 在您的应用程序中调用方法 `/dapr.proto.runtime.v1.AppCallbackHealthCheck/HealthCheck`。您很可能会使用 Dapr SDK 来实现此方法的处理程序。 + +在响应健康探测请求时,您的应用*可以*决定执行额外的内部健康检查,以确定它是否准备好处理来自 Dapr 运行时的工作。然而,这不是必需的;这取决于您的应用程序的需求。 + +### 间隔、超时和阈值 + +#### 间隔 +默认情况下,当启用应用健康检查时,Dapr 每 5 秒探测一次您的应用程序。您可以使用 `app-health-probe-interval` 配置间隔(以秒为单位)。这些探测会定期发生,无论您的应用程序是否健康。 + +#### 超时 +当 Dapr 运行时(sidecar)最初启动时,Dapr 会等待成功的健康探测,然后才认为应用程序是健康的。这意味着在第一次健康检查完成并成功之前,pub/sub 订阅、输入绑定和服务调用请求不会为您的应用程序启用。 + +如果应用程序在 `app-health-probe-timeout` 中配置的超时内发送成功响应(如上所述),则健康探测请求被视为成功。默认值为 500,对应于 500 毫秒(半秒)。 + +#### 阈值 +在 Dapr 认为应用程序进入不健康状态之前,它将等待 `app-health-threshold` 次连续失败,默认值为 3。此默认值意味着您的应用程序必须连续失败健康探测 3 次*才能*被视为不健康。 + +如果您将阈值设置为 1,任何失败都会导致 Dapr 假设您的应用程序不健康,并停止向其传递工作。 + +大于 1 的阈值可以帮助排除由于外部情况导致的瞬态故障。适合您的应用程序的正确值取决于您的要求。 + +阈值仅适用于失败。单个成功响应足以让 Dapr 认为您的应用程序是健康的,并恢复正常操作。 + +## 示例 + +{{< tabs "Self-Hosted (CLI)" Kubernetes >}} + +{{% codetab %}} + +使用 `dapr run` 命令的 CLI 标志启用应用健康检查: + +```sh +dapr run \ + --app-id my-app \ + --app-port 7001 \ + --app-protocol http \ + --enable-app-health-check \ + --app-health-check-path=/healthz \ + --app-health-probe-interval 3 \ + --app-health-probe-timeout 200 \ + --app-health-threshold 2 \ + -- \ + +``` + +{{% /codetab %}} + +{{% codetab %}} + +要在 Kubernetes 中启用应用健康检查,请将相关注释添加到您的 Deployment: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-app + labels: + app: my-app +spec: + template: + metadata: + labels: + app: my-app + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "my-app" + dapr.io/app-port: "7001" + dapr.io/app-protocol: "http" + dapr.io/enable-app-health-check: "true" + dapr.io/app-health-check-path: "/healthz" + dapr.io/app-health-probe-interval: "3" + dapr.io/app-health-probe-timeout: "200" + dapr.io/app-health-threshold: "2" +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 演示 + +观看此视频以获取[使用应用健康检查的概述](https://youtu.be/srczBuOsAkI?t=533): + + \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/resiliency/health-checks/sidecar-health.md b/src/translated_content/zh_CN/docs/operations/resiliency/health-checks/sidecar-health.md new file mode 100644 index 000000000..c6f237198 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/resiliency/health-checks/sidecar-health.md @@ -0,0 +1,145 @@ +--- +type: docs +title: "Sidecar 健康检查" +linkTitle: "Sidecar 健康检查" +weight: 200 +description: Dapr sidecar 健康检查 +--- + +Dapr 提供了一种方法,通过 [HTTP `/healthz` 端点]({{< ref health_api.md >}}) 来确定其健康状态。通过这个端点,*daprd* 进程或 sidecar 可以: + +- 检查整体健康状况 +- 在初始化期间确认 Dapr sidecar 的就绪状态 +- 在 Kubernetes 中确定就绪和存活状态 + +在本指南中,您将了解 Dapr `/healthz` 端点如何与应用托管平台(如 Kubernetes)以及 Dapr SDK 的健康检查功能集成。 + +{{% alert title="注意" color="primary" %}} +Dapr actor 也有一个健康 API 端点,Dapr 会探测应用程序以响应 Dapr 发出的信号,确认 actor 应用程序是健康且正在运行的。请参阅 [actor 健康 API]({{< ref "actors_api.md#health-check" >}})。 +{{% /alert %}} + +下图展示了 Dapr sidecar 启动时,healthz 端点和应用通道初始化的步骤。 + +Dapr 检查出站健康连接的图示。 + +## 出站健康端点 + +如上图中的红色边界线所示,`v1.0/healthz/` 端点用于等待以下情况: +- 所有组件已初始化; +- Dapr HTTP 端口可用;_并且,_ +- 应用通道已初始化。 + +这用于确认 Dapr sidecar 的完整初始化及其健康状况。 + +您可以通过设置 `DAPR_HEALTH_TIMEOUT` 环境变量来控制健康检查的超时时间,这在高延迟环境中可能很重要。 + +另一方面,如上图中的绿色边界线所示,当 `v1.0/healthz/outbound` 端点返回成功时: +- 所有组件已初始化; +- Dapr HTTP 端口可用;_但,_ +- 应用通道尚未建立。 + +在 Dapr SDK 中,`waitForSidecar`/`wait_until_ready` 方法(取决于[您使用的 SDK]({{< ref "#sdks-supporting-outbound-health-endpoint" >}}))用于通过 `v1.0/healthz/outbound` 端点进行此特定检查。使用这种方法,您的应用程序可以在应用通道初始化之前调用 Dapr sidecar API,例如,通过 secret API 读取 secret。 + +如果您在 SDK 上使用 `waitForSidecar`/`wait_until_ready` 方法,则会执行正确的初始化。否则,您可以在初始化期间调用 `v1.0/healthz/outbound` 端点,如果成功,您可以调用 Dapr sidecar API。 + +### 支持出站健康端点的 SDK +目前,`v1.0/healthz/outbound` 端点在以下 SDK 中得到支持: +- [.NET SDK]({{< ref "dotnet-client.md#wait-for-sidecar" >}}) +- [Java SDK]({{< ref "java-client.md#wait-for-sidecar" >}}) +- [Python SDK]({{< ref "python-client.md#health-timeout" >}}) +- [JavaScript SDK](https://github.com/dapr/js-sdk/blob/4189a3d2ad6897406abd766f4ccbf2300c8f8852/src/interfaces/Client/IClientHealth.ts#L14) + +## 健康端点:与 Kubernetes 的集成 +当将 Dapr 部署到像 Kubernetes 这样的托管平台时,Dapr 健康端点会自动为您配置。 + +Kubernetes 使用 *就绪* 和 *存活* 探针来确定容器的健康状况。 + +### 存活性 +kubelet 使用存活探针来判断何时需要重启容器。例如,存活探针可以捕获死锁(一个无法进展的运行应用程序)。在这种状态下重启容器可以帮助提高应用程序的可用性,即使存在错误。 + +#### 如何在 Kubernetes 中配置存活探针 + +在 pod 配置文件中,存活探针被添加到容器规范部分,如下所示: + +```yaml + livenessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 3 + periodSeconds: 3 +``` + +在上述示例中,`periodSeconds` 字段指定 kubelet 应每 3 秒执行一次存活探针。`initialDelaySeconds` 字段告诉 kubelet 应在执行第一次探针前等待 3 秒。为了执行探针,kubelet 向在容器中运行并监听端口 8080 的服务器发送 HTTP GET 请求。如果服务器的 `/healthz` 路径的处理程序返回成功代码,kubelet 认为容器是存活且健康的。如果处理程序返回失败代码,kubelet 会杀死容器并重启它。 + +任何介于 200 和 399 之间的 HTTP 状态代码表示成功;任何其他状态代码表示失败。 + +### 就绪性 +kubelet 使用就绪探针来判断容器何时准备好开始接受流量。当所有容器都准备好时,pod 被认为是就绪的。就绪信号的一个用途是控制哪些 pod 被用作 Kubernetes 服务的后端。当 pod 未就绪时,它会从 Kubernetes 服务负载均衡器中移除。 + +{{% alert title="注意" color="primary" %}} +一旦应用程序在其配置的端口上可访问,Dapr sidecar 将处于就绪状态。在应用程序启动/初始化期间,应用程序无法访问 Dapr 组件。 +{{% /alert %}} + +#### 如何在 Kubernetes 中配置就绪探针 + +就绪探针的配置与存活探针类似。唯一的区别是使用 `readinessProbe` 字段而不是 `livenessProbe` 字段: + +```yaml + readinessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 3 + periodSeconds: 3 +``` + +### Sidecar 注入器 + +在与 Kubernetes 集成时,Dapr sidecar 被注入了一个 Kubernetes 探针配置,告诉它使用 Dapr `healthz` 端点。这是由 "Sidecar 注入器" 系统服务完成的。与 kubelet 的集成如下面的图示所示。 + +Dapr 服务交互的图示 + +#### Dapr sidecar 健康端点如何与 Kubernetes 配置 + +如上所述,此配置由 Sidecar 注入器服务自动完成。本节描述了在存活和就绪探针上设置的具体值。 + +Dapr 在端口 3500 上有其 HTTP 健康端点 `/v1.0/healthz`。这可以与 Kubernetes 一起用于就绪和存活探针。当 Dapr sidecar 被注入时,存活和就绪探针在 pod 配置文件中配置为以下值: + +```yaml + livenessProbe: + httpGet: + path: v1.0/healthz + port: 3500 + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds : 5 + failureThreshold : 3 + readinessProbe: + httpGet: + path: v1.0/healthz + port: 3500 + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds : 5 + failureThreshold: 3 +``` + +## 延迟优雅关闭 + +Dapr 提供了一个 [`dapr.io/block-shutdown-duration` 注释或 `--dapr-block-shutdown-duration` CLI 标志]({{< ref arguments-annotations-overview.md >}}),它会延迟完整的关闭过程,直到指定的持续时间,或直到应用报告为不健康,以较早者为准。 + +在此期间,所有订阅和输入绑定都会关闭。这对于需要在其自身关闭过程中使用 Dapr API 的应用程序非常有用。 + +适用的注释或 CLI 标志包括: + +- `--dapr-graceful-shutdown-seconds`/`dapr.io/graceful-shutdown-seconds` +- `--dapr-block-shutdown-duration`/`dapr.io/block-shutdown-duration` + +在 [注释和参数指南]({{< ref arguments-annotations-overview.md >}}) 中了解更多关于这些及其使用方法。 + +## 相关链接 + +- [端点健康 API]({{< ref health_api.md >}}) +- [actor 健康 API]({{< ref "actors_api.md#health-check" >}}) +- [Kubernetes 探针配置参数](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) diff --git a/src/translated_content/zh_CN/docs/operations/resiliency/policies.md b/src/translated_content/zh_CN/docs/operations/resiliency/policies.md new file mode 100644 index 000000000..566c5f8dd --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/resiliency/policies.md @@ -0,0 +1,327 @@ +--- +type: docs +title: "弹性策略" +linkTitle: "策略" +weight: 200 +description: "配置超时、重试和断路器的弹性策略" +--- + +在 `policies` 下定义超时、重试和断路器策略。每个策略都有一个名称,以便您可以在弹性规范的 `targets` 部分中引用它们。 + +> 注意:Dapr 为某些 API 提供默认的重试机制。[请参阅此处]({{< ref "#overriding-default-retries" >}})了解如何使用用户定义的重试策略覆盖默认重试逻辑。 + +## 超时 + +超时是可选策略,用于提前终止长时间运行的操作。如果超过了超时时间: + +- 正在进行的操作将被终止(如果可能)。 +- 返回错误。 + +有效值是 Go 的 [time.ParseDuration](https://pkg.go.dev/time#ParseDuration) 接受的格式,例如:`15s`、`2m`、`1h30m`。超时没有设置最大值。 + +示例: + +```yaml +spec: + policies: + # 超时是简单的命名持续时间。 + timeouts: + general: 5s + important: 60s + largeResponse: 10s +``` + +如果未指定超时值,则策略不会强制执行时间限制,默认使用请求客户端设置的任何值。 + +## 重试 + +通过 `retries`,您可以为失败的操作定义重试策略,包括由于触发定义的超时或断路器策略而失败的请求。 + +{{% alert title="Pub/sub 组件重试与入站弹性" color="warning" %}} +每个 [pub/sub 组件]({{< ref supported-pubsub >}}) 都有其内置的重试行为。显式应用 Dapr 弹性策略不会覆盖这些内置重试机制。相反,重试策略补充了内置重试机制,这可能导致消息的重复聚集。 +{{% /alert %}} + +以下重试选项是可配置的: + +| 重试选项 | 描述 | +| ------------ | ----------- | +| `policy` | 确定退避和重试间隔策略。有效值为 `constant` 和 `exponential`。
默认为 `constant`。 | +| `duration` | 确定重试之间的时间间隔。仅适用于 `constant` 策略。
有效值为 `200ms`、`15s`、`2m` 等格式。
默认为 `5s`。| +| `maxInterval` | 确定 `exponential` 退避策略可以增长到的最大间隔。
额外的重试总是在 `maxInterval` 的持续时间之后发生。默认为 `60s`。有效值为 `5s`、`1m`、`1m30s` 等格式。 | +| `maxRetries` | 尝试的最大重试次数。
`-1` 表示无限次重试,而 `0` 表示请求不会被重试(本质上表现为未设置重试策略)。
默认为 `-1`。 | +| `matching.httpStatusCodes` | 可选:要重试的 HTTP 状态代码或代码范围的逗号分隔字符串。未列出的状态代码不重试。
有效值:100-599,[参考](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
格式:`` 或范围 `-`
示例:"429,501-503"
默认:空字符串 `""` 或字段未设置。重试所有 HTTP 错误。 | +| `matching.gRPCStatusCodes` | 可选:要重试的 gRPC 状态代码或代码范围的逗号分隔字符串。未列出的状态代码不重试。
有效值:0-16,[参考](https://grpc.io/docs/guides/status-codes/)
格式:`` 或范围 `-`
示例:"1,501-503"
默认:空字符串 `""` 或字段未设置。重试所有 gRPC 错误。 | + +{{% alert title="httpStatusCodes 和 gRPCStatusCodes 格式" color="warning" %}} +字段值应遵循字段描述中指定的格式或下面的“示例 2”中的格式。 +格式不正确的值将产生错误日志(“无法读取弹性策略”),并且 `daprd` 启动序列将继续。 +{{% /alert %}} + +指数退避窗口使用以下公式: + +``` +BackOffDuration = PreviousBackOffDuration * (随机值从 0.5 到 1.5) * 1.5 +if BackOffDuration > maxInterval { + BackoffDuration = maxInterval +} +``` + +示例: + +```yaml +spec: + policies: + # 重试是重试配置的命名模板,并在操作的生命周期内实例化。 + retries: + pubsubRetry: + policy: constant + duration: 5s + maxRetries: 10 + + retryForever: + policy: exponential + maxInterval: 15s + maxRetries: -1 # 无限重试 +``` + +示例 2: + +```yaml +spec: + policies: + retries: + retry5xxOnly: + policy: constant + duration: 5s + maxRetries: 3 + matching: + httpStatusCodes: "429,500-599" # 重试此范围内的 HTTP 状态代码。所有其他不重试。 + gRPCStatusCodes: "1-4,8-11,13,14" # 重试这些范围内的 gRPC 状态代码并分隔单个代码。 +``` + +## 断路器 + +断路器(CB)策略用于当其他应用程序/服务/组件经历较高的失败率时。CB 监控请求,并在满足某个条件时关闭所有流向受影响服务的流量(“打开”状态)。通过这样做,CB 给服务时间从其故障中恢复,而不是用事件淹没它。CB 还可以允许部分流量通过,以查看系统是否已恢复(“半开”状态)。一旦请求恢复成功,CB 进入“关闭”状态并允许流量完全恢复。 + +| 重试选项 | 描述 | +| ------------ | ----------- | +| `maxRequests` | 在 CB 半开(从故障中恢复)时允许通过的最大请求数。默认为 `1`。 | +| `interval` | CB 用于清除其内部计数的周期性时间段。如果设置为 0 秒,则永不清除。默认为 `0s`。 | +| `timeout` | 开放状态(直接在故障后)到 CB 切换到半开的时间段。默认为 `60s`。 | +| `trip` | 由 CB 评估的 [通用表达式语言(CEL)](https://github.com/google/cel-spec) 语句。当语句评估为 true 时,CB 触发并变为打开。默认为 `consecutiveFailures > 5`。其他可能的值是 `requests` 和 `totalFailures`,其中 `requests` 表示电路打开之前的成功或失败调用次数,`totalFailures` 表示电路打开之前的总失败尝试次数(不一定是连续的)。示例:`requests > 5` 和 `totalFailures >3`。| + +示例: + +```yaml +spec: + policies: + circuitBreakers: + pubsubCB: + maxRequests: 1 + interval: 8s + timeout: 45s + trip: consecutiveFailures > 8 +``` + +## 覆盖默认重试 + +Dapr 为任何不成功的请求(如失败和瞬态错误)提供默认重试。在弹性规范中,您可以通过定义具有保留名称关键字的策略来覆盖 Dapr 的默认重试逻辑。例如,定义名为 `DaprBuiltInServiceRetries` 的策略,覆盖通过服务到服务请求的 sidecar 之间的失败的默认重试。策略覆盖不适用于特定目标。 + +> 注意:尽管您可以使用更强大的重试覆盖默认值,但您不能使用比提供的默认值更低的值覆盖,或完全删除默认重试。这可以防止意外停机。 + +下面是描述 Dapr 默认重试和覆盖它们的策略关键字的表格: + +| 功能 | 覆盖关键字 | 默认重试行为 | 描述 | +| ------------------ | ------------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------------------- | +| 服务调用 | DaprBuiltInServiceRetries | 每次调用重试以 1 秒的退避间隔执行,最多达到 3 次的阈值。 | sidecar 到 sidecar 请求(服务调用方法调用)失败并导致 gRPC 代码 `Unavailable` 或 `Unauthenticated` | +| actor | DaprBuiltInActorRetries | 每次调用重试以 1 秒的退避间隔执行,最多达到 3 次的阈值。 | sidecar 到 sidecar 请求(actor 方法调用)失败并导致 gRPC 代码 `Unavailable` 或 `Unauthenticated` | +| actor 提醒 | DaprBuiltInActorReminderRetries | 每次调用重试以指数退避执行,初始间隔为 500ms,最多 60s,持续 15 分钟 | 请求失败将 actor 提醒持久化到状态存储 | +| 初始化重试 | DaprBuiltInInitializationRetries | 每次调用重试 3 次,指数退避,初始间隔为 500ms,持续 10s | 向应用程序发出请求以检索给定规范时的失败。例如,无法检索订阅、组件或弹性规范 | + +下面的弹性规范示例显示了使用保留名称关键字 'DaprBuiltInServiceRetries' 覆盖 _所有_ 服务调用请求的默认重试。 + +还定义了一个名为 'retryForever' 的重试策略,仅适用于 appB 目标。appB 使用 'retryForever' 重试策略,而所有其他应用程序服务调用重试失败使用覆盖的 'DaprBuiltInServiceRetries' 默认策略。 + +```yaml +spec: + policies: + retries: + DaprBuiltInServiceRetries: # 覆盖服务到服务调用的默认重试行为 + policy: constant + duration: 5s + maxRetries: 10 + + retryForever: # 用户定义的重试策略替换默认重试。目标仅依赖于应用的策略。 + policy: exponential + maxInterval: 15s + maxRetries: -1 # 无限重试 + + targets: + apps: + appB: # 目标服务的 app-id + retry: retryForever +``` + +## 设置默认策略 + +在弹性中,您可以设置默认策略,这些策略具有广泛的范围。这是通过保留关键字完成的,这些关键字让 Dapr 知道何时应用策略。有 3 种默认策略类型: + +- `DefaultRetryPolicy` +- `DefaultTimeoutPolicy` +- `DefaultCircuitBreakerPolicy` + +如果定义了这些策略,它们将用于服务、应用程序或组件的每个操作。它们还可以通过附加其他关键字进行更具体的修改。特定策略遵循以下模式,`Default%sRetryPolicy`、`Default%sTimeoutPolicy` 和 `Default%sCircuitBreakerPolicy`。其中 `%s` 被策略的目标替换。 + +下面是所有可能的默认策略关键字及其如何转换为策略名称的表格。 + +| 关键字 | 目标操作 | 示例策略名称 | +| -------------------------------- | ---------------------------------------------------- | ----------------------------------------------------------- | +| `App` | 服务调用。 | `DefaultAppRetryPolicy` | +| `Actor` | actor 调用。 | `DefaultActorTimeoutPolicy` | +| `Component` | 所有组件操作。 | `DefaultComponentCircuitBreakerPolicy` | +| `ComponentInbound` | 所有入站组件操作。 | `DefaultComponentInboundRetryPolicy` | +| `ComponentOutbound` | 所有出站组件操作。 | `DefaultComponentOutboundTimeoutPolicy` | +| `StatestoreComponentOutbound` | 所有状态存储组件操作。 | `DefaultStatestoreComponentOutboundCircuitBreakerPolicy` | +| `PubsubComponentOutbound` | 所有出站 pubsub(发布)组件操作。 | `DefaultPubsubComponentOutboundRetryPolicy` | +| `PubsubComponentInbound` | 所有入站 pubsub(订阅)组件操作。 | `DefaultPubsubComponentInboundTimeoutPolicy` | +| `BindingComponentOutbound` | 所有出站绑定(调用)组件操作。 | `DefaultBindingComponentOutboundCircuitBreakerPolicy` | +| `BindingComponentInbound` | 所有入站绑定(读取)组件操作。 | `DefaultBindingComponentInboundRetryPolicy` | +| `SecretstoreComponentOutbound` | 所有 secretstore 组件操作。 | `DefaultSecretstoreComponentTimeoutPolicy` | +| `ConfigurationComponentOutbound` | 所有配置组件操作。 | `DefaultConfigurationComponentOutboundCircuitBreakerPolicy` | +| `LockComponentOutbound` | 所有锁组件操作。 | `DefaultLockComponentOutboundRetryPolicy` | + +### 策略层次结构解析 + +如果正在执行的操作与策略类型匹配,并且没有更具体的策略针对它,则应用默认策略。对于每个目标类型(应用程序、actor 和组件),优先级最高的策略是命名策略,即专门针对该构造的策略。 + +如果不存在,则策略从最具体到最广泛应用。 + +#### 默认策略和内置重试如何协同工作 + +在 [内置重试]({{< ref "policies.md#Override Default Retries" >}}) 的情况下,默认策略不会阻止内置重试策略运行。两者一起使用,但仅在特定情况下。 + +对于服务和 actor 调用,内置重试专门处理连接到远程 sidecar 的问题(如有必要)。由于这些对于 Dapr 运行时的稳定性至关重要,因此它们不会被禁用**除非**为操作专门引用了命名策略。在某些情况下,可能会有来自内置重试和默认重试策略的额外重试,但这可以防止过于弱的默认策略降低 sidecar 的可用性/成功率。 + +应用程序的策略解析层次结构,从最具体到最广泛: + +1. 应用程序目标中的命名策略 +2. 默认应用程序策略 / 内置服务重试 +3. 默认策略 / 内置服务重试 + +actor 的策略解析层次结构,从最具体到最广泛: + +1. actor 目标中的命名策略 +2. 默认 actor 策略 / 内置 actor 重试 +3. 默认策略 / 内置 actor 重试 + +组件的策略解析层次结构,从最具体到最广泛: + +1. 组件目标中的命名策略 +2. 默认组件类型 + 组件方向策略 / 内置 actor 提醒重试(如适用) +3. 默认组件方向策略 / 内置 actor 提醒重试(如适用) +4. 默认组件策略 / 内置 actor 提醒重试(如适用) +5. 默认策略 / 内置 actor 提醒重试(如适用) + +例如,以下解决方案由三个应用程序、三个组件和两个 actor 类型组成: + +应用程序: + +- AppA +- AppB +- AppC + +组件: + +- Redis Pubsub: pubsub +- Redis 状态存储: statestore +- CosmosDB 状态存储: actorstore + +actor: + +- EventActor +- SummaryActor + +下面是使用默认和命名策略的策略,并将其应用于目标。 + +```yaml +spec: + policies: + retries: + # 全局重试策略 + DefaultRetryPolicy: + policy: constant + duration: 1s + maxRetries: 3 + + # 应用程序的全局重试策略 + DefaultAppRetryPolicy: + policy: constant + duration: 100ms + maxRetries: 5 + + # actor 的全局重试策略 + DefaultActorRetryPolicy: + policy: exponential + maxInterval: 15s + maxRetries: 10 + + # 入站组件操作的全局重试策略 + DefaultComponentInboundRetryPolicy: + policy: constant + duration: 5s + maxRetries: 5 + + # 状态存储的全局重试策略 + DefaultStatestoreComponentOutboundRetryPolicy: + policy: exponential + maxInterval: 60s + maxRetries: -1 + + # 命名策略 + fastRetries: + policy: constant + duration: 10ms + maxRetries: 3 + + # 命名策略 + retryForever: + policy: exponential + maxInterval: 10s + maxRetries: -1 + + targets: + apps: + appA: + retry: fastRetries + + appB: + retry: retryForever + + actors: + EventActor: + retry: retryForever + + components: + actorstore: + retry: fastRetries +``` + +下表是尝试调用此解决方案中的各种目标时应用的策略的细分。 + +| 目标 | 使用的策略 | +| ------------------ | ----------------------------------------------- | +| AppA | fastRetries | +| AppB | retryForever | +| AppC | DefaultAppRetryPolicy / DaprBuiltInActorRetries | +| pubsub - 发布 | DefaultRetryPolicy | +| pubsub - 订阅 | DefaultComponentInboundRetryPolicy | +| statestore | DefaultStatestoreComponentOutboundRetryPolicy | +| actorstore | fastRetries | +| EventActor | retryForever | +| SummaryActor | DefaultActorRetryPolicy | + +## 下一步 + +尝试其中一个弹性快速入门: +- [弹性:服务到服务]({{< ref resiliency-serviceinvo-quickstart.md >}}) +- [弹性:状态管理]({{< ref resiliency-state-quickstart.md >}}) diff --git a/src/translated_content/zh_CN/docs/operations/resiliency/resiliency-overview.md b/src/translated_content/zh_CN/docs/operations/resiliency/resiliency-overview.md new file mode 100644 index 000000000..68408f3c9 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/resiliency/resiliency-overview.md @@ -0,0 +1,182 @@ +--- +type: docs +title: "概述" +linkTitle: "概述" +weight: 100 +description: "配置 Dapr 的重试、超时和断路器" +--- + +Dapr 提供了一种通过[弹性规范]({{< ref "resiliency-overview.md#complete-example-policy" >}})来定义和应用容错策略的功能。弹性规范与组件规范存放在同一位置,并在 Dapr sidecar 启动时生效。sidecar 决定如何将这些策略应用于您的 Dapr API 调用。在自托管模式下,弹性规范文件必须命名为 `resiliency.yaml`。在 Kubernetes 中,Dapr 会找到您的应用程序使用的命名弹性规范。在弹性规范中,您可以定义常见的弹性模式策略,例如: + +- [超时]({{< ref "policies.md#timeouts" >}}) +- [重试/退避]({{< ref "policies.md#retries" >}}) +- [断路器]({{< ref "policies.md#circuit-breakers" >}}) + +这些策略可以应用于[目标]({{< ref "targets.md" >}}),包括: + +- 通过服务调用的[应用程序]({{< ref "targets.md#apps" >}}) +- [组件]({{< ref "targets.md#components" >}}) +- [actor]({{< ref "targets.md#actors" >}}) + +此外,弹性策略还可以[限定到特定应用程序]({{< ref "component-scopes.md#application-access-to-components-with-scopes" >}})。 + +## 演示视频 + +了解更多关于[如何使用 Dapr 编写弹性微服务](https://youtu.be/uC-4Q5KFq98?si=JSUlCtcUNZLBM9rW)。 + + + +## 弹性策略结构 + +以下是弹性策略的一般结构: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Resiliency +metadata: + name: myresiliency +scopes: + # 可选地将策略限定到特定应用程序 +spec: + policies: + timeouts: + # 超时策略定义 + + retries: + # 重试策略定义 + + circuitBreakers: + # 断路器策略定义 + + targets: + apps: + # 应用程序及其应用的策略 + + actors: + # actor 类型及其应用的策略 + + components: + # 组件及其应用的策略 +``` + +## 完整示例策略 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Resiliency +metadata: + name: myresiliency +# 类似于订阅和配置规范,scopes 列出了可以使用此弹性规范的 Dapr 应用程序 ID。 +scopes: + - app1 + - app2 +spec: + # policies 是定义超时、重试和断路器策略的地方。 + # 每个策略都有一个名称,以便可以在弹性规范的 targets 部分引用。 + policies: + # 超时是简单的命名持续时间。 + timeouts: + general: 5s + important: 60s + largeResponse: 10s + + # 重试是重试配置的命名模板,并在操作的生命周期内实例化。 + retries: + pubsubRetry: + policy: constant + duration: 5s + maxRetries: 10 + + retryForever: + policy: exponential + maxInterval: 15s + maxRetries: -1 # 无限重试 + + important: + policy: constant + duration: 5s + maxRetries: 30 + + someOperation: + policy: exponential + maxInterval: 15s + + largeResponse: + policy: constant + duration: 5s + maxRetries: 3 + + # 断路器会自动为每个组件和应用实例创建。 + # 断路器维护的计数器在 Dapr sidecar 运行期间存在。它们不会被持久化。 + circuitBreakers: + simpleCB: + maxRequests: 1 + timeout: 30s + trip: consecutiveFailures >= 5 + + pubsubCB: + maxRequests: 1 + interval: 8s + timeout: 45s + trip: consecutiveFailures > 8 + + # targets 是应用命名策略的对象。Dapr 支持 3 种目标类型 - 应用程序、组件和 actor + targets: + apps: + appB: + timeout: general + retry: important + # 服务的断路器是按应用实例限定的。 + # 当断路器被触发时,该路由将从负载均衡中移除,持续配置的 `timeout` 时间。 + circuitBreaker: simpleCB + + actors: + myActorType: # 自定义 actor 类型名称 + timeout: general + retry: important + # actor 的断路器可以按类型、ID 或两者限定。 + # 当断路器被触发时,该类型或 ID 将从配置表中移除,持续配置的 `timeout` 时间。 + circuitBreaker: simpleCB + circuitBreakerScope: both ## + circuitBreakerCacheSize: 5000 + + components: + # 对于状态存储,策略适用于保存和检索状态。 + statestore1: # 任何组件名称 -- 这里是一个状态存储 + outbound: + timeout: general + retry: retryForever + # 组件的断路器是按组件配置/实例限定的。例如 myRediscomponent。 + # 当此断路器被触发时,所有与该组件的交互将在配置的 `timeout` 时间内被阻止。 + circuitBreaker: simpleCB + + pubsub1: # 任何组件名称 -- 这里是一个 pubsub broker + outbound: + retry: pubsubRetry + circuitBreaker: pubsubCB + + pubsub2: # 任何组件名称 -- 这里是另一个 pubsub broker + outbound: + retry: pubsubRetry + circuitBreaker: pubsubCB + inbound: # inbound 仅适用于从 sidecar 到应用程序的传递 + timeout: general + retry: important + circuitBreaker: pubsubCB +``` + +## 相关链接 + +观看此视频以了解如何使用[弹性](https://www.youtube.com/watch?t=184&v=7D6HOU3Ms6g&feature=youtu.be): + +
+ +
+ +## 下一步 +了解更多关于弹性策略和目标: + - [策略]({{< ref "policies.md" >}}) + - [目标]({{< ref "targets.md" >}}) +尝试其中一个弹性快速入门: +- [弹性:服务到服务]({{< ref resiliency-serviceinvo-quickstart.md >}}) +- [弹性:状态管理]({{< ref resiliency-state-quickstart.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/resiliency/targets.md b/src/translated_content/zh_CN/docs/operations/resiliency/targets.md new file mode 100644 index 000000000..d7c1283ce --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/resiliency/targets.md @@ -0,0 +1,136 @@ +--- +type: docs +title: "目标" +linkTitle: "目标" +weight: 300 +description: "将弹性策略应用于包括应用程序、组件和actor在内的目标" +--- + +### 目标 + +命名的策略被应用于目标。Dapr支持三种目标类型,这些类型适用于所有Dapr构建块的API: +- `apps` +- `components` +- `actors` + +#### 应用程序 + +使用`apps`目标,您可以将`retry`、`timeout`和`circuitBreaker`策略应用于Dapr应用程序之间的服务调用。在`targets/apps`下,策略应用于每个目标服务的`app-id`。当sidecar之间的通信出现故障时,这些策略将被调用,如下图所示。 + +> Dapr提供了[内置的服务调用重试]({{< ref "service-invocation-overview.md#retries" >}}),因此任何应用的`retry`策略都是额外的。 + +显示服务调用弹性的图示 + +应用于目标应用程序`app-id`为"appB"的策略示例: + +```yaml +specs: + targets: + apps: + appB: # 目标服务的app-id + timeout: general + retry: general + circuitBreaker: general +``` + +#### 组件 + +使用`components`目标,您可以将`retry`、`timeout`和`circuitBreaker`策略应用于组件操作。 + +策略可以应用于`outbound`操作(从Dapr sidecar到组件的调用)和/或`inbound`(从sidecar到您的应用程序的调用)。 + +##### 出站 + +`outbound`操作是从sidecar到组件的调用,例如: + +- 持久化或检索状态。 +- 在pubsub组件上发布消息。 +- 调用输出绑定。 + +> 某些组件可能具有内置的重试功能,并且可以在每个组件的基础上进行配置。 + +显示服务调用弹性的图示 + +```yaml +spec: + targets: + components: + myStateStore: + outbound: + retry: retryForever + circuitBreaker: simpleCB +``` + +##### 入站 + +`inbound`操作是从sidecar到您的应用程序的调用,例如: + +- pubsub订阅在传递消息时。 +- 输入绑定。 + +> 某些组件可能具有内置的重试功能,并且可以在每个组件的基础上进行配置。 + +显示服务调用弹性的图示 + +```yaml +spec: + targets: + components: + myInputBinding: + inbound: + timeout: general + retry: general + circuitBreaker: general +``` + +##### PubSub + +在pubsub `target/component`中,您可以同时指定`inbound`和`outbound`操作。 + +显示服务调用弹性的图示 + +```yaml +spec: + targets: + components: + myPubsub: + outbound: + retry: pubsubRetry + circuitBreaker: pubsubCB + inbound: # 入站仅适用于从sidecar到应用程序的传递 + timeout: general + retry: general + circuitBreaker: general +``` + +#### Actor + +使用`actors`目标,您可以将`retry`、`timeout`和`circuitBreaker`策略应用于actor操作。 + +当为`actors`目标使用`circuitBreaker`策略时,您可以通过`circuitBreakerScope`指定电路断开的范围: + +- `id`:单个actor ID +- `type`:给定actor类型的所有actor +- `both`:以上两者 + +您还可以使用`circuitBreakerCacheSize`属性指定要在内存中保留的电路断路器数量的缓存大小,提供一个整数值,例如`5000`。 + +示例 + +```yaml +spec: + targets: + actors: + myActorType: + timeout: general + retry: general + circuitBreaker: general + circuitBreakerScope: both + circuitBreakerCacheSize: 5000 +``` + +## 下一步 + +尝试其中一个弹性快速入门: +- [弹性:服务到服务]({{< ref resiliency-serviceinvo-quickstart.md >}}) +- [弹性:状态管理]({{< ref resiliency-state-quickstart.md >}}) diff --git a/src/translated_content/zh_CN/docs/operations/security/_index.md b/src/translated_content/zh_CN/docs/operations/security/_index.md new file mode 100644 index 000000000..aa0865006 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/security/_index.md @@ -0,0 +1,19 @@ +--- +type: docs +title: "保护 Dapr 部署" +linkTitle: "安全" +weight: 500 +description: "关于如何保护您的 Dapr 应用程序的最佳实践和说明" +--- + +在使用 Dapr 部署应用程序时,确保安全性至关重要。Dapr 提供了一系列功能和最佳实践,帮助开发者保护他们的应用程序。这些功能包括身份验证、授权、数据加密以及安全的通信协议。 + +首先,身份验证是确保只有授权用户和服务可以访问您的 Dapr 应用程序的关键步骤。Dapr 支持多种身份验证机制,包括 OAuth 和 API 密钥。通过配置这些机制,您可以有效地控制对应用程序的访问。 + +其次,授权是在用户或服务通过身份验证后,确定其可以执行哪些操作。Dapr 提供了详细的权限控制,允许您定义不同角色和权限,以确保用户只能访问他们被授权的资源。 + +数据加密是保护敏感信息的另一重要措施。Dapr 支持在传输和存储过程中对数据进行加密。即使数据被截获,未授权用户也无法读取。 + +最后,Dapr 使用安全的通信协议来保护数据在网络中的传输。通过采用 HTTPS 和其他加密协议,Dapr 确保数据在传输过程中不会被窃听或篡改。 + +通过遵循这些最佳实践,您可以显著提高 Dapr 应用程序的安全性,保护您的数据和服务免受潜在威胁。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/security/api-token.md b/src/translated_content/zh_CN/docs/operations/security/api-token.md new file mode 100644 index 000000000..b2e7eac94 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/security/api-token.md @@ -0,0 +1,147 @@ +--- +type: docs +title: "在 Dapr 中启用 API 令牌认证" +linkTitle: "Dapr API 令牌认证" +weight: 3000 +description: "要求每个传入的 Dapr API 请求在通过之前包含一个认证令牌" +--- + +默认情况下,Dapr 通过网络边界限制对其公共 API 的访问。如果您计划在该边界之外公开 Dapr API,或者您的部署需要额外的安全级别,请考虑为 Dapr API 启用令牌认证。这意味着 Dapr 将要求每个传入的 gRPC 和 HTTP 请求在通过之前包含认证令牌。 + +## 创建令牌 + +Dapr 通过共享令牌进行 API 认证。您可以自由定义要使用的 API 令牌。 + +虽然 Dapr 对共享令牌的格式没有具体要求,但一个好的做法是生成一个随机字节序列并将其编码为 Base64。例如,以下命令生成一个随机的 32 字节密钥并将其编码为 Base64: + +```sh +openssl rand 16 | base64 +``` + +## 在 Dapr 中配置 API 令牌认证 + +对于 Kubernetes 或自托管 Dapr 部署,令牌认证配置略有不同: + +### 自托管 + +在自托管场景中,Dapr 会检查 `DAPR_API_TOKEN` 环境变量是否存在。如果在 `daprd` 进程启动时设置了该环境变量,Dapr 将对其公共 API 强制执行认证: + +```shell +export DAPR_API_TOKEN= +``` + +要更新配置的令牌,请将 `DAPR_API_TOKEN` 环境变量更新为新值并重新启动 `daprd` 进程。 + +### Kubernetes + +在 Kubernetes 部署中,Dapr 使用 Kubernetes secret 存储来保存共享令牌。要配置 Dapr API 认证,首先创建一个新的 secret: + +```shell +kubectl create secret generic dapr-api-token --from-literal=token= +``` + +> 注意,您需要在每个希望启用 Dapr 令牌认证的命名空间中创建上述 secret。 + +要指示 Dapr 使用该 secret 来保护其公共 API,请在您的 Deployment 模板规范中添加一个注释: + +```yaml +annotations: + dapr.io/enabled: "true" + dapr.io/api-token-secret: "dapr-api-token" # Kubernetes secret 的名称 +``` + +部署时,Dapr sidecar 注入器将自动创建一个 secret 引用并将实际值注入 `DAPR_API_TOKEN` 环境变量。 + +## 更新令牌 + +### 自托管 + +要在自托管中更新配置的令牌,请将 `DAPR_API_TOKEN` 环境变量更新为新值并重新启动 `daprd` 进程。 + +### Kubernetes + +要在 Kubernetes 中更新配置的令牌,请在每个命名空间中使用新令牌更新先前创建的 secret。您可以使用 `kubectl patch` 命令执行此操作,但在每个命名空间中更新这些的更简单方法是使用清单: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: dapr-api-token +type: Opaque +data: + token: +``` + +然后将其应用到每个命名空间: + +```shell +kubectl apply --file token-secret.yaml --namespace +``` + +要让 Dapr 开始使用新令牌,请触发对每个部署的滚动升级: + +```shell +kubectl rollout restart deployment/ --namespace +``` + +> 假设您的服务配置了多个副本,密钥更新过程不会导致任何停机时间。 + +## 向客户端 API 调用添加 API 令牌 + +一旦在 Dapr 中配置了令牌认证,所有调用 Dapr API 的客户端都需要在每个请求中附加 `dapr-api-token` 令牌。 + +> **注意:** Dapr SDK 会读取 [DAPR_API_TOKEN]({{< ref environment >}}) 环境变量并默认为您设置。 + + + +### HTTP + +在 HTTP 的情况下,Dapr 要求在 `dapr-api-token` 头中提供 API 令牌。例如: + +```text +GET http:///v1.0/metadata +dapr-api-token: +``` + +使用 curl,您可以使用 `--header`(或 `-H`)选项传递头。例如: + +```sh +curl http://localhost:3500/v1.0/metadata \ + --header "dapr-api-token: my-token" +``` + +### gRPC + +使用 gRPC 协议时,Dapr 将在 gRPC 元数据中检查传入调用的 API 令牌: + +```text +dapr-api-token[0]. +``` + +## 从应用访问令牌 + +### Kubernetes + +在 Kubernetes 中,建议将 secret 挂载到您的 pod 作为环境变量,如下例所示,其中名为 `dapr-api-token` 的 Kubernetes secret 用于保存令牌。 + +```yaml +containers: + - name: mycontainer + image: myregistry/myapp + envFrom: + - secretRef: + name: dapr-api-token +``` + +### 自托管 + +在自托管模式下,您可以将令牌设置为应用的环境变量: + +```sh +export DAPR_API_TOKEN= +``` + +## 相关链接 + +- 了解 [Dapr 安全概念]({{< ref security-concept.md >}}) +- 了解 [如何使用令牌认证从 Dapr 认证请求]({{< ref app-api-token.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/security/app-api-token.md b/src/translated_content/zh_CN/docs/operations/security/app-api-token.md new file mode 100644 index 000000000..dfb9bd88e --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/security/app-api-token.md @@ -0,0 +1,139 @@ +--- +type: docs +title: "使用令牌认证对Dapr请求进行身份验证" +linkTitle: "应用API令牌认证" +weight: 4000 +description: "要求每个来自Dapr的API请求都包含一个认证令牌" +--- + +对于一些构建块,例如pubsub、service-invocation和输入bindings,Dapr与应用程序通过HTTP或gRPC进行通信。 +为了让应用程序能够验证来自Dapr sidecar的请求,您可以配置Dapr在HTTP请求的头部或gRPC请求的元数据中发送一个API令牌。 + +## 创建令牌 + +Dapr使用共享令牌进行API认证。您可以自由定义API令牌。 + +虽然Dapr对共享令牌没有强制格式,但一个好的做法是生成一个随机字节序列并将其编码为Base64。例如,这个命令生成一个随机的32字节密钥并将其编码为Base64: + +```sh +openssl rand 16 | base64 +``` + +## 在Dapr中配置应用API令牌认证 + +令牌认证配置在Kubernetes或selfhosted Dapr部署中略有不同: + +### Selfhosted + +在selfhosted场景中,Dapr会检查`APP_API_TOKEN`环境变量是否存在。如果在`daprd`进程启动时设置了该环境变量,Dapr在调用应用程序时会包含该令牌: + +```shell +export APP_API_TOKEN= +``` + +要更新配置的令牌,修改`APP_API_TOKEN`环境变量为新值并重启`daprd`进程。 + +### Kubernetes + +在Kubernetes部署中,Dapr使用Kubernetes secrets存储来保存共享令牌。首先,创建一个新的secret: + +```shell +kubectl create secret generic app-api-token --from-literal=token= +``` + +> 注意,您需要在每个希望启用应用令牌认证的命名空间中创建上述secret + +要指示Dapr在向应用程序发送请求时使用secret中的令牌,请在您的Deployment模板规范中添加一个注解: + +```yaml +annotations: + dapr.io/enabled: "true" + dapr.io/app-token-secret: "app-api-token" # Kubernetes secret的名称 +``` + +部署时,Dapr Sidecar Injector会自动创建一个secret引用并将实际值注入到`APP_API_TOKEN`环境变量中。 + +## 轮换令牌 + +### Selfhosted + +要在selfhosted中更新配置的令牌,修改`APP_API_TOKEN`环境变量为新值并重启`daprd`进程。 + +### Kubernetes + +要在Kubernetes中更新配置的令牌,修改之前创建的secret中的新令牌在每个命名空间中。您可以使用`kubectl patch`命令来完成此操作,但更简单的方法是使用清单更新这些: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: app-api-token +type: Opaque +data: + token: +``` + +然后将其应用到每个命名空间: + +```shell +kubectl apply --file token-secret.yaml --namespace +``` + +要让Dapr开始使用新令牌,请触发对每个部署的滚动升级: + +```shell +kubectl rollout restart deployment/ --namespace +``` + +> 假设您的服务配置了多个副本,密钥轮换过程不会导致任何停机。 + +## 验证来自Dapr的请求 + +一旦使用环境变量或Kubernetes secret `app-api-token`配置了应用令牌认证,Dapr sidecar在调用应用程序时总是会在HTTP头部或gRPC元数据中包含`dapr-api-token: `。从应用程序端,确保您使用`dapr-api-token`值进行认证,该值使用您设置的`app-api-token`来验证来自Dapr的请求。 + + + +### HTTP + +在您的代码中,查找传入请求中的HTTP头部`dapr-api-token`: + +```text +dapr-api-token: +``` + +### gRPC + +使用gRPC协议时,检查传入调用中的gRPC元数据中的API令牌: + +```text +dapr-api-token[0]. +``` + +## 从应用程序访问令牌 + +### Kubernetes + +在Kubernetes中,建议将secret挂载到您的pod作为环境变量。 +假设我们创建了一个名为`app-api-token`的secret来保存令牌: + +```yaml +containers: + - name: mycontainer + image: myregistry/myapp + envFrom: + - secretRef: + name: app-api-token +``` + +### Selfhosted + +在selfhosted模式中,您可以将令牌设置为应用程序的环境变量: + +```sh +export APP_API_TOKEN= +``` + +## 相关链接 + +- 了解[Dapr安全概念]({{< ref security-concept.md >}}) +- 了解[如何在Dapr中启用API令牌认证]({{< ref api-token.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/security/mtls.md b/src/translated_content/zh_CN/docs/operations/security/mtls.md new file mode 100644 index 000000000..fed6cd27f --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/security/mtls.md @@ -0,0 +1,564 @@ +--- +type: docs +title: "设置和配置 mTLS 证书" +linkTitle: "设置和配置 mTLS 证书" +weight: 1000 +description: "使用自签名或用户提供的 x.509 证书加密应用程序之间的通信" +--- + +Dapr 支持通过 Dapr 控制平面的 Sentry 服务对 Dapr 实例之间的通信进行传输加密。Sentry 服务是一个中央证书颁发机构 (CA)。 + +Dapr 允许操作员和开发人员使用自己的证书,或者让 Dapr 自动创建并保存自签名的根证书和颁发者证书。 + +有关 mTLS 的详细信息,请阅读[安全概念部分]({{< ref "security-concept.md" >}})。 + +如果没有提供自定义证书,Dapr 会自动创建并保存有效期为一年的自签名证书。 +在 Kubernetes 中,证书会保存到 Dapr 系统 pod 所在命名空间的 secret 中,仅对它们可访问。 +在自托管模式中,证书会保存到磁盘。 + +## 控制平面 Sentry 服务配置 +mTLS 设置位于 Dapr 控制平面配置文件中。例如,当您将 Dapr 控制平面部署到 Kubernetes 时,此配置文件会自动创建,然后您可以编辑它。以下文件显示了在 `daprsystem` 命名空间中部署的配置资源中可用的 mTLS 设置: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: daprsystem + namespace: default +spec: + mtls: + enabled: true + workloadCertTTL: "24h" + allowedClockSkew: "15m" +``` + +此文件显示了默认的 `daprsystem` 配置设置。下面的示例向您展示如何在 Kubernetes 和自托管模式下更改和应用此配置到控制平面 Sentry 服务。 + +## Kubernetes + +### 使用配置资源设置 mTLS + +在 Kubernetes 中,Dapr 创建了一个启用 mTLS 的默认控制平面配置资源。 +Sentry 服务,即证书颁发机构系统 pod,可以通过 Helm 和 Dapr CLI 使用 `dapr init --kubernetes` 安装。 + +您可以使用以下命令查看控制平面配置资源: + +`kubectl get configurations/daprsystem --namespace -o yaml` + +要对控制平面配置资源进行更改,请运行以下命令进行编辑: + +``` +kubectl edit configurations/daprsystem --namespace +``` + +保存更改后,对控制平面执行滚动更新: + +``` +kubectl rollout restart deploy/dapr-sentry -n +kubectl rollout restart deploy/dapr-operator -n +kubectl rollout restart statefulsets/dapr-placement-server -n +``` + +*注意:控制平面 sidecar 注入器服务不需要重新部署* + +### 使用 Helm 禁用 mTLS +*控制平面将继续使用 mTLS* + +```bash +kubectl create ns dapr-system + +helm install \ + --set global.mtls.enabled=false \ + --namespace dapr-system \ + dapr \ + dapr/dapr +``` + +### 使用 CLI 禁用 mTLS +*控制平面将继续使用 mTLS* + +``` +dapr init --kubernetes --enable-mtls=false +``` + +### 查看日志 + +要查看 Sentry 服务日志,请运行以下命令: + +``` +kubectl logs --selector=app=dapr-sentry --namespace +``` + +### 使用您自己的证书 + +使用 Helm,您可以提供 PEM 编码的根证书、颁发者证书和私钥,这些将被填充到 Sentry 服务使用的 Kubernetes secret 中。 + +{{% alert title="避免停机" color="warning" %}} +为了避免在轮换过期证书时停机,请始终使用相同的私有根密钥签署您的证书。 +{{% /alert %}} + +_注意:此示例使用 OpenSSL 命令行工具,这是一个广泛分发的软件包,可以通过包管理器轻松安装在 Linux 上。在 Windows 上可以使用 [chocolatey](https://community.chocolatey.org/packages/openssl) 安装 OpenSSL。在 MacOS 上可以使用 brew 安装 `brew install openssl`_ + +创建用于生成证书的配置文件,这是生成带有 SAN(主题备用名称)扩展字段的 v3 证书所必需的。首先将以下内容保存到名为 `root.conf` 的文件中: + +```ini +[req] +distinguished_name = req_distinguished_name +x509_extensions = v3_req +prompt = no +[req_distinguished_name] +C = US +ST = VA +L = Daprville +O = dapr.io/sentry +OU = dapr.io/sentry +CN = cluster.local +[v3_req] +basicConstraints = critical, CA:true +keyUsage = critical, digitalSignature, cRLSign, keyCertSign +extendedKeyUsage = serverAuth, clientAuth +subjectAltName = @alt_names +[alt_names] +DNS.1 = cluster.local +``` + +对 `issuer.conf` 重复此操作,将相同的内容粘贴到文件中,但在 basicConstraints 行的末尾添加 `pathlen:0`,如下所示: + +```ini +basicConstraints = critical, CA:true, pathlen:0 +``` + +运行以下命令生成根证书和密钥 + +```bash +# 跳过以下行以重用现有的根密钥,这是轮换过期证书所需的 +openssl ecparam -genkey -name prime256v1 | openssl ec -out root.key +openssl req -new -nodes -sha256 -key root.key -out root.csr -config root.conf -extensions v3_req +openssl x509 -req -sha256 -days 365 -in root.csr -signkey root.key -outform PEM -out root.pem -extfile root.conf -extensions v3_req +``` + +接下来运行以下命令生成颁发者证书和密钥: + +```bash +# 跳过以下行以重用现有的颁发者密钥,这是轮换过期证书所需的 +openssl ecparam -genkey -name prime256v1 | openssl ec -out issuer.key +openssl req -new -sha256 -key issuer.key -out issuer.csr -config issuer.conf -extensions v3_req +openssl x509 -req -in issuer.csr -CA root.pem -CAkey root.key -CAcreateserial -outform PEM -out issuer.pem -days 365 -sha256 -extfile issuer.conf -extensions v3_req +``` + +安装 Helm 并通过配置将根证书、颁发者证书和颁发者密钥传递给 Sentry: + +```bash +kubectl create ns dapr-system + +helm install \ + --set-file dapr_sentry.tls.issuer.certPEM=issuer.pem \ + --set-file dapr_sentry.tls.issuer.keyPEM=issuer.key \ + --set-file dapr_sentry.tls.root.certPEM=root.pem \ + --namespace dapr-system \ + dapr \ + dapr/dapr +``` + +### 使用 CLI 升级根和颁发者证书(推荐) +以下 CLI 命令可用于更新 Kubernetes 集群中的根和颁发者证书。 + +#### 生成全新的证书 + +1. 下面的命令生成全新的根和颁发者证书,由新生成的私有根密钥签名。 + +> **注意:必须重启 `Dapr sentry 服务` 以及其余的控制平面服务,以便它们能够读取新证书。这可以通过向命令提供 `--restart` 标志来完成。** + +```bash +dapr mtls renew-certificate -k --valid-until --restart +``` + +2. 下面的命令生成全新的根和颁发者证书,由提供的私有根密钥签名。 + +> **注意:如果您现有的已部署证书是由此相同的私有根密钥签名的,则 `Dapr Sentry 服务` 可以在不重启的情况下读取这些新证书。** + +```bash +dapr mtls renew-certificate -k --private-key --valid-until +``` + +#### 使用提供的自定义证书更新证书 +要更新 Kubernetes 集群中提供的证书,可以使用以下 CLI 命令。 + +> **注意 - 它不支持 `valid-until` 标志来指定新证书的有效期。** + +```bash +dapr mtls renew-certificate -k --ca-root-certificate --issuer-private-key --issuer-public-certificate --restart +``` + +{{% alert title="重启 Dapr 启用的 pod" color="warning" %}} +无论使用哪个命令更新证书,您都必须重启所有 Dapr 启用的 pod。 +由于证书不匹配,您可能会在所有部署成功重启之前经历一些停机时间。 +{{% /alert %}} + +推荐的方法是对您的部署执行滚动重启: + +``` +kubectl rollout restart deploy/myapp +``` + +### 使用 Kubectl 更新根或颁发者证书 + +如果根或颁发者证书即将过期,您可以更新它们并重启所需的系统服务。 + +{{% alert title="在轮换证书时避免停机" color="warning" %}} +为了避免在轮换过期证书时停机,您的新证书必须使用与先前证书相同的私有根密钥签名。这目前无法使用 Dapr 生成的自签名证书实现。 +{{% /alert %}} + +#### Dapr 生成的自签名证书 + +1. 清除现有的 Dapr 信任包 secret,将以下 YAML 保存到文件(例如 `clear-trust-bundle.yaml`)并应用此 secret。 + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: dapr-trust-bundle + labels: + app: dapr-sentry +data: +``` + +```bash +kubectl apply -f `clear-trust-bundle.yaml` -n +``` + +2. 重启 Dapr Sentry 服务。这将生成一个新的证书包并更新 `dapr-trust-bundle` Kubernetes secret。 + +```bash +kubectl rollout restart -n deployment/dapr-sentry +``` + +3. 一旦 Sentry 服务已重启,重启其余的 Dapr 控制平面以获取新的 Dapr 信任包。 + +```bash +kubectl rollout restart deploy/dapr-operator -n +kubectl rollout restart statefulsets/dapr-placement-server -n +``` + +4. 重启您的 Dapr 应用程序以获取最新的信任包。 + +{{% alert title="启用 mTLS 时可能导致应用程序停机。" color="warning" %}} +使用 mTLS 进行服务调用的部署重启将失败,直到被调用的服务也已重启(从而加载新的 Dapr 信任包)。此外,placement 服务将无法分配新的 actor(而现有的 actor 不受影响),直到应用程序已重启以加载新的 Dapr 信任包。 +{{% /alert %}} + +```bash +kubectl rollout restart deployment/mydaprservice1 kubectl deployment/myotherdaprservice2 +``` + +#### 自定义证书(自带) + +首先,使用上面[使用您自己的证书](#bringing-your-own-certificates)中的步骤颁发新证书。 + +现在您有了新证书,使用 Helm 升级证书: + +```bash +helm upgrade \ + --set-file dapr_sentry.tls.issuer.certPEM=issuer.pem \ + --set-file dapr_sentry.tls.issuer.keyPEM=issuer.key \ + --set-file dapr_sentry.tls.root.certPEM=root.pem \ + --namespace dapr-system \ + dapr \ + dapr/dapr +``` + +或者,您可以更新保存它们的 Kubernetes secret: + +```bash +kubectl edit secret dapr-trust-bundle -n +``` + +用新证书的相应值替换 Kubernetes secret 中的 `ca.crt`、`issuer.crt` 和 `issuer.key` 键。 +*__注意:这些值必须是 base64 编码的__* + +如果您使用**相同的私有密钥**签署了新的证书根,Dapr Sentry 服务将自动获取新证书。您可以使用 `kubectl rollout restart` 重启您的应用程序部署而不会停机。无需一次性重启所有部署,只要在原始证书过期之前重启即可。 + +如果您使用**不同的私有密钥**签署了新的证书根,您必须重启 Dapr Sentry 服务,然后是其余的 Dapr 控制平面服务。 + +```bash +kubectl rollout restart deploy/dapr-sentry -n +``` + +一旦 Sentry 完全重启,运行: + +```bash +kubectl rollout restart deploy/dapr-operator -n +kubectl rollout restart statefulsets/dapr-placement-server -n +``` + +接下来,您必须重启所有 Dapr 启用的 pod。 +推荐的方法是对您的部署执行滚动重启: + +``` +kubectl rollout restart deploy/myapp +``` + +由于证书不匹配,您将经历潜在的停机,直到所有部署成功重启(从而加载新的 Dapr 证书)。 + +### Kubernetes 视频演示 +观看此视频以了解如何在 Kubernetes 上更新 mTLS 证书 + + + +### 设置 Dapr 控制平面 mTLS 证书过期的监控 + +从 mTLS 根证书过期前 30 天开始,Dapr sentry 服务将每小时发出警告级别日志,指示根证书即将过期。 + +作为在生产中运行 Dapr 的操作最佳实践,我们建议为这些特定的 sentry 服务日志配置监控,以便您了解即将到来的证书过期。 + +```bash +"Dapr root certificate expiration warning: certificate expires in 2 days and 15 hours" +``` + +一旦证书过期,您将看到以下消息: + +```bash +"Dapr root certificate expiration warning: certificate has expired." +``` + +在 Kubernetes 中,您可以这样查看 sentry 服务日志: + +```bash +kubectl logs deployment/dapr-sentry -n dapr-system +``` + +日志输出将如下所示:" + +```bash +{"instance":"dapr-sentry-68cbf79bb9-gdqdv","level":"warning","msg":"Dapr root certificate expiration warning: certificate expires in 2 days and 15 hours","scope":"dapr.sentry","time":"2022-04-01T23:43:35.931825236Z","type":"log","ver":"1.6.0"} +``` + +作为提醒您即将到来的证书过期的额外工具,从 1.7.0 版本开始,CLI 现在在您与基于 Kubernetes 的部署交互时打印证书过期状态。 + +示例: +```bash +dapr status -k + + NAME NAMESPACE HEALTHY STATUS REPLICAS VERSION AGE CREATED + dapr-sentry dapr-system True Running 1 1.7.0 17d 2022-03-15 09:29.45 + dapr-dashboard dapr-system True Running 1 0.9.0 17d 2022-03-15 09:29.45 + dapr-sidecar-injector dapr-system True Running 1 1.7.0 17d 2022-03-15 09:29.45 + dapr-operator dapr-system True Running 1 1.7.0 17d 2022-03-15 09:29.45 + dapr-placement-server dapr-system True Running 1 1.7.0 17d 2022-03-15 09:29.45 +⚠ Dapr root certificate of your Kubernetes cluster expires in 2 days. Expiry date: Mon, 04 Apr 2022 15:01:03 UTC. + 请参阅 docs.dapr.io 以获取证书更新说明,以避免服务中断。 +``` + +## 自托管 +### 运行控制平面 Sentry 服务 + +为了运行 Sentry 服务,您可以从[这里](https://github.com/dapr/dapr/releases)下载源代码或发布的二进制文件。 + +在从源代码构建时,请参考[此](https://github.com/dapr/dapr/blob/master/docs/development/developing-dapr.md#build-the-dapr-binaries)指南了解如何构建 Dapr。 + +其次,为 Sentry 服务创建一个目录以创建自签名的根证书: + +``` +mkdir -p $HOME/.dapr/certs +``` + +使用以下命令在本地运行 Sentry 服务: + +```bash +./sentry --issuer-credentials $HOME/.dapr/certs --trust-domain cluster.local +``` + +如果成功,Sentry 服务将运行并在给定目录中创建根证书。 +此命令使用默认配置值,因为没有给定自定义配置文件。请参阅下文了解如何使用自定义配置启动 Sentry 服务。 + +### 使用配置资源设置 mTLS + +#### Dapr 实例配置 + +在自托管模式下运行 Dapr 时,默认情况下禁用 mTLS。您可以通过创建以下配置文件来启用它: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: daprsystem + namespace: default +spec: + mtls: + enabled: true +``` + +除了 Dapr 配置,您还需要为每个 Dapr sidecar 实例提供 TLS 证书。您可以在运行 Dapr 实例之前设置以下环境变量来实现: + +{{< tabs "Linux/MacOS" Windows >}} + +{{% codetab %}} +```bash +export DAPR_TRUST_ANCHORS=`cat $HOME/.dapr/certs/ca.crt` +export DAPR_CERT_CHAIN=`cat $HOME/.dapr/certs/issuer.crt` +export DAPR_CERT_KEY=`cat $HOME/.dapr/certs/issuer.key` +export NAMESPACE=default +``` + +{{% /codetab %}} + +{{% codetab %}} +```powershell +$env:DAPR_TRUST_ANCHORS=$(Get-Content -raw $env:USERPROFILE\.dapr\certs\ca.crt) +$env:DAPR_CERT_CHAIN=$(Get-Content -raw $env:USERPROFILE\.dapr\certs\issuer.crt) +$env:DAPR_CERT_KEY=$(Get-Content -raw $env:USERPROFILE\.dapr\certs\issuer.key) +$env:NAMESPACE="default" +``` + +{{% /codetab %}} + +{{< /tabs >}} + +如果使用 Dapr CLI,请将 Dapr 指向上面的配置文件以启用 mTLS 运行 Dapr 实例: + +``` +dapr run --app-id myapp --config ./config.yaml node myapp.js +``` + +如果直接使用 `daprd`,请使用以下标志启用 mTLS: + +```bash +daprd --app-id myapp --enable-mtls --sentry-address localhost:50001 --config=./config.yaml +``` + +#### Sentry 服务配置 + +以下是一个 Sentry 配置示例,将工作负载证书 TTL 更改为 25 秒: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: daprsystem + namespace: default +spec: + mtls: + enabled: true + workloadCertTTL: "25s" +``` + +为了使用自定义配置启动 Sentry 服务,请使用以下标志: + +``` +./sentry --issuer-credentials $HOME/.dapr/certs --trust-domain cluster.local --config=./config.yaml +``` + +### 使用您自己的证书 + +为了提供您自己的凭据,请创建 ECDSA PEM 编码的根和颁发者证书并将它们放置在文件系统上。 +使用 `--issuer-credentials` 标志告诉 Sentry 服务从哪里加载证书。 + +下一个示例创建根和颁发者证书并将它们加载到 Sentry 服务中。 + +*注意:此示例使用 step 工具创建证书。您可以从[这里](https://smallstep.com/docs/step-cli/installation)安装 step 工具。Windows 二进制文件可从[这里](https://github.com/smallstep/cli/releases)获得* + +创建根证书: + +```bash +step certificate create cluster.local ca.crt ca.key --profile root-ca --no-password --insecure +``` + +创建颁发者证书: + +```bash +step certificate create cluster.local issuer.crt issuer.key --ca ca.crt --ca-key ca.key --profile intermediate-ca --not-after 8760h --no-password --insecure +``` + +这将创建根和颁发者证书和密钥。 +将 `ca.crt`、`issuer.crt` 和 `issuer.key` 放在所需路径中(以下示例中为 `$HOME/.dapr/certs`),并启动 Sentry: + +```bash +./sentry --issuer-credentials $HOME/.dapr/certs --trust-domain cluster.local +``` + +### 更新根或颁发者证书 + +如果根或颁发者证书即将过期,您可以更新它们并重启所需的系统服务。 + +要让 Dapr 生成新证书,请删除现有的 `$HOME/.dapr/certs` 证书并重启 sentry 服务以生成新证书。 + +```bash +./sentry --issuer-credentials $HOME/.dapr/certs --trust-domain cluster.local --config=./config.yaml +``` + +要替换为您自己的证书,请首先使用上面[使用您自己的证书](#bringing-your-own-certificates)中的步骤生成新证书。 + +将 `ca.crt`、`issuer.crt` 和 `issuer.key` 复制到每个配置的系统服务的文件系统路径,并重启进程或容器。 +默认情况下,系统服务将在 `/var/run/dapr/credentials` 中查找凭据。上面的示例使用 `$HOME/.dapr/certs` 作为自定义位置。 + +*注意:如果您使用不同的私有密钥签署了证书根,请重启 Dapr 实例。* + +## 社区通话视频关于证书轮换 +观看此[视频](https://www.youtube.com/watch?v=Hkcx9kBDrAc&feature=youtu.be&t=1400)以了解如何在证书即将过期时执行证书轮换。 + +
+ +
+ +## Sentry 令牌验证器 + +令牌通常用于身份验证和授权目的。 +令牌验证器是负责验证这些令牌的有效性和真实性的组件。 +例如,在 Kubernetes 环境中,一种常见的令牌验证方法是通过 Kubernetes 绑定服务帐户机制。 +此验证器检查绑定服务帐户令牌以确保其合法性。 + +Sentry 服务可以配置为: +- 启用除 Kubernetes 绑定服务帐户验证器之外的额外令牌验证器 +- 替换自托管模式下默认启用的 `insecure` 验证器 + +Sentry 令牌验证器用于将额外的非 Kubernetes 客户端加入到以 Kubernetes 模式运行的 Dapr 集群中,或替换自托管模式下的不安全“允许所有”验证器以启用适当的身份验证。 +除非您使用的是特殊的部署场景,否则不需要配置令牌验证器。 + +> 当前唯一支持的令牌验证器是 `jwks` 验证器。 + +### JWKS + +`jwks` 验证器使 Sentry 服务能够使用 JWKS 端点验证 JWT 令牌。 +令牌的内容_必须_包含与 Dapr 客户端的 SPIFFE 身份匹配的 `sub` 声明,格式为 `spiffe:///ns//`。 +令牌的受众必须是 Sentry 身份的 SPIFFE ID,例如 `spiffe://cluster.local/ns/dapr-system/dapr-sentry`。 +其他基本的 JWT 规则,如签名、过期等也适用。 + +`jwks` 验证器可以接受远程源以获取公钥列表或公钥的静态数组。 + +以下配置启用具有远程源的 `jwks` 令牌验证器。 +此远程源使用 HTTPS,因此 `caCertificate` 字段包含远程源的信任根。 + +```yaml +kind: Configuration +apiVersion: dapr.io/v1alpha1 +metadata: + name: sentryconfig +spec: + mtls: + enabled: true + tokenValidators: + - name: jwks + options: + minRefreshInterval: 2m + requestTimeout: 1m + source: "https://localhost:1234/" + caCertificate: "" +``` + +以下配置启用具有公钥静态数组的 `jwks` 令牌验证器。 + +```yaml +kind: Configuration +apiVersion: dapr.io/v1alpha1 +metadata: + name: sentryconfig +spec: + mtls: + enabled: true + tokenValidators: + - name: jwks + options: + minRefreshInterval: 2m + requestTimeout: 1m + source: | + {"keys":[ "12345.." ]} +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/security/oauth.md b/src/translated_content/zh_CN/docs/operations/security/oauth.md new file mode 100644 index 000000000..fbe71674c --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/security/oauth.md @@ -0,0 +1,169 @@ +--- +type: docs +title: "使用 OAuth 配置端点授权" +linkTitle: "使用 OAuth 配置端点授权" +weight: 2000 +description: "为您的 Web API 启用应用程序端点的 OAuth 授权" +--- + +Dapr 的 OAuth 2.0 中间件允许您在 Dapr 端点上为 Web API 启用 OAuth 授权,支持 [授权码模式](https://tools.ietf.org/html/rfc6749#section-4.1)。您还可以将授权令牌注入到端点 API 中,这些令牌可用于通过 [客户端凭证模式](https://tools.ietf.org/html/rfc6749#section-4.4)对 API 调用的外部 API 进行授权。启用中间件后,所有通过 Dapr 的方法调用在传递给用户代码之前都需要进行授权。 + +这两种模式的主要区别在于,`授权码模式`需要用户交互并授权用户,而`客户端凭证模式`不需要用户交互,授权的是服务或应用程序。 + +## 在授权服务器上注册您的应用程序 + +不同的授权服务器提供不同的应用程序注册体验。以下是一些示例: + +* [Microsoft Entra ID](https://docs.microsoft.com/azure/active-directory/develop/v1-protocols-oauth-code) +* [Facebook](https://developers.facebook.com/apps) +* [Fitbit](https://dev.fitbit.com/build/reference/web-api/oauth2/) +* [GitHub](https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/) +* [Google APIs](https://console.developers.google.com/apis/credentials/consen) +* [Slack](https://api.slack.com/docs/oauth) +* [Twitter](http://apps.twitter.com/) + +要配置 Dapr OAuth 中间件,您需要收集以下信息: + +* 客户端 ID (参见 [这里](https://www.oauth.com/oauth2-servers/client-registration/client-id-secret/)) +* 客户端密钥 (参见 [这里](https://www.oauth.com/oauth2-servers/client-registration/client-id-secret/)) +* 范围 (参见 [这里](https://oauth.net/2/scope/)) +* 授权 URL +* 令牌 URL + +一些流行的授权服务器的授权/令牌 URL: + + +| 服务器 | 授权 URL | 令牌 URL | +|---------|-------------------|-----------| +|Microsoft Entra ID||| +|GitHub||| +|Google|| | +|Twitter||| + + +## 定义中间件组件 + +### 定义授权码模式组件 + +OAuth 中间件(授权码模式)由以下组件定义: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: oauth2 + namespace: default +spec: + type: middleware.http.oauth2 + version: v1 + metadata: + - name: clientId + value: "" + - name: clientSecret + value: "" + - name: scopes + value: "" + - name: authURL + value: "" + - name: tokenURL + value: "" + - name: redirectURL + value: "" + - name: authHeaderName + value: "
" + - name: forceHTTPS + value: "" +``` + +### 为授权码模式定义自定义管道 + +要使用 OAuth 中间件(授权码模式),您需要使用 [Dapr 配置]({{< ref "configuration-overview" >}}) 创建一个 [自定义管道]({{< ref "middleware.md" >}}),如下所示: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: pipeline + namespace: default +spec: + httpPipeline: + handlers: + - name: oauth2 + type: middleware.http.oauth2 +``` + +### 定义客户端凭证模式组件 + +OAuth(客户端凭证模式)中间件由以下组件定义: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: myComponent +spec: + type: middleware.http.oauth2clientcredentials + version: v1 + metadata: + - name: clientId + value: "" + - name: clientSecret + value: "" + - name: scopes + value: "" + - name: tokenURL + value: "" + - name: headerName + value: "
" + - name: endpointParamsQuery + value: "" + - name: authStyle + value: "" +``` + +### 为客户端凭证模式定义自定义管道 + +要使用 OAuth 中间件(客户端凭证模式),您需要使用 [Dapr 配置]({{< ref "configuration-overview.md" >}}) 创建一个 [自定义管道]({{< ref "middleware.md" >}}),如下所示: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Configuration +metadata: + name: pipeline + namespace: default +spec: + httpPipeline: + handlers: + - name: myComponent + type: middleware.http.oauth2clientcredentials +``` + +## 应用配置 + +要将上述配置(无论授权类型)应用到您的 Dapr sidecar,请在您的 pod 规范中添加一个 ```dapr.io/config``` 注释: + +```yaml +apiVersion: apps/v1 +kind: Deployment +... +spec: + ... + template: + metadata: + ... + annotations: + dapr.io/enabled: "true" + ... + dapr.io/config: "pipeline" +... +``` + +## 访问访问令牌 + +### 授权码模式 + +配置完成后,每当客户端尝试通过 Dapr sidecar 调用 API 方法时(例如调用 *v1.0/invoke/* 端点),如果未找到访问令牌,客户端将被重定向到授权同意页面。否则,访问令牌将写入 **authHeaderName** 头中,供应用程序代码使用。 + +### 客户端凭证模式 + +配置完成后,每当客户端尝试通过 Dapr sidecar 调用 API 方法时(例如调用 *v1.0/invoke/* 端点),如果未找到现有的有效令牌,将检索一个新的访问令牌。访问令牌将写入 **headerName** 头中,供应用程序代码使用。这样,应用程序可以在调用请求该令牌的外部 API 时在授权头中转发令牌。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/support/_index.md b/src/translated_content/zh_CN/docs/operations/support/_index.md new file mode 100644 index 000000000..62d24e366 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/support/_index.md @@ -0,0 +1,8 @@ +--- +type: docs +title: "支持和版本控制" +linkTitle: "技术支持" +weight: 600 +description: "Dapr 的技术支持和版本控制方案" +--- + diff --git a/src/translated_content/zh_CN/docs/operations/support/alpha-beta-apis.md b/src/translated_content/zh_CN/docs/operations/support/alpha-beta-apis.md new file mode 100644 index 000000000..f958069fb --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/support/alpha-beta-apis.md @@ -0,0 +1,28 @@ +--- +type: docs +title: "Alpha 和 Beta API" +linkTitle: "Alpha & Beta API" +weight: 5000 +description: "当前 Alpha 和 Beta API 列表" +--- + +## Alpha API + +| 模块/API | gRPC | HTTP | 描述 | 文档 | 引入版本 | +| ------------------ | ---- | ---- | ----------- | ------------- | ------------------ | +| 查询状态 | [查询状态 proto](https://github.com/dapr/dapr/blob/5aba3c9aa4ea9b3f388df125f9c66495b43c5c9e/dapr/proto/runtime/v1/dapr.proto#L44) | `v1.0-alpha1/state/statestore/query` | 状态查询 API 可以让您检索、过滤和排序存储在状态存储组件中的键值数据。 | [查询状态 API]({{< ref "howto-state-query-api.md" >}}) | v1.5 | +| 分布式锁 | [锁 proto](https://github.com/dapr/dapr/blob/5aba3c9aa4ea9b3f388df125f9c66495b43c5c9e/dapr/proto/runtime/v1/dapr.proto#L112) | `/v1.0-alpha1/lock` | 分布式锁 API 可以让您对资源进行锁定。 | [分布式锁 API]({{< ref "distributed-lock-api-overview.md" >}}) | v1.8 | +| 批量发布 | [批量发布 proto](https://github.com/dapr/dapr/blob/5aba3c9aa4ea9b3f388df125f9c66495b43c5c9e/dapr/proto/runtime/v1/dapr.proto#L59) | `v1.0-alpha1/publish/bulk` | 批量发布 API 允许您在单个请求中向主题发布多条消息。 | [批量发布和订阅 API]({{< ref "pubsub-bulk.md" >}}) | v1.10 | +| 批量订阅 | [批量订阅 proto](https://github.com/dapr/dapr/blob/5aba3c9aa4ea9b3f388df125f9c66495b43c5c9e/dapr/proto/runtime/v1/appcallback.proto#L57) | N/A | 批量订阅应用程序回调可以在一次调用中接收来自主题的多条消息。 | [批量发布和订阅 API]({{< ref "pubsub-bulk.md" >}}) | v1.10 | +| 加密 | [加密 proto](https://github.com/dapr/dapr/blob/5aba3c9aa4ea9b3f388df125f9c66495b43c5c9e/dapr/proto/runtime/v1/dapr.proto#L118) | `v1.0-alpha1/crypto` | 加密 API 可以执行复杂的加密操作来加密和解密消息。 | [加密 API]({{< ref "cryptography-overview.md" >}}) | v1.11 | +| 任务 | [任务 proto](https://github.com/dapr/dapr/blob/master/dapr/proto/runtime/v1/dapr.proto#L212-219) | `v1.0-alpha1/jobs` | 任务 API 可以让您调度和编排任务。 | [任务 API]({{< ref "jobs-overview.md" >}}) | v1.14 | +| 对话 | [对话 proto](https://github.com/dapr/dapr/blob/master/dapr/proto/runtime/v1/dapr.proto#L221-222) | `v1.0-alpha1/conversation` | 使用对话 API 可以在不同的大型语言模型之间进行交流。 | [对话 API]({{< ref "conversation-overview.md" >}}) | v1.15 | + + +## Beta API + +当前没有 Beta API。 + +## 相关链接 + +[了解有关 Alpha、Beta 和稳定生命周期阶段的更多信息。]({{< ref "certification-lifecycle.md#certification-levels" >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/support/breaking-changes-and-deprecations.md b/src/translated_content/zh_CN/docs/operations/support/breaking-changes-and-deprecations.md new file mode 100644 index 000000000..8a419990c --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/support/breaking-changes-and-deprecations.md @@ -0,0 +1,75 @@ +--- +type: docs +title: "重大变更和弃用" +linkTitle: "重大变更和弃用" +weight: 2500 +description: "处理重大变更和弃用" +--- + +## 重大变更 + +重大变更是指对以下内容的修改,这些修改可能导致现有的第三方应用程序或脚本在升级到下一个稳定的小版本的 Dapr 工件(如 SDK、CLI、runtime 等)后出现编译错误或运行时问题: + +- 代码行为 +- 架构 +- 默认配置值 +- 命令行参数 +- 发布的指标 +- Kubernetes 资源模板 +- 公开访问的 API +- 公开可见的 SDK 接口、方法、类或属性 + +以下情况可以立即应用重大变更: + +- 版本未达到 1.0.0 的项目 +- 预览功能 +- Alpha API +- SDK 中的预览或 Alpha 接口、类、方法或属性 +- 处于 Alpha 或 Beta 阶段的 Dapr 组件 +- `github.com/dapr/components-contrib` 的接口 +- 文档和博客中的 URL +- **例外**情况,**需要**修复关键错误或安全漏洞。 + +### 应用重大变更的流程 + +应用重大变更需要遵循以下流程: + +1. 弃用通知必须作为发布的一部分进行发布。 +1. 重大变更将在弃用公告发布后的两个版本后生效。 + - 例如,功能 X 在 1.0.0 版本说明中宣布弃用,然后将在 1.2.0 中移除。 + +## 弃用 + +弃用可以应用于: + +1. API,包括 alpha API +1. 预览功能 +1. 组件 +1. CLI +1. 可能导致安全漏洞的功能 + +弃用信息会在发布说明中名为“弃用”的部分中列出,说明: + +- 当前弃用的功能将在未来某个版本中不再受支持。例如,发布 x.y.z。这至少是在两个版本之前。 +- 在发布说明中记录用户需要采取的任何步骤以修改其代码、操作等(如果适用)。 + +在宣布未来的重大变更后,该变更将在 2 个版本或 6 个月后生效,以较长者为准。弃用的功能应响应警告,但除此之外不执行任何操作。 + +## 已宣布的弃用 + +| 功能 | 弃用公告 | 移除 | +|-----------------------|-----------------------|------------------------- | +| GET /v1.0/shutdown API(用户应使用 [POST API]({{< ref kubernetes-job.md >}}) 代替) | 1.2.0 | 1.4.0 | +| Java 域构建器类已弃用(用户应使用 [setters](https://github.com/dapr/java-sdk/issues/587) 代替) | Java SDK 1.3.0 | Java SDK 1.5.0 | +| 当未指定内容类型时,服务调用将不再提供默认的 `application/json` 内容类型头。如果您的调用应用程序依赖于此头,则必须明确 [设置内容类型头]({{< ref "service_invocation_api.md#request-contents" >}})。 | 1.7.0 | 1.9.0 | +| 使用 `invoke` 方法的 gRPC 服务调用已弃用。请改用代理模式服务调用。请参阅 [How-To: Invoke services using gRPC ]({{< ref howto-invoke-services-grpc.md >}}) 以使用代理模式。| 1.9.0 | 1.10.0 | +| CLI 标志 `--app-ssl`(在 Dapr CLI 和 daprd 中)已弃用,建议使用 `--app-protocol`,值为 `https` 或 `grpcs`。[daprd:6158](https://github.com/dapr/dapr/issues/6158) [cli:1267](https://github.com/dapr/cli/issues/1267)| 1.11.0 | 1.13.0 | +| Hazelcast PubSub 组件 | 1.9.0 | 1.11.0 | +| Twitter Binding 组件 | 1.10.0 | 1.11.0 | +| NATS Streaming PubSub 组件 | 1.11.0 | 1.13.0 | +| Workflows API Alpha1 `/v1.0-alpha1/workflows` 被弃用,建议使用 Workflow Client | 1.15.0 | 1.17.0 | + +## 相关链接 + +- 阅读 [版本政策]({{< ref support-versioning.md >}}) +- 阅读 [支持的发布]({{< ref support-release-policy.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/support/support-preview-features.md b/src/translated_content/zh_CN/docs/operations/support/support-preview-features.md new file mode 100644 index 000000000..a255f45df --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/support/support-preview-features.md @@ -0,0 +1,26 @@ +--- +type: docs +title: "预览功能" +linkTitle: "预览功能" +weight: 4000 +description: "当前预览功能列表" +--- + +Dapr 的预览功能在首次发布时被视为实验性功能。 + +要使用运行时的预览功能,必须在 Dapr 的应用程序配置中通过预览设置功能进行显式选择加入。有关更多信息,请参阅[如何启用预览功能]({{}})。 + +对于 CLI,不需要显式选择加入,只需使用首次提供该功能的版本即可。 + +## 当前预览功能 + +| 功能 | 描述 | 设置 | 文档 | 引入版本 | +| --- | --- | --- | --- | --- | +| **可插拔组件** | 允许创建基于 gRPC 的自托管组件,这些组件可以用任何支持 gRPC 的语言编写。支持以下组件 API:状态存储、pub/sub、bindings | N/A | [可插拔组件概念]({{}})| v1.9 | +| **Kubernetes 的多应用运行** | 从单个配置文件配置多个 Dapr 应用程序,并在 Kubernetes 上通过单个命令运行 | `dapr run -k -f` | [多应用运行]({{< ref multi-app-dapr-run.md >}}) | v1.12 | +| **工作流** | 将工作流作为代码编写,以在应用程序中自动化和编排任务,如消息传递、状态管理和故障处理 | N/A | [工作流概念]({{< ref "components-concept#workflows" >}})| v1.10 | +| **加密** | 加密或解密数据而无需管理密钥 | N/A | [加密概念]({{< ref "components-concept#cryptography" >}})| v1.11 | +| **actor 状态 TTL** | 允许 actor 将记录保存到状态存储中,并设置生存时间 (TTL) 以自动清理旧数据。在当前实现中,带有 TTL 的 actor 状态可能无法被客户端正确反映。请阅读 [actor 状态事务]({{< ref actors_api.md >}}) 以获取更多信息。 | `ActorStateTTL` | [actor 状态事务]({{< ref actors_api.md >}}) | v1.11 | +| **组件热重载** | 允许 Dapr 加载的组件进行“热重载”。当在 Kubernetes 中或在自托管模式下更新文件中的组件规范时,组件会被重新加载。对 actor 状态存储和工作流后端的更改将被忽略。 | `HotReload`| [热重载]({{< ref components-concept.md >}}) | v1.13 | +| **订阅热重载** | 允许声明性订阅进行“热重载”。当在 Kubernetes 中更新订阅时,或在自托管模式下更新文件中的订阅时,订阅会被重新加载。重载时不会影响正在进行的消息。 | `HotReload`| [热重载]({{< ref "subscription-methods.md#declarative-subscriptions" >}}) | v1.14 | +| **调度器 actor 提醒** | 调度器 actor 提醒是存储在调度器控制平面服务中的 actor 提醒,与存储在放置控制平面服务中的 actor 提醒系统不同。`SchedulerReminders` 预览功能默认设置为 `true`,但您可以通过将其设置为 `false` 来禁用调度器 actor 提醒。 | `SchedulerReminders`| [调度器 actor 提醒]({{< ref "scheduler.md#actor-reminders" >}}) | v1.14 | diff --git a/src/translated_content/zh_CN/docs/operations/support/support-release-policy.md b/src/translated_content/zh_CN/docs/operations/support/support-release-policy.md new file mode 100644 index 000000000..bf07e3b42 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/support/support-release-policy.md @@ -0,0 +1,165 @@ +--- +type: docs +title: "支持的运行时和SDK版本" +linkTitle: "支持的版本" +weight: 2000 +description: "运行时和SDK版本的支持和升级策略" +--- + +## 介绍 +本主题详细介绍了Dapr版本的支持策略、升级策略,以及在所有Dapr代码库(如运行时、CLI、SDK等)中如何传达弃用和重大更改的信息,适用于1.x及以上版本。 + +Dapr版本采用`MAJOR.MINOR.PATCH`的版本号格式。例如,1.0.0。 + +| 版本号 | 描述 | +| ---------- | ----------- | +| `MAJOR` | 当运行时有不兼容的更改时更新,例如API的更改。`MAJOR`版本也可能在有显著功能添加或更改时发布,以便与之前版本区分。 | +| `MINOR` | 作为常规发布节奏的一部分更新,包括新功能、错误修复和安全修复。 | +| `PATCH` | 针对关键问题(如P0问题)和安全修复进行更新。 | + +支持的版本指的是: + +- 如果版本存在关键问题,例如主线中断或安全问题,将发布修补程序。每个问题都根据具体情况进行评估。 +- 对支持的版本进行问题调查。如果版本不再受支持,您需要升级到较新的版本以确定问题是否仍然存在。 + +从1.8.0版本开始,Dapr支持三个版本:当前版本和之前的两个版本。通常这些是`MINOR`版本更新。这意味着支持版本的动态窗口会向前移动,您有责任保持这些支持版本的最新状态。如果您使用较旧版本的Dapr,可能需要进行中间升级以达到支持的版本。 + +在major.minor版本发布之间至少有13周(3个月)的时间,给用户至少9个月的时间从不支持的版本进行升级。有关发布过程的更多详细信息,请阅读[发布周期和节奏](https://github.com/dapr/community/blob/master/release-process.md)。 + +补丁支持适用于当前和之前的支持版本。 + +## 构建变体 + +Dapr的sidecar镜像被发布到[GitHub容器注册表](https://github.com/dapr/dapr/pkgs/container/daprd)和[Docker注册表](https://hub.docker.com/r/daprio/daprd/tags)。默认镜像包含所有组件。从1.11版本开始,Dapr还提供了仅包含稳定组件的sidecar镜像变体。 + +* 默认sidecar镜像:`daprio/daprd:`或`ghcr.io/dapr/daprd:`(例如`ghcr.io/dapr/daprd:1.11.1`) +* 稳定组件的sidecar镜像:`daprio/daprd:-stablecomponents`或`ghcr.io/dapr/daprd:-stablecomponents`(例如`ghcr.io/dapr/daprd:1.11.1-stablecomponents`) + +在Kubernetes上,可以通过`dapr.io/sidecar-image`注释覆盖应用程序部署资源的sidecar镜像。有关更多信息,请参阅[Dapr的参数和注释]({{< ref "arguments-annotations-overview.md" >}})。如果未指定,则使用默认的'daprio/daprd:latest'镜像。 + +了解更多关于[Dapr组件的认证生命周期]({{< ref "certification-lifecycle.md" >}})。 + +## 支持的版本 + +下表显示了已一起测试并形成“打包”发布的Dapr版本。任何其他版本组合都不受支持。 + +| 发布日期 | 运行时 | CLI | SDKs | 仪表板 | 状态 | 发布说明 | +|--------------------|:--------:|:--------|---------|---------|---------|------------| +| 2024年9月16日 | 1.14.4
| 1.14.1 | Java 1.12.0
Go 1.11.0
PHP 1.2.0
Python 1.14.0
.NET 1.14.0
JS 3.3.1 | 0.15.0 | 支持(当前) | [v1.14.4发布说明](https://github.com/dapr/dapr/releases/tag/v1.14.4) | +| 2024年9月13日 | 1.14.3
| 1.14.1 | Java 1.12.0
Go 1.11.0
PHP 1.2.0
Python 1.14.0
.NET 1.14.0
JS 3.3.1 | 0.15.0 | ⚠️ 已召回 | [v1.14.3发布说明](https://github.com/dapr/dapr/releases/tag/v1.14.3) | +| 2024年9月6日 | 1.14.2
| 1.14.1 | Java 1.12.0
Go 1.11.0
PHP 1.2.0
Python 1.14.0
.NET 1.14.0
JS 3.3.1 | 0.15.0 | 支持(当前) | [v1.14.2发布说明](https://github.com/dapr/dapr/releases/tag/v1.14.2) | +| 2024年8月14日 | 1.14.1
| 1.14.1 | Java 1.12.0
Go 1.11.0
PHP 1.2.0
Python 1.14.0
.NET 1.14.0
JS 3.3.1 | 0.15.0 | 支持(当前) | [v1.14.1发布说明](https://github.com/dapr/dapr/releases/tag/v1.14.1) | +| 2024年8月14日 | 1.14.0
| 1.14.0 | Java 1.12.0
Go 1.11.0
PHP 1.2.0
Python 1.14.0
.NET 1.14.0
JS 3.3.1 | 0.15.0 | 支持(当前) | [v1.14.0发布说明](https://github.com/dapr/dapr/releases/tag/v1.14.0) | +| 2024年5月29日 | 1.13.4
| 1.13.0 | Java 1.11.0
Go 1.10.0
PHP 1.2.0
Python 1.13.0
.NET 1.13.0
JS 3.3.0 | 0.14.0 | 支持 | [v1.13.4发布说明](https://github.com/dapr/dapr/releases/tag/v1.13.4) | +| 2024年5月21日 | 1.13.3
| 1.13.0 | Java 1.11.0
Go 1.10.0
PHP 1.2.0
Python 1.13.0
.NET 1.13.0
JS 3.3.0 | 0.14.0 | 支持 | [v1.13.3发布说明](https://github.com/dapr/dapr/releases/tag/v1.13.3) | +| 2024年4月3日 | 1.13.2
| 1.13.0 | Java 1.11.0
Go 1.10.0
PHP 1.2.0
Python 1.13.0
.NET 1.13.0
JS 3.3.0 | 0.14.0 | 支持 | [v1.13.2发布说明](https://github.com/dapr/dapr/releases/tag/v1.13.2) | +| 2024年3月26日 | 1.13.1
| 1.13.0 | Java 1.11.0
Go 1.10.0
PHP 1.2.0
Python 1.13.0
.NET 1.13.0
JS 3.3.0 | 0.14.0 | 支持 | [v1.13.1发布说明](https://github.com/dapr/dapr/releases/tag/v1.13.1) | +| 2024年3月6日 | 1.13.0
| 1.13.0 | Java 1.11.0
Go 1.10.0
PHP 1.2.0
Python 1.13.0
.NET 1.13.0
JS 3.3.0 | 0.14.0 | 支持 | [v1.13.0发布说明](https://github.com/dapr/dapr/releases/tag/v1.13.0) | +| 2024年1月17日 | 1.12.4
| 1.12.0 | Java 1.10.0
Go 1.9.1
PHP 1.2.0
Python 1.12.0
.NET 1.12.0
JS 3.2.0 | 0.14.0 | 支持 | [v1.12.4发布说明](https://github.com/dapr/dapr/releases/tag/v1.12.4) | +| 2024年1月2日 | 1.12.3
| 1.12.0 | Java 1.10.0
Go 1.9.1
PHP 1.2.0
Python 1.12.0
.NET 1.12.0
JS 3.2.0 | 0.14.0 | 支持 | [v1.12.3发布说明](https://github.com/dapr/dapr/releases/tag/v1.12.3) | +| 2023年11月18日 | 1.12.2
| 1.12.0 | Java 1.10.0
Go 1.9.1
PHP 1.2.0
Python 1.12.0
.NET 1.12.0
JS 3.2.0 | 0.14.0 | 支持 | [v1.12.2发布说明](https://github.com/dapr/dapr/releases/tag/v1.12.2) | +| 2023年11月16日 | 1.12.1
| 1.12.0 | Java 1.10.0
Go 1.9.1
PHP 1.2.0
Python 1.12.0
.NET 1.12.0
JS 3.2.0 | 0.14.0 | 支持 | [v1.12.1发布说明](https://github.com/dapr/dapr/releases/tag/v1.12.1) | +| 2023年10月11日 | 1.12.0
| 1.12.0 | Java 1.10.0
Go 1.9.0
PHP 1.1.0
Python 1.11.0
.NET 1.12.0
JS 3.1.2 | 0.14.0 | 支持 | [v1.12.0发布说明](https://github.com/dapr/dapr/releases/tag/v1.12.0) | +| 2023年11月18日 | 1.11.6
| 1.11.0 | Java 1.9.0
Go 1.8.0
PHP 1.1.0
Python 1.10.0
.NET 1.11.0
JS 3.1.0 | 0.13.0 | 不支持 | [v1.11.6发布说明](https://github.com/dapr/dapr/releases/tag/v1.11.6) | +| 2023年11月3日 | 1.11.5
| 1.11.0 | Java 1.9.0
Go 1.8.0
PHP 1.1.0
Python 1.10.0
.NET 1.11.0
JS 3.1.0 | 0.13.0 | 不支持 | [v1.11.5发布说明](https://github.com/dapr/dapr/releases/tag/v1.11.5) | +| 2023年10月5日 | 1.11.4
| 1.11.0 | Java 1.9.0
Go 1.8.0
PHP 1.1.0
Python 1.10.0
.NET 1.11.0
JS 3.1.0 | 0.13.0 | 不支持 | [v1.11.4发布说明](https://github.com/dapr/dapr/releases/tag/v1.11.4) | +| 2023年8月31日 | 1.11.3
| 1.11.0 | Java 1.9.0
Go 1.8.0
PHP 1.1.0
Python 1.10.0
.NET 1.11.0
JS 3.1.0 | 0.13.0 | 不支持 | [v1.11.3发布说明](https://github.com/dapr/dapr/releases/tag/v1.11.3) | +| 2023年7月20日 | 1.11.2
| 1.11.0 | Java 1.9.0
Go 1.8.0
PHP 1.1.0
Python 1.10.0
.NET 1.11.0
JS 3.1.0 | 0.13.0 | 不支持 | [v1.11.2发布说明](https://github.com/dapr/dapr/releases/tag/v1.11.2) | +| 2023年6月22日 | 1.11.1
| 1.11.0 | Java 1.9.0
Go 1.8.0
PHP 1.1.0
Python 1.10.0
.NET 1.11.0
JS 3.1.0 | 0.13.0 | 不支持 | [v1.11.1发布说明](https://github.com/dapr/dapr/releases/tag/v1.11.1) | +| 2023年6月12日 | 1.11.0
| 1.11.0 | Java 1.9.0
Go 1.8.0
PHP 1.1.0
Python 1.10.0
.NET 1.11.0
JS 3.1.0 | 0.13.0 | 不支持 | [v1.11.0发布说明](https://github.com/dapr/dapr/releases/tag/v1.11.0) | +| 2023年11月18日 | 1.10.10
| 1.10.0 | Java 1.8.0
Go 1.7.0
PHP 1.1.0
Python 1.9.0
.NET 1.10.0
JS 3.0.0 | 0.11.0 | 不支持 | | +| 2023年7月20日 | 1.10.9
| 1.10.0 | Java 1.8.0
Go 1.7.0
PHP 1.1.0
Python 1.9.0
.NET 1.10.0
JS 3.0.0 | 0.11.0 | 不支持 | | +| 2023年6月22日 | 1.10.8
| 1.10.0 | Java 1.8.0
Go 1.7.0
PHP 1.1.0
Python 1.9.0
.NET 1.10.0
JS 3.0.0 | 0.11.0 | 不支持 | | +| 2023年5月15日 | 1.10.7
| 1.10.0 | Java 1.8.0
Go 1.7.0
PHP 1.1.0
Python 1.9.0
.NET 1.10.0
JS 3.0.0 | 0.11.0 | 不支持 | | +| 2023年5月12日 | 1.10.6
| 1.10.0 | Java 1.8.0
Go 1.7.0
PHP 1.1.0
Python 1.9.0
.NET 1.10.0
JS 3.0.0 | 0.11.0 | 不支持 | | +| 2023年4月13日 |1.10.5
| 1.10.0 | Java 1.8.0
Go 1.6.0
PHP 1.1.0
Python 1.9.0
.NET 1.10.0
JS 3.0.0 | 0.11.0 | 不支持 | | +| 2023年3月16日 | 1.10.4
| 1.10.0 | Java 1.8.0
Go 1.6.0
PHP 1.1.0
Python 1.9.0
.NET 1.10.0
JS 2.5.0 | 0.11.0 | 不支持 | | +| 2023年3月14日 | 1.10.3
| 1.10.0 | Java 1.8.0
Go 1.6.0
PHP 1.1.0
Python 1.9.0
.NET 1.10.0
JS 2.5.0 | 0.11.0 | 不支持 | | +| 2023年2月24日 | 1.10.2
| 1.10.0 | Java 1.8.0
Go 1.6.0
PHP 1.1.0
Python 1.9.0
.NET 1.10.0
JS 2.5.0 | 0.11.0 | 不支持 | | +| 2023年2月20日 | 1.10.1
| 1.10.0 | Java 1.8.0
Go 1.6.0
PHP 1.1.0
Python 1.9.0
.NET 1.10.0
JS 2.5.0 | 0.11.0 | 不支持 | | +| 2023年2月14日 | 1.10.0
| 1.10.0 | Java 1.8.0
Go 1.6.0
PHP 1.1.0
Python 1.9.0
.NET 1.10.0
JS 2.5.0 | 0.11.0 | 不支持 | | +| 2022年12月2日 | 1.9.5
| 1.9.1 | Java 1.7.0
Go 1.6.0
PHP 1.1.0
Python 1.8.3
.NET 1.9.0
JS 2.4.2 | 0.11.0 | 不支持 | | +| 2022年11月17日 | 1.9.4
| 1.9.1 | Java 1.7.0
Go 1.6.0
PHP 1.1.0
Python 1.8.3
.NET 1.9.0
JS 2.4.2 | 0.11.0 | 不支持 | | +| 2022年11月4日 | 1.9.3
| 1.9.1 | Java 1.7.0
Go 1.6.0
PHP 1.1.0
Python 1.8.3
.NET 1.9.0
JS 2.4.2 | 0.11.0 | 不支持 | | +| 2022年11月1日 | 1.9.2
| 1.9.1 | Java 1.7.0
Go 1.6.0
PHP 1.1.0
Python 1.8.1
.NET 1.9.0
JS 2.4.2 | 0.11.0 | 不支持 | | +| 2022年10月26日 | 1.9.1
| 1.9.1 | Java 1.7.0
Go 1.6.0
PHP 1.1.0
Python 1.8.1
.NET 1.9.0
JS 2.4.2 | 0.11.0 | 不支持 | | +| 2022年10月13日 | 1.9.0
| 1.9.1 | Java 1.7.0
Go 1.6.0
PHP 1.1.0
Python 1.8.3
.NET 1.9.0
JS 2.4.2 | 0.11.0 | 不支持 | | +| 2022年10月26日 | 1.8.6
| 1.8.1 | Java 1.6.0
Go 1.5.0
PHP 1.1.0
Python 1.7.0
.NET 1.8.0
JS 2.3.0 | 0.11.0 | 不支持 | | +| 2022年10月13日 | 1.8.5
| 1.8.1 | Java 1.6.0
Go 1.5.0
PHP 1.1.0
Python 1.7.0
.NET 1.8.0
JS 2.3.0 | 0.11.0 | 不支持 | | +| 2022年8月10日 | 1.8.4
| 1.8.1 | Java 1.6.0
Go 1.5.0
PHP 1.1.0
Python 1.7.0
.NET 1.8.0
JS 2.3.0 | 0.11.0 | 不支持 | | +| 2022年7月29日 | 1.8.3
| 1.8.0 | Java 1.6.0
Go 1.5.0
PHP 1.1.0
Python 1.7.0
.NET 1.8.0
JS 2.3.0 | 0.11.0 | 不支持 | | +| 2022年7月21日 | 1.8.2
| 1.8.0 | Java 1.6.0
Go 1.5.0
PHP 1.1.0
Python 1.7.0
.NET 1.8.0
JS 2.3.0 | 0.11.0 | 不支持 | | +| 2022年7月20日 | 1.8.1
| 1.8.0 | Java 1.6.0
Go 1.5.0
PHP 1.1.0
Python 1.7.0
.NET 1.8.0
JS 2.3.0 | 0.11.0 | 不支持 | | +| 2022年7月7日 | 1.8.0
| 1.8.0 | Java 1.6.0
Go 1.5.0
PHP 1.1.0
Python 1.7.0
.NET 1.8.0
JS 2.3.0 | 0.11.0 | 不支持 | | +| 2022年10月26日 | 1.7.5
| 1.7.0 | Java 1.5.0
Go 1.4.0
PHP 1.1.0
Python 1.6.0
.NET 1.7.0
JS 2.2.1 | 0.10.0 | 不支持 | | +| 2022年5月31日 | 1.7.4
| 1.7.0 | Java 1.5.0
Go 1.4.0
PHP 1.1.0
Python 1.6.0
.NET 1.7.0
JS 2.2.1 | 0.10.0 | 不支持 | | +| 2022年5月17日 | 1.7.3
| 1.7.0 | Java 1.5.0
Go 1.4.0
PHP 1.1.0
Python 1.6.0
.NET 1.7.0
JS 2.2.1 | 0.10.0 | 不支持 | | +| 2022年4月22日 | 1.7.2
| 1.7.0 | Java 1.5.0
Go 1.4.0
PHP 1.1.0
Python 1.6.0
.NET 1.7.0
JS 2.1.0 | 0.10.0 | 不支持 | | +| 2022年4月20日 | 1.7.1
| 1.7.0 | Java 1.5.0
Go 1.4.0
PHP 1.1.0
Python 1.6.0
.NET 1.7.0
JS 2.1.0 | 0.10.0 | 不支持 | | +| 2022年4月7日 | 1.7.0
| 1.7.0 | Java 1.5.0
Go 1.4.0
PHP 1.1.0
Python 1.6.0
.NET 1.7.0
JS 2.1.0 | 0.10.0 | 不支持 | | +| 2022年4月20日 | 1.6.2
| 1.6.0 | Java 1.4.0
Go 1.3.1
PHP 1.1.0
Python 1.5.0
.NET 1.6.0
JS 2.0.0 | 0.9.0 | 不支持 | | +| 2022年3月25日 | 1.6.1
| 1.6.0 | Java 1.4.0
Go 1.3.1
PHP 1.1.0
Python 1.5.0
.NET 1.6.0
JS 2.0.0 | 0.9.0 | 不支持 | | +| 2022年1月25日 | 1.6.0
| 1.6.0 | Java 1.4.0
Go 1.3.1
PHP 1.1.0
Python 1.5.0
.NET 1.6.0
JS 2.0.0 | 0.9.0 | 不支持 | | + +## SDK兼容性 +SDK和运行时承诺除了安全问题所需的更改外,不会有重大更改。如果需要,所有重大更改都会在发布说明中宣布。 + +**SDK和运行时的前向兼容性** +较新的Dapr SDK支持最新版本的Dapr运行时和之前的两个版本(N-2)。 + +**SDK和运行时的后向兼容性** +对于新的Dapr运行时,当前的SDK版本和之前的两个版本(N-2)都受到支持。 + +## 升级路径 + +在运行时1.0版本发布后,可能会出现需要通过额外版本显式升级以达到目标的情况。例如,从v1.0升级到v1.2可能需要经过v1.1。 + +{{% alert title="注意" color="primary" %}} +Dapr仅在单个次要版本中升级补丁版本或从一个次要版本升级到下一个次要版本时提供无缝保证。例如,从`v1.6.0`升级到`v1.6.4`或`v1.6.4`升级到`v1.7.0`是经过保证测试的。一次升级多个次要版本是未经测试的,并被视为尽力而为。 +{{% /alert %}} + +下表显示了Dapr运行时的测试升级路径。任何其他升级组合都没有经过测试。 + +有关升级的一般指导可以在[selfhost模式]({{< ref self-hosted-upgrade >}})和[Kubernetes]({{< ref kubernetes-upgrade >}})部署中找到。最好查看目标版本的发布说明以获得具体指导。 + +| 当前运行时版本 | 必须通过的版本 | 目标运行时版本 | +|--------------------------|-----------------------|------------------------- | +| 1.5.0 到 1.5.2 | N/A | 1.6.0 | +| | 1.6.0 | 1.6.2 | +| | 1.6.2 | 1.7.5 | +| | 1.7.5 | 1.8.6 | +| | 1.8.6 | 1.9.6 | +| | 1.9.6 | 1.10.7 | +| 1.6.0 到 1.6.2 | N/A | 1.7.5 | +| | 1.7.5 | 1.8.6 | +| | 1.8.6 | 1.9.6 | +| | 1.9.6 | 1.10.7 | +| 1.7.0 到 1.7.5 | N/A | 1.8.6 | +| | 1.8.6 | 1.9.6 | +| | 1.9.6 | 1.10.7 | +| 1.8.0 到 1.8.6 | N/A | 1.9.6 | +| 1.9.0 到 1.9.6 | N/A | 1.10.8 | +| 1.10.0 到 1.10.8 | N/A | 1.11.4 | +| 1.11.0 到 1.11.4 | N/A | 1.12.4 | +| 1.12.0 到 1.12.4 | N/A | 1.13.5 | +| 1.13.0 到 1.13.5 | N/A | 1.14.0 | +| 1.14.0 到 1.14.2 | N/A | 1.14.2 | + +## 在托管平台上升级 + +Dapr可以支持多个生产托管平台。在1.0版本发布时,支持的两个平台是Kubernetes和物理机。有关Kubernetes升级,请参阅[Kubernetes上的生产指南]({{< ref kubernetes-production.md >}}) + +### 依赖项的支持版本 + +以下是最新版本的Dapr(v{{% dapr-latest-version long="true" %}})已测试的软件列表。 + +| 依赖项 | 支持的版本 | +|-----------------------|----------------------------------------------------------------------------------------------------------------------------------| +| Kubernetes | Dapr对Kubernetes的支持与[Kubernetes版本偏差策略](https://kubernetes.io/releases/version-skew-policy/)保持一致 | +| [Open Telemetry collector (OTEL)](https://github.com/open-telemetry/opentelemetry-collector/releases)| v0.101.0| +| [Prometheus](https://prometheus.io/download/) | v2.28 | + +## 相关链接 + +- 阅读[版本控制策略]({{< ref support-versioning.md >}}) +- 阅读[重大更改和弃用策略]({{< ref breaking-changes-and-deprecations.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/support/support-security-issues.md b/src/translated_content/zh_CN/docs/operations/support/support-security-issues.md new file mode 100644 index 000000000..c7bdd919d --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/support/support-security-issues.md @@ -0,0 +1,49 @@ +--- +type: docs +title: "报告安全问题" +linkTitle: "报告安全问题" +weight: 3000 +description: "如何向 Dapr 维护者报告安全问题或漏洞。" +--- + +Dapr 项目和维护者将安全性视为操作和设计软件的核心关注点。从 Dapr 二进制文件到 GitHub 发布流程,我们采取了多种措施以确保用户应用程序和数据的安全。有关 Dapr 安全功能的更多信息,请访问[安全页面]({{< ref security-concept.md >}})。 + +## 涵盖的存储库和问题 + +提到“Dapr 中的安全漏洞”时,指的是[dapr GitHub 组织](https://github.com/dapr/)下任何存储库中的安全问题。 + +此报告流程仅适用于 Dapr 项目本身的安全问题,不适用于使用 Dapr 的应用程序或不影响安全性的问题。 + +如果问题无法通过对上述涵盖的存储库之一的更改来解决,建议在适当的存储库中创建 GitHub 问题或在 Discord 中提出问题。 + +**如果您不确定,**请谨慎行事,在通过 GitHub、Discord 或其他渠道提出问题之前,使用报告流程进行联系。 + +### 明确不涵盖:漏洞扫描器报告 + +我们不接受仅仅是从漏洞扫描工具复制粘贴输出的报告,**除非**已经专门确认工具报告的漏洞确实存在于 Dapr 中,包括 CLI、Dapr SDKs、components-contrib 存储库或 Dapr 组织下的任何其他存储库。 + +我们也使用这些工具,并根据它们的输出采取行动。然而,当这些报告被发送到我们的安全邮件列表时,通常是误报,因为这些工具往往只检查库的存在,而不考虑库在上下文中的使用方式。 + +如果我们收到的报告似乎只是来自扫描器的漏洞列表,我们保留忽略它的权利。 + +这尤其适用于工具生成的漏洞标识符不是公开可见或以某种方式是专有的情况。我们可以查找 CVE 或其他公开可用的标识符以获取更多详细信息,但不能对专有标识符执行相同操作。 + +## 安全联系人 + +有权阅读您的安全报告的人列在[`maintainers.md`](https://github.com/dapr/community/blob/master/MAINTAINERS.md)中。 + +## 报告流程 + +1. 用英语描述问题,最好附上一些示例配置或代码,以便重现问题。解释为什么您认为这是 Dapr 中的安全问题。 +2. 将这些信息放入电子邮件中。使用描述性标题。 +3. 发送电子邮件至[Security (security@dapr.io)](mailto:security@dapr.io?subject=[Security%20Disclosure]:%20ISSUE%20TITLE) + +## 响应 + +响应时间可能会受到周末、假期、休息或时区差异的影响。尽管如此,维护者团队会尽快回复,理想情况下在 3 个工作日内。 + +如果团队得出结论认为报告的问题确实是 Dapr 项目中的安全漏洞,至少两名维护者团队成员会尽快讨论下一步,理想情况下在 24 小时内。 + +一旦团队决定报告是真实漏洞,团队中的一名成员会回复报告者,确认问题并建立披露时间表,应该尽快进行。 + +分类、响应、修补和公告应在 30 天内完成。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/support/support-versioning.md b/src/translated_content/zh_CN/docs/operations/support/support-versioning.md new file mode 100644 index 000000000..950050245 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/support/support-versioning.md @@ -0,0 +1,111 @@ +--- +type: docs +title: "版本控制政策" +linkTitle: "版本控制" +weight: 1000 +description: "Dapr 的版本控制政策" +--- + +## 介绍 +Dapr 通过版本控制方案为未来的运行时、API 和组件的变化做好了设计。本主题描述了 API、组件和 Github 仓库的版本控制方案和策略。 + +## 版本控制 +版本控制是为计算机软件的每个独特状态分配唯一版本名称或版本号的过程。 +- 版本控制提供兼容性、明确的变更控制,并处理变更,尤其是重大变更。 +- Dapr 力求保持向后兼容性。如果需要重大变更,将会[提前宣布]({{< ref "support-release-policy#feature-and-deprecations" >}})。 +- 废弃的功能将在多个版本中逐步淘汰,新旧功能将并行工作。 + +版本控制涉及以下 Dapr 仓库:dapr、CLI、稳定语言 SDK、dashboard、components-contrib、quickstarts、helm-charts 和文档。 + +Dapr 具有以下版本控制方案: +- Dapr `HTTP API` 采用 `MAJOR.MINOR` 版本控制 +- Dapr `GRPC API` 采用 `MAJOR` 版本控制 +- 发布版本(包括 GitHub 仓库中的 dapr、CLI、SDK 和 Helm Chart)采用 `MAJOR.MINOR.PATCH` 版本控制 +- 文档和 Quickstarts 仓库与 Dapr 运行时仓库版本控制一致。 +- Dapr `组件` 在 components-contrib GitHub 仓库中采用 `MAJOR` 版本控制。 +- Dapr `清单` 采用 `MAJOR.MINOR` 版本控制。这些包括订阅和配置。 + +请注意,Dapr 的 API、二进制发布(运行时、CLI、SDK)和组件都是相互独立的。 + +## Dapr HTTP API +Dapr HTTP API 根据这些[REST API 指南](https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#71-url-structure)进行版本控制。 + +根据这些指南; +- 当预期旧版本的弃用时,API 的 `MAJOR` 版本会递增。任何此类弃用将被通知,并提供升级路径。 +- `MINOR` 版本*可能*因其他更改而递增。例如,发送到 API 的消息的 JSON 模式的更改。 +API 的重大变更定义可以在[这里](https://github.com/microsoft/api-guidelines/blob/vNext/Guidelines.md#123-definition-of-a-breaking-change)查看。 +- 实验性 API 包含一个“alpha”后缀以表示其 alpha 状态。例如 v1.0alpha、v2.0alpha 等。 + +## Dapr 运行时 +Dapr 发布使用 `MAJOR.MINOR.PATCH` 版本控制。例如 1.0.0。阅读[支持的发布]({{< ref support-release-policy.md >}})以了解更多关于发布版本控制的信息。 + +## Helm Charts +[helm-charts 仓库](https://github.com/dapr/helm-charts)中的 Helm charts 与 Dapr 运行时版本一致。Helm charts 用于[Kubernetes 部署]({{< ref "kubernetes-deploy#install-with-helm-advanced" >}}) + +## 语言 SDK、CLI 和 dashboard +Dapr 语言 SDK、CLI 和 dashboard 独立于 Dapr 运行时进行版本控制,并可以在不同的时间表上发布。请参阅此[表格]({{< ref "support-release-policy#supported-versions" >}})以显示 SDK、CLI、dashboard 和运行时版本之间的兼容性。每个新的运行时发布都会列出相应支持的 SDK、CLI 和 Dashboard。 + +SDK、CLI 和 Dashboard 的版本控制遵循 `MAJOR.MINOR.PATCH` 格式。当 SDK 中存在非向后兼容的更改时(例如,更改客户端方法的参数),主版本会递增。次版本用于新功能和错误修复,补丁版本在出现错误或安全热修复时递增。 + +SDK 中的示例和例子与该仓库的版本一致。 + +## 组件 +组件在 components-contrib 仓库中实现,并遵循 `MAJOR` 版本控制方案。组件的版本遵循主版本(vX),因为补丁和非破坏性更改会添加到最新的主版本中。当组件接口中存在非向后兼容的更改时,例如更改 State Store 接口中的现有方法,版本会递增。 + +[components-contrib](https://github.com/dapr/components-contrib/) 仓库发布是所有内部组件的统一版本。也就是说,components-contrib 仓库发布的版本由其内部所有组件的模式组成。如果没有组件更改,Dapr 的新版本并不意味着 components-contrib 有新的发布。 + +注意:组件具有生产使用生命周期状态:Alpha、Beta 和 Stable。这些状态与其版本控制无关。支持的组件表显示了它们的版本和状态。 +* [state store 组件列表]({{< ref supported-state-stores.md >}}) +* [pub/sub 组件列表]({{< ref supported-pubsub.md >}}) +* [binding 组件列表]({{< ref supported-bindings.md >}}) +* [secret store 组件列表]({{< ref supported-secret-stores.md >}}) +* [configuration store 组件列表]({{< ref supported-configuration-stores.md >}}) +* [lock 组件列表]({{< ref supported-locks.md >}}) +* [cryptography 组件列表]({{< ref supported-cryptography.md >}}) +* [middleware 组件列表]({{< ref supported-middleware.md >}}) + +有关组件版本控制的更多信息,请阅读[组件的版本 2 及以后](https://github.com/dapr/components-contrib/blob/master/docs/developing-component.md#version-2-and-beyond-of-a-component) + +### 组件模式 + +组件 YAML 的版本控制有两种形式: +- 组件清单的版本控制。`apiVersion` +- 组件实现的版本。`.spec.version` + +组件清单在 `.spec.metadata` 字段中包含实现的模式,`.type` 字段表示实现 + +请参阅下面示例中的注释: +```yaml +apiVersion: dapr.io/v1alpha1 # <-- 这是组件清单的版本 +kind: Component +metadata: + name: pubsub +spec: + version: v1 # <-- 这是 pubsub.redis 模式实现的版本 + type: pubsub.redis + metadata: + - name: redisHost + value: redis-master:6379 + - name: redisPassword + value: general-kenobi +``` + +### 组件清单版本 +组件 YAML 清单的版本为 `dapr.io/v1alpha1`。 + +### 组件实现版本 +组件实现的版本由示例中的 `.spec.version` 字段确定。`.spec.version` 字段在模式实例中是必需的,如果不存在,该组件将无法加载。在 Dapr 1.0.0 发布时,所有组件都标记为 `v1`。组件实现版本仅在非向后兼容更改时递增。 + +### 组件弃用 +组件的弃用将在两个(2)版本之前宣布。组件的弃用会导致组件版本的主版本更新。经过 2 个版本后,该组件将从 Dapr 运行时中注销,尝试加载它将抛出致命异常。 + +组件的弃用和移除将在发布说明中宣布。 + +## Quickstarts 和示例 +[Quickstarts 仓库](https://github.com/dapr/quickstarts)中的 Quickstarts 与运行时版本一致,其中相应版本的表格位于示例仓库的首页。用户应仅使用与正在运行的运行时版本相对应的 Quickstarts。 + +[Samples 仓库](https://github.com/dapr/samples)中的示例根据示例维护者的情况逐个版本控制。与运行时发布(多个版本之前)非常不一致或超过 1 年未维护的示例将被移除。 + +## 相关链接 +* 阅读[支持的发布]({{< ref support-release-policy.md >}}) +* 阅读[重大变更和弃用政策]({{< ref breaking-changes-and-deprecations.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/troubleshooting/_index.md b/src/translated_content/zh_CN/docs/operations/troubleshooting/_index.md new file mode 100644 index 000000000..e4bcc9d52 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/troubleshooting/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "调试与故障排除" +linkTitle: "调试与故障排除" +weight: 700 +description: "提供工具、技术和常见问题,帮助用户有效调试和诊断Dapr相关问题" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/troubleshooting/api-logs-troubleshooting.md b/src/translated_content/zh_CN/docs/operations/troubleshooting/api-logs-troubleshooting.md new file mode 100644 index 000000000..819287b6d --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/troubleshooting/api-logs-troubleshooting.md @@ -0,0 +1,128 @@ +--- +type: docs +title: "Dapr API 日志" +linkTitle: "API 日志" +weight: 3000 +description: "了解 Dapr 中的 API 日志记录工作原理以及如何查看日志" +--- + +API 日志记录可以让您查看应用程序对 Dapr sidecar 的 API 调用情况。这对于监控应用程序行为或进行调试非常有用。您还可以将 Dapr API 日志记录与 Dapr 日志事件结合使用(参见[配置和查看 Dapr 日志]({{< ref "logs-troubleshooting.md" >}})),以便更好地利用日志记录功能。 + +## 概述 + +API 日志记录默认情况下是禁用的。 + +要启用 API 日志记录,可以在启动 `daprd` 进程时使用 `--enable-api-logging` 命令行选项。例如: + +```bash +./daprd --enable-api-logging +``` + +## 在自托管模式下配置 API 日志记录 + +当使用 Dapr CLI 运行应用程序时,要启用 API 日志记录,请传递 `--enable-api-logging` 标志: + +```bash +dapr run \ + --enable-api-logging \ + -- node myapp.js +``` + +### 在自托管模式下查看 API 日志 + +使用 Dapr CLI 运行 Dapr 时,您的应用程序日志输出和 Dapr 运行时日志输出会被重定向到同一会话中,便于调试。 + +下面的示例显示了一些 API 日志: + +```bash +$ dapr run --enable-api-logging -- node myapp.js + +ℹ️ Starting Dapr with id order-processor on port 56730 +✅ You are up and running! Both Dapr and your app logs will appear here. +..... +INFO[0000] HTTP API Called app_id=order-processor instance=mypc method="POST /v1.0/state/mystate" scope=dapr.runtime.http-info type=log useragent=Go-http-client/1.1 ver=edge +== APP == INFO:root:Saving Order: {'orderId': '483'} +INFO[0000] HTTP API Called app_id=order-processor instance=mypc method="GET /v1.0/state/mystate/key123" scope=dapr.runtime.http-info type=log useragent=Go-http-client/1.1 ver=edge +== APP == INFO:root:Getting Order: {'orderId': '483'} +INFO[0000] HTTP API Called app_id=order-processor instance=mypc method="DELETE /v1.0/state/mystate" scope=dapr.runtime.http-info type=log useragent=Go-http-client/1.1 ver=edge +== APP == INFO:root:Deleted Order: {'orderId': '483'} +INFO[0000] HTTP API Called app_id=order-processor instance=mypc method="PUT /v1.0/metadata/cliPID" scope=dapr.runtime.http-info type=log useragent=Go-http-client/1.1 ver=edge +``` + +## 在 Kubernetes 中配置 API 日志记录 + +您可以通过在 pod 规范模板中添加以下注释来为 sidecar 启用 API 日志: + +```yaml +annotations: + dapr.io/enable-api-logging: "true" +``` + +### 在 Kubernetes 上查看 API 日志 + +Dapr API 日志会被写入标准输出(stdout)和标准错误(stderr),您可以在 Kubernetes 上查看这些日志。 + +通过执行以下命令查看 Kubernetes API 日志。 + +```bash +kubectl logs daprd -n +``` + +下面的示例显示了在 Kubernetes 中的 `info` 级别 API 日志记录(启用了[URL 混淆](#obfuscate-urls-in-http-api-logging))。 + +```bash +time="2022-03-16T18:32:02.487041454Z" level=info msg="HTTP API Called" method="POST /v1.0/invoke/{id}/method/{method:*}" app_id=invoke-caller instance=invokecaller-f4f949886-cbnmt scope=dapr.runtime.http-info type=log useragent=Go-http-client/1.1 ver=edge +time="2022-03-16T18:32:02.698387866Z" level=info msg="HTTP API Called" method="POST /v1.0/invoke/{id}/method/{method:*}" app_id=invoke-caller instance=invokecaller-f4f949886-cbnmt scope=dapr.runtime.http-info type=log useragent=Go-http-client/1.1 ver=edge +time="2022-03-16T18:32:02.917629403Z" level=info msg="HTTP API Called" method="POST /v1.0/invoke/{id}/method/{method:*}" app_id=invoke-caller instance=invokecaller-f4f949886-cbnmt scope=dapr.runtime.http-info type=log useragent=Go-http-client/1.1 ver=edge +time="2022-03-16T18:32:03.137830112Z" level=info msg="HTTP API Called" method="POST /v1.0/invoke/{id}/method/{method:*}" app_id=invoke-caller instance=invokecaller-f4f949886-cbnmt scope=dapr.runtime.http-info type=log useragent=Go-http-client/1.1 ver=edge +time="2022-03-16T18:32:03.359097916Z" level=info msg="HTTP API Called" method="POST /v1.0/invoke/{id}/method/{method:*}" app_id=invoke-caller instance=invokecaller-f4f949886-cbnmt scope=dapr.runtime.http-info type=log useragent=Go-http-client/1.1 ver=edge +``` + +## API 日志记录配置 + +使用 [Dapr 配置规范]({{< ref "configuration-overview.md" >}}#sidecar-configuration),您可以配置 Dapr 运行时中 API 日志记录的默认行为。 + +### 默认启用 API 日志记录 + +使用 Dapr 配置规范,您可以为 `--enable-api-logging` 标志(以及在 Kubernetes 上运行时的相应注释)设置默认值,使用 `logging.apiLogging.enabled` 选项。此值适用于引用定义该配置文档或资源的所有 Dapr 运行时。 + +- 如果 `logging.apiLogging.enabled` 设置为 `false`,即默认值,则 Dapr 运行时的 API 日志记录是禁用的,除非 `--enable-api-logging` 设置为 `true`(或添加 `dapr.io/enable-api-logging: true` 注释)。 +- 当 `logging.apiLogging.enabled` 为 `true` 时,Dapr 运行时默认启用 API 日志记录,可以通过设置 `--enable-api-logging=false` 或使用 `dapr.io/enable-api-logging: false` 注释来禁用。 + +例如: + +```yaml +logging: + apiLogging: + enabled: true +``` + +### 在 HTTP API 日志记录中混淆 URL + +默认情况下,HTTP 端点的 API 调用日志包括被调用的完整 URL(例如,`POST /v1.0/invoke/directory/method/user-123`),这可能包含个人可识别信息(PII)。 + +为了减少在启用 API 日志记录时意外包含 PII 的风险,Dapr 可以记录被调用的抽象路由(例如,`POST /v1.0/invoke/{id}/method/{method:*}`)。这有助于确保符合 GDPR 等隐私法规。 + +要在 Dapr 的 HTTP API 日志中启用 URL 混淆,请将 `logging.apiLogging.obfuscateURLs` 设置为 `true`。例如: + +```yaml +logging: + apiLogging: + obfuscateURLs: true +``` + +Dapr gRPC API 发出的日志不受此配置选项的影响,因为它们仅包含被调用方法的名称而不包含参数。 + +### 从 API 日志记录中省略健康检查 + +当启用 API 日志记录时,所有对 Dapr API 服务器的调用都会被记录,包括对健康检查端点的调用(例如 `/v1.0/healthz`)。根据您的环境,这可能会每分钟生成多行日志,并可能产生不必要的噪音。 + +您可以使用 Dapr 配置规范配置 Dapr 在启用 API 日志记录时不记录对健康检查端点的调用,通过设置 `logging.apiLogging.omitHealthChecks: true`。默认值为 `false`,这意味着健康检查调用会记录在 API 日志中。 + +例如: + +```yaml +logging: + apiLogging: + omitHealthChecks: true +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/troubleshooting/common_issues.md b/src/translated_content/zh_CN/docs/operations/troubleshooting/common_issues.md new file mode 100644 index 000000000..ab8709057 --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/troubleshooting/common_issues.md @@ -0,0 +1,291 @@ +--- +type: docs +title: "运行 Dapr 时的常见问题" +linkTitle: "常见问题" +weight: 1000 +description: "运行 Dapr 应用程序时遇到的常见问题和问题" +--- + +本指南涵盖了安装和运行 Dapr 时可能遇到的常见问题。 + +## 安装 Dapr CLI 时 Dapr 无法连接到 Docker + +在安装和初始化 Dapr CLI 时,如果在运行 `dapr init` 后看到以下错误信息: + +```bash +⌛ 正在进行初始化... +❌ 无法连接到 Docker。Docker 可能未安装或未运行 +``` + +请通过以下步骤进行排查: + +1. [确保容器正确运行。]({{< ref "install-dapr-selfhost.md#step-4-verify-containers-are-running" >}}) +2. 在 Docker Desktop 中,确认已选择 **允许使用默认 Docker 套接字(需要密码)** 选项。 + + + +## 我没有看到 Dapr sidecar 注入到我的 pod 中 + +sidecar 未注入到 pod 中可能有多种原因。首先,检查您的部署或 pod YAML 文件,确保在正确的位置有以下注释: + +```yaml +annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "nodeapp" + dapr.io/app-port: "3000" +``` + +### 示例部署: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nodeapp + namespace: default + labels: + app: node +spec: + replicas: 1 + selector: + matchLabels: + app: node + template: + metadata: + labels: + app: node + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "nodeapp" + dapr.io/app-port: "3000" + spec: + containers: + - name: node + image: dapriosamples/hello-k8s-node + ports: + - containerPort: 3000 + imagePullPolicy: Always +``` + +在某些情况下,这可能无法正常工作: + +- 如果您的 pod 规范模板注释正确,但仍未看到 sidecar 注入,请确保在部署或 pod 部署之前,Dapr 已部署到集群中。 + + 如果是这种情况,重启 pod 将解决问题。 + +- 如果您在私有 GKE 集群上部署 Dapr,sidecar 注入在没有额外步骤的情况下不起作用。请参阅 [设置 Google Kubernetes Engine 集群]({{< ref setup-gke.md >}})。 + + 为了进一步诊断任何问题,请检查 Dapr sidecar 注入器的日志: + + ```bash + kubectl logs -l app=dapr-sidecar-injector -n dapr-system + ``` + + *注意:如果您将 Dapr 安装到不同的命名空间,请将上面的 dapr-system 替换为所需的命名空间* + +- 如果您在 Amazon EKS 上部署 Dapr 并使用诸如 Calico 的覆盖网络,您需要将 `hostNetwork` 参数设置为 true,这是 EKS 在此类 CNI 上的限制。 + + 您可以使用 Helm `values.yaml` 文件设置此参数: + + ``` + helm upgrade --install dapr dapr/dapr \ + --namespace dapr-system \ + --create-namespace \ + --values values.yaml + ``` + + `values.yaml` + ```yaml + dapr_sidecar_injector: + hostNetwork: true + ``` + + 或使用命令行: + + ``` + helm upgrade --install dapr dapr/dapr \ + --namespace dapr-system \ + --create-namespace \ + --set dapr_sidecar_injector.hostNetwork=true + ``` + +- 确保 kube api 服务器可以访问以下 webhook 服务: + - [Sidecar Mutating Webhook Injector Service](https://github.com/dapr/dapr/blob/44235fe8e8799589bb393a3124d2564db2dd6885/charts/dapr/charts/dapr_sidecar_injector/templates/dapr_sidecar_injector_deployment.yaml#L157) 在端口 __4000__,由 sidecar 注入器提供服务。 + - [Resource Conversion Webhook Service](https://github.com/dapr/dapr/blob/44235fe8e8799589bb393a3124d2564db2dd6885/charts/dapr/charts/dapr_operator/templates/dapr_operator_service.yaml#L28) 在端口 __19443__,由 operator 提供服务。 + + 请与您的集群管理员联系,以设置允许从 kube api 服务器到上述端口 __4000__ 和 __19443__ 的入口规则。 + +## 由于 daprd sidecar,我的 pod 处于 CrashLoopBackoff 或其他失败状态 + +如果 Dapr sidecar (`daprd`) 初始化时间过长,可能会被 Kubernetes 视为健康检查失败。 + +如果您的 pod 处于失败状态,您应该检查以下内容: + +```bash +kubectl describe pod +``` + +您可能会在命令输出的末尾看到如下表格: + +```txt + Normal Created 7m41s (x2 over 8m2s) kubelet, aks-agentpool-12499885-vmss000000 Created container daprd + Normal Started 7m41s (x2 over 8m2s) kubelet, aks-agentpool-12499885-vmss000000 Started container daprd + Warning Unhealthy 7m28s (x5 over 7m58s) kubelet, aks-agentpool-12499885-vmss000000 Readiness probe failed: Get http://10.244.1.10:3500/v1.0/healthz: dial tcp 10.244.1.10:3500: connect: connection refused + Warning Unhealthy 7m25s (x6 over 7m55s) kubelet, aks-agentpool-12499885-vmss000000 Liveness probe failed: Get http://10.244.1.10:3500/v1.0/healthz: dial tcp 10.244.1.10:3500: connect: connection refused + Normal Killing 7m25s (x2 over 7m43s) kubelet, aks-agentpool-12499885-vmss000000 Container daprd failed liveness probe, will be restarted + Warning BackOff 3m2s (x18 over 6m48s) kubelet, aks-agentpool-12499885-vmss000000 Back-off restarting failed container +``` + +消息 `Container daprd failed liveness probe, will be restarted` 表示 Dapr sidecar 未通过健康检查并将被重启。消息 `Readiness probe failed: Get http://10.244.1.10:3500/v1.0/healthz: dial tcp 10.244.1.10:3500: connect: connection refused` 和 `Liveness probe failed: Get http://10.244.1.10:3500/v1.0/healthz: dial tcp 10.244.1.10:3500: connect: connection refused` 表明健康检查失败是因为无法连接到 sidecar。 + +此故障的最常见原因是某个组件(如状态存储)配置错误,导致初始化时间过长。当初始化时间过长时,健康检查可能会在 sidecar 记录任何有用信息之前终止它。 + +要诊断根本原因: + +- 显著增加存活探测延迟 - [链接]({{< ref "arguments-annotations-overview.md" >}}) +- 将 sidecar 的日志级别设置为调试 - [链接]({{< ref "logs-troubleshooting.md#setting-the-sidecar-log-level" >}}) +- 观察日志以获取有意义的信息 - [链接]({{< ref "logs-troubleshooting.md#viewing-logs-on-kubernetes" >}}) + +> 解决问题后,请记得将存活检查延迟和日志级别配置回您期望的值。 + +## 我无法保存状态或获取状态 + +您是否在集群中安装了 Dapr 状态存储? + +要检查,请使用 kubectl 获取组件列表: + +```bash +kubectl get components +``` + +如果没有状态存储组件,则意味着您需要设置一个。 +访问 [这里]({{< ref "state-management" >}}) 了解更多详细信息。 + +如果一切设置正确,请确保您获得了正确的凭据。 +搜索 Dapr 运行时日志并查找任何状态存储错误: + +```bash +kubectl logs daprd +``` + +## 我无法发布和接收事件 + +您是否在集群中安装了 Dapr 消息总线? + +要检查,请使用 kubectl 获取组件列表: + +```bash +kubectl get components +``` + +如果没有 pub/sub 组件,则意味着您需要设置一个。 +访问 [这里]({{< ref "pubsub" >}}) 了解更多详细信息。 + +如果一切设置正确,请确保您获得了正确的凭据。 +搜索 Dapr 运行时日志并查找任何 pub/sub 错误: + +```bash +kubectl logs daprd +``` + +## 调用 Dapr 时收到 500 错误响应 + +这意味着 Dapr 运行时内部存在一些问题。 +要诊断,请查看 sidecar 的日志: + +```bash +kubectl logs daprd +``` + +## 调用 Dapr 时收到 404 未找到响应 + +这意味着您正在尝试调用一个不存在的 Dapr API 端点或 URL 格式错误。 +查看 Dapr API 参考 [这里]({{< ref "api" >}}) 并确保您正在调用正确的端点。 + +## 我没有看到来自其他服务的任何传入事件或调用 + +您是否指定了应用程序正在监听的端口? +在 Kubernetes 中,确保指定了 `dapr.io/app-port` 注释: + +```yaml +annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "nodeapp" + dapr.io/app-port: "3000" +``` + +如果使用 Dapr Standalone 和 Dapr CLI,请确保将 `--app-port` 标志传递给 `dapr run` 命令。 + +## 我的 Dapr 启用的应用程序行为不正确 + +首先要做的是检查 Dapr API 返回的 HTTP 错误代码(如果有)。 +如果仍然找不到问题,请尝试为 Dapr 运行时启用 `debug` 日志级别。请参阅 [这里]({{< ref "logs.md" >}}) 了解如何操作。 + +您可能还需要查看您自己进程的错误日志。如果在 Kubernetes 上运行,找到包含您的应用程序的 pod,并执行以下操作: + +```bash +kubectl logs +``` + +如果在 Standalone 模式下运行,您应该在主控制台会话中看到应用程序的 stderr 和 stdout 输出。 + +## 本地运行 actor 时出现超时/连接错误 + +每个 Dapr 实例都会向放置服务报告其主机地址。放置服务然后将节点及其地址的表分发给所有 Dapr 实例。如果该主机地址无法访问,您可能会遇到套接字超时错误或其他请求失败错误。 + +除非通过设置名为 `DAPR_HOST_IP` 的环境变量为可访问的、可 ping 的地址来指定主机名,否则 Dapr 将遍历网络接口并选择第一个非回环地址。 + +如上所述,为了告诉 Dapr 应该使用哪个主机名,只需设置一个名为 `DAPR_HOST_IP` 的环境变量。 + +以下示例显示如何将主机 IP 环境变量设置为 `127.0.0.1`: + +**注意:对于版本 <= 0.4.0 使用 `HOST_IP`** + +```bash +export DAPR_HOST_IP=127.0.0.1 +``` + +## 我的应用程序启动时没有加载任何组件。我不断收到“错误组件 X 找不到” + +这通常是由于以下问题之一 + +- 您可能在本地定义了 `NAMESPACE` 环境变量或将组件部署到 Kubernetes 中的不同命名空间。检查您的应用程序和组件部署到哪个命名空间。阅读 [将组件限定到一个或多个应用程序]({{< ref "component-scopes.md" >}}) 了解更多信息。 +- 您可能没有在 Dapr `run` 命令中提供 `--resources-path` 或没有将组件放入操作系统的默认组件文件夹中。阅读 [定义组件]({{< ref "get-started-component.md" >}}) 了解更多信息。 +- 您的组件 YAML 文件中可能存在语法问题。使用组件 [YAML 示例]({{< ref "components.md" >}}) 检查您的组件 YAML。 + +## 服务调用失败,我的 Dapr 服务缺少 appId(macOS) + +一些组织会实施软件来过滤掉所有 UDP 流量,而 mDNS 正是基于此的。在 MacOS 上,`Microsoft Content Filter` 通常是罪魁祸首。 + +为了使 mDNS 正常工作,请确保 `Microsoft Content Filter` 处于非活动状态。 + +- 打开终端 shell。 +- 输入 `mdatp system-extension network-filter disable` 并按回车。 +- 输入您的帐户密码。 + +当输出为“Success”时,Microsoft Content Filter 被禁用。 + +> 一些组织会不时重新启用过滤器。如果您反复遇到 app-id 值丢失,首先检查过滤器是否已重新启用,然后再进行更广泛的故障排除。 + +## 准入 webhook 拒绝了请求 + +由于准入 webhook 对服务帐户创建或修改资源有一个允许列表,您可能会遇到类似于以下的错误。 + +``` +root:[dapr]$ kubectl run -i --tty --rm debug --image=busybox --restart=Never -- sh +Error from server: admission webhook "sidecar-injector.dapr.io" denied the request: service account 'user-xdd5l' not on the list of allowed controller accounts +``` + +要解决此错误,您应该为当前用户创建一个 `clusterrolebind`: + +```bash +kubectl create clusterrolebinding dapr- --clusterrole=dapr-operator-admin --user +``` + +您可以运行以下命令以获取集群中的所有用户: + +```bash +kubectl config get-users +``` + +您可以在 [这里](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/) 了解有关 webhooks 的更多信息。 diff --git a/src/translated_content/zh_CN/docs/operations/troubleshooting/logs-troubleshooting.md b/src/translated_content/zh_CN/docs/operations/troubleshooting/logs-troubleshooting.md new file mode 100644 index 000000000..97db135ec --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/troubleshooting/logs-troubleshooting.md @@ -0,0 +1,204 @@ +--- +type: docs +title: "配置和查看 Dapr 日志" +linkTitle: "日志" +weight: 2000 +description: "了解 Dapr 中日志的工作原理以及如何配置和查看日志" +--- + +本节将帮助您了解 Dapr 中日志的工作原理,以及如何配置和查看日志。 + +## 概述 + +日志有不同的可配置级别。 +以下列出的级别适用于系统组件和 Dapr sidecar 进程/容器: + +1. error +2. warn +3. info +4. debug + +error 级别输出最少,而 debug 级别输出最多。默认级别是 info,它在正常情况下为操作 Dapr 提供了足够的信息。 + +要设置输出级别,可以使用 `--log-level` 命令行选项。例如: + +```bash +./daprd --log-level error +./placement --log-level debug +``` + +这将以 `error` 日志级别启动 Dapr 运行时二进制文件,并以 `debug` 日志级别启动 Dapr actor 放置服务。 + +## 独立模式下的日志 + +在使用 Dapr CLI 运行应用程序时,可以通过传递 `log-level` 参数来设置日志级别: + +```bash +dapr run --log-level warn node myapp.js +``` + +如上所述,每个 Dapr 二进制文件都接受一个 `--log-level` 参数。例如,要以警告级别启动放置服务: + +```bash +./placement --log-level warn +``` + +### 查看独立模式下的日志 + +当使用 Dapr CLI 运行 Dapr 时,您的应用程序日志输出和运行时输出将被重定向到同一会话,方便调试。 +例如,这是运行 Dapr 时的输出: + +```bash +dapr run node myapp.js +ℹ️ Starting Dapr with id Trackgreat-Lancer on port 56730 +✅ You are up and running! Both Dapr and your app logs will appear here. + +== APP == App listening on port 3000! +== DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="starting Dapr Runtime -- version 0.3.0-alpha -- commit b6f2810-dirty" +== DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="log level set to: info" +== DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="standalone mode configured" +== DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="app id: Trackgreat-Lancer" +== DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="loaded component statestore (state.redis)" +== DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="loaded component messagebus (pubsub.redis)" +== DAPR == 2019/09/05 12:26:43 redis: connecting to localhost:6379 +== DAPR == 2019/09/05 12:26:43 redis: connected to localhost:6379 (localAddr: [::1]:56734, remAddr: [::1]:6379) +== DAPR == time="2019-09-05T12:26:43-07:00" level=warn msg="failed to init input bindings: app channel not initialized" +== DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30s" +== DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="actors: starting connection attempt to placement service at localhost:50005" +== DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="http server is running on port 56730" +== DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="gRPC server is running on port 56731" +== DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 8.772922000000001ms" +== DAPR == time="2019-09-05T12:26:43-07:00" level=info msg="actors: established connection to placement service at localhost:50005" +``` + +## Kubernetes 模式下的日志 + +> [了解如何在 Kubernetes 上调试 `daprd`。]({{< ref "debug-daprd.md" >}}) + +您可以通过在 pod 规范模板中提供以下注释,为每个 sidecar 单独设置日志级别: + +```yml +annotations: + dapr.io/log-level: "debug" +``` + +### 设置系统 pod 的日志级别 + +使用 Helm 3.x 将 Dapr 部署到集群时,您可以为每个 Dapr 系统组件单独设置日志级别: + +```bash +helm install dapr dapr/dapr --namespace dapr-system --set .logLevel= +``` + +组件: +- dapr_operator +- dapr_placement +- dapr_sidecar_injector + +示例: + +```bash +helm install dapr dapr/dapr --namespace dapr-system --set dapr_operator.logLevel=error +``` + +### 在 Kubernetes 上查看日志 + +Dapr 日志写入到标准输出(stdout)和标准错误(stderr)。 +本节将指导您如何查看 Dapr 系统组件以及 Dapr sidecar 的日志。 + +#### Sidecar 日志 + +在 Kubernetes 中部署时,Dapr sidecar 注入器会将一个名为 `daprd` 的 Dapr 容器注入到您的注释 pod 中。 +要查看 sidecar 的日志,只需通过运行 `kubectl get pods` 找到相关的 pod: + +```bash +NAME READY STATUS RESTARTS AGE +addapp-74b57fb78c-67zm6 2/2 Running 0 40h +``` + +接下来,获取 Dapr sidecar 容器的日志: + +```bash +kubectl logs addapp-74b57fb78c-67zm6 -c daprd + +time="2019-09-04T02:52:27Z" level=info msg="starting Dapr Runtime -- version 0.3.0-alpha -- commit b6f2810-dirty" +time="2019-09-04T02:52:27Z" level=info msg="log level set to: info" +time="2019-09-04T02:52:27Z" level=info msg="kubernetes mode configured" +time="2019-09-04T02:52:27Z" level=info msg="app id: addapp" +time="2019-09-04T02:52:27Z" level=info msg="application protocol: http. waiting on port 6000" +time="2019-09-04T02:52:27Z" level=info msg="application discovered on port 6000" +time="2019-09-04T02:52:27Z" level=info msg="actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30s" +time="2019-09-04T02:52:27Z" level=info msg="actors: starting connection attempt to placement service at dapr-placement.dapr-system.svc.cluster.local:80" +time="2019-09-04T02:52:27Z" level=info msg="http server is running on port 3500" +time="2019-09-04T02:52:27Z" level=info msg="gRPC server is running on port 50001" +time="2019-09-04T02:52:27Z" level=info msg="dapr initialized. Status: Running. Init Elapsed 64.234049ms" +time="2019-09-04T02:52:27Z" level=info msg="actors: established connection to placement service at dapr-placement.dapr-system.svc.cluster.local:80" +``` + +#### 系统日志 + +Dapr 运行以下系统 pod: + +* Dapr operator +* Dapr sidecar 注入器 +* Dapr 放置服务 + +#### Operator 日志 + +```Bash +kubectl logs -l app=dapr-operator -n dapr-system + +I1207 06:01:02.891031 1 leaderelection.go:243] attempting to acquire leader lease dapr-system/operator.dapr.io... +I1207 06:01:02.913696 1 leaderelection.go:253] successfully acquired lease dapr-system/operator.dapr.io +time="2021-12-07T06:01:03.092529085Z" level=info msg="getting tls certificates" instance=dapr-operator-84bb47f895-dvbsj scope=dapr.operator type=log ver=unknown +time="2021-12-07T06:01:03.092703283Z" level=info msg="tls certificates loaded successfully" instance=dapr-operator-84bb47f895-dvbsj scope=dapr.operator type=log ver=unknown +time="2021-12-07T06:01:03.093062379Z" level=info msg="starting gRPC server" instance=dapr-operator-84bb47f895-dvbsj scope=dapr.operator.api type=log ver=unknown +time="2021-12-07T06:01:03.093123778Z" level=info msg="Healthz server is listening on :8080" instance=dapr-operator-84bb47f895-dvbsj scope=dapr.operator type=log ver=unknown +time="2021-12-07T06:01:03.497889776Z" level=info msg="starting webhooks" instance=dapr-operator-84bb47f895-dvbsj scope=dapr.operator type=log ver=unknown +I1207 06:01:03.497944 1 leaderelection.go:243] attempting to acquire leader lease dapr-system/webhooks.dapr.io... +I1207 06:01:03.516641 1 leaderelection.go:253] successfully acquired lease dapr-system/webhooks.dapr.io +time="2021-12-07T06:01:03.526202227Z" level=info msg="Successfully patched webhook in CRD "subscriptions.dapr.io"" instance=dapr-operator-84bb47f895-dvbsj scope=dapr.operator type=log ver=unknown +``` + +*注意:如果 Dapr 安装在不同的命名空间而不是 dapr-system,只需在上述命令中将命名空间替换为所需的命名空间* + +#### Sidecar 注入器日志 + +```Bash +kubectl logs -l app=dapr-sidecar-injector -n dapr-system + +time="2021-12-07T06:01:01.554859058Z" level=info msg="log level set to: info" instance=dapr-sidecar-injector-5d88fcfcf5-2gmvv scope=dapr.injector type=log ver=unknown +time="2021-12-07T06:01:01.555114755Z" level=info msg="metrics server started on :9090/" instance=dapr-sidecar-injector-5d88fcfcf5-2gmvv scope=dapr.metrics type=log ver=unknown +time="2021-12-07T06:01:01.555233253Z" level=info msg="starting Dapr Sidecar Injector -- version 1.5.1 -- commit c6daae8e9b11b3e241a9cb84c33e5aa740d74368" instance=dapr-sidecar-injector-5d88fcfcf5-2gmvv scope=dapr.injector type=log ver=unknown +time="2021-12-07T06:01:01.557646524Z" level=info msg="Healthz server is listening on :8080" instance=dapr-sidecar-injector-5d88fcfcf5-2gmvv scope=dapr.injector type=log ver=unknown +time="2021-12-07T06:01:01.621291968Z" level=info msg="Sidecar injector is listening on :4000, patching Dapr-enabled pods" instance=dapr-sidecar-injector-5d88fcfcf5-2gmvv scope=dapr.injector type=log ver=unknown +``` + +*注意:如果 Dapr 安装在不同的命名空间而不是 dapr-system,只需在上述命令中将命名空间替换为所需的命名空间* + +#### 查看放置服务日志 + +```Bash +kubectl logs -l app=dapr-placement-server -n dapr-system + +time="2021-12-04T05:08:05.733416791Z" level=info msg="starting Dapr Placement Service -- version 1.5.0 -- commit 83fe579f5dc93bef1ce3b464d3167a225a3aff3a" instance=dapr-placement-server-0 scope=dapr.placement type=log ver=unknown +time="2021-12-04T05:08:05.733469491Z" level=info msg="log level set to: info" instance=dapr-placement-server-0 scope=dapr.placement type=log ver=1.5.0 +time="2021-12-04T05:08:05.733512692Z" level=info msg="metrics server started on :9090/" instance=dapr-placement-server-0 scope=dapr.metrics type=log ver=1.5.0 +time="2021-12-04T05:08:05.735207095Z" level=info msg="Raft server is starting on 127.0.0.1:8201..." instance=dapr-placement-server-0 scope=dapr.placement.raft type=log ver=1.5.0 +time="2021-12-04T05:08:05.735221195Z" level=info msg="mTLS enabled, getting tls certificates" instance=dapr-placement-server-0 scope=dapr.placement type=log ver=1.5.0 +time="2021-12-04T05:08:05.735265696Z" level=info msg="tls certificates loaded successfully" instance=dapr-placement-server-0 scope=dapr.placement type=log ver=1.5.0 +time="2021-12-04T05:08:05.735276396Z" level=info msg="placement service started on port 50005" instance=dapr-placement-server-0 scope=dapr.placement type=log ver=1.5.0 +time="2021-12-04T05:08:05.735553696Z" level=info msg="Healthz server is listening on :8080" instance=dapr-placement-server-0 scope=dapr.placement type=log ver=1.5.0 +time="2021-12-04T05:08:07.036850257Z" level=info msg="cluster leadership acquired" instance=dapr-placement-server-0 scope=dapr.placement type=log ver=1.5.0 +time="2021-12-04T05:08:07.036909357Z" level=info msg="leader is established." instance=dapr-placement-server-0 scope=dapr.placement type=log ver=1.5.0 +``` + +*注意:如果 Dapr 安装在不同的命名空间而不是 dapr-system,只需在上述命令中将命名空间替换为所需的命名空间* + +### 非 Kubernetes 环境 + +以上示例特定于 Kubernetes,但对于任何类型的基于容器的环境,原则是相同的:只需获取 Dapr sidecar 和/或系统组件(如果适用)的容器 ID 并查看其日志。 + +## 参考资料 + +* [如何在 Dapr 中设置日志]({{< ref "logging.md" >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/operations/troubleshooting/profiling-debugging.md b/src/translated_content/zh_CN/docs/operations/troubleshooting/profiling-debugging.md new file mode 100644 index 000000000..2be41dbac --- /dev/null +++ b/src/translated_content/zh_CN/docs/operations/troubleshooting/profiling-debugging.md @@ -0,0 +1,122 @@ +--- +type: docs +title: "性能分析与调试" +linkTitle: "调试" +weight: 4000 +description: "通过性能分析会话发现并解决并发、性能、CPU和内存使用等问题" +--- + +在实际应用中,程序可能会出现资源使用高峰的问题。CPU和内存的使用高峰在很多情况下是常见的。 + +Dapr 允许用户通过其性能分析服务端点使用 `pprof` 启动按需性能分析会话,以检测并发、性能、CPU 和内存使用等问题。 + +## 启用性能分析 + +Dapr 支持在 Kubernetes 和独立模式下启用性能分析。 + +### 独立模式 + +在独立模式下启用性能分析时,可以通过 Dapr CLI 传递 `--enable-profiling` 和 `--profile-port` 标志: +注意,`profile-port` 是可选的,如果未指定,Dapr 会自动选择一个可用端口。 + +```bash +dapr run --enable-profiling --profile-port 7777 python myapp.py +``` + +### Kubernetes + +在 Kubernetes 中启用性能分析,只需在 Dapr 注解的 pod 中添加 `dapr.io/enable-profiling` 注解: + +```yml + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "rust-app" + dapr.io/enable-profiling: "true" +``` + +## 调试性能分析会话 + +启用性能分析后,可以启动性能分析会话来调查 Dapr 运行时的情况。 + +### 独立模式 + +对于独立模式,首先找到需要分析的 Dapr 实例: + +```bash +dapr list +APP ID DAPR PORT APP PORT COMMAND AGE CREATED PID +node-subscriber 3500 3000 node app.js 12s 2019-09-09 15:11.24 896 +``` + +获取 DAPR PORT,如果已按上述步骤启用性能分析,现在可以使用 `pprof` 对 Dapr 进行分析。 +查看上面的 Kubernetes 示例以获取一些有用的命令来分析 Dapr。 + +有关 pprof 的更多信息可以在[这里](https://github.com/google/pprof)找到。 + +### Kubernetes + +首先,找到包含 Dapr 运行时的 pod。如果不确定 pod 名称,可以输入 `kubectl get pods`: + +```bash +NAME READY STATUS RESTARTS AGE +divideapp-6dddf7dc74-6sq4l 2/2 Running 0 2d23h +``` + +如果性能分析已成功启用,运行时日志应显示以下内容: +`time="2019-09-09T20:56:21Z" level=info msg="starting profiling server on port 7777"` + +在这种情况下,我们希望在 pod `divideapp-6dddf7dc74-6sq4l` 内启动 Dapr 运行时的会话。 + +可以通过端口转发连接到 pod 来实现: + +```bash +kubectl port-forward divideapp-6dddf7dc74-6sq4 7777:7777 +Forwarding from 127.0.0.1:7777 -> 7777 +Forwarding from [::1]:7777 -> 7777 +Handling connection for 7777 +``` + +现在连接已建立,可以使用 `pprof` 对 Dapr 运行时进行分析。 + +以下示例将创建一个 `cpu.pprof` 文件,其中包含持续 120 秒的分析会话的样本: + +```bash +curl "http://localhost:7777/debug/pprof/profile?seconds=120" > cpu.pprof +``` + +使用 pprof 分析文件: + +```bash +pprof cpu.pprof +``` + +还可以将结果以可视化方式保存在 PDF 中: + +```bash +go tool pprof --pdf your-binary-file http://localhost:7777/debug/pprof/profile?seconds=120 > profile.pdf +``` + +对于内存相关问题,可以分析堆: + +```bash +go tool pprof --pdf your-binary-file http://localhost:7777/debug/pprof/heap > heap.pdf +``` + +![heap](/images/heap.png) + +分析已分配的对象: + +```bash +go tool pprof http://localhost:7777/debug/pprof/heap +> exit + +Saved profile in /Users/myusername/pprof/pprof.daprd.alloc_objects.alloc_space.inuse_objects.inuse_space.003.pb.gz +``` + +要进行分析,获取上面的文件路径(这是一个动态文件路径,因此请注意不要粘贴此路径),然后执行: + +```bash +go tool pprof -alloc_objects --pdf /Users/myusername/pprof/pprof.daprd.alloc_objects.alloc_space.inuse_objects.inuse_space.003.pb.gz > alloc-objects.pdf +``` + +![alloc](/images/alloc.png) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/_index.md b/src/translated_content/zh_CN/docs/reference/_index.md new file mode 100644 index 000000000..5e3808824 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "Dapr 文档资料" +linkTitle: "参考资料" +weight: 50 +description: "提供关于 Dapr API、CLI、绑定等方面的详细文档" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/api/_index.md b/src/translated_content/zh_CN/docs/reference/api/_index.md new file mode 100644 index 000000000..4693c8252 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: Dapr API 文档指南 +linkTitle: "Dapr API" +weight: 100 +description: "提供关于每个 API、相关端点及其功能的详细信息" +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/api/actors_api.md b/src/translated_content/zh_CN/docs/reference/api/actors_api.md new file mode 100644 index 000000000..bf6357b58 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/actors_api.md @@ -0,0 +1,757 @@ +--- +type: docs +title: "Actors API 参考" +linkTitle: "Actors API" +description: "关于 actor API 的详细文档" +weight: 600 +--- + +Dapr 提供了原生、跨平台和跨语言的虚拟 actor 功能。 +除了[特定语言的 SDK]({{}}),开发者还可以使用以下 API 端点来调用 actor。 + +## 用户服务代码调用 Dapr + +### 调用 actor 方法 + +使用 Dapr 调用 actor 方法。 + +#### HTTP 请求 + +``` +POST/GET/PUT/DELETE http://localhost:/v1.0/actors///method/ +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 请求成功 +500 | 请求失败 +XXX | 上游调用的状态码 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口。 +`actorType` | actor 类型。 +`actorId` | actor ID。 +`method` | 要调用的方法名称。 + +> 注意,所有 URL 参数区分大小写。 + +#### 示例 + +调用 actor 上的方法示例: + +```shell +curl -X POST http://localhost:3500/v1.0/actors/stormtrooper/50/method/shoot \ + -H "Content-Type: application/json" +``` + +您可以在请求体中提供方法参数和值,例如在 curl 中使用 `-d "{\"param\":\"value\"}"`。调用带参数的 actor 方法示例: + +```shell +curl -X POST http://localhost:3500/v1.0/actors/x-wing/33/method/fly \ + -H "Content-Type: application/json" \ + -d '{ + "destination": "Hoth" + }' +``` + +或 + +```shell +curl -X POST http://localhost:3500/v1.0/actors/x-wing/33/method/fly \ + -H "Content-Type: application/json" \ + -d "{\"destination\":\"Hoth\"}" +``` + +远程端点的响应(方法返回值)将包含在响应体中。 + +### actor 状态事务 + +以多项事务的方式持久化 actor 状态的更改。 + +***请注意,此操作依赖于支持多项事务的状态存储组件。*** + +#### TTL + +启用 [`ActorStateTTL` 功能]({{< ref "support-preview-features.md" >}})后,actor 客户端可以在事务元数据中设置 `ttlInSeconds` 字段,以便状态在指定秒数后过期。如果未设置 `ttlInSeconds` 字段,状态将不会过期。 + +在构建启用此功能的 actor 应用程序时请记住;目前,所有 actor SDK 都会在本地缓存中保留 actor 状态,即使状态已过期。这意味着即使 TTL 已过期,actor 状态也不会从本地缓存中移除,直到 actor 重新启动或停用。此行为将在未来版本中更改。 + +有关 actor 状态 TTL 的更多详细信息,请参阅 Dapr 社区电话会议 80 的录音。 + + +#### HTTP 请求 + +``` +POST/PUT http://localhost:/v1.0/actors///state +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +204 | 请求成功 +400 | 未找到 actor +500 | 请求失败 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口。 +`actorType` | actor 类型。 +`actorId` | actor ID。 + +> 注意,所有 URL 参数区分大小写。 + +#### 示例 + +> 注意,以下示例使用了 `ttlInSeconds` 字段,这需要启用 [`ActorStateTTL` 功能]({{< ref "support-preview-features.md" >}})。 + +```shell +curl -X POST http://localhost:3500/v1.0/actors/stormtrooper/50/state \ + -H "Content-Type: application/json" \ + -d '[ + { + "operation": "upsert", + "request": { + "key": "key1", + "value": "myData", + "metadata": { + "ttlInSeconds": "3600" + } + } + }, + { + "operation": "delete", + "request": { + "key": "key2" + } + } + ]' +``` + +### 获取 actor 状态 + +使用指定的键获取 actor 的状态。 + +#### HTTP 请求 + +``` +GET http://localhost:/v1.0/actors///state/ +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 请求成功 +204 | 未找到键,响应将为空 +400 | 未找到 actor +500 | 请求失败 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口。 +`actorType` | actor 类型。 +`actorId` | actor ID。 +`key` | 状态值的键。 + +> 注意,所有 URL 参数区分大小写。 + +#### 示例 + +```shell +curl http://localhost:3500/v1.0/actors/stormtrooper/50/state/location \ + -H "Content-Type: application/json" +``` + +上述命令返回状态: + +```json +{ + "location": "Alderaan" +} +``` + +### 创建 actor 提醒 + +为 actor 创建一个持久化的提醒。 + +#### HTTP 请求 + +``` +POST/PUT http://localhost:/v1.0/actors///reminders/ +``` + +#### 提醒请求体 + +一个包含以下字段的 JSON 对象: + +| 字段 | 描述 | +|-------|--------------| +| `dueTime` | 指定提醒被调用的时间。其格式应为 [time.ParseDuration](https://pkg.go.dev/time#ParseDuration) +| `period` | 指定不同调用之间的周期。其格式应为 [time.ParseDuration](https://pkg.go.dev/time#ParseDuration) 或带有可选重复的 ISO 8601 持续时间格式。 +| `ttl` | 设置计时器或提醒将在何时或间隔后过期并被删除。其格式应为 [time.ParseDuration 格式](https://pkg.go.dev/time#ParseDuration)、RFC3339 日期格式或 ISO 8601 持续时间格式。 +| `data` | 一个字符串值,可以是任何相关内容。内容在提醒过期时返回。例如,这可能用于返回 URL 或与内容相关的任何内容。 + +`period` 字段支持 `time.Duration` 格式和 ISO 8601 格式,但有一些限制。对于 `period`,仅支持 ISO 8601 持续时间格式 `Rn/PnYnMnWnDTnHnMnS`。`Rn/` 指定提醒将被调用 `n` 次。 + +- `n` 应为大于 0 的正整数。 +- 如果某些值为 0,则可以缩短 `period`;例如,10 秒可以在 ISO 8601 持续时间中指定为 `PT10S`。 + +如果未指定 `Rn/`,则提醒将无限次运行,直到被删除。 + +如果仅设置了 `ttl` 和 `dueTime`,则提醒将被接受。然而,只有 `dueTime` 生效。例如,提醒在 `dueTime` 触发,`ttl` 被忽略。 + +如果设置了 `ttl`、`dueTime` 和 `period`,则提醒首先在 `dueTime` 触发,然后根据 `period` 和 `ttl` 重复触发并过期。 + +以下示例指定了 3 秒的 `dueTime` 和 7 秒的周期。 + +```json +{ + "dueTime":"0h0m3s0ms", + "period":"0h0m7s0ms" +} +``` + +`dueTime` 为 0 表示立即触发。以下请求体表示立即触发,然后每 9 秒触发一次。 + +```json +{ + "dueTime":"0h0m0s0ms", + "period":"0h0m9s0ms" +} +``` + +要配置提醒仅触发一次,周期应设置为空字符串。以下指定了 3 秒的 `dueTime` 和空字符串的周期,这意味着提醒将在 3 秒后触发,然后不再触发。 + +```json +{ + "dueTime":"0h0m3s0ms", + "period":"" +} +``` + +当您在 `period` 和 `ttl` 中同时指定重复次数时,当任一条件满足时,计时器/提醒将停止。以下示例中,计时器的 `period` 为 3 秒(ISO 8601 持续时间格式),`ttl` 为 20 秒。此计时器在注册后立即触发,然后每 3 秒触发一次,持续 20 秒,之后由于 `ttl` 满足而不再触发。 + +```json +{ + "period":"PT3S", + "ttl":"20s" +} +``` + +需要对数据进行描述。 + +```json +{ + "data": "someData", + "dueTime": "1m", + "period": "20s" +} +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +204 | 请求成功 +500 | 请求失败 +400 | 未找到 actor 或请求格式错误 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口。 +`actorType` | actor 类型。 +`actorId` | actor ID。 +`name` | 要创建的提醒名称。 + +> 注意,所有 URL 参数区分大小写。 + +#### 示例 + +```shell +curl http://localhost:3500/v1.0/actors/stormtrooper/50/reminders/checkRebels \ + -H "Content-Type: application/json" \ +-d '{ + "data": "someData", + "dueTime": "1m", + "period": "20s" + }' +``` + +### 获取 actor 提醒 + +获取 actor 的提醒。 + +#### HTTP 请求 + +``` +GET http://localhost:/v1.0/actors///reminders/ +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 请求成功 +500 | 请求失败 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口。 +`actorType` | actor 类型。 +`actorId` | actor ID。 +`name` | 要获取的提醒名称。 + +> 注意,所有 URL 参数区分大小写。 + +#### 示例 + +```shell +curl http://localhost:3500/v1.0/actors/stormtrooper/50/reminders/checkRebels \ + "Content-Type: application/json" +``` + +上述命令返回提醒: + +```json +{ + "dueTime": "1s", + "period": "5s", + "data": "0", +} +``` + +### 删除 actor 提醒 + +删除 actor 的提醒。 + +#### HTTP 请求 + +``` +DELETE http://localhost:/v1.0/actors///reminders/ +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +204 | 请求成功 +500 | 请求失败 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口。 +`actorType` | actor 类型。 +`actorId` | actor ID。 +`name` | 要删除的提醒名称。 + +> 注意,所有 URL 参数区分大小写。 + +#### 示例 + +```shell +curl -X DELETE http://localhost:3500/v1.0/actors/stormtrooper/50/reminders/checkRebels \ + -H "Content-Type: application/json" +``` + +### 创建 actor 计时器 + +为 actor 创建一个计时器。 + +#### HTTP 请求 + +``` +POST/PUT http://localhost:/v1.0/actors///timers/ +``` + +#### 计时器请求体: +计时器请求体的格式与[actor 提醒]({{< ref "#reminder-request-body" >}})相同。例如: + +以下指定了 3 秒的 `dueTime` 和 7 秒的周期。 + +```json +{ + "dueTime":"0h0m3s0ms", + "period":"0h0m7s0ms" +} +``` + +`dueTime` 为 0 表示立即触发。以下请求体表示立即触发,然后每 9 秒触发一次。 + +```json +{ + "dueTime":"0h0m0s0ms", + "period":"0h0m9s0ms" +} +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +204 | 请求成功 +500 | 请求失败 +400 | 未找到 actor 或请求格式错误 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口。 +`actorType` | actor 类型。 +`actorId` | actor ID。 +`name` | 要创建的计时器名称。 + +> 注意,所有 URL 参数区分大小写。 + +#### 示例 + +```shell +curl http://localhost:3500/v1.0/actors/stormtrooper/50/timers/checkRebels \ + -H "Content-Type: application/json" \ +-d '{ + "data": "someData", + "dueTime": "1m", + "period": "20s", + "callback": "myEventHandler" + }' +``` + +### 删除 actor 计时器 + +删除 actor 的计时器。 + +#### HTTP 请求 + +``` +DELETE http://localhost:/v1.0/actors///timers/ +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +204 | 请求成功 +500 | 请求失败 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口。 +`actorType` | actor 类型。 +`actorId` | actor ID。 +`name` | 要删除的计时器名称。 + +> 注意,所有 URL 参数区分大小写。 + +```shell +curl -X DELETE http://localhost:3500/v1.0/actors/stormtrooper/50/timers/checkRebels \ + -H "Content-Type: application/json" +``` + +## Dapr 调用用户服务代码 + +### 获取注册的 actor + +获取此应用程序的注册 actor 类型和 Dapr actor 配置设置。 + +#### HTTP 请求 + +``` +GET http://localhost:/dapr/config +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 请求成功 +500 | 请求失败 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`appPort` | 应用程序端口。 + +#### 示例 + +获取注册 actor 的示例: + +```shell +curl -X GET http://localhost:3000/dapr/config \ + -H "Content-Type: application/json" +``` + +上述命令返回配置(所有字段都是可选的): + +参数 | 描述 +----------|------------ +`entities` | 此应用程序支持的 actor 类型。 +`actorIdleTimeout` | 指定在停用空闲 actor 之前等待的时间。如果没有 actor 方法调用且没有提醒触发,则 actor 为空闲状态。 +`actorScanInterval` | 指定扫描以停用空闲 actor 的频率。空闲时间超过 actorIdleTimeout 的 actor 将被停用。 +`drainOngoingCallTimeout` | 在重新平衡 actor 的过程中使用的持续时间。指定等待当前活动的 actor 方法完成的时间。如果没有当前的 actor 方法调用,则忽略此项。 +`drainRebalancedActors` | 一个布尔值。如果为 true,Dapr 将等待 `drainOngoingCallTimeout` 以允许当前 actor 调用完成,然后再尝试停用 actor。如果为 false,则不等待。 +`reentrancy` | 一个配置对象,包含 actor 重入的选项。 +`enabled` | 重入配置中启用重入所需的标志。 +`maxStackDepth` | 重入配置中控制对同一 actor 进行的重入调用次数的值。 +`entitiesConfig` | 允许每个 actor 类型设置的实体配置数组。此处定义的任何配置都必须有一个映射回根级别实体的实体。 + +{{% alert title="注意" color="primary" %}} +配置中的 actor 设置的超时和间隔使用 [time.ParseDuration](https://pkg.go.dev/time#ParseDuration) 格式。您可以使用字符串格式表示持续时间。例如: +- `1h30m` 或 `1.5h`:1 小时 30 分钟的持续时间 +- `1d12h`:1 天 12 小时的持续时间 +- `500ms`:500 毫秒的持续时间 +- `-30m`:负 30 分钟的持续时间 + +{{% /alert %}} + +```json +{ + "entities":["actorType1", "actorType2"], + "actorIdleTimeout": "1h", + "actorScanInterval": "30s", + "drainOngoingCallTimeout": "30s", + "drainRebalancedActors": true, + "reentrancy": { + "enabled": true, + "maxStackDepth": 32 + }, + "entitiesConfig": [ + { + "entities": ["actorType1"], + "actorIdleTimeout": "1m", + "drainOngoingCallTimeout": "10s", + "reentrancy": { + "enabled": false + } + } + ] +} +``` + +### 停用 actor + +通过将 actor 的实例持久化到具有指定 actorId 的状态存储中来停用 actor。 + +#### HTTP 请求 + +``` +DELETE http://localhost:/actors// +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 请求成功 +400 | 未找到 actor +500 | 请求失败 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`appPort` | 应用程序端口。 +`actorType` | actor 类型。 +`actorId` | actor ID。 + +> 注意,所有 URL 参数区分大小写。 + +#### 示例 + +以下示例停用了具有 `actorId` 为 50 的 `stormtrooper` actor 类型。 + +```shell +curl -X DELETE http://localhost:3000/actors/stormtrooper/50 \ + -H "Content-Type: application/json" +``` + +### 调用 actor 方法 + +调用具有指定 `methodName` 的 actor 方法,其中: + +- 方法的参数在请求消息体中传递。 +- 返回值在响应消息体中提供。 + +如果 actor 尚未运行,应用程序端应[激活](#activating-an-actor)它。 + +#### HTTP 请求 + +``` +PUT http://localhost:/actors///method/ +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 请求成功 +500 | 请求失败 +404 | 未找到 actor + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`appPort` | 应用程序端口。 +`actorType` | actor 类型。 +`actorId` | actor ID。 +`methodName` | 要调用的方法名称。 + +> 注意,所有 URL 参数区分大小写。 + +#### 示例 + +以下示例调用了具有 `actorId` 为 50 的 `stormtrooper` actor 类型的 `performAction` 方法。 + +```shell +curl -X POST http://localhost:3000/actors/stormtrooper/50/method/performAction \ + -H "Content-Type: application/json" +``` + +### 调用提醒 + +调用具有指定 reminderName 的 actor 提醒。如果 actor 尚未运行,应用程序端应[激活](#activating-an-actor)它。 + +#### HTTP 请求 + +``` +PUT http://localhost:/actors///method/remind/ +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 请求成功 +500 | 请求失败 +404 | 未找到 actor + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`appPort` | 应用程序端口。 +`actorType` | actor 类型。 +`actorId` | actor ID。 +`reminderName` | 要调用的提醒名称。 + +> 注意,所有 URL 参数区分大小写。 + +#### 示例 + +以下示例调用了具有 `actorId` 为 50 的 `stormtrooper` actor 类型的 `checkRebels` 提醒方法。 + +```shell +curl -X POST http://localhost:3000/actors/stormtrooper/50/method/remind/checkRebels \ + -H "Content-Type: application/json" +``` + +### 调用计时器 + +调用具有指定 `timerName` 的 actor 计时器。如果 actor 尚未运行,应用程序端应[激活](#activating-an-actor)它。 + +#### HTTP 请求 + +``` +PUT http://localhost:/actors///method/timer/ +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 请求成功 +500 | 请求失败 +404 | 未找到 actor + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`appPort` | 应用程序端口。 +`actorType` | actor 类型。 +`actorId` | actor ID。 +`timerName` | 要调用的计时器名称。 + +> 注意,所有 URL 参数区分大小写。 + +#### 示例 + +以下示例调用了具有 `actorId` 为 50 的 `stormtrooper` actor 类型的 `checkRebels` 计时器方法。 + +```shell +curl -X POST http://localhost:3000/actors/stormtrooper/50/method/timer/checkRebels \ + -H "Content-Type: application/json" +``` + +### 健康检查 + +探测应用程序以响应信号,通知 Dapr 应用程序健康且正在运行。 +任何非 `200` 的响应状态码都将被视为不健康的响应。 + +响应体不是必需的。 + +#### HTTP 请求 + +``` +GET http://localhost:/healthz +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 应用程序健康 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`appPort` | 应用程序端口。 + +#### 示例 + +从应用程序获取健康检查响应的示例: + +```shell +curl -X GET http://localhost:3000/healthz \ +``` + +## 激活 actor + +从概念上讲,激活 actor 意味着创建 actor 的对象并将 actor 添加到跟踪表中。[查看 .NET SDK 的示例](https://github.com/dapr/dotnet-sdk/blob/6c271262231c41b21f3ca866eb0d55f7ce8b7dbc/src/Dapr.Actors/Runtime/ActorManager.cs#L199)。 + +## 外部查询 actor 状态 + +为了使 actor 状态可见并允许复杂场景(如状态聚合),Dapr 将 actor 状态保存在外部状态存储中,例如数据库。因此,可以通过组合正确的键或查询来外部查询 actor 状态。 + +Dapr 为 actor 创建的状态命名空间由以下项目组成: + +- 应用程序 ID:表示分配给 Dapr 应用程序的唯一 ID。 +- actor 类型:表示 actor 的类型。 +- actor ID:表示 actor 类型的 actor 实例的唯一 ID。 +- 键:特定状态值的键。一个 actor ID 可以持有多个状态键。 + +以下示例显示了如何在 `myapp` 应用程序 ID 命名空间下构造 actor 实例状态的键: + +`myapp||cat||hobbit||food` + +在上述示例中,我们获取了 `myapp` 应用程序 ID 命名空间下,actor 类型为 `cat`,actor ID 为 `hobbit` 的状态键 `food` 的值。 diff --git a/src/translated_content/zh_CN/docs/reference/api/bindings_api.md b/src/translated_content/zh_CN/docs/reference/api/bindings_api.md new file mode 100644 index 000000000..88bd5ac0d --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/bindings_api.md @@ -0,0 +1,270 @@ +--- +type: docs +title: "Bindings API 参考" +linkTitle: "Bindings API" +description: "关于 bindings API 的详细文档" +weight: 500 +--- + +Dapr 为应用程序提供了双向绑定的功能,提供了一种与不同云服务或本地系统交互的统一方法。开发人员可以通过 Dapr API 调用输出绑定,并让 Dapr 运行时通过输入绑定来触发应用程序。 + +bindings 的示例包括 `Kafka`、`Rabbit MQ`、`Azure Event Hubs`、`AWS SQS`、`GCP Storage` 等。 + +## Bindings 结构 + +一个 Dapr Binding 的 yaml 文件结构如下: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: + namespace: +spec: + type: bindings. + version: v1 + metadata: + - name: + value: +``` + +`metadata.name` 是绑定的名称。 + +如果在本地自托管运行,请将此文件放在 `components` 文件夹中,与状态存储和消息队列 yml 配置相邻。 + +如果在 Kubernetes 上运行,请将组件应用到您的集群中。 + +> **注意:** 在生产环境中,切勿在 Dapr 组件文件中放置密码或秘密。有关使用 secret 存储安全存储和检索秘密的信息,请参阅 [设置 Secret Store]({{< ref setup-secret-store >}}) + +### 绑定方向(可选) + +在某些情况下,向 Dapr 提供额外的信息以指示绑定组件支持的方向是有帮助的。 + +指定绑定的 `direction` 可以帮助 Dapr sidecar 避免进入“等待应用程序准备就绪”的状态,这种状态下它会无限期地等待应用程序可用。这解耦了 Dapr sidecar 和应用程序之间的生命周期依赖。 + +您可以在组件元数据中指定 `direction` 字段。此字段的有效值为: +- `"input"` +- `"output"` +- `"input, output"` + +{{% alert title="注意" color="primary" %}} +强烈建议所有绑定都应包含 `direction` 属性。 +{{% /alert %}} + +以下是一些 `direction` 元数据字段可能有帮助的场景: + +- 当一个应用程序(与 sidecar 分离)作为无服务器工作负载运行并缩放到零时,Dapr sidecar 执行的“等待应用程序准备就绪”检查变得毫无意义。 + +- 如果分离的 Dapr sidecar 缩放到零,并且应用程序在启动 HTTP 服务器之前到达 sidecar,“等待应用程序准备就绪”会导致应用程序和 sidecar 互相等待而陷入死锁。 + +### 示例 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: kafkaevent +spec: + type: bindings.kafka + version: v1 + metadata: + - name: brokers + value: "http://localhost:5050" + - name: topics + value: "someTopic" + - name: publishTopic + value: "someTopic2" + - name: consumerGroup + value: "group1" + - name: "direction" + value: "input, output" +``` + +## 通过输入绑定调用服务代码 + +希望通过输入绑定来触发应用程序的开发人员可以在 `POST` http 端点上监听,路由名称与 `metadata.name` 相同。 + +启动时,Dapr 向 `metadata.name` 端点发送 `OPTIONS` 请求,并期望不同的状态码为 `NOT FOUND (404)`,如果此应用程序希望订阅绑定。 + +`metadata` 部分是一个开放的键/值元数据对,允许绑定定义连接属性,以及组件实现特有的自定义属性。 + +### 示例 + +例如,以下是一个 Python 应用程序如何使用符合 Dapr API 的平台订阅来自 `Kafka` 的事件。注意组件中的 metadata.name 值 `kafkaevent` 与 Python 代码中的 POST 路由名称匹配。 + +#### Kafka 组件 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: kafkaevent +spec: + type: bindings.kafka + version: v1 + metadata: + - name: brokers + value: "http://localhost:5050" + - name: topics + value: "someTopic" + - name: publishTopic + value: "someTopic2" + - name: consumerGroup + value: "group1" +``` + +#### Python 代码 + +```python +from flask import Flask +app = Flask(__name__) + +@app.route("/kafkaevent", methods=['POST']) +def incoming(): + print("Hello from Kafka!", flush=True) + + return "Kafka Event Processed!" +``` + +### 绑定端点 + +bindings 是从组件 yaml 文件中发现的。Dapr 在启动时调用此端点以确保应用程序可以处理此调用。如果应用程序没有该端点,Dapr 会忽略它。 + +#### HTTP 请求 + +``` +OPTIONS http://localhost:/ +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +404 | 应用程序不想绑定到该绑定 +2xx 或 405 | 应用程序想要绑定到该绑定 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +appPort | 应用程序端口 +name | 绑定的名称 + +> 注意,所有 URL 参数区分大小写。 + +### 绑定负载 + +为了传递绑定输入,会向用户代码发出一个以绑定名称为 URL 路径的 POST 调用。 + +#### HTTP 请求 + +``` +POST http://localhost:/ +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 应用程序成功处理了输入绑定 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +appPort | 应用程序端口 +name | 绑定的名称 + +> 注意,所有 URL 参数区分大小写。 + +#### HTTP 响应体(可选) + +可选地,可以使用响应体直接将输入绑定与状态存储或输出绑定绑定。 + +**示例:** +Dapr 将 `stateDataToStore` 存储到名为 "stateStore" 的状态存储中。 +Dapr 将 `jsonObject` 并行发送到名为 "storage" 和 "queue" 的输出绑定。 +如果未设置 `concurrency`,则按顺序发送(下面的示例显示这些操作是并行完成的) + +```json +{ + "storeName": "stateStore", + "state": stateDataToStore, + + "to": ['storage', 'queue'], + "concurrency": "parallel", + "data": jsonObject, +} +``` + +## 调用输出绑定 + +此端点允许您调用 Dapr 输出绑定。Dapr bindings 支持各种操作,例如 `create`。 + +请参阅每个绑定的[不同规范]({{< ref supported-bindings >}})以查看支持的操作列表。 + +### HTTP 请求 + +``` +POST/PUT http://localhost:/v1.0/bindings/ +``` + +### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 请求成功 +204 | 空响应 +400 | 请求格式错误 +500 | 请求失败 + +### 负载 + +bindings 端点接收以下 JSON 负载: + +```json +{ + "data": "", + "metadata": { + "": "" + }, + "operation": "" +} +``` + +> 注意,所有 URL 参数区分大小写。 + +`data` 字段接受任何 JSON 可序列化的值,并作为要发送到输出绑定的负载。`metadata` 字段是一个键/值对数组,允许您为每次调用设置绑定特定的元数据。`operation` 字段告诉 Dapr 绑定它应该执行哪个操作。 + +### URL 参数 + +参数 | 描述 +--------- | ----------- +daprPort | Dapr 端口 +name | 要调用的输出绑定的名称 + +> 注意,所有 URL 参数区分大小写。 + +### 示例 + +```shell +curl -X POST http://localhost:3500/v1.0/bindings/myKafka \ + -H "Content-Type: application/json" \ + -d '{ + "data": { + "message": "Hi" + }, + "metadata": { + "key": "redis-key-1" + }, + "operation": "create" + }' +``` + +### 常见元数据值 + +有一些常见的元数据属性在多个绑定组件中支持。以下列表展示了它们: + +|属性|描述|绑定定义|可用于 +|-|-|-|-| +|ttlInSeconds|定义消息的生存时间(以秒为单位)|如果在绑定定义中设置,将导致所有消息具有默认的生存时间。消息 ttl 覆盖绑定定义中的任何值。|RabbitMQ, Azure Service Bus, Azure Storage Queue| diff --git a/src/translated_content/zh_CN/docs/reference/api/configuration_api.md b/src/translated_content/zh_CN/docs/reference/api/configuration_api.md new file mode 100644 index 000000000..ce3ed55ba --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/configuration_api.md @@ -0,0 +1,264 @@ +--- +type: docs +title: "配置 API 参考" +linkTitle: "配置 API" +description: "关于配置 API 的详细文档" +weight: 800 +--- + +## 获取配置 + +该端点用于从存储中获取配置。 + +### HTTP 请求 + +``` +GET http://localhost:/v1.0/configuration/ +``` + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口 +`storename` | `metadata.name` 字段组件文件。请参阅 [组件规范]({{< ref component-schema.md>}}) + +#### 查询参数 + +如果不提供查询参数,将返回所有配置项。 +要指定需要获取的配置项的键,请使用一个或多个 `key` 查询参数。例如: + +``` +GET http://localhost:/v1.0/configuration/mystore?key=config1&key=config2 +``` + +要检索所有配置项: + +``` +GET http://localhost:/v1.0/configuration/mystore +``` + +#### 请求体 + +无 + +### HTTP 响应 + +#### 响应代码 + +代码 | 描述 +---- | ----------- +`204` | 获取操作成功 +`400` | 配置存储缺失或配置错误或请求格式错误 +`500` | 获取配置失败 + +#### 响应体 + +每个配置项的键/值对的 JSON 编码值。 + +### 示例 + +```shell +curl -X GET 'http://localhost:3500/v1.0/configuration/mystore?key=myConfigKey' +``` + +> 上述命令返回以下 JSON: + +```json +{ + "myConfigKey": { + "value":"myConfigValue" + } +} +``` + +## 订阅配置 + +该端点用于订阅配置更改。当配置存储中的值被更新或删除时,会发送通知。这使应用程序能够对配置更改做出反应。 + +### HTTP 请求 + +``` +GET http://localhost:/v1.0/configuration//subscribe +``` + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口 +`storename` | `metadata.name` 字段组件文件。请参阅 [组件规范]({{< ref component-schema.md>}}) + +#### 查询参数 + +如果不提供查询参数,将订阅所有配置项。 +要指定需要订阅的配置项的键,请使用一个或多个 `key` 查询参数。例如: + +``` +GET http://localhost:/v1.0/configuration/mystore/subscribe?key=config1&key=config2 +``` + +要订阅所有更改: + +``` +GET http://localhost:/v1.0/configuration/mystore/subscribe +``` + +#### 请求体 + +无 + +### HTTP 响应 + +#### 响应代码 + +代码 | 描述 +---- | ----------- +`200` | 订阅操作成功 +`400` | 配置存储缺失或配置错误或请求格式错误 +`500` | 订阅配置更改失败 + +#### 响应体 + +JSON 编码值 + +### 示例 + +```shell +curl -X GET 'http://localhost:3500/v1.0/configuration/mystore/subscribe?key=myConfigKey' +``` + +> 上述命令返回以下 JSON: + +```json +{ + "id": "" +} +``` + +返回的 `id` 参数可用于取消订阅在订阅 API 调用中提供的特定键集。应用程序应保存此参数。 + +## 取消订阅配置 + +该端点用于取消订阅配置更改。 + +### HTTP 请求 + +``` +GET http://localhost:/v1.0/configuration///unsubscribe +``` + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口 +`storename` | `metadata.name` 字段组件文件。请参阅 [组件规范]({{< ref component-schema.md>}}) +`subscription-id` | 从订阅端点响应中返回的 `id` 字段的值 + +#### 查询参数 + +无 + +#### 请求体 + +无 + +### HTTP 响应 + +#### 响应代码 + +代码 | 描述 +---- | ----------- +`200` | 取消订阅操作成功 +`400` | 配置存储缺失或配置错误或请求格式错误 +`500` | 取消订阅配置更改失败 + +#### 响应体 + +```json +{ + "ok" : true +} +``` + +### 示例 + +```shell +curl -X GET 'http://localhost:3500/v1.0-alpha1/configuration/mystore/bf3aa454-312d-403c-af95-6dec65058fa2/unsubscribe' +``` + +> 上述命令返回以下 JSON: + +在操作成功的情况下: + +```json +{ + "ok": true +} +``` +在操作不成功的情况下: + +```json +{ + "ok": false, + "message": "" +} +``` + +## 可选应用程序路由 + +### 提供一个路由以便 Dapr 发送配置更改 + +订阅配置更改时,Dapr 会在配置项更改时调用应用程序。您的应用程序可以有一个 `/configuration` 端点,用于接收所有已订阅键的更新。可以通过在路由中添加 `/` 和 `//` 来使端点更具体,以适应给定的配置存储。 + +#### HTTP 请求 + +``` +POST http://localhost:/configuration// +``` + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`appPort` | 应用程序端口 +`storename` | `metadata.name` 字段组件文件。请参阅 [组件规范]({{< ref component-schema.md>}}) +`key` | 已订阅的键 + +#### 请求体 + +给定订阅 id 的配置项列表。配置项可以有一个与之关联的版本,该版本在通知中返回。 + +```json +{ + "id": "", + "items": [ + { + "key": "", + "value": "", + "version": "" + } + ] +} +``` + +#### 示例 + +```json +{ + "id": "bf3aa454-312d-403c-af95-6dec65058fa2", + "items": [ + { + "key": "config-1", + "value": "abcdefgh", + "version": "1.1" + } + ] +} +``` + +## 下一步 + +- [配置 API 概述]({{< ref configuration-api-overview.md >}}) +- [如何:从存储管理配置]({{< ref howto-manage-configuration.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/api/conversation_api.md b/src/translated_content/zh_CN/docs/reference/api/conversation_api.md new file mode 100644 index 000000000..3f62c4fbc --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/conversation_api.md @@ -0,0 +1,73 @@ +--- +type: docs +title: "会话API参考" +linkTitle: "会话API" +description: "关于会话API的详细文档" +weight: 1400 +--- + +{{% alert title="Alpha" color="primary" %}} +会话API目前为[alpha]({{< ref "certification-lifecycle.md#certification-levels" >}})阶段。 +{{% /alert %}} + +Dapr提供了一种API,用于与大型语言模型(LLMs)进行交互。通过提示缓存和模糊化个人身份信息(PII)等功能,提升了性能和安全性。 + +## 会话 + +通过此端点可以与LLMs进行会话。 + +``` +POST /v1.0-alpha1/conversation//converse +``` + +### URL参数 + +| 参数 | 描述 | +| --------- | ----------- | +| `llm-name` | LLM组件的名称。[查看所有可用会话组件的列表。]({{< ref supported-conversation >}}) + +### 请求体 + +| 字段 | 描述 | +| --------- | ----------- | +| `conversationContext` | 会话的上下文信息,用于维持对话状态。 | +| `inputs` | 用户输入的文本数组。 | +| `parameters` | 额外的参数配置。 | + +### 请求示例 + +```json +REQUEST = { + "inputs": ["什么是Dapr", "为什么使用Dapr"], + "parameters": {}, +} +``` + +### HTTP响应代码 + +代码 | 描述 +---- | ----------- +`202` | 请求已被接受 +`400` | 请求格式错误 +`500` | 请求格式正确,但Dapr代码或底层组件出错 + +### 响应示例 + +```json +RESPONSE = { + "outputs": [ + { + "result": "Dapr是分布式应用运行时...", + "parameters": {}, + }, + { + "result": "Dapr可以帮助开发者...", + "parameters": {}, + } + ], +} +``` + +## 下一步 + +[会话API概述]({{< ref conversation-overview.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/api/cryptography_api.md b/src/translated_content/zh_CN/docs/reference/api/cryptography_api.md new file mode 100644 index 000000000..0984b3a66 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/cryptography_api.md @@ -0,0 +1,121 @@ +--- +type: docs +title: "加密 API 参考" +linkTitle: "加密 API" +description: "关于加密 API 的详细文档" +weight: 1300 +--- + +Dapr 通过加密模块提供跨平台和跨语言的加密和解密支持。除了[特定语言的 SDK]({{}})之外,开发者还可以使用下面的 HTTP API 端点来调用这些功能。 + +> HTTP API 仅用于开发和测试。在生产环境中,强烈推荐使用 SDK,因为它们实现了 gRPC API,提供比 HTTP API 更高的性能和功能。 + +## 加密数据 + +此端点允许您使用指定的密钥和加密组件加密以字节数组形式提供的值。 + +### HTTP 请求 + +``` +PUT http://localhost:/v1.0-alpha1/crypto//encrypt +``` + +#### URL 参数 +| 参数 | 描述 | +|-------------------|-------------------------------------------------------------| +| daprPort | Dapr 端口 | +| crypto-store-name | 用于获取加密密钥的加密存储名称 | + +> 注意,所有 URL 参数区分大小写。 + +#### 请求头 +通过设置请求头来配置其他加密参数。下表详细说明了每个加密请求需要设置的必需和可选请求头。 + +| 请求头键 | 描述 | 允许值 | 必需性 | +|----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------|--------------------------------------------------------| +| dapr-key-name | 用于加密操作的密钥名称 | | 是 | +| dapr-key-wrap-algorithm | 使用的密钥包装算法 | `A256KW`, `A128CBC`, `A192CBC`, `RSA-OAEP-256` | 是 | +| dapr-omit-decryption-key-name | 如果为 true,则在输出中省略请求头 `dapr-decryption-key-name` 中的解密密钥名称。 | 以下值将被接受为 true:`y`, `yes`, `true`, `t`, `on`, `1` | 否 | +| dapr-decryption-key-name | 如果 `dapr-omit-decryption-key-name` 为 true,则包含要在输出中包含的预期解密密钥的名称。 | | 仅当 `dapr-omit-decryption-key-name` 为 true 时必需 | +| dapr-data-encryption-cipher| 用于加密操作的密码 | `aes-gcm` 或 `chacha20-poly1305` | 否 | + +### HTTP 响应 + +#### 响应体 +加密请求的响应将其内容类型请求头设置为 `application/octet-stream`,因为它返回一个包含加密数据的字节数组。 + +#### 响应代码 +| 代码 | 描述 | +|------|-----------------------------------------------------------------| +| 200 | OK | +| 400 | 找不到加密提供者 | +| 500 | 请求格式正确,但 Dapr 代码或底层组件出错 | + +### 示例 +```shell +curl http://localhost:3500/v1.0-alpha1/crypto/myAzureKeyVault/encrypt \ + -X PUT \ + -H "dapr-key-name: myCryptoKey" \ + -H "dapr-key-wrap-algorithm: aes-gcm" \ + -H "Content-Type: application/octet-stream" \ + --data-binary "\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64" +``` + +> 上述命令发送一个表示“hello world”的 UTF-8 编码字节数组,并将在响应中返回一个类似于以下内容的 8 位值流,包含加密数据: + +```bash +gAAAAABhZfZ0Ywz4dQX8y9J0Zl5v7w6Z7xq4jV3cW9o2l4pQ0YD1LdR0Zk7zIYi4n2Ll7t6f0Z4X7r8x9o6a8GyL0X1m9Q0Z0A== +``` + +## 解密数据 + +此端点允许您使用指定的密钥和加密组件解密以字节数组形式提供的值。 + +#### HTTP 请求 + +``` +PUT curl http://localhost:3500/v1.0-alpha1/crypto//decrypt +``` + +#### URL 参数 + +| 参数 | 描述 | +|-------------------|-------------------------------------------------------------| +| daprPort | Dapr 端口 | +| crypto-store-name | 用于获取解密密钥的加密存储名称 | + +> 注意,所有参数区分大小写。 + +#### 请求头 +通过设置请求头来配置其他解密参数。下表详细说明了每个解密请求需要设置的必需和可选请求头。 + +| 请求头键 | 描述 | 必需性 | +|------------|--------------------------------------------------|--------| +| dapr-key-name | 用于解密操作的密钥名称。 | 是 | + +### HTTP 响应 + +#### 响应体 +解密请求的响应将其内容类型请求头设置为 `application/octet-stream`,因为它返回一个表示解密数据的字节数组。 + +#### 响应代码 +| 代码 | 描述 | +|------|-----------------------------------------------------------------| +| 200 | OK | +| 400 | 找不到加密提供者 | +| 500 | 请求格式正确,但 Dapr 代码或底层组件出错 | + +### 示例 +```bash +curl http://localhost:3500/v1.0-alpha1/crypto/myAzureKeyVault/decrypt \ + -X PUT \ + -H "dapr-key-name: myCryptoKey" \ + -H "Content-Type: application/octet-stream" \ + --data-binary "gAAAAABhZfZ0Ywz4dQX8y9J0Zl5v7w6Z7xq4jV3cW9o2l4pQ0YD1LdR0Zk7zIYi4n2Ll7t6f0Z4X7r8x9o6a8GyL0X1m9Q0Z0A==" +``` + +> 上述命令发送一个加密消息负载的 base-64 编码字符串,并将返回一个响应,内容类型请求头设置为 `application/octet-stream`,返回响应体 `hello world`。 + +```bash +hello world +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/api/distributed_lock_api.md b/src/translated_content/zh_CN/docs/reference/api/distributed_lock_api.md new file mode 100644 index 000000000..632670ced --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/distributed_lock_api.md @@ -0,0 +1,156 @@ +--- +type: docs +title: "分布式锁 API 参考" +linkTitle: "分布式锁 API" +description: "关于分布式锁 API 的详细文档" +weight: 900 +--- + +## 锁 + +通过此端点,您可以通过提供锁所有者的名称和要锁定的资源 ID 来获取锁。 + +### HTTP 请求 + +``` +POST http://localhost:/v1.0-alpha1/lock/ +``` + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口 +`storename` | `metadata.name` 字段的组件文件。请参阅[组件模式]({{< ref component-schema.md >}}) + +#### 查询参数 + +无 + +### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 请求成功 +204 | 空响应 +400 | 请求格式错误 +500 | 请求失败 + +### HTTP 请求体 + +锁端点需要接收以下 JSON 负载: + +```json +{ + "resourceId": "", + "lockOwner": "", + "expiryInSeconds": 0 +} +``` + +字段 | 描述 +---- | ----------- +resourceId | 要锁定的资源 ID。可以是任何值 +lockOwner | 锁所有者的名称。每次请求都应设置为唯一值 +expiryInSeconds | 锁定在过期前保持的时间(秒) + +### HTTP 响应体 + +锁端点会返回以下负载: + +```json +{ + "success": true +} +``` + +### 示例 + +```shell +curl -X POST http://localhost:3500/v1.0-alpha/lock/redisStore \ + -H "Content-Type: application/json" \ + -d '{ + "resourceId": "lock1", + "lockOwner": "vader", + "expiryInSeconds": 60 + }' + +{ + "success": "true" +} +``` + +## 解锁 + +通过此端点,您可以根据锁所有者和资源 ID 解锁现有锁。 + +### HTTP 请求 + +``` +POST http://localhost:/v1.0-alpha1/unlock/ +``` + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口 +`storename` | `metadata.name` 字段的组件文件。请参阅[组件模式]({{< ref component-schema.md >}}) + +#### 查询参数 + +无 + +### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 请求成功 +204 | 空响应 +400 | 请求格式错误 +500 | 请求失败 + +### HTTP 请求体 + +解锁端点需要接收以下 JSON 负载: + +```json +{ + "resourceId": "", + "lockOwner": "" +} +``` + +### HTTP 响应体 + +解锁端点会返回以下负载: + +```json +{ + "status": 0 +} +``` + +`status` 字段包含以下响应代码: + +代码 | 描述 +---- | ----------- +0 | 成功 +1 | 锁未找到 +2 | 锁属于其他所有者 +3 | 内部错误 + +### 示例 + +```shell +curl -X POST http://localhost:3500/v1.0-alpha/unlock/redisStore \ + -H "Content-Type: application/json" \ + -d '{ + "resourceId": "lock1", + "lockOwner": "vader" + }' + +{ + "status": 0 +} +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/api/health_api.md b/src/translated_content/zh_CN/docs/reference/api/health_api.md new file mode 100644 index 000000000..dce6ad371 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/health_api.md @@ -0,0 +1,86 @@ +--- +type: docs +title: "健康 API 参考" +linkTitle: "健康 API" +description: "关于健康 API 的详细文档" +weight: 1000 +--- + +Dapr 提供健康检查功能,用于检查 Dapr 的就绪状态或存活状态,以及从 SDKs 检查初始化的就绪性。 + +## 获取 Dapr 健康状态 + +可以通过以下方式获取 Dapr 的健康状态: +- 检查 sidecar 的健康状况 +- 检查 sidecar 的健康状况,包括组件的就绪性,适用于初始化期间。 + +### 等待 Dapr HTTP 端口可用 + +等待所有组件初始化完成,Dapr HTTP 端口可用,同时应用程序通道已初始化。例如,此端点用于 Kubernetes 的存活性探针。 + +#### HTTP 请求 + +``` +GET http://localhost:/v1.0/healthz +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +204 | Dapr 是健康的 +500 | Dapr 是不健康的 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +daprPort | Dapr 端口 + +#### 示例 + +```shell +curl -i http://localhost:3500/v1.0/healthz +``` + +### 等待 `/outbound` 路径的特定健康检查 + +等待所有组件初始化完成,Dapr HTTP 端口可用,但应用程序通道尚未建立。此端点允许您的应用程序在应用程序通道初始化之前调用 Dapr sidecar 的 API,例如使用 secret API 读取机密信息。在 Dapr SDKs 中,可以使用 `waitForSidecar` 方法(例如 .NET 和 Java SDKs)来检查 sidecar 是否已正确初始化,以便进行后续调用。 + +例如,[Java SDK]({{< ref "java-client.md#wait-for-sidecar" >}}) 和 [.NET SDK]({{< ref "dotnet-client.md#wait-for-sidecar" >}}) 使用此端点进行初始化。 + +目前,`v1.0/healthz/outbound` 端点在以下 SDK 中支持: +- [.NET SDK]({{< ref "dotnet-client.md#wait-for-sidecar" >}}) +- [Java SDK]({{< ref "java-client.md#wait-for-sidecar" >}}) +- [Python SDK]({{< ref "python-client.md#health-timeout" >}}) +- [JavaScript SDK](https://github.com/dapr/js-sdk/blob/4189a3d2ad6897406abd766f4ccbf2300c8f8852/src/interfaces/Client/IClientHealth.ts#L14) + +#### HTTP 请求 + +``` +GET http://localhost:/v1.0/healthz/outbound +``` + +#### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +204 | Dapr 是健康的 +500 | Dapr 是不健康的 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +daprPort | Dapr 端口 + +#### 示例 + +```shell +curl -i http://localhost:3500/v1.0/healthz/outbound +``` + +## 相关文章 + +- [Sidecar 健康]({{< ref "sidecar-health.md" >}}) +- [应用程序健康]({{< ref "app-health.md" >}}) diff --git a/src/translated_content/zh_CN/docs/reference/api/jobs_api.md b/src/translated_content/zh_CN/docs/reference/api/jobs_api.md new file mode 100644 index 000000000..d2f822ee6 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/jobs_api.md @@ -0,0 +1,168 @@ +--- +type: docs +title: "作业API参考" +linkTitle: "作业API" +description: "关于作业API的详细文档" +weight: 1300 +--- + +{{% alert title="注意" color="primary" %}} +作业API目前处于测试阶段。 +{{% /alert %}} + +使用作业API,您可以预定未来的作业和任务。 + +> HTTP API仅供开发和测试使用。在生产环境中,强烈推荐使用SDK,因为它们实现了gRPC API,提供比HTTP API更高的性能和功能。 + +## 调度作业 + +通过名称来调度作业。 + +``` +POST http://localhost:3500/v1.0-alpha1/jobs/ +``` + +### URL参数 + +{{% alert title="注意" color="primary" %}} +必须提供`schedule`或`dueTime`中的至少一个,也可以同时提供。 +{{% /alert %}} + +参数 | 描述 +--------- | ----------- +`name` | 您正在调度的作业的名称 +`data` | 一个JSON格式的值或对象。 +`schedule` | 作业的可选计划。格式详情如下。 +`dueTime` | 作业应激活的时间,或"一次性"时间,如果未提供其他调度类型字段。接受RFC3339格式的时间字符串、Go持续时间字符串(从创建时间计算)或非重复的ISO8601格式。 +`repeats` | 作业应触发的次数。如果未设置,作业将无限期运行或直到过期。 +`ttl` | 作业的生存时间或过期时间。接受RFC3339格式的时间字符串、Go持续时间字符串(从作业创建时间计算)或非重复的ISO8601格式。 + +#### schedule +`schedule`接受systemd计时器风格的cron表达式,以及以'@'为前缀的人类可读周期字符串。 + +systemd计时器风格的cron表达式包含6个字段: +秒 | 分钟 | 小时 | 月中的某天 | 月份 | 星期中的某天 +--- | --- | --- | --- | --- | --- +0-59 | 0-59 | 0-23 | 1-31 | 1-12/jan-dec | 0-6/sun-sat + +##### 示例 1 +"0 30 * * * *" - 每小时的30分钟 + +##### 示例 2 +"0 15 3 * * *" - 每天03:15 + +周期字符串表达式: +条目 | 描述 | 等同于 +----- | ----------- | ------------- +@every | 每隔运行一次 (例如 '@every 1h30m') | N/A +@yearly (或 @annually) | 每年运行一次,午夜,1月1日 | 0 0 0 1 1 * +@monthly | 每月运行一次,午夜,月初 | 0 0 0 1 * * +@weekly | 每周运行一次,周日午夜 | 0 0 0 * * 0 +@daily (或 @midnight) | 每天运行一次,午夜 | 0 0 0 * * * +@hourly | 每小时运行一次,整点 | 0 0 * * * * + + +### 请求体 + +```json +{ + "data": "some data", + "dueTime": "30s" +} +``` + +### HTTP响应代码 + +代码 | 描述 +---- | ----------- +`204` | 已接受 +`400` | 请求格式错误 +`500` | 请求格式正确,但dapr代码或调度器控制平面服务中出错 + +### 响应内容 + +以下示例curl命令创建一个名为`jobforjabba`的作业,并指定`schedule`、`repeats`和`data`。 + +```bash +$ curl -X POST \ + http://localhost:3500/v1.0-alpha1/jobs/jobforjabba \ + -H "Content-Type: application/json" \ + -d '{ + "data": "{\"value\":\"Running spice\"}", + "schedule": "@every 1m", + "repeats": 5 + }' +``` + +## 获取作业数据 + +通过名称获取作业。 + +``` +GET http://localhost:3500/v1.0-alpha1/jobs/ +``` + +### URL参数 + +参数 | 描述 +--------- | ----------- +`name` | 您正在检索的已调度作业的名称 + +### HTTP响应代码 + +代码 | 描述 +---- | ----------- +`200` | 已接受 +`400` | 请求格式错误 +`500` | 请求格式正确,但作业不存在或dapr代码或调度器控制平面服务中出错 + +### 响应内容 + +运行以下示例curl命令后,返回的响应是包含作业`name`、`dueTime`和`data`的JSON。 + +```bash +$ curl -X GET http://localhost:3500/v1.0-alpha1/jobs/jobforjabba -H "Content-Type: application/json" +``` + +```json +{ + "name": "jobforjabba", + "schedule": "@every 1m", + "repeats": 5, + "data": 123 +} +``` +## 删除作业 + +删除一个命名的作业。 + +``` +DELETE http://localhost:3500/v1.0-alpha1/jobs/ +``` + +### URL参数 + +参数 | 描述 +--------- | ----------- +`name` | 您正在删除的作业的名称 + +### HTTP响应代码 + +代码 | 描述 +---- | ----------- +`204` | 已接受 +`400` | 请求格式错误 +`500` | 请求格式正确,但dapr代码或调度器控制平面服务中出错 + +### 响应内容 + +在以下示例curl命令中,名为`test1`且app-id为`sub`的作业将被删除 + +```bash +$ curl -X DELETE http://localhost:3500/v1.0-alpha1/jobs/jobforjabba -H "Content-Type: application/json" +``` + + +## 下一步 + +[作业API概述]({{< ref jobs-overview.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/api/metadata_api.md b/src/translated_content/zh_CN/docs/reference/api/metadata_api.md new file mode 100644 index 000000000..ff94508b7 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/metadata_api.md @@ -0,0 +1,341 @@ +--- +type: docs +title: "元数据 API 参考" +linkTitle: "元数据 API" +description: "关于元数据 API 的详细文档" +weight: 1100 +--- + +Dapr 提供了一个元数据 API,可以返回有关 sidecar 的信息,从而支持运行时发现。元数据端点返回以下信息: +- 运行时版本 +- 已加载的资源列表(包括 `components`、`subscriptions` 和 `HttpEndpoints`) +- 注册的 actor 类型 +- 启用的功能 +- 应用程序连接的详细信息 +- 自定义的临时属性信息。 + +## 元数据 API + +### 组件 +每个加载的组件提供其名称、类型和版本,以及支持的功能信息。这些功能适用于 [state store]({{< ref supported-state-stores.md >}}) 和 [binding]({{< ref supported-bindings.md >}}) 组件类型。下表显示了给定版本的组件类型和能力列表。此列表可能会在将来扩展,仅代表当前已加载组件的能力。 + +组件类型 | 能力 +---------| ---- +State Store | ETAG, TRANSACTION, ACTOR, QUERY_API +Binding | INPUT_BINDING, OUTPUT_BINDING + +### HTTPEndpoints +每个加载的 `HttpEndpoint` 提供一个名称,以便轻松识别与运行时关联的 Dapr 资源。 + +### 订阅 +元数据 API 返回应用程序已向 Dapr 运行时注册的 pub/sub 订阅列表。这包括 pub/sub 名称、主题、路由、死信主题、订阅类型和与订阅相关的元数据。 + +### 启用的功能 +通过配置规范启用的功能列表(包括构建时的覆盖)。 + +### 应用程序连接详细信息 +元数据 API 返回与 Dapr 连接到应用程序相关的信息。这包括应用程序端口、协议、主机、最大并发性以及健康检查的详细信息。 + +### 属性 + +元数据 API 允许您以键值对的格式存储附加的属性信息。这些信息是临时的内存信息,如果 sidecar 重新加载则不会持久化。此信息应在 sidecar 创建时添加(例如,在应用程序启动后)。 + +## 获取 Dapr sidecar 信息 + +从元数据端点获取 Dapr sidecar 信息。 + +### 用例: +获取元数据 API 可用于发现已加载组件支持的不同能力。它可以帮助操作员确定要为所需能力提供哪些组件。 + +### HTTP 请求 + +``` +GET http://localhost:/v1.0/metadata +``` + +### URL 参数 + +参数 | 描述 +---------| ---- +daprPort | Dapr 端口。 + +### HTTP 响应代码 + +代码 | 描述 +---- | ---- +200 | 返回元数据信息 +500 | Dapr 无法返回元数据信息 + +### HTTP 响应体 + +**元数据 API 响应对象** + +名称 | 类型 | 描述 +---- | ---- | ---- +id | string | 应用程序 ID +runtimeVersion | string | Dapr 运行时版本 +enabledFeatures | string[] | 由 Dapr 配置启用的功能列表,参见 https://docs.dapr.io/operations/configuration/preview-features/ +actors | [元数据 API 响应注册的 actor](#metadataapiresponseactor)[] | 注册的 actor 元数据的 JSON 编码数组。 +extended.attributeName | string | 自定义属性的键值对列表,其中键是属性名称。 +components | [元数据 API 响应组件](#metadataapiresponsecomponent)[] | 已加载组件元数据的 JSON 编码数组。 +httpEndpoints | [元数据 API 响应 HttpEndpoint](#metadataapiresponsehttpendpoint)[] | 已加载 HttpEndpoints 元数据的 JSON 编码数组。 +subscriptions | [元数据 API 响应订阅](#metadataapiresponsesubscription)[] | pub/sub 订阅元数据的 JSON 编码数组。 +appConnectionProperties| [元数据 API 响应应用程序连接属性](#metadataapiresponseappconnectionproperties) | 应用程序连接属性的 JSON 编码对象。 + +**元数据 API 响应注册的 actor** + +名称 | 类型 | 描述 +---- | ---- | ---- +type | string | 注册的 actor 类型。 +count | integer | 运行的 actor 数量。 + +**元数据 API 响应组件** + +名称 | 类型 | 描述 +---- | ---- | ---- +name | string | 组件名称。 +type | string | 组件类型。 +version | string | 组件版本。 +capabilities | array | 此组件类型和版本支持的能力。 + +**元数据 API 响应 HttpEndpoint** + +名称 | 类型 | 描述 +---- | ---- | ---- +name | string | HttpEndpoint 的名称。 + +**元数据 API 响应订阅** + +名称 | 类型 | 描述 +---- | ---- | ---- +pubsubname | string | pub/sub 的名称。 +topic | string | 主题名称。 +metadata | object | 与订阅相关的元数据。 +rules | [元数据 API 响应订阅规则](#metadataapiresponsesubscriptionrules)[] | 与订阅相关的规则列表。 +deadLetterTopic | string | 死信主题名称。 +type | string | 订阅类型,可以是 `DECLARATIVE`、`STREAMING` 或 `PROGRAMMATIC`。 + +**元数据 API 响应订阅规则** + +名称 | 类型 | 描述 +---- | ---- | ---- +match | string | 用于匹配消息的 CEL 表达式,参见 https://docs.dapr.io/developing-applications/building-blocks/pubsub/howto-route-messages/#common-expression-language-cel +path | string | 如果匹配表达式为真,则路由消息的路径。 + +**元数据 API 响应应用程序连接属性** + +名称 | 类型 | 描述 +---- | ---- | ---- +port | integer| 应用程序监听的端口。 +protocol | string | 应用程序使用的协议。 +channelAddress| string | 应用程序监听的主机地址。 +maxConcurrency| integer| 应用程序可以处理的最大并发请求数。 +health | [元数据 API 响应应用程序连接属性健康](#metadataapiresponseappconnectionpropertieshealth) | 应用程序的健康检查详细信息。 + +**元数据 API 响应应用程序连接属性健康** + +名称 | 类型 | 描述 +---- | ---- | ---- +healthCheckPath | string | 健康检查路径,适用于 HTTP 协议。 +healthProbeInterval | string | 每次健康探测之间的时间,以 go duration 格式表示。 +healthProbeTimeout | string | 每次健康探测的超时时间,以 go duration 格式表示。 +healthThreshold | integer | 在应用程序被认为不健康之前失败的健康探测的最大次数。 + +### 示例 + +```shell +curl http://localhost:3500/v1.0/metadata +``` + +```json +{ + "id": "myApp", + "runtimeVersion": "1.12.0", + "enabledFeatures": [ + "ServiceInvocationStreaming" + ], + "actors": [ + { + "type": "DemoActor" + } + ], + "components": [ + { + "name": "pubsub", + "type": "pubsub.redis", + "version": "v1" + }, + { + "name": "statestore", + "type": "state.redis", + "version": "v1", + "capabilities": [ + "ETAG", + "TRANSACTIONAL", + "ACTOR" + ] + } + ], + "httpEndpoints": [ + { + "name": "my-backend-api" + } + ], + "subscriptions": [ + { + "type": "DECLARATIVE", + "pubsubname": "pubsub", + "topic": "orders", + "deadLetterTopic": "", + "metadata": { + "ttlInSeconds": "30" + }, + "rules": [ + { + "match": "%!s()", + "path": "orders" + } + ] + } + ], + "extended": { + "appCommand": "uvicorn --port 3000 demo_actor_service:app", + "appPID": "98121", + "cliPID": "98114", + "daprRuntimeVersion": "1.12.0" + }, + "appConnectionProperties": { + "port": 3000, + "protocol": "http", + "channelAddress": "127.0.0.1", + "health": { + "healthProbeInterval": "5s", + "healthProbeTimeout": "500ms", + "healthThreshold": 3 + } + } +} +``` + +## 向 Dapr sidecar 信息添加自定义标签 + +向元数据端点存储的 Dapr sidecar 信息添加自定义标签。 + +### 用例: +例如,元数据端点被 Dapr CLI 用于在 selfhost 模式下运行 Dapr 时存储托管 sidecar 的进程的 PID,并存储用于运行应用程序的命令。应用程序也可以在启动后添加属性作为键。 + +### HTTP 请求 + +``` +PUT http://localhost:/v1.0/metadata/attributeName +``` + +### URL 参数 + +参数 | 描述 +--------- | ---- +daprPort | Dapr 端口。 +attributeName | 自定义属性名称。这是键值对中的键名称。 + +### HTTP 请求体 + +在请求中需要以 RAW 数据传递自定义属性值: + +```json +{ + "Content-Type": "text/plain" +} +``` + +在请求体中放置您想要存储的自定义属性值: + +``` +attributeValue +``` + +### HTTP 响应代码 + +代码 | 描述 +---- | ---- +204 | 自定义属性已添加到元数据信息中 + +### 示例 + +向元数据端点添加自定义属性: + +```shell +curl -X PUT -H "Content-Type: text/plain" --data "myDemoAttributeValue" http://localhost:3500/v1.0/metadata/myDemoAttribute +``` + +获取元数据信息以确认您的自定义属性已添加: + +```json +{ + "id": "myApp", + "runtimeVersion": "1.12.0", + "enabledFeatures": [ + "ServiceInvocationStreaming" + ], + "actors": [ + { + "type": "DemoActor" + } + ], + "components": [ + { + "name": "pubsub", + "type": "pubsub.redis", + "version": "v1" + }, + { + "name": "statestore", + "type": "state.redis", + "version": "v1", + "capabilities": [ + "ETAG", + "TRANSACTIONAL", + "ACTOR" + ] + } + ], + "httpEndpoints": [ + { + "name": "my-backend-api" + } + ], + "subscriptions": [ + { + "type": "PROGRAMMATIC", + "pubsubname": "pubsub", + "topic": "orders", + "deadLetterTopic": "", + "metadata": { + "ttlInSeconds": "30" + }, + "rules": [ + { + "match": "%!s()", + "path": "orders" + } + ] + } + ], + "extended": { + "myDemoAttribute": "myDemoAttributeValue", + "appCommand": "uvicorn --port 3000 demo_actor_service:app", + "appPID": "98121", + "cliPID": "98114", + "daprRuntimeVersion": "1.12.0" + }, + "appConnectionProperties": { + "port": 3000, + "protocol": "http", + "channelAddress": "127.0.0.1", + "health": { + "healthProbeInterval": "5s", + "healthProbeTimeout": "500ms", + "healthThreshold": 3 + } + } +} +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/api/placement_api.md b/src/translated_content/zh_CN/docs/reference/api/placement_api.md new file mode 100644 index 000000000..20c82c3c5 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/placement_api.md @@ -0,0 +1,86 @@ +--- +type: docs +title: "Placement API 参考" +linkTitle: "Placement API" +description: "Placement API 的详细文档" +weight: 1200 +--- + +Dapr 提供了一个 HTTP API `/placement/state`,用于 Placement 服务,公开 placement 表信息。该 API 在 sidecar 上与 healthz 使用相同的端口。这是一个未经身份验证的端点,默认情况下是禁用的。 + +要在自托管模式下启用 placement 元数据,可以设置 `DAPR_PLACEMENT_METADATA_ENABLED` 环境变量为 `true`,或者在 Placement 服务上使用 `metadata-enabled` 命令行参数。请参阅[如何在自托管模式下运行 Placement 服务]({{< ref "self-hosted-no-docker.md#enable-actors" >}})。 + +{{% alert title="重要" color="warning" %}} +在 [多租户模式]({{< ref namespaced-actors.md >}})下运行 placement 时,请禁用 `metadata-enabled` 命令行参数,以防止不同命名空间之间的数据泄露。 +{{% /alert %}} + +如果您在 Kubernetes 上使用 Helm 部署 Placement 服务,要启用 placement 元数据,请将 `dapr_placement.metadataEnabled` 设置为 `true`。 + +## 使用场景 + +placement 表 API 可用于检索当前的 placement 表,其中包含所有注册的 actor。这对于调试非常有帮助,并允许工具提取和展示关于 actor 的信息。 + +## HTTP 请求 + +``` +GET http://localhost:/placement/state +``` + +## HTTP 响应代码 + +代码 | 描述 +---- | ----------- +200 | 成功返回 placement 表信息 +500 | 无法返回 placement 表信息 + +## HTTP 响应体 + +**Placement 表 API 响应对象** + +名称 | 类型 | 描述 +---- | ---- | ----------- +tableVersion | int | placement 表版本 +hostList | [Actor 主机信息](#actorhostinfo)[] | 注册的 actor 主机信息的 JSON 数组。 + +**Actor 主机信息** + +名称 | 类型 | 描述 +---- | ---- | ----------- +name | string | actor 的主机:端口地址。 +appId | string | 应用 ID。 +actorTypes | json string array | 它所托管的 actor 类型列表。 +updatedAt | timestamp | actor 注册/更新的时间戳。 + +## 示例 + +```shell + curl localhost:8080/placement/state +``` + +```json +{ + "hostList": [{ + "name": "198.18.0.1:49347", + "namespace": "ns1", + "appId": "actor1", + "actorTypes": ["testActorType1", "testActorType3"], + "updatedAt": 1690274322325260000 + }, + { + "name": "198.18.0.2:49347", + "namespace": "ns2", + "appId": "actor2", + "actorTypes": ["testActorType2"], + "updatedAt": 1690274322325260000 + }, + { + "name": "198.18.0.3:49347", + "namespace": "ns2", + "appId": "actor2", + "actorTypes": ["testActorType2"], + "updatedAt": 1690274322325260000 + } + ], + "tableVersion": 1 +} +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/api/pubsub_api.md b/src/translated_content/zh_CN/docs/reference/api/pubsub_api.md new file mode 100644 index 000000000..83d5c5ff9 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/pubsub_api.md @@ -0,0 +1,308 @@ +--- +type: docs +title: "发布/订阅 API 参考" +linkTitle: "发布/订阅 API" +description: "关于发布/订阅 API 的详细文档" +weight: 200 +--- + +## 向指定主题发布消息 + +此端点允许您将数据发布到多个正在监听某个 `topic` 的消费者。Dapr 保证此端点至少会被调用一次。 + +### HTTP 请求 + +``` +POST http://localhost:/v1.0/publish//[?] +``` + +### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +204 | 消息已送达 +403 | 访问控制禁止消息 +404 | 未提供 pubsub 名称或主题 +500 | 传递失败 + +### URL 参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr 端口 +`pubsubname` | pubsub 组件的名称 +`topic` | 主题的名称 +`metadata` | 查询参数,用于元数据,如下所述 + +> 注意,所有 URL 参数区分大小写。 + +```shell +curl -X POST http://localhost:3500/v1.0/publish/pubsubName/deathStarStatus \ + -H "Content-Type: application/json" \ + -d '{ + "status": "completed" + }' +``` + +### 头部 + +`Content-Type` 头部告知 Dapr 在构建 CloudEvent 信封时您的数据遵循哪种内容类型。`Content-Type` 头部的值填充 CloudEvent 中的 `datacontenttype` 字段。 + +除非指定,否则 Dapr 假定为 `text/plain`。如果您的内容类型是 JSON,请使用值为 `application/json` 的 `Content-Type` 头部。 + +如果您想发送自定义的 CloudEvent,请为 `Content-Type` 头部使用 `application/cloudevents+json` 值。 + +#### 元数据 + +元数据可以通过请求 URL 中的查询参数发送。它必须以 `metadata.` 为前缀,如下所示。 + +参数 | 描述 +--------- | ----------- +`metadata.ttlInSeconds` | 消息过期的秒数,如[此处所述]({{< ref pubsub-message-ttl.md >}}) +`metadata.rawPayload` | 布尔值,决定 Dapr 是否应在不将事件包装为 CloudEvent 的情况下发布事件,如[此处所述]({{< ref pubsub-raw.md >}}) + +> 根据每个 pubsub 组件,还可以使用其他元数据参数。 + +## 向指定主题发布多条消息 + +此端点允许您将多条消息发布到正在监听某个 `topic` 的消费者。 + +### HTTP 请求 + +``` +POST http://localhost:/v1.0-alpha1/publish/bulk//[?] +``` + +请求体应包含一个 JSON 数组,其中包含: +- 唯一的条目 ID +- 要发布的事件 +- 事件的内容类型 + +如果事件的内容类型不是 `application/cloudevents+json`,则会自动包装为 CloudEvent(除非 `metadata.rawPayload` 设置为 `true`)。 + +示例: + +```bash +curl -X POST http://localhost:3500/v1.0-alpha1/publish/bulk/pubsubName/deathStarStatus \ + -H 'Content-Type: application/json' \ + -d '[ + { + "entryId": "ae6bf7c6-4af2-11ed-b878-0242ac120002", + "event": "first text message", + "contentType": "text/plain" + }, + { + "entryId": "b1f40bd6-4af2-11ed-b878-0242ac120002", + "event": { + "message": "second JSON message" + }, + "contentType": "application/json" + }, + ]' +``` + +### 头部 + +由于请求体是一个 JSON 数组,因此 `Content-Type` 头部应始终设置为 `application/json`。 + +### URL 参数 + +|**参数**|**描述**| +|--|--| +|`daprPort`|Dapr 端口| +|`pubsubname`|发布/订阅组件的名称| +|`topic`|主题的名称| +|`metadata`|[元数据]({{< ref "pubsub_api.md#metadata" >}})的查询参数| + +### 元数据 + +元数据可以通过请求 URL 中的查询参数发送。它必须以 `metadata.` 为前缀,如下表所示。 + +|**参数**|**描述**| +|--|--| +|`metadata.rawPayload`|布尔值,决定 Dapr 是否应在不将消息包装为 CloudEvent 的情况下发布消息。| +|`metadata.maxBulkPubBytes`|批量发布请求中要发布的最大字节数。| + +#### HTTP 响应 + +|**HTTP 状态**|**描述**| +|--|--| +|204|所有消息已送达| +|400|发布/订阅不存在| +|403|访问控制禁止| +|500|至少一条消息未能送达| + +如果状态码为 500,响应体将包含一个 JSON 对象,其中包含未能送达的条目列表。例如,在我们上面的请求中,如果事件 `"first text message"` 的条目未能送达,响应将包含其条目 ID 和来自底层 pub/sub 组件的错误消息。 + +```json +{ + "failedEntries": [ + { + "entryId": "ae6bf7c6-4af2-11ed-b878-0242ac120002", + "error": "some error message" + }, + ], + "errorCode": "ERR_PUBSUB_PUBLISH_MESSAGE" +} +``` + +## 可选应用程序(用户代码)路由 + +### 提供一个路由以供 Dapr 发现主题订阅 + +Dapr 将调用用户代码上的以下端点以发现主题订阅: + +#### HTTP 请求 + +``` +GET http://localhost:/dapr/subscribe +``` + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`appPort` | 应用程序端口 + +#### HTTP 响应体 + +一个 JSON 编码的字符串数组。 + +示例: + +```json +[ + { + "pubsubname": "pubsub", + "topic": "newOrder", + "routes": { + "rules": [ + { + "match": "event.type == order", + "path": "/orders" + } + ] + "default" : "/otherorders" + }, + "metadata": { + "rawPayload": "true" + } + } +] +``` + +> 注意,所有订阅参数区分大小写。 + +#### 元数据 + +可选地,元数据可以通过请求体发送。 + +参数 | 描述 +--------- | ----------- +`rawPayload` | 布尔值,订阅不符合 CloudEvent 规范的事件,如[此处所述]({{< ref pubsub-raw.md >}}) + +### 提供路由以供 Dapr 传递主题事件 + +为了传递主题事件,将使用订阅响应中指定的路由对用户代码进行 `POST` 调用。在 `routes` 下,您可以提供[在接收到消息主题时匹配特定条件到特定路径的规则。]({{< ref "howto-route-messages.md" >}}) 您还可以为没有特定匹配的任何规则提供默认路由。 + +以下示例说明了这一点,考虑到主题 `newOrder` 的订阅和端口 3000 上的路由 `orders`:`POST http://localhost:3000/orders` + +#### HTTP 请求 + +``` +POST http://localhost:/ +``` + +> 注意,所有 URL 参数区分大小写。 + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +`appPort` | 应用程序端口 +`path` | 订阅配置中的路由路径 + +#### 预期的 HTTP 响应 + +HTTP 2xx 响应表示消息处理成功。 + +为了更丰富的响应处理,可以发送一个带有处理状态的 JSON 编码的负载体: + +```json +{ + "status": "" +} +``` + +状态 | 描述 +--------- | ----------- +`SUCCESS` | 消息处理成功 +`RETRY` | 消息由 Dapr 重试 +`DROP` | 记录警告并丢弃消息 +其他 | 错误,消息由 Dapr 重试 + +Dapr 假定没有 `status` 字段的 JSON 编码负载响应或带有 HTTP 2xx 的空负载响应为 `SUCCESS`。 + +HTTP 响应可能与 HTTP 2xx 不同。以下是 Dapr 在不同 HTTP 状态下的行为: + +HTTP 状态 | 描述 +--------- | ----------- +2xx | 消息根据负载中的状态处理(如果为空则为 `SUCCESS`;如果负载无效则忽略)。 +404 | 记录错误并丢弃消息 +其他 | 记录警告并重试消息 + +## 从指定主题订阅多条消息 + +这允许您在监听某个 `topic` 时从代理订阅多条消息。 + +为了以批量方式接收主题订阅中的消息,应用程序: + +- 需要在发送要订阅的主题列表时选择 `bulkSubscribe` +- 可选地,可以配置 `maxMessagesCount` 和/或 `maxAwaitDurationMs` +有关如何选择的更多详细信息,请参阅[批量发送和接收消息]({{< ref pubsub-bulk.md >}})指南。 + +#### 批量订阅的预期 HTTP 响应 + +HTTP 2xx 响应表示应用程序已处理此批量消息中的条目(单个消息),Dapr 现在将检查每个 EntryId 状态。 +需要发送一个带有每个条目处理状态的 JSON 编码负载体: + +```json +{ + "statuses": + [ + { + "entryId": "", + "status": "" + }, + { + "entryId": "", + "status": "" + } + ] +} +``` + +> 注意:如果 Dapr 在从应用程序接收到的响应中找不到 EntryId 状态,则该条目的状态被视为 `RETRY`。 + +状态 | 描述 +--------- | ----------- +`SUCCESS` | 消息处理成功 +`RETRY` | 消息由 Dapr 重试 +`DROP` | 记录警告并丢弃消息 + +HTTP 响应可能与 HTTP 2xx 不同。以下是 Dapr 在不同 HTTP 状态下的行为: + +HTTP 状态 | 描述 +--------- | ----------- +2xx | 消息根据负载中的状态处理。 +404 | 记录错误并丢弃所有消息 +其他 | 记录警告并重试所有消息 + +## 消息信封 + +Dapr 发布/订阅遵循 [CloudEvents 1.0 版本](https://github.com/cloudevents/spec/blob/v1.0/spec.md)。 + +## 相关链接 + +* [如何发布和消费主题]({{< ref howto-publish-subscribe.md >}}) +* [发布/订阅示例](https://github.com/dapr/quickstarts/tree/master/tutorials/pub-sub) diff --git a/src/translated_content/zh_CN/docs/reference/api/secrets_api.md b/src/translated_content/zh_CN/docs/reference/api/secrets_api.md new file mode 100644 index 000000000..66f123619 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/secrets_api.md @@ -0,0 +1,171 @@ +--- +type: docs +title: "Secrets API 参考" +linkTitle: "Secrets API" +description: "关于 secrets API 的详细文档" +weight: 700 +--- + +## 获取 Secret + +此接口允许您获取指定 secret 存储中的 secret 值。 + +### HTTP 请求 + +``` +GET http://localhost:/v1.0/secrets// +``` + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +daprPort | Dapr 端口 +secret-store-name | 要从中获取 secret 的 secret 存储名称 +name | 要获取的 secret 名称 + +> 请注意,所有 URL 参数区分大小写。 + +#### 查询参数 + +某些 secret 存储支持**可选**的、每个请求的元数据属性。您可以通过查询参数来提供这些属性。例如: + +``` +GET http://localhost:/v1.0/secrets//?metadata.version_id=15 +``` + +请注意,并非所有 secret 存储都支持相同的参数集。例如: +- Hashicorp Vault、GCP Secret Manager 和 AWS Secret Manager 支持 `version_id` 参数 +- 只有 AWS Secret Manager 支持 `version_stage` 参数 +- 只有 Kubernetes Secrets 支持 `namespace` 参数 +请查阅每个 [secret 存储的文档]({{< ref supported-secret-stores.md >}}) 以获取支持的参数列表。 + +### HTTP 响应 + +#### 响应体 + +如果 secret 存储支持 secret 中的多个键值,将返回一个 JSON 负载,其中键名作为字段及其各自的值。 + +如果 secret 存储仅具有名称/值语义,将返回一个 JSON 负载,其中 secret 的名称作为字段,secret 的值作为值。 + +[查看支持 secret 中多个键和名称/值语义的 secret 存储的分类]({{< ref supported-secret-stores.md >}})。 + +##### secret 中有多个键的响应(例如 Kubernetes): + +```shell +curl http://localhost:3500/v1.0/secrets/kubernetes/db-secret +``` + +```json +{ + "key1": "value1", + "key2": "value2" +} +``` + +上面的示例展示了来自具有多个键的 secret 存储的响应。请注意,secret 名称 (`db-secret`) **不**作为结果的一部分返回。 + +##### 具有名称/值语义的 secret 存储的响应: + +```shell +curl http://localhost:3500/v1.0/secrets/vault/db-secret +``` + +```json +{ + "db-secret": "value1" +} +``` + +上面的示例展示了来自具有名称/值语义的 secret 存储的响应。与来自具有多个键的 secret 存储的结果相比,此结果返回一个键值对,其中 secret 名称 (`db-secret`) 作为键返回。 + +#### 响应代码 + +代码 | 描述 +---- | ----------- +200 | OK +204 | Secret 未找到 +400 | Secret 存储缺失或配置错误 +403 | 访问被拒绝 +500 | 获取 secret 失败或未定义 secret 存储 + +### 示例 + +```shell +curl http://localhost:3500/v1.0/secrets/mySecretStore/db-secret +``` + +```shell +curl http://localhost:3500/v1.0/secrets/myAwsSecretStore/db-secret?metadata.version_id=15&metadata.version_stage=production +``` + +## 获取批量 Secret + +此接口允许您获取 secret 存储中的所有 secret。 +建议为 Dapr 配置 secret 存储时使用 [令牌认证]({{}})。 + +### HTTP 请求 + +``` +GET http://localhost:/v1.0/secrets//bulk +``` + +#### URL 参数 + +参数 | 描述 +--------- | ----------- +daprPort | Dapr 端口 +secret-store-name | 要从中获取 secret 的 secret 存储名称 + +> 请注意,所有 URL 参数区分大小写。 + +### HTTP 响应 + +#### 响应体 + +返回的响应是一个包含 secrets 的 JSON。JSON 对象将包含 secret 名称作为字段,并将 secret 键和值的映射作为字段值。 + +##### 具有多个 secrets 和 secret 中多个键/值的响应(例如 Kubernetes): + +```shell +curl http://localhost:3500/v1.0/secrets/kubernetes/bulk +``` + +```json +{ + "secret1": { + "key1": "value1", + "key2": "value2" + }, + "secret2": { + "key3": "value3", + "key4": "value4" + } +} +``` + +#### 响应代码 + +代码 | 描述 +---- | ----------- +200 | OK +400 | Secret 存储缺失或配置错误 +403 | 访问被拒绝 +500 | 获取 secret 失败或未定义 secret 存储 + +### 示例 + +```shell +curl http://localhost:3500/v1.0/secrets/vault/bulk +``` + +```json +{ + "key1": { + "key1": "value1" + }, + "key2": { + "key2": "value2" + } +} +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/api/service_invocation_api.md b/src/translated_content/zh_CN/docs/reference/api/service_invocation_api.md new file mode 100644 index 000000000..3a561aedb --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/service_invocation_api.md @@ -0,0 +1,152 @@ +--- +type: docs +title: "服务调用API参考" +linkTitle: "服务调用API" +description: "关于服务调用API的详细文档" +weight: 100 +--- + +Dapr为用户提供了使用唯一命名标识符(appId)来调用其他使用Dapr的应用程序的功能,或者调用不使用Dapr的HTTP端点。 +这使得应用程序可以通过命名标识符相互交互,并将服务发现的责任交给Dapr运行时。 + +## 调用远程Dapr应用上的方法 + +这个端点允许您在另一个启用了Dapr的应用中调用方法。 + +### HTTP请求 + +``` +PATCH/POST/GET/PUT/DELETE http://localhost:/v1.0/invoke//method/ +``` + +## 调用非Dapr端点上的方法 + +这个端点允许您使用`HTTPEndpoint`资源名称或完全限定域名(FQDN)URL在非Dapr端点上调用方法。 + +### HTTP请求 + +``` +PATCH/POST/GET/PUT/DELETE http://localhost:/v1.0/invoke//method/ + +PATCH/POST/GET/PUT/DELETE http://localhost:/v1.0/invoke//method/ +``` + +### HTTP响应代码 + +当一个服务通过Dapr调用另一个服务时,被调用服务的状态码将返回给调用者。 +如果存在网络错误或其他瞬态错误,Dapr将返回一个`500`错误,并附带详细的错误信息。 + +如果用户通过HTTP调用Dapr与启用gRPC的服务通信,来自被调用gRPC服务的错误将返回为`500`,而成功的响应将返回为`200 OK`。 + +代码 | 描述 +---- | ----------- +XXX | 上游状态返回 +400 | 未提供方法名称 +403 | 访问控制禁止调用 +500 | 请求失败 + +### URL参数 + +参数 | 描述 +--------- | ----------- +daprPort | Dapr端口 +appID | 与远程应用关联的应用ID +HTTPEndpoint name | 与外部端点关联的HTTPEndpoint资源 +FQDN URL | 在外部端点上调用的完全限定域名URL +method-name | 要在远程应用上调用的方法或URL的名称 + +> 注意,所有URL参数区分大小写。 + +### 请求内容 + +在请求中,您可以传递头信息: + +```json +{ + "Content-Type": "application/json" +} +``` + +在请求体中放置您想要发送给服务的数据: + +```json +{ + "arg1": 10, + "arg2": 23, + "operator": "+" +} +``` + +### 被调用服务接收到的请求 + +一旦您的服务代码在另一个启用了Dapr的应用或非Dapr端点中调用了方法,Dapr会在``端点上发送请求,并附带头信息和请求体。 + +被调用的Dapr应用或非Dapr端点需要监听并响应该端点上的请求。 + +### 跨命名空间调用 + +在支持命名空间的托管平台上,Dapr应用ID符合包含目标命名空间的有效FQDN格式。 +例如,以下字符串包含应用ID(`myApp`)以及应用运行的命名空间(`production`)。 + +``` +myApp.production +``` + +#### 支持命名空间的平台 + +- Kubernetes + +### 示例 + +您可以通过发送以下内容来调用`mathService`服务上的`add`方法: + +```shell +curl http://localhost:3500/v1.0/invoke/mathService/method/add \ + -H "Content-Type: application/json" + -d '{ "arg1": 10, "arg2": 23}' +``` + +`mathService`服务需要在`/add`端点上监听以接收和处理请求。 + +对于一个Node应用,这将如下所示: + +```js +app.post('/add', (req, res) => { + let args = req.body; + const [operandOne, operandTwo] = [Number(args['arg1']), Number(args['arg2'])]; + + let result = operandOne + operandTwo; + res.send(result.toString()); +}); + +app.listen(port, () => console.log(`Listening on port ${port}!`)); +``` + +> 来自远程端点的响应将返回在响应体中。 + +如果您的服务监听在更嵌套的路径上(例如`/api/v1/add`),Dapr实现了一个完整的反向代理,因此您可以将所有必要的路径片段附加到您的请求URL中,如下所示: + +`http://localhost:3500/v1.0/invoke/mathService/method/api/v1/add` + +如果您在不同的命名空间中调用`mathService`,您可以使用以下URL: + +`http://localhost:3500/v1.0/invoke/mathService.testing/method/api/v1/add` + +在此URL中,`testing`是`mathService`运行的命名空间。 + +#### 非Dapr端点示例 + +如果`mathService`服务是一个非Dapr应用程序,则可以通过`HTTPEndpoint`以及完全限定域名(FQDN)URL进行服务调用。 + +```shell +curl http://localhost:3500/v1.0/invoke/mathHTTPEndpoint/method/add \ + -H "Content-Type: application/json" + -d '{ "arg1": 10, "arg2": 23}' + +curl http://localhost:3500/v1.0/invoke/http://mathServiceURL.com/method/add \ + -H "Content-Type: application/json" + -d '{ "arg1": 10, "arg2": 23}' +``` + +## 下一步 +- [如何:调用和发现服务]({{< ref howto-invoke-discover-services.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/api/state_api.md b/src/translated_content/zh_CN/docs/reference/api/state_api.md new file mode 100644 index 000000000..08d5d76cf --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/state_api.md @@ -0,0 +1,707 @@ +--- +type: docs +title: "状态管理API参考" +linkTitle: "状态管理API" +description: "关于状态管理API的详细文档" +weight: 400 +--- + +## 组件文件 + +Dapr的`statestore.yaml`组件文件结构如下: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: + namespace: +spec: + type: state. + version: v1 + metadata: + - name: + value: + - name: + value: +``` + +| 设置 | 描述 | +| ------- | ----------- | +| `metadata.name` | 状态存储的名称。 | +| `spec/metadata` | 一个开放的键值对元数据,允许绑定定义连接属性。 | + +## 键方案 + +Dapr状态存储是键/值存储。Dapr要求这些数据存储遵循固定的键方案,以确保数据兼容性。对于一般状态,键格式为: + +``` +|| +``` + +对于actor状态,键格式为: + +``` +|||||| +``` + +## 保存状态 + +通过该端点可以保存一组状态对象。 + +### HTTP请求 + +``` +POST http://localhost:/v1.0/state/ +``` + +#### URL参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr端口 +`storename` | 用户配置的`statestore.yaml`组件文件中的`metadata.name`字段。请参阅上面提到的[Dapr状态存储配置结构](#component-file)。 + +可选的请求元数据通过URL查询参数传递。例如, +``` +POST http://localhost:3500/v1.0/state/myStore?metadata.contentType=application/json +``` +> 所有URL参数区分大小写。 + +> 由于`||`是用作键方案中的分隔符,因此不能在``字段中使用。 + +#### 请求体 + +状态对象的JSON数组,每个状态对象包含以下字段: + +字段 | 描述 +---- | ----------- +`key` | 状态键 +`value` | 状态值,可以是任何字节数组 +`etag` | (可选)状态ETag +`metadata` | (可选)要传递给状态存储的附加键值对 +`options` | (可选)状态操作选项;请参阅[状态操作选项](#optional-behaviors) + +> **ETag格式:** Dapr运行时将ETags视为不透明字符串。确切的ETag格式由相应的数据存储定义。 + +#### 元数据 + +元数据可以通过请求的URL中的查询参数发送。它必须以`metadata.`为前缀,如下所示。 + +参数 | 描述 +--------- | ----------- +`metadata.ttlInSeconds` | 消息过期的秒数,如[此处所述]({{< ref state-store-ttl.md >}}) + +> **TTL:** 只有某些状态存储支持TTL选项,根据[支持的状态存储]({{< ref supported-state-stores.md >}})。 + +### HTTP响应 + +#### 响应代码 + +代码 | 描述 +---- | ----------- +`204` | 状态已保存 +`400` | 状态存储缺失或配置错误或请求格式错误 +`500` | 保存状态失败 + +#### 响应体 + +无。 + +### 示例 + +```shell +curl -X POST http://localhost:3500/v1.0/state/starwars?metadata.contentType=application/json \ + -H "Content-Type: application/json" \ + -d '[ + { + "key": "weapon", + "value": "DeathStar", + "etag": "1234" + }, + { + "key": "planet", + "value": { + "name": "Tatooine" + } + } + ]' +``` + +## 获取状态 + +通过该端点可以获取特定键的状态。 + +### HTTP请求 + +``` +GET http://localhost:/v1.0/state// +``` + +#### URL参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr端口 +`storename` | 用户配置的statestore.yaml组件文件中的`metadata.name`字段。请参阅上面提到的[Dapr状态存储配置结构](#component-file)。 +`key` | 所需状态的键 +`consistency` | (可选)读取一致性模式;请参阅[状态操作选项](#optional-behaviors) +`metadata` | (可选)作为查询参数传递给状态存储的元数据 + +可选的请求元数据通过URL查询参数传递。例如, +``` +GET http://localhost:3500/v1.0/state/myStore/myKey?metadata.contentType=application/json +``` + +> 注意,所有URL参数区分大小写。 + +### HTTP响应 + +#### 响应代码 + +代码 | 描述 +---- | ----------- +`200` | 获取状态成功 +`204` | 找不到键 +`400` | 状态存储缺失或配置错误 +`500` | 获取状态失败 + +#### 响应头 + +头 | 描述 +--------- | ----------- +`ETag` | 返回值的ETag + +#### 响应体 + +JSON编码的值 + +### 示例 + +```shell +curl http://localhost:3500/v1.0/state/starwars/planet?metadata.contentType=application/json +``` + +> 上述命令返回状态: + +```json +{ + "name": "Tatooine" +} +``` + +要将元数据作为查询参数传递: + +``` +GET http://localhost:3500/v1.0/state/starwars/planet?metadata.partitionKey=mypartitionKey&metadata.contentType=application/json +``` + +## 获取批量状态 + +通过该端点可以获取给定键列表的值列表。 + +### HTTP请求 + +``` +POST/PUT http://localhost:/v1.0/state//bulk +``` + +#### URL参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr端口 +`storename` | 用户配置的statestore.yaml组件文件中的`metadata.name`字段。请参阅上面提到的[Dapr状态存储配置结构](#component-file)。 +`metadata` | (可选)作为查询参数传递给状态存储的元数据 + +可选的请求元数据通过URL查询参数传递。例如, +``` +POST/PUT http://localhost:3500/v1.0/state/myStore/bulk?metadata.partitionKey=mypartitionKey +``` + +> 注意,所有URL参数区分大小写。 + +### HTTP响应 + +#### 响应代码 + +代码 | 描述 +---- | ----------- +`200` | 获取状态成功 +`400` | 状态存储缺失或配置错误 +`500` | 获取批量状态失败 + +#### 响应体 + +一个JSON编码的值数组 + +### 示例 + +```shell +curl http://localhost:3500/v1.0/state/myRedisStore/bulk \ + -H "Content-Type: application/json" \ + -d '{ + "keys": [ "key1", "key2" ], + "parallelism": 10 + }' +``` + +> 上述命令返回一个键/值对象数组: + +```json +[ + { + "key": "key1", + "value": "value1", + "etag": "1" + }, + { + "key": "key2", + "value": "value2", + "etag": "1" + } +] +``` + +要将元数据作为查询参数传递: + +``` +POST http://localhost:3500/v1.0/state/myRedisStore/bulk?metadata.partitionKey=mypartitionKey +``` + +## 删除状态 + +通过该端点可以删除特定键的状态。 + +### HTTP请求 + +``` +DELETE http://localhost:/v1.0/state// +``` + +#### URL参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr端口 +`storename` | 用户配置的statestore.yaml组件文件中的`metadata.name`字段。请参阅上面提到的[Dapr状态存储配置结构](#component-file)。 +`key` | 所需状态的键 +`concurrency` | (可选)*first-write*或*last-write*;请参阅[状态操作选项](#optional-behaviors) +`consistency` | (可选)*strong*或*eventual*;请参阅[状态操作选项](#optional-behaviors) + +可选的请求元数据通过URL查询参数传递。例如, +``` +DELETE http://localhost:3500/v1.0/state/myStore/myKey?metadata.contentType=application/json +``` + +> 注意,所有URL参数区分大小写。 + +#### 请求头 + +头 | 描述 +--------- | ----------- +If-Match | (可选)与要删除的键关联的ETag + +### HTTP响应 + +#### 响应代码 + +代码 | 描述 +---- | ----------- +`204` | 删除状态成功 +`400` | 状态存储缺失或配置错误 +`500` | 删除状态失败 + +#### 响应体 + +无。 + +### 示例 + +```shell +curl -X DELETE http://localhost:3500/v1.0/state/starwars/planet -H "If-Match: xxxxxxx" +``` + +## 查询状态 + +通过该端点可以查询键/值状态。 + +{{% alert title="alpha" color="warning" %}} +此API处于alpha阶段。 +{{% /alert %}} + +### HTTP请求 + +``` +POST/PUT http://localhost:/v1.0-alpha1/state//query +``` + +#### URL参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr端口 +`storename` | 用户配置的statestore.yaml组件文件中的`metadata.name`字段。请参阅上面提到的[Dapr状态存储配置结构](#component-file)。 +`metadata` | (可选)作为查询参数传递给状态存储的元数据 + +可选的请求元数据通过URL查询参数传递。例如, +``` +POST http://localhost:3500/v1.0-alpha1/state/myStore/query?metadata.contentType=application/json +``` + +> 注意,所有URL参数区分大小写。 + +#### 响应代码 + +代码 | 描述 +---- | ----------- +`200` | 状态查询成功 +`400` | 状态存储缺失或配置错误 +`500` | 状态查询失败 + +#### 响应体 + +一个JSON编码的值数组 + +### 示例 + +```shell +curl -X POST http://localhost:3500/v1.0-alpha1/state/myStore/query?metadata.contentType=application/json \ + -H "Content-Type: application/json" \ + -d '{ + "filter": { + "OR": [ + { + "EQ": { "person.org": "Dev Ops" } + }, + { + "AND": [ + { + "EQ": { "person.org": "Finance" } + }, + { + "IN": { "state": [ "CA", "WA" ] } + } + ] + } + ] + }, + "sort": [ + { + "key": "state", + "order": "DESC" + }, + { + "key": "person.id" + } + ], + "page": { + "limit": 3 + } + }' +``` + +> 上述命令返回一个对象数组以及一个令牌: + +```json +{ + "results": [ + { + "key": "1", + "data": { + "person": { + "org": "Dev Ops", + "id": 1036 + }, + "city": "Seattle", + "state": "WA" + }, + "etag": "6f54ad94-dfb9-46f0-a371-e42d550adb7d" + }, + { + "key": "4", + "data": { + "person": { + "org": "Dev Ops", + "id": 1042 + }, + "city": "Spokane", + "state": "WA" + }, + "etag": "7415707b-82ce-44d0-bf15-6dc6305af3b1" + }, + { + "key": "10", + "data": { + "person": { + "org": "Dev Ops", + "id": 1054 + }, + "city": "New York", + "state": "NY" + }, + "etag": "26bbba88-9461-48d1-8a35-db07c374e5aa" + } + ], + "token": "3" +} +``` + +要将元数据作为查询参数传递: + +``` +POST http://localhost:3500/v1.0-alpha1/state/myStore/query?metadata.partitionKey=mypartitionKey +``` + +## 状态事务 + +将更改持久化到状态存储作为[事务操作]({{< ref "state-management-overview.md#transactional-operations" >}})。 + +> 此API依赖于支持事务的状态存储组件。 + +请参阅[状态存储组件规范]({{< ref "supported-state-stores.md" >}})以获取支持事务的状态存储的完整、当前列表。 + +#### HTTP请求 + +``` +POST/PUT http://localhost:/v1.0/state//transaction +``` + +#### HTTP响应代码 + +代码 | 描述 +---- | ----------- +`204` | 请求成功 +`400` | 状态存储缺失或配置错误或请求格式错误 +`500` | 请求失败 + +#### URL参数 + +参数 | 描述 +--------- | ----------- +`daprPort` | Dapr端口 +`storename` | 用户配置的statestore.yaml组件文件中的`metadata.name`字段。请参阅上面提到的[Dapr状态存储配置结构](#component-file)。 + +可选的请求元数据通过URL查询参数传递。例如, +``` +POST http://localhost:3500/v1.0/state/myStore/transaction?metadata.contentType=application/json +``` + +> 注意,所有URL参数区分大小写。 + +#### 请求体 + +字段 | 描述 +---- | ----------- +`operations` | 状态`operation`的JSON数组 +`metadata` | (可选)适用于所有操作的事务`metadata` + +所有事务性数据库实现以下必需操作: + +操作 | 描述 +--------- | ----------- +`upsert` | 添加或更新值 +`delete` | 删除值 + +每个操作都有一个关联的`request`,由以下字段组成: + +请求 | 描述 +---- | ----------- +`key` | 状态键 +`value` | 状态值,可以是任何字节数组 +`etag` | (可选)状态ETag +`metadata` | (可选)要传递给状态存储的附加键值对,适用于此操作 +`options` | (可选)状态操作选项;请参阅[状态操作选项](#optional-behaviors) + +#### 示例 +下面的示例显示了`key1`的`upsert`操作和`key2`的`delete`操作。这适用于状态存储中名为'planet'的分区。两个操作在事务中要么成功要么失败。 + +```shell +curl -X POST http://localhost:3500/v1.0/state/starwars/transaction \ + -H "Content-Type: application/json" \ + -d '{ + "operations": [ + { + "operation": "upsert", + "request": { + "key": "key1", + "value": "myData" + } + }, + { + "operation": "delete", + "request": { + "key": "key2" + } + } + ], + "metadata": { + "partitionKey": "planet" + } + }' +``` + +## 为actor配置状态存储 + +actor不支持多个状态存储,并且需要使用事务性状态存储与Dapr一起使用。[查看当前实现事务性状态存储接口的服务]({{< ref "supported-state-stores.md" >}})。 + +在`statestore.yaml`组件文件的元数据部分中为属性`actorStateStore`指定一个`true`值,以指定用于actor的状态存储。 +例如,以下组件yaml将配置Redis用作actor的状态存储。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: statestore +spec: + type: state.redis + version: v1 + metadata: + - name: redisHost + value: + - name: redisPassword + value: "" + - name: actorStateStore + value: "true" + +``` + +## 可选行为 + +### 键方案 + +一个Dapr兼容的状态存储应使用以下键方案: + +* *\||\* 键格式用于一般状态 +* *\||\||\||\* 键格式用于actor状态。 + +### 并发 + +Dapr使用带有ETags的乐观并发控制(OCC)。Dapr对状态存储提出以下可选要求: + +* 一个Dapr兼容的状态存储可以支持使用ETags的乐观并发控制。存储允许在ETag: + * 与*保存*或*删除*请求相关联时。 + * 匹配数据库中的最新ETag时。 +* 当写请求中缺少ETag时,状态存储应以*最后写入优先*的方式处理请求。这允许对高吞吐量写入场景进行优化,其中数据争用较低或没有负面影响。 +* 存储在返回状态给调用者时应*始终*返回ETags。 + +### 一致性 + +Dapr允许客户端将一致性提示附加到*获取*、*设置*和*删除*操作。Dapr支持两种一致性级别:**强一致性**和**最终一致性**。 + +#### 最终一致性 + +Dapr假定数据存储默认是最终一致的。状态应: + +* 对于*读取*请求,从任何副本返回数据。 +* 对于*写入*请求,在确认更新请求后异步复制更新到配置的法定人数。 + +#### 强一致性 + +当附加了强一致性提示时,状态存储应: + +* 对于*读取*请求,始终返回跨副本一致的最新数据。 +* 对于*写入*/*删除*请求,在完成写入请求之前同步复制更新的数据到配置的法定人数。 + +### 示例:完整选项请求示例 + +以下是一个带有完整`options`定义的*设置*请求示例: + +```shell +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" + } + } + ]' +``` + +### 示例:使用ETags + +以下是一个在兼容状态存储中*设置*/*删除*对象时使用ETag的示例演练。此示例将Redis定义为`statestore`。 + +1. 在状态存储中存储一个对象: + + ```shell + curl -X POST http://localhost:3500/v1.0/state/statestore \ + -H "Content-Type: application/json" \ + -d '[ + { + "key": "sampleData", + "value": "1" + } + ]' + ``` + +1. 获取对象以查找由状态存储自动设置的ETag: + + ```shell + curl http://localhost:3500/v1.0/state/statestore/sampleData -v + * Connected to localhost (127.0.0.1) port 3500 (#0) + > GET /v1.0/state/statestore/sampleData HTTP/1.1 + > Host: localhost:3500 + > User-Agent: curl/7.64.1 + > Accept: */* + > + < HTTP/1.1 200 OK + < Server: fasthttp + < Date: Sun, 14 Feb 2021 04:51:50 GMT + < Content-Type: application/json + < Content-Length: 3 + < Etag: 1 + < Traceparent: 00-3452582897d134dc9793a244025256b1-b58d8d773e4d661d-01 + < + * Connection #0 to host localhost left intact + "1"* Closing connection 0 + ``` + + 上述返回的ETag为1。如果您发送一个新的请求以错误的ETag更新或删除数据,它将返回错误。省略ETag将允许请求。 + + ```shell + # 更新 + curl -X POST http://localhost:3500/v1.0/state/statestore \ + -H "Content-Type: application/json" \ + -d '[ + { + "key": "sampleData", + "value": "2", + "etag": "2" + } + ]' + {"errorCode":"ERR_STATE_SAVE","message":"failed saving state in state store statestore: possible etag mismatch. error from state store: ERR Error running script (call to f_83e03ec05d6a3b6fb48483accf5e594597b6058f): @user_script:1: user_script:1: failed to set key nodeapp||sampleData"} + + # 删除 + curl -X DELETE -H 'If-Match: 5' http://localhost:3500/v1.0/state/statestore/sampleData + {"errorCode":"ERR_STATE_DELETE","message":"failed deleting state with key sampleData: possible etag mismatch. error from state store: ERR Error running script (call to f_9b5da7354cb61e2ca9faff50f6c43b81c73c0b94): @user_script:1: user_script:1: failed to delete node + app||sampleData"} + ``` + +1. 通过简单地在请求体(更新)或`If-Match`头(删除)中匹配ETag来更新或删除对象。当状态更新时,它会接收一个新的ETag,未来的更新或删除将需要使用。 + + ```shell + # 更新 + curl -X POST http://localhost:3500/v1.0/state/statestore \ + -H "Content-Type: application/json" \ + -d '[ + { + "key": "sampleData", + "value": "2", + "etag": "1" + } + ]' + + # 删除 + curl -X DELETE -H 'If-Match: 1' http://localhost:3500/v1.0/state/statestore/sampleData + ``` + +## 下一步 + +- [状态管理概述]({{< ref state-management-overview.md >}}) +- [如何:保存和获取状态]({{< ref howto-get-save-state.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/api/workflow_api.md b/src/translated_content/zh_CN/docs/reference/api/workflow_api.md new file mode 100644 index 000000000..d19381cdf --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/api/workflow_api.md @@ -0,0 +1,272 @@ +--- +type: docs +title: "工作流 API 参考" +linkTitle: "工作流 API" +description: "关于工作流 API 的详细文档" +weight: 300 +--- + +Dapr 提供了与工作流交互的功能,并自带一个内置的 `dapr` 组件。 + +## 启动工作流请求 + +使用指定名称启动一个工作流实例,并可选地指定一个实例 ID。 + +``` +POST http://localhost:3500/v1.0/workflows///start[?instanceID=] +``` + +请注意,工作流实例 ID 只能包含字母、数字、下划线和破折号。 + +### URL 参数 + +参数 | 描述 +--------- | ----------- +`workflowComponentName` | 对于 Dapr 工作流使用 `dapr` +`workflowName` | 标识工作流类型 +`instanceID` | (可选)为特定工作流的每次运行创建的唯一值 + +### 请求内容 + +任何请求内容都将作为输入传递给工作流。Dapr API 会原样传递内容,不会尝试解释。 + +### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +`202` | 已接受 +`400` | 请求格式错误 +`500` | 请求格式正确,但 Dapr 代码或底层组件出错 + +### 响应内容 + +API 调用将返回如下的响应: + +```json +{ + "instanceID": "12345678" +} +``` + +## 终止工作流请求 + +终止具有指定名称和实例 ID 的正在运行的工作流实例。 + +``` +POST http://localhost:3500/v1.0/workflows///terminate +``` + +{{% alert title="注意" color="primary" %}} +终止一个工作流将同时终止该实例创建的所有子工作流。 + +终止一个工作流不会影响由该实例启动的任何正在进行的活动。 +{{% /alert %}} + +### URL 参数 + +参数 | 描述 +--------- | ----------- +`workflowComponentName` | 对于 Dapr 工作流使用 `dapr` +`instanceId` | 为特定工作流的每次运行创建的唯一值 + +### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +`202` | 已接受 +`400` | 请求格式错误 +`500` | 请求格式正确,但 Dapr 代码或底层组件出错 + +### 响应内容 + +此 API 不返回任何内容。 + +## 触发事件请求 + +对于支持订阅外部事件的工作流组件,例如 Dapr 工作流引擎,可以使用以下“触发事件”API 将命名事件传递给特定的工作流实例。 + +``` +POST http://localhost:3500/v1.0/workflows///raiseEvent/ +``` + +{{% alert title="注意" color="primary" %}} +订阅事件的具体机制取决于您使用的工作流组件。Dapr 工作流有一种订阅外部事件的方式,但其他工作流组件可能有不同的方式。 +{{% /alert %}} + +### URL 参数 + +参数 | 描述 +--------- | ----------- +`workflowComponentName` | 对于 Dapr 工作流使用 `dapr` +`instanceId` | 为特定工作流的每次运行创建的唯一值 +`eventName` | 要触发的事件名称 + +### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +`202` | 已接受 +`400` | 请求格式错误 +`500` | 请求格式正确,但 Dapr 代码或底层组件出错 + +### 响应内容 + +无。 + +## 暂停工作流请求 + +暂停一个正在运行的工作流实例。 + +``` +POST http://localhost:3500/v1.0/workflows///pause +``` + +### URL 参数 + +参数 | 描述 +--------- | ----------- +`workflowComponentName` | 对于 Dapr 工作流使用 `dapr` +`instanceId` | 为特定工作流的每次运行创建的唯一值 + +### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +`202` | 已接受 +`400` | 请求格式错误 +`500` | Dapr 代码或底层组件出错 + +### 响应内容 + +无。 + +## 恢复工作流请求 + +恢复一个已暂停的工作流实例。 + +``` +POST http://localhost:3500/v1.0/workflows///resume +``` + +### URL 参数 + +参数 | 描述 +--------- | ----------- +`workflowComponentName` | 对于 Dapr 工作流使用 `dapr` +`instanceId` | 为特定工作流的每次运行创建的唯一值 + +### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +`202` | 已接受 +`400` | 请求格式错误 +`500` | Dapr 代码或底层组件出错 + +### 响应内容 + +无。 + +## 清除工作流请求 + +使用工作流的实例 ID 从您的状态存储中清除工作流状态。 + +``` +POST http://localhost:3500/v1.0/workflows///purge +``` + +{{% alert title="注意" color="primary" %}} +只有状态为 `COMPLETED`、`FAILED` 或 `TERMINATED` 的工作流可以被清除。 +{{% /alert %}} + +### URL 参数 + +参数 | 描述 +--------- | ----------- +`workflowComponentName` | 对于 Dapr 工作流使用 `dapr` +`instanceId` | 为特定工作流的每次运行创建的唯一值 + +### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +`202` | 已接受 +`400` | 请求格式错误 +`500` | Dapr 代码或底层组件出错 + +### 响应内容 + +无。 + +## 获取工作流请求 + +获取给定工作流实例的信息。 + +``` +GET http://localhost:3500/v1.0/workflows// +``` + +### URL 参数 + +参数 | 描述 +--------- | ----------- +`workflowComponentName` | 对于 Dapr 工作流使用 `dapr` +`instanceId` | 为特定工作流的每次运行创建的唯一值 + +### HTTP 响应代码 + +代码 | 描述 +---- | ----------- +`200` | 正常 +`400` | 请求格式错误 +`500` | 请求格式正确,但 Dapr 代码或底层组件出错 + +### 响应内容 + +API 调用将返回如下的 JSON 响应: + +```json +{ +  "createdAt": "2023-01-12T21:31:13Z", +  "instanceID": "12345678", + "lastUpdatedAt": "2023-01-12T21:31:13Z", +  "properties": { + "property1": "value1", + "property2": "value2", + }, + "runtimeStatus": "RUNNING", + } +``` + +参数 | 描述 +--------- | ----------- +`runtimeStatus` | 工作流实例的状态。值包括:`"RUNNING"`、`"COMPLETED"`、`"CONTINUED_AS_NEW"`、`"FAILED"`、`"CANCELED"`、`"TERMINATED"`、`"PENDING"`、`"SUSPENDED"` + +## 组件格式 + +一个 Dapr `workflow.yaml` 组件文件具有以下结构: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: workflow. + version: v1.0-alpha1 + metadata: + - name: + value: + ``` + +| 设置 | 描述 | +| ------- | ----------- | +| `metadata.name` | 工作流组件的名称。 | +| `spec/metadata` | 由工作流组件指定的附加元数据参数 | + +然而,Dapr 附带一个内置的基于 Dapr actor 的 `dapr` 工作流组件。使用内置的 Dapr 工作流组件不需要组件文件。 + +## 下一步 + +- [工作流 API 概述]({{< ref workflow-overview.md >}}) +- [将用户路由到工作流模式]({{< ref workflow-patterns.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/arguments-annotations-overview.md b/src/translated_content/zh_CN/docs/reference/arguments-annotations-overview.md new file mode 100644 index 000000000..ac88edcee --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/arguments-annotations-overview.md @@ -0,0 +1,76 @@ +--- +type: docs +title: "Dapr 参数和注解用于 daprd、CLI 和 Kubernetes" +linkTitle: "参数和注解" +description: "在不同环境中配置 Dapr 时可用的参数和注解" +weight: 300 +aliases: + - "/zh-hans/operations/hosting/kubernetes/kubernetes-annotations/" +--- + +此表旨在帮助用户了解在不同环境中运行 Dapr sidecar 的对应选项:通过 [CLI]({{< ref cli-overview.md >}}) 直接运行,通过 daprd,或在 [Kubernetes]({{< ref kubernetes-overview.md >}}) 上通过注解运行。 + +| daprd | Dapr CLI | CLI 简写 | Kubernetes 注解 | 描述 | +|----- | ------- | -----------| ----------| ------------ | +| `--allowed-origins` | 不支持 | | 不支持 | 允许的 HTTP 来源(默认 "*") | +| `--app-id` | `--app-id` | `-i` | `dapr.io/app-id` | 应用程序的唯一 ID。用于服务发现、状态封装和 pub/sub 消费者 ID | +| `--app-port` | `--app-port` | `-p` | `dapr.io/app-port` | 指定应用程序监听的端口 | +| `--components-path` | `--components-path` | `-d` | 不支持 | **已弃用**,建议使用 `--resources-path` | +| `--resources-path` | `--resources-path` | `-d` | 不支持 | 组件目录的路径。如果为空,则不会加载组件 | +| `--config` | `--config` | `-c` | `dapr.io/config` | 指定 Dapr 使用的配置资源 | +| `--control-plane-address` | 不支持 | | 不支持 | Dapr 控制平面的地址 | +| `--dapr-grpc-port` | `--dapr-grpc-port` | | `dapr.io/grpc-port` | 设置 Dapr API gRPC 端口(默认 `50001`);所有集群服务必须使用相同的端口进行通信 | +| `--dapr-http-port` | `--dapr-http-port` | | 不支持 | Dapr API 监听的 HTTP 端口(默认 `3500`) | +| `--dapr-http-max-request-size` | `--dapr-http-max-request-size` | | `dapr.io/http-max-request-size` | **已弃用**,建议使用 `--max-body-size`。增加请求最大主体大小以处理使用 http 和 grpc 协议的大文件上传。默认是 `4` MB | +| `--max-body-size` | 不支持 | | `dapr.io/max-body-size` | 增加请求最大主体大小以处理使用 http 和 grpc 协议的大文件上传。使用大小单位设置值(例如,`16Mi` 表示 16MB)。默认是 `4Mi` | +| `--dapr-http-read-buffer-size` | `--dapr-http-read-buffer-size` | | `dapr.io/http-read-buffer-size` | **已弃用**,建议使用 `--read-buffer-size`。增加 http 头读取缓冲区的最大大小(以 KB 为单位)以支持更大的头值,例如 `16` 支持最大 16KB 的头。默认是 `16` 表示 16KB | +| `--read-buffer-size` | 不支持 | | `dapr.io/read-buffer-size` | 增加 http 头读取缓冲区的最大大小(以 KB 为单位)以支持更大的头值。使用大小单位设置值,例如 `32Ki` 将支持最大 32KB 的头。默认是 `4` 表示 4KB | +| 不支持 | `--image` | | `dapr.io/sidecar-image` | Dapr sidecar 镜像。默认是 daprio/daprd:latest。Dapr sidecar 使用此镜像而不是最新的默认镜像。当构建您自己的 Dapr 自定义镜像或[使用替代的稳定 Dapr 镜像]({{< ref "support-release-policy.md#build-variations" >}})时使用此选项 | +| `--internal-grpc-port` | 不支持 | | `dapr.io/internal-grpc-port` | 设置内部 Dapr gRPC 端口(默认 `50002`);所有集群服务必须使用相同的端口进行通信 | +| `--enable-metrics` | 不支持 | | 配置规范 | 启用 [prometheus 指标]({{< ref prometheus >}})(默认 true) | +| `--enable-mtls` | 不支持 | | 配置规范 | 启用 daprd 到 daprd 通信通道的自动 mTLS | +| `--enable-profiling` | `--enable-profiling` | | `dapr.io/enable-profiling` | [启用分析]({{< ref profiling-debugging >}}) | +| `--unix-domain-socket` | `--unix-domain-socket` | `-u` | `dapr.io/unix-domain-socket-path` | 套接字文件的父目录。在 Linux 上,与 Dapr sidecar 通信时,使用 unix 域套接字以获得比 TCP 端口更低的延迟和更高的吞吐量。在 Windows 操作系统上不可用。 | +| `--log-as-json` | 不支持 | | `dapr.io/log-as-json` | 将此参数设置为 `true` 输出[JSON 格式的日志]({{< ref logs >}})。默认是 `false` | +| `--log-level` | `--log-level` | | `dapr.io/log-level` | 设置 Dapr sidecar 的[日志级别]({{< ref logs-troubleshooting >}})。允许的值是 `debug`、`info`、`warn`、`error`。默认是 `info` | +| `--enable-api-logging` | `--enable-api-logging` | | `dapr.io/enable-api-logging` | 为 Dapr sidecar [启用 API 日志记录]({{< ref "api-logs-troubleshooting.md#configuring-api-logging-in-kubernetes" >}}) | +| `--app-max-concurrency` | `--app-max-concurrency` | | `dapr.io/app-max-concurrency` | 限制[应用程序的并发性]({{< ref "control-concurrency.md#setting-app-max-concurrency" >}})。有效值是大于 `0` 的任何数字。默认值:`-1`,表示无并发。 | +| `--metrics-port` | `--metrics-port` | | `dapr.io/metrics-port` | 设置 sidecar 指标服务器的端口。默认是 `9090` | +| `--mode` | 不支持 | | 不支持 | Dapr 的运行时托管选项模式,可以是 `"standalone"` 或 `"kubernetes"`(默认 `"standalone"`)。[了解更多。]({{< ref hosting >}}) | +| `--placement-host-address` | `--placement-host-address` | | `dapr.io/placement-host-address` | Dapr actor 放置服务器的地址列表,以逗号分隔。

当未设置注解时,默认值由 Sidecar Injector 设置。

当注解设置且值为单个空格(`' '`)或 "empty" 时,sidecar 不连接到放置服务器。这可以在 sidecar 中没有运行 actor 时使用。

当注解设置且值不为空时,sidecar 连接到配置的地址。例如:`127.0.0.1:50057,127.0.0.1:50058` | +| `--scheduler-host-address` | `--scheduler-host-address` | | `dapr.io/scheduler-host-address` | Dapr 调度服务器的地址列表,以逗号分隔。

当未设置注解时,默认值由 Sidecar Injector 设置。

当注解设置且值为单个空格(`' '`)或 "empty" 时,sidecar 不连接到调度服务器。

当注解设置且值不为空时,sidecar 连接到配置的地址。例如:`127.0.0.1:50055,127.0.0.1:50056` | +| `--actors-service` | 不支持 | | 不支持 | 提供 actor 放置信息的服务的配置。格式为 `:
`。例如,将此值设置为 `placement:127.0.0.1:50057,127.0.0.1:50058` 是使用 `--placement-host-address` 标志的替代方法。 | +| `--reminders-service` | 不支持 | | 不支持 | 启用 actor 提醒的服务的配置。格式为 `[:
]`。目前,唯一支持的值是 `"default"`(这也是默认值),它使用 Dapr sidecar 中的内置提醒子系统。 | +| `--profiling-port` | `--profiling-port` | | 不支持 | 配置文件服务器的端口(默认 `7777`) | +| `--app-protocol` | `--app-protocol` | `-P` | `dapr.io/app-protocol` | 配置 Dapr 用于与您的应用程序通信的协议。有效选项是 `http`、`grpc`、`https`(带 TLS 的 HTTP)、`grpcs`(带 TLS 的 gRPC)、`h2c`(HTTP/2 明文)。请注意,Dapr 不验证应用程序提供的 TLS 证书。默认是 `http` | +| `--enable-app-health-check` | `--enable-app-health-check` | | `dapr.io/enable-app-health-check` | 启用[健康检查]({{< ref "app-health.md#configuring-app-health-checks" >}})的布尔值。默认是 `false`。 | +| `--app-health-check-path` | `--app-health-check-path` | | `dapr.io/app-health-check-path` | 当应用程序通道为 HTTP 时,Dapr 调用的健康探测路径(如果应用程序通道使用 gRPC,则忽略此值)。需要[启用应用程序健康检查]({{< ref "app-health.md#configuring-app-health-checks" >}})。默认是 `/healthz`。 | +| `--app-health-probe-interval` | `--app-health-probe-interval` | | `dapr.io/app-health-probe-interval` | 每次健康探测之间的*秒数*。需要[启用应用程序健康检查]({{< ref "app-health.md#configuring-app-health-checks" >}})。默认是 `5` | +| `--app-health-probe-timeout` | `--app-health-probe-timeout` | | `dapr.io/app-health-probe-timeout` | 健康探测请求的超时时间(以*毫秒*为单位)。需要[启用应用程序健康检查]({{< ref "app-health.md#configuring-app-health-checks" >}})。默认是 `500` | +| `--app-health-threshold` | `--app-health-threshold` | | `dapr.io/app-health-threshold"` | 在应用程序被认为不健康之前的最大连续失败次数。需要[启用应用程序健康检查]({{< ref "app-health.md#configuring-app-health-checks" >}})。默认是 `3` | +| `--sentry-address` | `--sentry-address` | | 不支持 | [Sentry CA 服务]({{< ref sentry >}})的地址 | +| `--version` | `--version` | `-v` | 不支持 | 打印运行时版本 | +| `--dapr-graceful-shutdown-seconds` | 不支持 | | `dapr.io/graceful-shutdown-seconds` | Dapr 的优雅关闭持续时间(以秒为单位),在等待所有进行中的请求完成时的最大持续时间,然后强制关闭。默认是 `5`。如果您在 Kubernetes 模式下运行,此值不应大于 Kubernetes 终止宽限期,其默认值为 `30`。| +| `--dapr-block-shutdown-duration` | 不支持 | | `dapr.io/block-shutdown-duration` | 阻止关闭的持续时间。如果设置了此参数,优雅关闭过程(如上所述)将被延迟,直到给定的持续时间已过或应用程序变得不健康(通过应用程序健康选项配置)。这对于需要在其自身终止过程中执行 Dapr API 的应用程序很有用。一旦阻止过期,应用程序将无法再调用任何 Dapr API。接受 [Go 持续时间](https://pkg.go.dev/time#ParseDuration) 字符串。 | +| 不支持 | 不支持 | | `dapr.io/enabled` | 将此参数设置为 true 将 Dapr sidecar 注入到 pod 中 | +| 不支持 | 不支持 | | `dapr.io/api-token-secret` | 指定 Dapr 使用哪个 Kubernetes secret 进行[基于令牌的 API 认证]({{< ref api-token >}})。默认情况下未设置 | +| 不支持 | 不支持 | | `dapr.io/app-token-secret` | 指定 Dapr 使用哪个 Kubernetes secret 进行[基于令牌的应用程序认证]({{< ref app-api-token >}})。默认情况下未设置 | +| `--dapr-listen-addresses` | 不支持 | | `dapr.io/sidecar-listen-addresses` | sidecar 将监听的 IP 地址列表,以逗号分隔。在 standalone 模式下默认为所有。在 Kubernetes 中默认为 `[::1],127.0.0.1`。要监听所有 IPv4 地址,请使用 `0.0.0.0`。要监听所有 IPv6 地址,请使用 `[::]`。| +| 不支持 | 不支持 | | `dapr.io/sidecar-cpu-limit` | Dapr sidecar 可以使用的最大 CPU 量。查看有效值[这里](https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/quota-memory-cpu-namespace/)。默认情况下未设置| +| 不支持 | 不支持 | | `dapr.io/sidecar-memory-limit` | Dapr sidecar 可以使用的最大内存量。查看有效值[这里](https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/quota-memory-cpu-namespace/)。默认情况下未设置| +| 不支持 | 不支持 | | `dapr.io/sidecar-cpu-request` | Dapr sidecar 请求的 CPU 量。查看有效值[这里](https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/quota-memory-cpu-namespace/)。默认情况下未设置| +| 不支持 | 不支持 | | `dapr.io/sidecar-memory-request` | Dapr sidecar 请求的内存量。查看有效值[这里](https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/quota-memory-cpu-namespace/)。默认情况下未设置| +| 不支持 | 不支持 | | `dapr.io/sidecar-liveness-probe-delay-seconds` | sidecar 容器启动后启动活跃性探测之前的秒数。阅读更多[这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。默认是 `3`| +| 不支持 | 不支持 | | `dapr.io/sidecar-liveness-probe-timeout-seconds` | sidecar 活跃性探测超时后的秒数。阅读更多[这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。默认是 `3`| +| 不支持 | 不支持 | | `dapr.io/sidecar-liveness-probe-period-seconds` | 执行 sidecar 活跃性探测的频率(以秒为单位)。阅读更多[这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。默认是 `6`| +| 不支持 | 不支持 | | `dapr.io/sidecar-liveness-probe-threshold` | 当 sidecar 活跃性探测失败时,Kubernetes 将尝试 N 次后放弃。在这种情况下,Pod 将被标记为不健康。阅读更多关于 `failureThreshold` 的信息[这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。默认是 `3`| +| 不支持 | 不支持 | | `dapr.io/sidecar-readiness-probe-delay-seconds` | sidecar 容器启动后启动就绪探测之前的秒数。阅读更多[这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。默认是 `3`| +| 不支持 | 不支持 | | `dapr.io/sidecar-readiness-probe-timeout-seconds` | sidecar 就绪探测超时后的秒数。阅读更多[这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。默认是 `3`| +| 不支持 | 不支持 | | `dapr.io/sidecar-readiness-probe-period-seconds` | 执行 sidecar 就绪探测的频率(以秒为单位)。阅读更多[这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。默认是 `6`| +| 不支持 | 不支持 | | `dapr.io/sidecar-readiness-probe-threshold` | 当 sidecar 就绪探测失败时,Kubernetes 将尝试 N 次后放弃。在这种情况下,Pod 将被标记为未就绪。阅读更多关于 `failureThreshold` 的信息[这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。默认是 `3`| +| 不支持 | 不支持 | | `dapr.io/env` | 要注入到 sidecar 中的环境变量列表。由以逗号分隔的键=值对组成的字符串。| +| 不支持 | 不支持 | | `dapr.io/env-from-secret` | 从 secret 注入到 sidecar 中的环境变量列表。由 `"key=secret-name:secret-key"` 对组成的字符串以逗号分隔。 | +| 不支持 | 不支持 | | `dapr.io/volume-mounts` | 以只读模式挂载到 sidecar 容器的 [pod 卷列表]({{< ref "kubernetes-volume-mounts" >}})。由 `volume:path` 对组成的字符串以逗号分隔。例如,`"volume-1:/tmp/mount1,volume-2:/home/root/mount2"`。 | +| 不支持 | 不支持 | | `dapr.io/volume-mounts-rw` | 以读写模式挂载到 sidecar 容器的 [pod 卷列表]({{< ref "kubernetes-volume-mounts" >}})。由 `volume:path` 对组成的字符串以逗号分隔。例如,`"volume-1:/tmp/mount1,volume-2:/home/root/mount2"`。 | +| `--disable-builtin-k8s-secret-store` | 不支持 | | `dapr.io/disable-builtin-k8s-secret-store` | 禁用内置 Kubernetes secret 存储。默认值为 false。有关详细信息,请参阅 [Kubernetes secret 存储组件]({{< ref "kubernetes-secret-store.md" >}})。 | +| 不支持 | 不支持 | | `dapr.io/sidecar-seccomp-profile-type` | 将 sidecar 容器的 `securityContext.seccompProfile.type` 设置为 `Unconfined`、`RuntimeDefault` 或 `Localhost`。默认情况下,此注解未在 Dapr sidecar 上设置,因此该字段从 sidecar 容器中省略。 | diff --git a/src/translated_content/zh_CN/docs/reference/cli/_index.md b/src/translated_content/zh_CN/docs/reference/cli/_index.md new file mode 100644 index 000000000..da0bf0539 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "Dapr CLI 参考文档" +linkTitle: "Dapr CLI" +description: "Dapr CLI 命令的详细介绍" +weight: 200 +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/cli-overview.md b/src/translated_content/zh_CN/docs/reference/cli/cli-overview.md new file mode 100644 index 000000000..9cf8ff71f --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/cli-overview.md @@ -0,0 +1,81 @@ +--- +type: docs +title: "Dapr 命令行界面 (CLI) 参考" +linkTitle: "概述" +description: "关于 Dapr CLI 的详细信息" +weight: 10 +--- + +Dapr CLI 使您能够在本地开发环境或 Kubernetes 集群上配置 Dapr,提供调试支持,并启动和管理 Dapr 实例。 + +```bash + + __ + ____/ /___ _____ _____ + / __ / __ '/ __ \/ ___/ + / /_/ / /_/ / /_/ / / + \__,_/\__,_/ .___/_/ + /_/ + +=============================== +分布式应用运行时 + +用法: + dapr [命令] + +可用命令: + annotate 为 Kubernetes 配置添加 Dapr 注释。适用平台:Kubernetes + build-info 显示 Dapr CLI 和运行时的构建信息 + completion 生成 shell 自动补全脚本 + components 列出所有 Dapr 组件。适用平台:Kubernetes + configurations 列出所有 Dapr 配置。适用平台:Kubernetes + dashboard 启动 Dapr 仪表板。适用平台:Kubernetes 和 本地托管 + help 获取任何命令的帮助信息 + init 在支持的平台上安装 Dapr。适用平台:Kubernetes 和 本地托管 + invoke 调用指定 Dapr 应用程序上的方法。适用平台:本地托管 + list 列出所有 Dapr 实例。适用平台:Kubernetes 和 本地托管 + logs 获取应用程序的 Dapr sidecar 日志。适用平台:Kubernetes + mtls 检查 mTLS 是否已启用。适用平台:Kubernetes + publish 发布一个 pubsub 事件。适用平台:本地托管 + run 运行 Dapr 并可选择与您的应用程序一起运行。适用平台:本地托管 + status 显示 Dapr 服务的健康状态。适用平台:Kubernetes + stop 停止 Dapr 实例及其关联的应用程序。适用平台:本地托管 + uninstall 卸载 Dapr 运行时。适用平台:Kubernetes 和 本地托管 + upgrade 升级集群中的 Dapr 控制平面安装。适用平台:Kubernetes + version 显示 Dapr 运行时和 CLI 的版本信息 + +标志: + -h, --help 获取 dapr 的帮助信息 + --log-as-json 以 JSON 格式记录输出 + -v, --version 获取 dapr 的版本信息 + +使用 "dapr [command] --help" 获取有关命令的更多信息。 +``` + +### 命令参考 + +您可以通过以下链接了解每个 Dapr 命令的详细信息。 + + - [`dapr annotate`]({{< ref dapr-annotate.md >}}) + - [`dapr build-info`]({{< ref dapr-build-info.md >}}) + - [`dapr completion`]({{< ref dapr-completion.md >}}) + - [`dapr components`]({{< ref dapr-components.md >}}) + - [`dapr configurations`]({{< ref dapr-configurations.md >}}) + - [`dapr dashboard`]({{< ref dapr-dashboard.md >}}) + - [`dapr help`]({{< ref dapr-help.md >}}) + - [`dapr init`]({{< ref dapr-init.md >}}) + - [`dapr invoke`]({{< ref dapr-invoke.md >}}) + - [`dapr list`]({{< ref dapr-list.md >}}) + - [`dapr logs`]({{< ref dapr-logs.md >}}) + - [`dapr mtls`]({{< ref dapr-mtls >}}) + - [`dapr publish`]({{< ref dapr-publish.md >}}) + - [`dapr run`]({{< ref dapr-run.md >}}) + - [`dapr status`]({{< ref dapr-status.md >}}) + - [`dapr stop`]({{< ref dapr-stop.md >}}) + - [`dapr uninstall`]({{< ref dapr-uninstall.md >}}) + - [`dapr upgrade`]({{< ref dapr-upgrade.md >}}) + - [`dapr version`]({{< ref dapr-version.md >}}) + +### 环境变量 + +一些 Dapr 标志可以通过环境变量进行设置(例如,`dapr init` 命令的 `--network` 标志可以通过 `DAPR_NETWORK` 环境变量设置)。请注意,在命令行中指定的标志会覆盖任何已设置的环境变量。 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-annotate.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-annotate.md new file mode 100644 index 000000000..57b949729 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-annotate.md @@ -0,0 +1,84 @@ +--- +type: docs +title: "annotate CLI 命令参考" +linkTitle: "annotate" +description: "在 Kubernetes 配置中添加 Dapr 注解" +--- + +### 描述 + +在 Kubernetes 配置中添加 Dapr 注解。这允许您在部署文件中添加或更改 Dapr 注解。有关每个可用注解的详细说明,请参见 [Kubernetes 注解]({{< ref arguments-annotations-overview >}})。 + +### 支持的平台 + +- [Kubernetes]({{< ref kubernetes >}}) + +### 用法 + +```bash +dapr annotate [flags] CONFIG-FILE +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 +| --- | --- | --- | --- | +| `--kubernetes, -k` | | | 将注解应用于 Kubernetes 资源。必需 | +| `--api-token-secret` | | | 用于 API token 的 secret | +| `--app-id, -a` | | | 要注解的应用 ID | +| `--app-max-concurrency` | | `-1` | 允许的最大并发请求数 | +| `--app-port, -p` | | `-1` | 用于暴露应用的端口 | +| `--app-protocol` | | | 应用使用的协议:`http`(默认),`grpc`,`https`,`grpcs`,`h2c` | +| `--app-token-secret` | | | 用于应用 token 的 secret | +| `--config, -c` | | | 要注解的配置文件 | +| `--cpu-limit` | | | 为 sidecar 设置的 CPU 限制。查看有效值 [这里](https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/quota-memory-cpu-namespace/)。 | +| `--cpu-request` | | | 为 sidecar 设置的 CPU 请求。查看有效值 [这里](https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/quota-memory-cpu-namespace/)。 | +| `--dapr-image` | | | 用于 dapr sidecar 容器的镜像 | +| `--enable-debug` | | `false` | 启用调试 | +| `--enable-metrics` | | `false` | 启用指标 | +| `--enable-profile` | | `false` | 启用分析 | +| `--env` | | | 要设置的环境变量(键值对,逗号分隔) | +| `--graceful-shutdown-seconds` | | `-1` | 等待应用关闭的秒数 | +| `--help, -h` | | | annotate 的帮助信息 | +| `--listen-addresses` | | | sidecar 监听的地址。要监听所有 IPv4 地址,请使用 `0.0.0.0`。要监听所有 IPv6 地址,请使用 `[::]`。 | +| `--liveness-probe-delay` | | `-1` | sidecar 用于存活探测的延迟。阅读更多 [这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。 | +| `--liveness-probe-period` | | `-1` | sidecar 用于存活探测的周期。阅读更多 [这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。 | +| `--liveness-probe-threshold` | | `-1` | sidecar 用于存活探测的阈值。阅读更多 [这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。 | +| `--liveness-probe-timeout` | | `-1` | sidecar 用于存活探测的超时。阅读更多 [这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。 | +| `--log-level` | | | 使用的日志级别 | +| `--max-request-body-size` | | `-1` | 使用的最大请求体大小 | +| `--http-read-buffer-size` | | `-1` | HTTP 头读取缓冲区的最大大小(以千字节为单位) | +| `--memory-limit` | | | 为 sidecar 设置的内存限制。查看有效值 [这里](https://kubernetes.io/docs/tasks/administer-cluster/manage-resources/quota-memory-cpu-namespace/) | +| `--memory-request`| | | 为 sidecar 设置的内存请求 | +| `--metrics-port` | | `-1` | 用于暴露指标的端口 | +| `--namespace, -n` | | | 资源目标所在的命名空间(仅在设置 `--resource` 时可用) | +| `--readiness-probe-delay` | | `-1` | sidecar 用于就绪探测的延迟。阅读更多 [这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。| +| `--readiness-probe-period` | | `-1` | sidecar 用于就绪探测的周期。阅读更多 [这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。 | +| `--readiness-probe-threshold` | | `-1` | sidecar 用于就绪探测的阈值。阅读更多 [这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。 | +| `--readiness-probe-timeout` | | `-1` | sidecar 用于就绪探测的超时。阅读更多 [这里](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes)。 | +| `--resource, -r` | | | 要注解的 Kubernetes 资源目标 | +| `--enable-api-logging` | | | 为 Dapr sidecar 启用 API 日志记录 | +| `--unix-domain-socket-path` | | | 用于与 Dapr sidecar 通信的 Linux 域套接字路径 | +| `--volume-mounts` | | | 要以只读模式挂载到 sidecar 容器的 pod 卷列表 | +| `--volume-mounts-rw` | | | 要以读写模式挂载到 sidecar 容器的 pod 卷列表 | +| `--disable-builtin-k8s-secret-store` | | | 禁用内置的 Kubernetes secret 存储 | +| `--placement-host-address` | | | Dapr actor 放置服务器的地址列表(逗号分隔) | + +{{% alert title="警告" color="warning" %}} +如果未使用 `--app-id, -a` 提供应用 ID,将自动生成一个格式为 `--` 的 ID。 +{{% /alert %}} + +### 示例 + +```bash +# 注解输入中找到的第一个部署 +kubectl get deploy -l app=node -o yaml | dapr annotate -k - | kubectl apply -f - + +# 按名称在链中注解多个部署 +kubectl get deploy -o yaml | dapr annotate -k -r nodeapp - | dapr annotate -k -r pythonapp - | kubectl apply -f - + +# 从文件或目录中按名称注解特定命名空间中的部署 +dapr annotate -k -r nodeapp -n namespace mydeploy.yaml | kubectl apply -f - + +# 从 URL 按名称注解部署 +dapr annotate -k -r nodeapp --log-level debug https://raw.githubusercontent.com/dapr/quickstarts/master/tutorials/hello-kubernetes/deploy/node.yaml | kubectl apply -f - diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-build-info.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-build-info.md new file mode 100644 index 000000000..0357c1197 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-build-info.md @@ -0,0 +1,24 @@ +--- +type: docs +title: "build-info CLI 命令指南" +linkTitle: "build-info" +description: "关于 dapr CLI 和 daprd 可执行文件的详细构建信息" +--- + +### 描述 + +获取 `dapr` 和 `daprd` 可执行文件的版本和 Git 提交信息。 + +### 支持的平台 + +- [本地托管]({{< ref self-hosted >}}) + +### 用法 + +```bash +dapr build-info +``` + +### 相关信息 + +您可以通过运行 `daprd --build-info` 命令直接获取 `daprd` 的构建信息。 diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-completion.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-completion.md new file mode 100644 index 000000000..4c9021a37 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-completion.md @@ -0,0 +1,116 @@ +--- +type: docs +title: "completion CLI 命令参考" +linkTitle: "completion" +description: "关于 completion CLI 命令的详细信息" +--- + +### 描述 + +生成用于 shell 的自动补全脚本 + +### 用法 + +```bash +dapr completion [flags] +dapr completion [command] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| -------------- | -------- | ------- | ------------------------ | +| `--help`, `-h` | | | 显示此帮助信息 | + +### 示例 + +#### 在 macOS 上使用 Homebrew 安装 bash 自动补全 + +如果你使用的是 macOS 自带的 Bash 3.2: + +```bash +brew install bash-completion +``` + +或者,如果你使用的是 Bash 4.1+: + +```bash +brew install bash-completion@2 +``` + +将补全脚本添加到你的补全目录中: + +```bash +dapr completion bash > $(brew --prefix)/etc/bash_completion.d/dapr +source ~/.bash_profile +``` + +#### 在 Linux 上安装 bash 自动补全 + +如果 Linux 上未安装 bash-completion,请通过发行版的包管理器安装 bash-completion 包。 + +将 dapr 的 bash 补全代码加载到当前 shell: + +```bash +source <(dapr completion bash) +``` + +将 bash 补全代码写入文件,并从 .bash_profile 中加载: + +```bash +dapr completion bash > ~/.dapr/completion.bash.inc +printf "source '$HOME/.dapr/completion.bash.inc'" >> $HOME/.bash_profile +source $HOME/.bash_profile +``` + +#### 在 macOS 上使用 Homebrew 安装 zsh 自动补全 + +如果 macOS 上未安装 zsh-completion,请安装 'zsh-completion' 包: + +```bash +brew install zsh-completions +``` + +设置 dapr 的 zsh 补全代码在 zsh 启动时自动加载: +```bash +dapr completion zsh > "${fpath[1]}/_dapr" +source ~/.zshrc +``` + +#### 在 Linux 上安装 zsh 自动补全 + +如果 Linux 上未安装 zsh-completion,请通过发行版的包管理器安装 'zsh-completion' 包。 + +将 dapr 的 zsh 补全代码加载到当前 shell: + +```bash +source <(dapr completion zsh) +``` + +设置 dapr 的 zsh 补全代码在 zsh 启动时自动加载: + +```bash +dapr completion zsh > "${fpath[1]}/_dapr" +``` + +#### 在 Windows 上安装 Powershell 自动补全 + +如果 $PROFILE 不存在,请创建: + +```bash +if (!(Test-Path -Path $PROFILE )){ New-Item -Type File -Path $PROFILE -Force } +``` + +将补全脚本添加到你的配置文件中: + +```bash +dapr completion powershell >> $PROFILE +``` + +### 可用命令 + +```txt +bash 生成 bash 自动补全脚本 +powershell 生成 powershell 自动补全脚本 +zsh 生成 zsh 自动补全脚本 +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-components.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-components.md new file mode 100644 index 000000000..ebf78b011 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-components.md @@ -0,0 +1,58 @@ +--- +type: docs +title: "components CLI 命令指南" +linkTitle: "components" +description: "components CLI 命令的详细说明" +--- + +### 描述 + +列出所有 Dapr 组件。 + +### 支持的平台 + +- [Kubernetes]({{< ref kubernetes >}}) + +### 用法 + +```bash +dapr components [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 +| --- | --- | --- | --- | +| `--kubernetes`, `-k` | | `false` | 在 Kubernetes 集群中列出所有 Dapr 组件(此模式下必需) | +| `--all-namespaces`, `-A` | | `true` | 若为 true,列出所有命名空间的 Dapr 组件 | +| `--help`, `-h` | | | 显示帮助信息 | +| `--name`, `-n` | | | 指定要显示的组件名称(可选) | +| `--namespace` | | | 列出指定命名空间中的所有组件 | +| `--output`, `-o` | | `list` | 输出格式(选项:json、yaml 或 list) | + +### 示例 + +```bash +# 列出 Kubernetes 模式下所有命名空间的 Dapr 组件 +dapr components -k + +# 列出 Kubernetes 模式下特定命名空间的 Dapr 组件 +dapr components -k --namespace default + +# 显示 Kubernetes 模式下特定的 Dapr 组件 +dapr components -k -n mycomponent + +# 列出 Kubernetes 模式下所有命名空间的 Dapr 组件 +dapr components -k --all-namespaces +``` + +### 警告信息 +此命令可能会显示警告信息。 + +#### 根证书更新警告 +如果部署到 Kubernetes 集群的 mtls 根证书在 30 天内过期,将显示以下警告信息: + +``` +您的 Kubernetes 集群的 Dapr 根证书将在 天后过期。到期日期: UTC。 +请参阅 docs.dapr.io 获取证书更新说明,以避免服务中断。 +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-configurations.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-configurations.md new file mode 100644 index 000000000..4b6202228 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-configurations.md @@ -0,0 +1,58 @@ +--- +type: docs +title: "配置 CLI 命令参考" +linkTitle: "配置" +description: "关于配置 CLI 命令的详细信息" +--- + +### 描述 + +显示所有的 Dapr 配置项。 + +### 支持的平台 + +- [Kubernetes]({{< ref kubernetes >}}) + +### 用法 + +```bash +dapr configurations [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 +| --- | --- | --- | --- | +| `--kubernetes`, `-k` | | `false` | 列出 Kubernetes 集群中的所有 Dapr 配置(必选项)。 +| `--all-namespaces`, `-A` | | `true` | 若选择此项,则列出所有命名空间中的所有 Dapr 配置(可选)。 +| `--namespace` | | | 列出特定命名空间中的 Dapr 配置。 +| `--name`, `-n` | | | 打印特定的 Dapr 配置。(可选) +| `--output`, `-o` | | `list`| 输出格式(选项:json 或 yaml 或 list) +| `--help`, `-h` | | | 打印此帮助信息 | + +### 示例 + +```bash +# 在 Kubernetes 模式下列出所有命名空间中的 Dapr 配置 +dapr configurations -k + +# 在 Kubernetes 模式下列出特定命名空间中的 Dapr 配置 +dapr configurations -k --namespace default + +# 在 Kubernetes 模式下打印特定的 Dapr 配置 +dapr configurations -k -n appconfig + +# 在 Kubernetes 模式下列出所有命名空间中的 Dapr 配置 +dapr configurations -k --all-namespaces +``` + +### 警告信息 +此命令可能会显示警告信息。 + +#### 根证书更新警告 +如果部署到 Kubernetes 集群的 mtls 根证书在 30 天内过期,将显示以下警告信息: + +``` +您的 Kubernetes 集群的 Dapr 根证书将在 天后过期。到期日期: UTC。 +请访问 docs.dapr.io 查看证书更新说明,以避免服务中断。 +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-dashboard.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-dashboard.md new file mode 100644 index 000000000..892376c23 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-dashboard.md @@ -0,0 +1,62 @@ +--- +type: docs +title: "dashboard CLI 命令参考" +linkTitle: "dashboard" +description: "关于 dashboard CLI 命令的详细信息" +--- + +### 描述 + +启动 [Dapr 仪表板](https://github.com/dapr/dashboard)。 + +### 支持的平台类型 + +- [自托管]({{< ref self-hosted >}}) +- [Kubernetes]({{< ref kubernetes >}}) + +### 用法 + +```bash +dapr dashboard [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| -------------------- | -------------------- | ------------- | --------------------------------------------------------------------------- | +| `--address`, `-a` | | `localhost` | 监听的地址。仅接受 IP 地址或 localhost 作为值 | +| `--help`, `-h` | | | 显示帮助信息 | +| `--kubernetes`, `-k` | | `false` | 通过本地代理在浏览器中打开 Dapr 仪表板以连接到 Kubernetes 集群 | +| `--namespace`, `-n` | | `dapr-system` | Dapr 仪表板运行所在的命名空间 | +| `--port`, `-p` | | `8080` | 提供 Dapr 仪表板服务的本地端口 | +| `--version`, `-v` | | `false` | 显示 Dapr 仪表板的版本信息 | + +### 示例 + +```bash +# 本地启动仪表板 +dapr dashboard + +# 在指定端口本地启动仪表板服务 +dapr dashboard -p 9999 + +# 通过端口转发连接到 Kubernetes 中运行的仪表板服务 +dapr dashboard -k + +# 在所有地址上通过指定端口转发连接到 Kubernetes 中运行的仪表板服务 +dapr dashboard -k -p 9999 --address 0.0.0.0 + +# 通过指定端口转发连接到 Kubernetes 中运行的仪表板服务 +dapr dashboard -k -p 9999 +``` + +### 警告信息 - Kubernetes 模式 +此命令可能会显示警告信息。 + +#### 根证书更新警告 +如果部署在 Kubernetes 集群中的 mtls 根证书将在 30 天内过期,将显示以下警告信息: + +``` +您的 Kubernetes 集群的 Dapr 根证书将在 天后过期。到期日期: UTC。 +请访问 docs.dapr.io 获取证书更新说明,以避免服务中断。 +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-help.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-help.md new file mode 100644 index 000000000..a94413bad --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-help.md @@ -0,0 +1,22 @@ +--- +type: docs +title: "help 命令行界面命令参考" +linkTitle: "help" +description: "关于 help 命令行界面命令的详细信息" +--- + +### 描述 + +Help 命令为应用程序中的任何命令提供帮助。 + +### 用法 + +```bash +dapr help [command] [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| -------------- | -------------------- | ------- | ------------------------ | +| `--help`, `-h` | | | 显示此帮助信息 | diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-init.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-init.md new file mode 100644 index 000000000..969fe142b --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-init.md @@ -0,0 +1,205 @@ +--- +type: docs +title: "init CLI 命令参考" +linkTitle: "init" +description: "关于 init CLI 命令的详细信息" +--- + +### 描述 + +在支持的平台上安装 Dapr。 + +### 支持的平台 + +- [本地托管]({{< ref self-hosted >}}) +- [Kubernetes]({{< ref kubernetes >}}) + +### 用法 + +```bash +dapr init [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| --------------------- | -------------------- | ------------- | ------------------------------------------------------------------------------------ | +| `--dashboard-version` | | `latest` | 要安装的 Dapr 仪表板版本,例如:`1.0.0` | +| `--enable-ha` | | `false` | 启用高可用性 (HA) 模式 | +| `--enable-mtls` | | `true` | 在集群中启用 mTLS | +| `--from-dir` | | | 本地目录的路径,包含下载的 "Dapr 安装程序包" 版本,用于在隔离环境中 `init` | +| `--help`, `-h` | | | 打印此帮助信息 | +| `--image-registry` | | | 从指定的镜像注册表中拉取 Dapr 所需的容器镜像 | +| `--kubernetes`, `-k` | | `false` | 将 Dapr 部署到 Kubernetes 集群 | +| `--namespace`, `-n` | | `dapr-system` | 要在其中安装 Dapr 的 Kubernetes 命名空间 | +| `--network` | | | 要安装和部署 Dapr 运行时的 Docker 网络 | +| `--runtime-version` | | `latest` | 要安装的 Dapr 运行时版本,例如:`1.0.0` | +| `--image-variant` | | | 要用于 Dapr 运行时的镜像变体,例如:`mariner` | +| `--set` | | | 在命令行上配置选项以传递给 Dapr Helm 图表和 Kubernetes 集群进行安装。可以在逗号分隔的列表中指定多个值,例如:`key1=val1,key2=val2` | +| `--slim`, `-s` | | `false` | 从本地托管安装中排除放置服务、调度服务以及 Redis 和 Zipkin 容器 | +| `--timeout` | | `300` | Kubernetes 安装的等待超时时间 | +| `--wait` | | `false` | 等待 Kubernetes 初始化完成 | +| N/A |DAPR_DEFAULT_IMAGE_REGISTRY| | 用于指定默认的容器注册表以从中拉取镜像。当其值设置为 `GHCR` 或 `ghcr` 时,它从 Github 容器注册表中拉取所需的镜像。要默认使用 Docker hub,请取消设置环境变量或将其留空| +| N/A |DAPR_HELM_REPO_URL| | 指定私有 Dapr Helm 图表的 URL| +| N/A | DAPR_HELM_REPO_USERNAME | 私有 Helm 图表的用户名 | 访问私有 Dapr Helm 图表所需的用户名。如果可以公开访问,则无需设置此环境变量| +| N/A | DAPR_HELM_REPO_PASSWORD | 私有 Helm 图表的密码 |访问私有 Dapr Helm 图表所需的密码。如果可以公开访问,则无需设置此环境变量| | +| `--container-runtime` | | `docker` | 用于传递除 Docker 之外的其他容器运行时。支持的容器运行时有:`docker`、`podman` | +| `--dev` | | | 在 Kubernetes 中运行时创建 Redis 和 Zipkin 部署。 | +| `--scheduler-volume` | | | 仅限本地托管。可选地,您可以为调度服务数据目录指定一个卷。默认情况下,如果没有此标志,调度数据不会持久化且不具备重启恢复能力。 | + + +### 示例 + +{{< tabs "本地托管" "Kubernetes" >}} + +{{% codetab %}} + +**安装** + +通过拉取放置、调度、Redis 和 Zipkin 的容器镜像来安装 Dapr。默认情况下,这些镜像从 Docker Hub 拉取。 + +> 默认情况下,为调度服务创建一个 `dapr_scheduler` 本地卷,用作数据库目录。此卷的主机文件位置可能位于 `/var/lib/docker/volumes/dapr_scheduler/_data` 或 `~/.local/share/containers/storage/volumes/dapr_scheduler/_data`,具体取决于您的容器运行时。 + +```bash +dapr init +``` + +Dapr 也可以在没有 Docker 的情况下运行[精简本地托管模式]({{< ref self-hosted-no-docker.md >}})。 + +```bash +dapr init -s +``` + +> 要切换到 Dapr Github 容器注册表作为默认注册表,请将 `DAPR_DEFAULT_IMAGE_REGISTRY` 环境变量值设置为 `GHCR`。要切换回 Docker Hub 作为默认注册表,请取消设置此环境变量。 + +**指定运行时版本** + +您还可以指定特定的运行时版本。默认情况下,使用最新版本。 + +```bash +dapr init --runtime-version 1.13.4 +``` + +**安装带有镜像变体** + +您还可以安装带有特定镜像变体的 Dapr,例如:[mariner]({{< ref "kubernetes-deploy.md#using-mariner-based-images" >}})。 + +```bash +dapr init --image-variant mariner +``` + +**使用 Dapr 安装程序包** + +在离线或隔离环境中,您可以[下载 Dapr 安装程序包](https://github.com/dapr/installer-bundle/releases)并使用它来安装 Dapr,而不是从网络拉取镜像。 + +```bash +dapr init --from-dir +``` + +Dapr 也可以在没有 Docker 的隔离环境中以精简本地托管模式运行。 + +```bash +dapr init -s --from-dir +``` + +**指定私有注册表** + +您还可以指定一个私有注册表以从中拉取容器镜像。需要将这些镜像发布到私有注册表中,如下所示,以便 Dapr CLI 能够通过 `dapr init` 命令成功拉取它们: + +1. Dapr 运行时容器镜像(dapr) (用于运行放置) - dapr/dapr: +2. Redis 容器镜像(rejson) - dapr/3rdparty/rejson +3. Zipkin 容器镜像(zipkin) - dapr/3rdparty/zipkin + +Dapr 使用的所有必需镜像都需要位于 `dapr` 路径下。第三方镜像必须发布在 `dapr/3rdparty` 路径下。 + +`image-registry` URI 遵循 `docker.io/` 格式。 + +```bash +dapr init --image-registry docker.io/username +``` + +此命令解析完整的镜像 URI,如下所示 - +1. 放置容器镜像(dapr) - docker.io/username/dapr/dapr: +2. Redis 容器镜像(rejson) - docker.io/username/dapr/3rdparty/rejson +3. zipkin 容器镜像(zipkin) - docker.io/username/dapr/3rdparty/zipkin + +在设置 Dapr 时,您可以指定不同的容器运行时。如果省略 `--container-runtime` 标志,默认的容器运行时是 Docker。 + +```bash +dapr init --container-runtime podman +``` + +**使用 Docker 网络** + +您可以将本地容器部署到 Docker 网络中,这对于部署到单独的网络或使用 Docker Compose 进行本地开发以部署应用程序非常有用。 + +创建 Docker 网络。 + +```bash +docker network create mynet +``` + +初始化 Dapr 并指定创建的 Docker 网络。 + +```bash +dapr init --network mynet +``` + +验证所有容器是否在指定网络中运行。 + +```bash +docker ps +``` + +从该 Docker 网络中卸载 Dapr。 + +```bash +dapr uninstall --all --network mynet +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +dapr init -k +``` + +使用 `--dev` 标志以开发模式初始化 Dapr,其中包括 Zipkin 和 Redis。 +```bash +dapr init -k --dev +``` + +您可以使用 `--wait` 标志等待安装完成其部署。 +默认超时时间为 300 秒(5 分钟),但可以使用 `--timeout` 标志自定义。 + +```bash +dapr init -k --wait --timeout 600 +``` + +您还可以指定特定的运行时版本。 + +```bash +dapr init -k --runtime-version 1.4.0 +``` + +使用 `--set` 标志在 Dapr 安装期间配置一组 [Helm 图表值](https://github.com/dapr/dapr/tree/master/charts/dapr#configuration) 以帮助设置 Kubernetes 集群。 + +```bash +dapr init -k --set global.tag=1.0.0 --set dapr_operator.logLevel=error +``` + +您还可以指定一个私有注册表以从中拉取容器镜像。目前 `dapr init -k` 不使用 sentry、operator、placement、scheduler 和 sidecar 的特定镜像。它仅依赖于 Dapr 运行时容器镜像 `dapr` 来处理所有这些镜像。 + +场景 1:dapr 镜像直接托管在私有注册表的根文件夹下 - +```bash +dapr init -k --image-registry docker.io/username +``` +场景 2:dapr 镜像托管在私有注册表的新/不同目录下 - +```bash +dapr init -k --image-registry docker.io/username/ +``` + +{{% /codetab %}} + +{{< /tabs >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-invoke.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-invoke.md new file mode 100644 index 000000000..10d6eeb55 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-invoke.md @@ -0,0 +1,41 @@ +--- +type: docs +title: "invoke CLI 命令参考" +linkTitle: "invoke" +description: "关于 invoke CLI 命令的详细信息" +--- + +### 描述 + +调用指定 Dapr 应用程序的方法。 + +### 支持的平台 + +- [自托管]({{< ref self-hosted >}})(即在本地或私有服务器上运行) + +### 用法 + +```bash +dapr invoke [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| ------------------- | -------------------- | ------- | ----------------------------------------------------- | +| `--app-id`, `-a` | `APP_ID` | | 目标应用程序的 ID | +| `--help`, `-h` | | | 显示帮助信息 | +| `--method`, `-m` | | | 需要调用的方法名称 | +| `--data`, `-d` | | | JSON 格式的数据字符串(可选) | +| `--data-file`, `-f` | | | 包含 JSON 格式数据的文件(可选) | +| `--verb`, `-v` | | `POST` | 使用的 HTTP 请求方法 | + +### 示例 + +```bash +# 使用 POST 请求方法调用目标应用的一个示例方法 +dapr invoke --app-id target --method sample --data '{"key":"value"}' + +# 使用 GET 请求方法调用目标应用的一个示例方法 +dapr invoke --app-id target --method sample --verb GET +``` diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-list.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-list.md new file mode 100644 index 000000000..afe4ff7e2 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-list.md @@ -0,0 +1,61 @@ +--- +type: docs +title: "list CLI 命令参考" +linkTitle: "list" +description: "关于 list CLI 命令的详细信息" +--- + +### 描述 + +显示 Dapr 实例列表。 + +### 支持的平台 + +- [本地托管]({{< ref self-hosted >}}) +- [Kubernetes]({{< ref kubernetes >}}) + +### 用法 + +```bash +dapr list [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 +| --- | --- | --- | --- | +| `--all-namespaces`, `-A` | | `false` | 列出所有命名空间的 Dapr pods(可选) | +| `--help`, `-h` | | | 显示帮助信息 | +| `--kubernetes`, `-k` | | `false` | 列出 Kubernetes 集群中的所有 Dapr pods(可选) | +| `--namespace`, `-n` | | `default` | 列出 Kubernetes 指定命名空间的 Dapr pods。仅与 `-k` 标志一起使用(可选) | +| `--output`, `-o` | | `table` | 列表的输出格式。有效值为:`json`、`yaml` 或 `table` + +### 示例 + +```bash +# 列出本地托管模式下的 Dapr 实例 +dapr list + +# 列出 Kubernetes 模式下所有命名空间的 Dapr 实例 +dapr list -k + +# 以 JSON 格式列出 Dapr 实例 +dapr list -o json + +# 在 Kubernetes 模式下列出特定命名空间的 Dapr 实例 +dapr list -k --namespace default + +# 在 Kubernetes 模式下列出所有命名空间的 Dapr 实例 +dapr list -k --all-namespaces +``` + +### 警告信息 - Kubernetes 环境 +此命令可能会显示警告信息。 + +#### 根证书更新警告 +如果部署到 Kubernetes 集群的 mtls 根证书在 30 天内过期,将显示以下警告信息: + +``` +Kubernetes 集群的 Dapr 根证书将在 天内过期。到期日期: UTC。 +请参阅 docs.dapr.io 以获取证书更新说明,以避免服务中断。 +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-logs.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-logs.md new file mode 100644 index 000000000..ffc3e5e64 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-logs.md @@ -0,0 +1,48 @@ +--- +type: docs +title: "logs CLI 命令参考" +linkTitle: "logs" +description: "关于 logs CLI 命令的详细信息" +--- + +### 描述 + +获取应用程序的 Dapr sidecar 的日志。 + +### 支持的平台环境 + +- [Kubernetes]({{< ref kubernetes >}}) + +### 用法 + +```bash +dapr logs [flags] +``` + +### 标志 + + | 名称 | 环境变量 | 默认值 | 描述 | + | -------------------- | -------------------- | --------- | ---------------------------------------------------------------------------------------- | + | `--app-id`, `-a` | `APP_ID` | | 需要获取日志的应用程序 ID | + | `--help`, `-h` | | | 显示帮助信息 | + | `--kubernetes`, `-k` | | `true` | 从 Kubernetes 集群中获取日志 | + | `--namespace`, `-n` | | `default` | 部署应用程序的 Kubernetes 命名空间 | + | `--pod-name`, `-p` | | | Kubernetes 中 pod 的名称,如果应用程序有多个 pod(可选) | + +### 示例 + +```bash +# 从自定义命名空间中的目标 pod 获取示例应用的日志 +dapr logs -k --app-id sample --pod-name target --namespace custom +``` + +### 警告信息 +此命令可能会发出警告信息。 + +#### 根证书更新警告 +如果部署在 Kubernetes 集群中的 mTLS 根证书将在 30 天内过期,将显示以下警告信息: + +``` +您的 Kubernetes 集群的 Dapr 根证书将在 天后过期。到期日期: UTC。 +请访问 docs.dapr.io 查看证书更新说明,以避免服务中断。 +`` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-mtls/_index.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-mtls/_index.md new file mode 100644 index 000000000..8352a4b07 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-mtls/_index.md @@ -0,0 +1,62 @@ +--- +type: docs +title: "mtls CLI 命令参考" +linkTitle: "mtls" +description: "关于 mtls CLI 命令的详细信息" +--- + +### 描述 + +检查 mTLS 是否已启用。 + +### 支持的平台 + +支持的平台包括 Kubernetes。 + +### 用法 + +```bash +dapr mtls [flags] +dapr mtls [command] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| ------------------- | -------------------- | ------- | ------------------------------------------------- | +| `--help`, `-h` | | | 显示帮助信息 | +| `--kubernetes`, `-k`| | `false` | 检查 Kubernetes 集群是否启用了 mTLS | + +### 可用命令 + +```txt +expiry 检查根证书颁发机构 (CA) 证书的到期时间 +export 将根证书颁发机构 (CA)、颁发者证书和颁发者密钥导出到本地文件 +renew-certificate 更新现有的根证书颁发机构 (CA)、颁发者证书和颁发者密钥 +``` + +### 命令参考 + +查看以下链接以获取每个子命令的详细信息。 + +- [`dapr mtls expiry`]({{< ref dapr-mtls-expiry.md >}}) +- [`dapr mtls export`]({{< ref dapr-mtls-export.md >}}) +- [`dapr mtls renew-certificate`]({{< ref dapr-mtls-renew-certificate.md >}}) + +### 示例 + +```bash +# 检查 Kubernetes 集群上是否启用了 mTLS +dapr mtls -k +``` + +### 警告信息 +此命令可能会发出警告信息。 + +#### 根证书更新警告 +如果部署到 Kubernetes 集群的 mTLS 根证书将在 30 天内到期,将显示以下警告信息: + +``` +您的 Kubernetes 集群的 Dapr 根证书将在 天后到期。到期日期: UTC。 +请参阅 docs.dapr.io 以获取证书更新说明,以避免服务中断。 +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-mtls/dapr-mtls-expiry.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-mtls/dapr-mtls-expiry.md new file mode 100644 index 000000000..7ddba562a --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-mtls/dapr-mtls-expiry.md @@ -0,0 +1,34 @@ +--- +type: docs +title: "mtls expiry CLI 命令指南" +linkTitle: "mtls expiry" +description: "mtls expiry CLI 命令的详细说明" +weight: 2000 +--- + +### 描述 + +用于检查根证书颁发机构 (CA) 证书的有效期 + +### 支持的平台 + +- [Kubernetes]({{< ref kubernetes >}}) + +### 用法 + +```bash +dapr mtls expiry [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| -------------- | -------------------- | ------- | ----------------------- | +| `--help`, `-h` | | | 显示 expiry 的帮助信息 | + +### 示例 + +```bash +# 查看 Kubernetes 证书的有效期 +dapr mtls expiry +``` diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-mtls/dapr-mtls-export.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-mtls/dapr-mtls-export.md new file mode 100644 index 000000000..a0830d1da --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-mtls/dapr-mtls-export.md @@ -0,0 +1,46 @@ +--- +type: docs +title: "mtls export CLI 命令参考" +linkTitle: "mtls export" +description: "关于 mtls export CLI 命令的详细信息" +weight: 1000 +--- + +### 描述 + +将根证书颁发机构(CA)、颁发者证书和密钥导出到本地文件中 + +### 适用平台 + +- [Kubernetes]({{< ref kubernetes >}}) + +### 用法 + +```bash +dapr mtls export [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| -------------- | -------------------- | ----------------- | ------------------------------------------- | +| `--help`, `-h` | | | 导出命令的帮助信息 | +| `--out`, `-o` | | 当前目录 | 证书保存的输出目录路径 | + +### 示例 + +```bash +# 检查 Kubernetes 证书的到期时间 +dapr mtls export -o ./certs +``` + +### 警告信息 +此命令可能会发出警告信息。 + +#### 根证书更新警告 +如果部署到 Kubernetes 集群的 mtls 根证书在 30 天内到期,将显示以下警告信息: + +``` +您的 Kubernetes 集群的 Dapr 根证书将在 天后到期。到期日期: UTC。 +请访问 docs.dapr.io 获取证书更新说明,以避免服务中断。 +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-mtls/dapr-mtls-renew-certificate.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-mtls/dapr-mtls-renew-certificate.md new file mode 100644 index 000000000..2a24fda92 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-mtls/dapr-mtls-renew-certificate.md @@ -0,0 +1,72 @@ +--- +type: docs +title: "mtls renew certificate CLI 命令参考" +linkTitle: "mtls renew certificate" +description: "关于 mtls renew certificate CLI 命令的详细信息" +weight: 3000 +--- + +### 描述 +此命令用于更新即将到期的 Dapr 证书。例如,Dapr Sentry 服务会生成应用程序使用的默认根证书和颁发者证书。详情请参见[安全的 Dapr 到 Dapr 通信]({{< ref "#secure-dapr-to-dapr-communication" >}}) + +### 支持的平台 + +- [Kubernetes]({{< ref kubernetes >}}) + +### 用法 + +```bash +dapr mtls renew-certificate [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| -------------- | -------------------- | ----------------- | ------------------------------------------- | +| `--help`, `-h` | | | renew-certificate 的帮助信息 | +| `--kubernetes`, `-k` | | `false` | 支持的平台 | +| `--valid-until` | | 365 天 | 新创建证书的有效期 | +| `--restart` | | false | 重启 Dapr 控制平面服务(Sentry 服务、Operator 服务和 Placement 服务器) | +| `--timeout` | | 300 秒 | 证书更新过程的超时时间 | +| `--ca-root-certificate` | | | 用户提供的 PEM 根证书的文件路径 | +| `--issuer-public-certificate` | | | 用户提供的 PEM 颁发者证书的文件路径 | +| `--issuer-private-key` | | | 用户提供的 PEM 颁发者私钥的文件路径 | +| `--private-key` | | | 用户提供的用于生成根证书的 root.key 文件 | + +### 示例 + +#### 通过生成全新证书来更新证书 +为 Kubernetes 集群生成新的根证书和颁发者证书,默认有效期为 365 天。证书不会立即应用于 Dapr 控制平面。 +```bash +dapr mtls renew-certificate -k +``` +为 Kubernetes 集群生成新的根证书和颁发者证书,默认有效期为 365 天,并重启 Dapr 控制平面服务。 +```bash +dapr mtls renew-certificate -k --restart +``` +为 Kubernetes 集群生成具有指定有效期的新的根证书和颁发者证书。 +```bash +dapr mtls renew-certificate -k --valid-until <天数> +``` +为 Kubernetes 集群生成具有指定有效期的新的根证书和颁发者证书,并重启 Dapr 控制平面服务。 +```bash +dapr mtls renew-certificate -k --valid-until <天数> --restart +``` +#### 使用用户提供的证书更新证书 +使用提供的 ca.pem、issuer.pem 和 issuer.key 文件路径为 Kubernetes 集群更新证书,并重启 Dapr 控制平面服务。 +```bash +dapr mtls renew-certificate -k --ca-root-certificate --issuer-private-key --issuer-public-certificate --restart +``` +使用提供的 ca.pem、issuer.pem 和 issuer.key 文件路径为 Kubernetes 集群更新证书。 +```bash +dapr mtls renew-certificate -k --ca-root-certificate --issuer-private-key --issuer-public-certificate +``` +#### 使用提供的根私钥生成全新证书来更新证书 +使用现有的私有 root.key 为 Kubernetes 集群生成新的根证书和颁发者证书,并设置指定的有效期。 +```bash +dapr mtls renew-certificate -k --private-key myprivatekey.key --valid-until <天数> +``` +使用现有的私有 root.key 为 Kubernetes 集群生成新的根证书和颁发者证书。 +```bash +dapr mtls renew-certificate -k --private-key myprivatekey.key +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-publish.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-publish.md new file mode 100644 index 000000000..7bda0fe65 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-publish.md @@ -0,0 +1,46 @@ +--- +type: docs +title: "发布命令行工具参考" +linkTitle: "发布" +description: "关于发布命令行工具的详细信息" +--- + +### 描述 + +发布一个发布-订阅事件。 + +### 支持的平台 + +- [自托管]({{< ref self-hosted >}}) + +### 用法 + +```bash +dapr publish [flags] +``` + +### 参数 + +| 名称 | 环境变量 | 默认值 | 描述 | +| ---------------------------- | -------- | ----------------------------------------------------------- | ---------------------------------------------- | +| `--publish-app-id`, `-i` | | 您要发布的应用程序的 ID | +| `--pubsub`, `-p` | | 发布-订阅组件的名称 | +| `--topic`, `-t` | | | 要发布的主题 | +| `--data`, `-d` | | | JSON 序列化的字符串(可选) | +| `--data-file`, `-f` | | | 包含 JSON 序列化数据的文件(可选) | +| `--help`, `-h` | | | 显示帮助信息 | +| `--metadata`, `-m` | | | JSON 序列化的发布元数据(可选) | +| `--unix-domain-socket`, `-u` | | | Unix 域套接字的路径(可选) | + +### 示例 + +```bash +# 通过应用程序发布到目标发布-订阅系统中的示例主题 +dapr publish --publish-app-id appId --topic sample --pubsub target --data '{"key":"value"}' + +# 使用 Unix 域套接字通过应用程序发布到目标发布-订阅系统中的示例主题 +dapr publish --enable-domain-socket --publish-app-id myapp --pubsub target --topic sample --data '{"key":"value"}' + +# 通过应用程序在不使用云事件的情况下发布到目标发布-订阅系统中的示例主题 +dapr publish --publish-app-id myapp --pubsub target --topic sample --data '{"key":"value"}' --metadata '{"rawPayload":"true"}' +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-run.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-run.md new file mode 100644 index 000000000..96b24935c --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-run.md @@ -0,0 +1,93 @@ +--- +type: docs +title: "运行 CLI 命令参考" +linkTitle: "运行" +description: "关于运行 CLI 命令的详细信息" +--- + +### 描述 + +运行 Dapr,并且可以选择同时运行您的应用程序。完整的 daprd 参数、CLI 参数和 Kubernetes 注释的对比列表可以在[这里]({{< ref arguments-annotations-overview.md >}})找到。 + +### 支持的平台 + +- [本地部署]({{< ref self-hosted >}}) + +### 用法 + +```bash +dapr run [flags] [command] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| ------------------------------ | -------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | +| `--app-id`, `-a` | `APP_ID` | | 您的应用程序的 ID,用于服务发现。不能包含点。 | +| `--app-max-concurrency` | | `unlimited` | 应用程序的并发级别;默认是无限制 | +| `--app-port`, `-p` | `APP_PORT` | | 您的应用程序正在监听的端口 | +| `--app-protocol`, `-P` | | `http` | Dapr 用于与应用程序通信的协议。有效值为:`http`、`grpc`、`https`(带 TLS 的 HTTP)、`grpcs`(带 TLS 的 gRPC)、`h2c`(HTTP/2 明文) | +| `--resources-path`, `-d` | | Linux/Mac: `$HOME/.dapr/components`
Windows: `%USERPROFILE%\.dapr\components` | 资源目录的路径。如果您已将资源组织到多个文件夹中(例如,一个文件夹中的组件,另一个文件夹中的弹性策略),您可以定义多个资源路径。请参见下面的[示例]({{< ref "#examples" >}})。 | +| `--app-channel-address` | | `127.0.0.1` | 应用程序监听的网络地址 | +| `--runtime-path` | | | Dapr 运行时安装路径 | +| `--config`, `-c` | | Linux/Mac: `$HOME/.dapr/config.yaml`
Windows: `%USERPROFILE%\.dapr\config.yaml` | Dapr 配置文件 | +| `--dapr-grpc-port`, `-G` | `DAPR_GRPC_PORT` | `50001` | Dapr 监听的 gRPC 端口 | +| `--dapr-internal-grpc-port`, `-I` | | `50002` | Dapr 内部 API 监听的 gRPC 端口。用于开发期间解决 mDNS 缓存导致的服务调用失败问题,或配置防火墙后面的 Dapr sidecar。可以是大于 1024 的任何值,并且每个应用程序必须不同。 | +| `--dapr-http-port`, `-H` | `DAPR_HTTP_PORT` | `3500` | Dapr 监听的 HTTP 端口 | +| `--enable-profiling` | | `false` | 通过 HTTP 端点启用 "pprof" 性能分析 | +| `--help`, `-h` | | | 打印帮助信息 | +| `--run-file`, `-f` | | Linux/MacOS: `$HOME/.dapr/dapr.yaml` | 使用多应用程序运行模板文件同时运行多个应用程序。目前处于[alpha]({{< ref "support-preview-features.md" >}})阶段,仅在 Linux/MacOS 上可用 | +| `--image` | | | 使用自定义 Docker 镜像。格式为 Docker Hub 的 `repository/image`,或自定义注册表的 `example.com/repository/image`。 | +| `--log-level` | | `info` | 日志详细程度。有效值为:`debug`、`info`、`warn`、`error`、`fatal` 或 `panic` | +| `--enable-api-logging` | | `false` | 启用从应用程序到 Dapr 的所有 API 调用的日志记录 | +| `--metrics-port` | `DAPR_METRICS_PORT` | `9090` | Dapr 发送其指标信息的端口 | +| `--profile-port` | | `7777` | 配置文件服务器监听的端口 | +| `--placement-host-address` | | Linux/Mac: `$HOME/.dapr/components`
Windows: `%USERPROFILE%\.dapr\components` | 在 Docker 网络中的任何容器中运行。使用 `` 或 `:`。如果省略端口,默认值为:
  • Linux/MacOS: `50005`
  • Windows: `6050`
| +| `--scheduler-host-address` | | Linux/Mac: `$HOME/.dapr/components`
Windows: `%USERPROFILE%\.dapr\components` | 在 Docker 网络中的任何容器中运行。使用 `` 或 `:`。如果省略端口,默认值为:
  • Linux/MacOS: `50006`
  • Windows: `6060`
| +| `--enable-app-health-check` | | `false` | 使用 app-protocol 定义的协议启用应用程序的健康检查 | +| `--app-health-check-path` | | | 用于健康检查的路径;仅限 HTTP | +| `--app-health-probe-interval` | | | 以秒为单位探测应用程序健康状况的间隔 | +| `--app-health-probe-timeout` | | | 应用程序健康探测的超时时间,以毫秒为单位 | +| `--app-health-threshold` | | | 应用程序被视为不健康的连续失败次数 | +| `--unix-domain-socket`, `-u` | | | Unix 域套接字目录挂载的路径。如果指定,与 Dapr sidecar 的通信使用 Unix 域套接字,与使用 TCP 端口相比,具有更低的延迟和更高的吞吐量。在 Windows 上不可用。 | +| `--dapr-http-max-request-size` | | `4` | 请求体的最大大小,以 MB 为单位。 | +| `--dapr-http-read-buffer-size` | | `4` | HTTP 读取缓冲区的最大大小,以 KB 为单位。这也限制了 HTTP 头的最大大小。默认值为 4 KB | +| `--kubernetes`, `-k` | | | 在 Kubernetes 上运行 Dapr,并用于 [Kubernetes 上的多应用程序运行模板文件]({{< ref multi-app-dapr-run >}})。 | +| `--components-path`, `-d` | | Linux/Mac: `$HOME/.dapr/components`
Windows: `%USERPROFILE%\.dapr\components` | **已弃用**,建议使用 `--resources-path` | + +### 示例 + +```bash +# 运行一个 .NET 应用程序 +dapr run --app-id myapp --app-port 5000 -- dotnet run + +# 使用 Unix 域套接字运行一个 .Net 应用程序 +dapr run --app-id myapp --app-port 5000 --unix-domain-socket /tmp -- dotnet run + +# 运行一个 Java 应用程序 +dapr run --app-id myapp -- java -jar myapp.jar + +# 运行一个监听端口 3000 的 NodeJs 应用程序 +dapr run --app-id myapp --app-port 3000 -- node myapp.js + +# 运行一个 Python 应用程序 +dapr run --app-id myapp -- python myapp.py + +# 仅运行 sidecar +dapr run --app-id myapp + +# 运行一个用 Go 编写的 gRPC 应用程序(监听端口 3000) +dapr run --app-id myapp --app-port 5000 --app-protocol grpc -- go run main.go + +# 运行一个启用 API 日志记录的监听端口 3000 的 NodeJs 应用程序 +dapr run --app-id myapp --app-port 3000 --enable-api-logging -- node myapp.js + +# 传递多个资源路径 +dapr run --app-id myapp --resources-path path1 --resources-path path2 + +# 运行多应用程序运行模板文件 +dapr run -f dapr.yaml + +# 在 Kubernetes 上运行多应用程序运行模板文件 +dapr run -k -f dapr.yaml +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-status.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-status.md new file mode 100644 index 000000000..36f45ad7d --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-status.md @@ -0,0 +1,45 @@ +--- +type: docs +title: "status CLI 命令参考" +linkTitle: "status" +description: "关于 status CLI 命令的详细信息" +--- + +### 描述 + +显示 Dapr 服务的运行状态。 + +### 支持的平台类型 + +- [Kubernetes]({{< ref kubernetes >}}) + +### 用法 + +```bash +dapr status -k +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| -------------------- | -------------------- | ------- | ------------------------------------------------------------ | +| `--help`, `-h` | | | 打印此帮助信息 | +| `--kubernetes`, `-k` | | `false` | 显示 Kubernetes 集群中 Dapr 服务的状态 | + +### 示例 + +```bash +# 从 Kubernetes 获取 Dapr 服务的状态 +dapr status -k +``` + +### 警告信息 +此命令可能会发出警告信息。 + +#### 根证书更新警告 +如果部署到 Kubernetes 集群的 mtls 根证书在 30 天内过期,将显示以下警告信息: + +``` +Kubernetes 集群中的 Dapr 根证书将在 天后过期,具体到期日期为: UTC。 +请参阅 docs.dapr.io 以获取证书更新说明,以避免服务中断。 +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-stop.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-stop.md new file mode 100644 index 000000000..97586d3b6 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-stop.md @@ -0,0 +1,35 @@ +--- +type: docs +title: "stop CLI 命令参考" +linkTitle: "stop" +description: "关于 stop CLI 命令的详细信息" +--- + +### 描述 + +停止 Dapr 实例及其相关应用程序。 + +### 适用平台 + +- [自托管]({{< ref self-hosted >}}) + +### 用法 + +```bash +dapr stop [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| -------------------- | -------------------- | ------- | ----------------------------------- | +| `--app-id`, `-a` | `APP_ID` | | 要停止的应用程序 ID | +| `--help`, `-h` | | | 显示帮助信息 | +| `--run-file`, `-f` | | | 使用多应用运行模板文件来同时停止多个应用程序。目前处于[alpha]({{< ref "support-preview-features.md" >}})阶段,仅在 Linux/MacOS 上可用 | + +### 示例 + +```bash +# 停止 Dapr 应用程序 +dapr stop --app-id +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-uninstall.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-uninstall.md new file mode 100644 index 000000000..5d8dc3e8a --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-uninstall.md @@ -0,0 +1,57 @@ +--- +type: docs +title: "卸载 CLI 命令参考" +linkTitle: "卸载" +description: "关于卸载 CLI 命令的详细信息" +--- + +### 描述 + +卸载 Dapr 运行环境。 + +### 支持的平台 + +- [自托管]({{< ref self-hosted >}}) +- [Kubernetes]({{< ref kubernetes >}}) + +### 用法 + +```bash +dapr uninstall [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| -------------------- | -------------------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--all` | | `false` | 移除 Redis、Zipkin 容器以及默认 Dapr 目录(位于 `$HOME/.dapr` 或 `%USERPROFILE%\.dapr\`),但保留调度服务和 actor 放置服务容器。 | +| `--help`, `-h` | | | 显示帮助信息 | +| `--kubernetes`, `-k` | | `false` | 从 Kubernetes 集群中卸载 Dapr | +| `--namespace`, `-n` | | `dapr-system` | 从指定的 Kubernetes 命名空间卸载 Dapr | +| `--container-runtime` | | `docker` | 指定使用 Docker 以外的容器运行时。支持的选项包括:`docker`,`podman` | + +### 示例 + +#### 从自托管模式卸载 + +```bash +dapr uninstall +``` + +您还可以使用 `--all` 选项来移除 .dapr 目录、Redis、Placement、Scheduler 和 Zipkin 容器 + +```bash +dapr uninstall --all +``` + +在配置 Dapr 时,您可以指定不同的容器运行时。如果省略 `--container-runtime` 标志,默认使用 Docker。 + +```bash +dapr uninstall --all --container-runtime podman +``` + +#### 从 Kubernetes 卸载 + +```bash +dapr uninstall -k +``` \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-upgrade.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-upgrade.md new file mode 100644 index 000000000..2936d2bde --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-upgrade.md @@ -0,0 +1,71 @@ +--- +type: docs +title: "升级 CLI 命令参考" +linkTitle: "升级" +description: "关于升级 CLI 命令的详细信息" +--- + +### 描述 + +在支持的托管平台上升级或回退 Dapr。 + +{{% alert title="警告" color="warning" %}} +版本升级或回退应逐步进行,包括小版本的更新。 + +在回退之前,请确认组件是向后兼容的,并且应用程序代码没有使用以前版本的 Dapr 不支持的 API。 +{{% /alert %}} + +### 支持的平台 + +- [Kubernetes]({{< ref kubernetes >}}) + +### 用法 + +```bash +dapr upgrade [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 | +| -------------------- | -------------------- | -------- | --------------------------------------------------------------------------------------------------------- | +| `--help`, `-h` | | | 显示帮助信息 | +| `--kubernetes`, `-k` | | `false` | 在 Kubernetes 集群中升级/回退 Dapr | +| `--runtime-version` | | `latest` | 要升级/回退到的 Dapr 运行时版本,例如:`1.0.0` | +| `--set` | | | 在命令行上设置值(可以指定多个值或用逗号分隔:key1=val1,key2=val2) | +| `--image-registry` | | | 从指定的镜像注册表中拉取 Dapr 所需的容器镜像 | + +### 示例 + +```bash +# 在 Kubernetes 中将 Dapr 升级到最新版本 +dapr upgrade -k + +# 在 Kubernetes 中升级或回退到指定版本的 Dapr 运行时 +dapr upgrade -k --runtime-version 1.2 + +# 在 Kubernetes 中升级或回退到指定版本的 Dapr 运行时并设置值 +dapr upgrade -k --runtime-version 1.2 --set global.logAsJson=true +``` +```bash +# 使用私有注册表进行升级或回退,如果您在托管 Dapr 镜像时使用了私有注册表并在执行 `dapr init -k` 时使用了它 +# 场景 1:Dapr 镜像直接托管在私有注册表的根目录下 - +dapr init -k --image-registry docker.io/username +# 场景 2:Dapr 镜像托管在私有注册表的不同目录下 - +dapr init -k --image-registry docker.io/username/ +``` + +### 警告信息 +此命令可能会发出警告信息。 + +#### 根证书更新警告 +如果部署到 Kubernetes 集群的 mtls 根证书将在 30 天内过期,则会显示以下警告信息: + +``` +您的 Kubernetes 集群的 Dapr 根证书将在 天后过期。到期日期: UTC。 +请参阅 docs.dapr.io 以获取证书更新说明,以避免服务中断。 +``` + +### 相关链接 + +- [在 Kubernetes 集群上升级 Dapr]({{< ref kubernetes-upgrade.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/cli/dapr-version.md b/src/translated_content/zh_CN/docs/reference/cli/dapr-version.md new file mode 100644 index 000000000..fd60ea465 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/cli/dapr-version.md @@ -0,0 +1,40 @@ +--- +type: docs +title: "version CLI 命令参考" +linkTitle: "version" +description: "显示 Dapr 运行时和 CLI 的版本信息。" +--- + +### 描述 + +显示 `dapr` CLI 和 `daprd` 可执行文件的版本信息,可以选择普通格式或 JSON 格式。 + +### 支持的平台 + +- [自托管平台]({{< ref self-hosted >}}) + +### 用法 + +```bash +dapr version [flags] +``` + +### 标志 + +| 名称 | 环境变量 | 默认值 | 描述 +| --- | --- | --- | --- | +| `--help`, `-h` | | | 显示此帮助信息 | +| `--output`, `-o` | | | 输出格式(选项:json) | + +### 示例 + +```bash +# 获取 Dapr CLI 和运行时的版本信息 +dapr version --output json +``` + +### 相关信息 + +您可以通过运行 `daprd --version` 命令直接查看 `daprd` 的版本。 + +您也可以通过运行 `dapr --version` 命令获取普通格式的版本信息。 diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/_index.md b/src/translated_content/zh_CN/docs/reference/components-reference/_index.md new file mode 100644 index 000000000..cc899ab8e --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/_index.md @@ -0,0 +1,7 @@ +--- +type: docs +title: "Dapr 组件指南" +linkTitle: "组件规范" +description: "Dapr 组件的详细信息与规范说明" +weight: 400 +--- \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/_index.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/_index.md new file mode 100644 index 000000000..95e222fe2 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/_index.md @@ -0,0 +1,18 @@ +--- +type: docs +title: "Bindings 组件规格" +linkTitle: "Bindings" +weight: 4000 +description: 支持与 Dapr 接口的外部绑定 +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/" +no_list: true +--- + +下表列出了 Dapr 构建块支持的输入和输出绑定。[了解如何为 Dapr 设置不同的输入和输出绑定组件。]({{< ref setup-bindings.md >}}) + +{{< partial "components/description.html" >}} + +每个绑定组件都有其特定的属性。点击名称链接查看每个绑定的组件规格。 + +{{< partial "components/bindings.html" >}} \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/alicloud-dingtalk.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/alicloud-dingtalk.md new file mode 100644 index 000000000..5f8bddc21 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/alicloud-dingtalk.md @@ -0,0 +1,87 @@ +--- +type: docs +title: "阿里云钉钉绑定组件规范" +linkTitle: "阿里云钉钉" +description: "关于阿里云钉钉绑定组件的详细文档" +--- + +## 配置 Dapr 组件 +要配置阿里云钉钉绑定组件,请创建一个类型为 `bindings.dingtalk.webhook` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用 secretstore 配置。有关如何引用和使用 Dapr 组件的密钥,请参阅[此指南]({{< ref component-secrets.md >}})。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.dingtalk.webhook + version: v1 + metadata: + - name: id + value: "test_webhook_id" + - name: url + value: "https://oapi.dingtalk.com/robot/send?access_token=******" + - name: secret + value: "****************" + - name: direction + value: "input, output" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中使用了明文字符串作为密钥。建议使用密钥存储来存储密钥,详情请参阅[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 元数据字段说明 +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|--------|--------|---------| +| `id` | 是 | 输入/输出 |唯一标识符| `"test_webhook_id"` +| `url` | 是 | 输入/输出 |钉钉的 Webhook 地址 | `"https://oapi.dingtalk.com/robot/send?access_token=******"` +| `secret` | 否 | 输入/输出 |钉钉 Webhook 的密钥 | `"****************"` +| `direction` | 否 | 输入/输出 |绑定的方向 | `"input"`, `"output"`, `"input, output"` + +## 绑定支持 + +此组件支持**输入和输出**绑定接口。 + +此组件支持以下操作的**输出绑定**: +- `create` +- `get` + +## 示例操作 + +以下示例展示了如何根据[此处](https://developers.dingtalk.com/document/app/custom-robot-access)的说明设置负载的数据: + +```shell +curl -X POST http://localhost:3500/v1.0/bindings/myDingTalk \ + -H "Content-Type: application/json" \ + -d '{ + "data": { + "msgtype": "text", + "text": { + "content": "Hi" + } + }, + "operation": "create" + }' +``` + +```shell +curl -X POST http://localhost:3500/v1.0/bindings/myDingTalk \ + -H "Content-Type: application/json" \ + -d '{ + "data": { + "msgtype": "text", + "text": { + "content": "Hi" + } + }, + "operation": "get" + }' +``` +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [Bindings 构建块]({{< ref bindings >}}) +- [操作指南:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [操作指南:使用 bindings 与外部资源接口]({{< ref howto-bindings.md >}}) +- [Bindings API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/alicloudoss.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/alicloudoss.md new file mode 100644 index 000000000..cb1d026eb --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/alicloudoss.md @@ -0,0 +1,139 @@ +--- +type: docs +title: "阿里云对象存储服务绑定指南" +linkTitle: "阿里云对象存储" +description: "关于阿里云对象存储绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/alicloudoss/" +--- + +## 组件格式 + +要配置阿里云对象存储绑定,请创建一个类型为 `bindings.alicloud.oss` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用secretstore配置。有关如何[引用secrets]({{< ref component-secrets.md >}})以检索和使用Dapr组件的secret,请参阅此指南。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: alicloudobjectstorage +spec: + type: bindings.alicloud.oss + version: v1 + metadata: + - name: endpoint + value: "[endpoint]" + - name: accessKeyID + value: "[key-id]" + - name: accessKey + value: "[access-key]" + - name: bucket + value: "[bucket]" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中使用了明文字符串作为secrets。建议使用secret store来存储secrets,详情请见[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 元数据字段说明 + +| 字段 | 必需 | 绑定功能 | 详情 | 示例 | +|---------------|------|---------|---------|---------| +| `endpoint` | 是 | 输出 | 阿里云OSS端点。 | https://oss-cn-hangzhou.aliyuncs.com +| `accessKeyID` | 是 | 输出 | 访问密钥ID凭证。 | +| `accessKey` | 是 | 输出 | 访问密钥凭证。 | +| `bucket` | 是 | 输出 | 存储桶的名称。 | + +## 绑定功能 + +此组件支持**输出绑定**,具有以下操作: + +- `create`: [创建对象](#create-object) + +### 创建对象 + +要执行创建对象操作,请使用`POST`方法调用绑定,并使用以下JSON主体: + +```json +{ + "operation": "create", + "data": "YOUR_CONTENT" +} +``` + +{{% alert title="注意" color="primary" %}} +默认情况下,会自动生成一个随机UUID作为对象键。请参阅下面的元数据支持以设置对象的键。 +{{% /alert %}} + +#### 示例 + +**保存到随机生成的UUID文件** + +{{< tabs "Windows" "Linux/MacOS" >}} + +{{% codetab %}} + +```bash +curl -d "{ \"operation\": \"create\", \"data\": \"Hello World\" }" http://localhost:/v1.0/bindings/ +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +curl -d '{ "operation": "create", "data": "Hello World" }' http://localhost:/v1.0/bindings/ +``` + +{{% /codetab %}} + +{{< /tabs >}} + +
+ +**保存到特定文件** +{{< tabs "Windows" "Linux/MacOS" >}} + +{{% codetab %}} + +```bash +curl -d "{ \"operation\": \"create\", \"data\": \"Hello World\", \"metadata\": { \"key\": \"my-key\" } }" http://localhost:/v1.0/bindings/ +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +curl -d '{ "operation": "create", "data": "Hello World", "metadata": { "key": "my-key" } }' http://localhost:/v1.0/bindings/ +``` + +{{% /codetab %}} + +{{< /tabs >}} + +{{% alert title="注意" color="primary" %}} +在Windows CMD中需要对`"`字符进行转义。 +{{% /alert %}} + +## 元数据信息 + +### 对象键 + +默认情况下,阿里云OSS输出绑定会自动生成一个UUID作为对象键。您可以使用以下元数据来设置自定义键: + +```json +{ + "data": "file content", + "metadata": { + "key": "my-key" + }, + "operation": "create" +} +``` + +## 相关链接 + +- [Bindings构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用bindings与外部资源接口]({{< ref howto-bindings.md >}}) +- [Bindings API参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/alicloudsls.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/alicloudsls.md new file mode 100644 index 000000000..7c1f38092 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/alicloudsls.md @@ -0,0 +1,100 @@ +--- +type: docs +title: "阿里云日志存储服务绑定指南" +linkTitle: "阿里云日志存储" +description: "关于阿里云日志存储绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/alicloudsls/" +--- + +## 组件配置格式 + +要配置一个阿里云SLS绑定,请创建一个类型为`bindings.alicloud.sls`的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})以了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: alicloud.sls +spec: + type: bindings.alicloud.sls + version: v1 + metadata: + - name: AccessKeyID + value: "[accessKey-id]" + - name: AccessKeySecret + value: "[accessKey-secret]" + - name: Endpoint + value: "[endpoint]" +``` + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|---------------|----------|---------|---------|---------| +| `AccessKeyID` | 是 | 输出 | 访问密钥ID凭证。 | +| `AccessKeySecret` | 是 | 输出 | 访问密钥凭证secret | +| `Endpoint` | 是 | 输出 | 阿里云SLS端点。 | + +## 绑定支持 + +该组件支持**输出绑定**,具有以下操作: + +- `create`: [创建对象](#create-object) + +### 请求格式 + +要执行日志存储操作,请使用`POST`方法调用绑定,并使用以下JSON主体: + +```json +{ + "metadata":{ + "project":"your-sls-project-name", + "logstore":"your-sls-logstore-name", + "topic":"your-sls-topic-name", + "source":"your-sls-source" + }, + "data":{ + "custome-log-filed":"any other log info" + }, + "operation":"create" +} +``` + +{{% alert title="注意" color="primary" %}} +请确保在元数据属性中提供"project","logstore","topic"和"source"的值。 +{{% /alert %}} + +#### 示例 + +{{< tabs "Windows" "Linux/MacOS" >}} + +{{% codetab %}} + +```bash +curl -X POST -H "Content-Type: application/json" -d "{\"metadata\":{\"project\":\"project-name\",\"logstore\":\"logstore-name\",\"topic\":\"topic-name\",\"source\":\"source-name\"},\"data\":{\"log-filed\":\"log info\"}" http://localhost:/v1.0/bindings/ +``` + +{{% /codetab %}} + +{{% codetab %}} + +```bash +curl -X POST -H "Content-Type: application/json" -d '{"metadata":{"project":"project-name","logstore":"logstore-name","topic":"topic-name","source":"source-name"},"data":{"log-filed":"log info"}' http://localhost:/v1.0/bindings/ +``` + +{{% /codetab %}} + +{{< /tabs >}} + +
+ +### 响应格式 +由于阿里云SLS生产者API是异步的,因此此绑定没有直接响应(没有回调接口来接收成功或失败的响应,只有在失败时会记录到控制台日志)。 + +## 相关链接 + +- [bindings构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用bindings与外部资源接口]({{< ref howto-bindings.md >}}) +- [bindings API参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/alicloudtablestore.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/alicloudtablestore.md new file mode 100644 index 000000000..4e840bf87 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/alicloudtablestore.md @@ -0,0 +1,142 @@ +--- +type: docs +title: "阿里云 Tablestore 绑定组件规范" +linkTitle: "阿里云 Tablestore" +description: "关于阿里云 Tablestore 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/alicloudtablestore/" +--- + +## 组件格式 + +要配置阿里云 Tablestore 绑定组件,请创建一个类型为 `bindings.alicloud.tablestore` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用 secretstore 配置。有关如何[引用 secrets]({{< ref component-secrets.md >}})以获取和使用 Dapr 组件的机密信息,请参阅此指南。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: mytablestore +spec: + type: bindings.alicloud.tablestore + version: v1 + metadata: + - name: endpoint + value: "[endpoint]" + - name: accessKeyID + value: "[key-id]" + - name: accessKey + value: "[access-key]" + - name: instanceName + value: "[instance]" + - name: tableName + value: "[table]" + - name: endpoint + value: "[endpoint]" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中使用了明文字符串作为机密信息。建议使用 secret store 来存储机密信息,详情请参阅[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 说明 | 示例 | +|---------------|----------|---------|---------|---------| +| `endpoint` | 是 | 输出 | 阿里云 Tablestore 的访问端点。 | https://tablestore-cn-hangzhou.aliyuncs.com +| `accessKeyID` | 是 | 输出 | 访问密钥 ID。 | +| `accessKey` | 是 | 输出 | 访问密钥。 | +| `instanceName` | 是 | 输出 | 实例名称。 | +| `tableName` | 是 | 输出 | 表名称。 | + +## 绑定功能支持 + +此组件支持以下操作的**输出绑定**: + +- `create`: [创建对象](#create-object) + +### 创建对象 + +要执行创建对象操作,请使用 `POST` 方法调用绑定,并提供以下 JSON 正文: + +```json +{ + "operation": "create", + "data": "YOUR_CONTENT", + "metadata": { + "primaryKeys": "pk1" + } +} +``` + +{{% alert title="注意" color="primary" %}} +请确保 `metadata.primaryKeys` 字段是必填项。 +{{% /alert %}} + +### 删除对象 + +要执行删除对象操作,请使用 `POST` 方法调用绑定,并提供以下 JSON 正文: + +```json +{ + "operation": "delete", + "metadata": { + "primaryKeys": "pk1", + "columnToGet": "name,age,date" + }, + "data": { + "pk1": "data1" + } +} +``` + +{{% alert title="注意" color="primary" %}} +请确保 `metadata.primaryKeys` 字段是必填项。 +{{% /alert %}} + +### 列出对象 + +要执行列出对象操作,请使用 `POST` 方法调用绑定,并提供以下 JSON 正文: + +```json +{ + "operation": "list", + "metadata": { + "primaryKeys": "pk1", + "columnToGet": "name,age,date" + }, + "data": { + "pk1": "data1", + "pk2": "data2" + } +} +``` + +{{% alert title="注意" color="primary" %}} +请确保 `metadata.primaryKeys` 字段是必填项。 +{{% /alert %}} + +### 获取对象 + +要执行获取对象操作,请使用 `POST` 方法调用绑定,并提供以下 JSON 正文: + +```json +{ + "operation": "get", + "metadata": { + "primaryKeys": "pk1" + }, + "data": { + "pk1": "data1" + } +} +``` + +{{% alert title="注意" color="primary" %}} +请确保 `metadata.primaryKeys` 字段是必填项。 +{{% /alert %}} + +## 相关链接 + +- [绑定构建块]({{< ref bindings >}}) +- [操作指南:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/apns.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/apns.md new file mode 100644 index 000000000..fd3929ad4 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/apns.md @@ -0,0 +1,139 @@ +--- +type: docs +title: "Apple 推送通知服务绑定说明" +linkTitle: "Apple 推送通知服务" +description: "关于 Apple 推送通知服务绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/apns/" +--- + +## 组件格式 + +要配置 Apple 推送通知绑定,请创建一个类型为 `bindings.apns` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.apns + version: v1 + metadata: + - name: development + value: "" + - name: key-id + value: "" + - name: team-id + value: "" + - name: private-key + secretKeyRef: + name: + key: "" +``` + +## 元数据字段说明 + +| 字段 | 必需 | 绑定功能支持 | 详情 | 示例 | +|--------------------|:--------:| ----------------|---------|---------| +| `development` | Y | 输出 | 指定使用哪个 APNs 服务。设置为 `"true"` 使用开发服务,或 `"false"` 使用生产服务。默认值:`"true"` | `"true"` | +| `key-id` | Y | 输出 | 来自 Apple 开发者门户的私钥标识符 | `"private-key-id`" | +| `team-id` | Y | 输出 | 来自 Apple 开发者门户的组织或作者标识符 | `"team-id"` | +| `private-key` | Y | 输出 | 这是一个 PKCS #8 格式的私钥。建议将私钥存储在 secret 存储中,而不是直接在配置中暴露。详情请参见[此处](#private-key) | `"pem file"` | + +### 私钥 + +APNS 绑定需要一个加密私钥来生成 APNS 服务的身份验证令牌。 +私钥可以从 Apple 开发者门户生成,并以 PKCS #8 文件形式提供,存储在 PEM 格式中。 +建议将私钥存储在 Dapr 的 secret 存储中,而不是直接在绑定的配置文件中。 + +以下是 APNS 绑定的示例配置文件: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: apns +spec: + type: bindings.apns + metadata: + - name: development + value: false + - name: key-id + value: PUT-KEY-ID-HERE + - name: team-id + value: PUT-APPLE-TEAM-ID-HERE + - name: private-key + secretKeyRef: + name: apns-secrets + key: private-key +``` + +如果使用 Kubernetes,示例 secret 配置可能如下所示: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: apns-secrets +stringData: + private-key: | + -----BEGIN PRIVATE KEY----- + KEY-DATA-GOES-HERE + -----END PRIVATE KEY----- +``` + +## 绑定功能支持 + +此组件支持以下操作的**输出绑定**: + +- `create` + +## 推送通知格式 + +APNS 绑定是 Apple 推送通知服务的直接接口。APNS 绑定将请求直接发送到 APNS 服务而不进行任何处理。 +因此,了解 APNS 服务期望的推送通知的有效负载格式非常重要。 +有效负载格式记录在[此处](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification)。 + +### 请求格式 + +```json +{ + "data": { + "aps": { + "alert": { + "title": "New Updates!", + "body": "There are new updates for your review" + } + } + }, + "metadata": { + "device-token": "PUT-DEVICE-TOKEN-HERE", + "apns-push-type": "alert", + "apns-priority": "10", + "apns-topic": "com.example.helloworld" + }, + "operation": "create" +} +``` + +`data` 对象包含一个完整的推送通知规范,如 [Apple 文档](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification)中所述。`data` 对象将直接发送到 APNs 服务。 + +除了 `device-token` 值外,[Apple 文档](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns)中指定的 HTTP 头可以作为元数据字段发送,并将包含在对 APNs 服务的 HTTP 请求中。 + + +### 响应格式 + +```json +{ + "messageID": "UNIQUE-ID-FOR-NOTIFICATION" +} +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/blobstorage.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/blobstorage.md new file mode 100644 index 000000000..103f6dd8b --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/blobstorage.md @@ -0,0 +1,431 @@ +--- +type: docs +title: "Azure Blob Storage 绑定指南" +linkTitle: "Azure Blob Storage" +description: "详细介绍 Azure Blob Storage 绑定组件的文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/blobstorage/" +--- + +## 组件格式 + +要配置 Azure Blob Storage 绑定,需创建一个类型为 `bindings.azure.blobstorage` 的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.azure.blobstorage + version: v1 + metadata: + - name: accountName + value: myStorageAccountName + - name: accountKey + value: *********** + - name: containerName + value: container1 +# - name: decodeBase64 +# value: +# - name: getBlobRetryCount +# value: +# - name: publicAccessLevel +# value: +``` +{{% alert title="警告" color="warning" %}} +上述示例中,secret 以明文字符串形式使用。建议使用 secret 存储来保护 secret,具体方法请参见[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|--------|---------|---------| +| `accountName` | Y | 输入/输出 | Azure 存储账户的名称 | `"myexmapleaccount"` | +| `accountKey` | Y* | 输入/输出 | Azure 存储账户的访问密钥。仅在不使用 Microsoft Entra ID 认证时需要。 | `"access-key"` | +| `containerName` | Y | 输出 | 要写入的 Blob Storage 容器的名称 | `myexamplecontainer` | +| `endpoint` | N | 输入/输出 | 可选的自定义端点 URL。这在使用 [Azurite 模拟器](https://github.com/Azure/azurite)或使用 Azure 存储的自定义域时很有用(尽管这不是官方支持的)。端点必须是完整的基本 URL,包括协议(`http://` 或 `https://`)、IP 或 FQDN,以及可选端口。 | `"http://127.0.0.1:10000"` +| `decodeBase64` | N | 输出 | 配置在保存到 Blob Storage 之前解码 base64 文件内容。(在保存具有二进制内容的文件时)。默认为 `false` | `true`, `false` | +| `getBlobRetryCount` | N | 输出 | 指定在从 RetryReader 读取时将进行的最大 HTTP GET 请求次数。默认为 `10` | `1`, `2` +| `publicAccessLevel` | N | 输出 | 指定容器中的数据是否可以公开访问以及访问级别(仅在容器由 Dapr 创建时使用)。默认为 `none` | `blob`, `container`, `none` + +### Microsoft Entra ID 认证 + +Azure Blob Storage 绑定组件支持使用所有 Microsoft Entra ID 机制进行认证。有关更多信息以及根据选择的 Microsoft Entra ID 认证机制提供的相关组件元数据字段,请参阅[认证到 Azure 的文档]({{< ref authenticating-azure.md >}})。 + +## 绑定支持 + +此组件支持以下操作的**输出绑定**: + +- `create` : [创建 blob](#create-blob) +- `get` : [获取 blob](#get-blob) +- `delete` : [删除 blob](#delete-blob) +- `list`: [列出 blobs](#list-blobs) + +Blob 存储组件的**输入绑定**使用 [Azure Event Grid]({{< ref eventgrid.md >}})触发和推送事件。 + +请参考[响应 Blob 存储事件](https://learn.microsoft.com/azure/storage/blobs/storage-blob-event-overview)指南以获取更多设置和信息。 + +### 创建 blob + +要执行创建 blob 操作,请使用 `POST` 方法调用 Azure Blob Storage 绑定,并使用以下 JSON 正文: + +> 注意:默认情况下,会生成一个随机 UUID。请参阅下文的元数据支持以设置名称 + +```json +{ + "operation": "create", + "data": "YOUR_CONTENT" +} +``` + +#### 示例 + +##### 将文本保存到随机生成的 UUID blob + +{{< tabs Windows Linux >}} + {{% codetab %}} + 在 Windows 上,使用 cmd 提示符(PowerShell 有不同的转义机制) + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"Hello World\" }" http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "Hello World" }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 将文本保存到特定 blob + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"Hello World\", \"metadata\": { \"blobName\": \"my-test-file.txt\" } }" \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "Hello World", "metadata": { "blobName": "my-test-file.txt" } }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 将文件保存到 blob + +要上传文件,请将其编码为 Base64 并让绑定知道要反序列化它: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.azure.blobstorage + version: v1 + metadata: + - name: accountName + value: myStorageAccountName + - name: accountKey + value: *********** + - name: containerName + value: container1 + - name: decodeBase64 + value: true +``` + +然后您可以像往常一样上传它: + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"YOUR_BASE_64_CONTENT\", \"metadata\": { \"blobName\": \"my-test-file.jpg\" } }" http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "YOUR_BASE_64_CONTENT", "metadata": { "blobName": "my-test-file.jpg" } }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文将包含以下 JSON: + +```json +{ + "blobURL": "https://. blob.core.windows.net//" +} + +``` + +### 获取 blob + +要执行获取 blob 操作,请使用 `POST` 方法调用 Azure Blob Storage 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "get", + "metadata": { + "blobName": "myblob", + "includeMetadata": "true" + } +} +``` + +元数据参数为: + +- `blobName` - blob 的名称 +- `includeMetadata`- (可选)定义是否应返回用户定义的元数据,默认为:false + +#### 示例 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"get\", \"metadata\": { \"blobName\": \"myblob\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "get", "metadata": { "blobName": "myblob" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文包含存储在 blob 对象中的值。如果启用,用户定义的元数据将作为 HTTP 头返回,格式为: + +`Metadata.key1: value1` +`Metadata.key2: value2` + +### 删除 blob + +要执行删除 blob 操作,请使用 `POST` 方法调用 Azure Blob Storage 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "delete", + "metadata": { + "blobName": "myblob" + } +} +``` + +元数据参数为: + +- `blobName` - blob 的名称 +- `deleteSnapshots` - (可选)如果 blob 具有关联的快照,则需要。指定以下两个选项之一: + - include: 删除基础 blob 及其所有快照 + - only: 仅删除 blob 的快照,而不删除 blob 本身 + +#### 示例 + +##### 删除 blob + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"delete\", \"metadata\": { \"blobName\": \"myblob\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "delete", "metadata": { "blobName": "myblob" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 仅删除 blob 快照 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"delete\", \"metadata\": { \"blobName\": \"myblob\", \"deleteSnapshots\": \"only\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "delete", "metadata": { "blobName": "myblob", "deleteSnapshots": "only" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 删除 blob 包括快照 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"delete\", \"metadata\": { \"blobName\": \"myblob\", \"deleteSnapshots\": \"include\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "delete", "metadata": { "blobName": "myblob", "deleteSnapshots": "include" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +如果成功,将返回 HTTP 204(无内容)和空正文。 + +### 列出 blobs + +要执行列出 blobs 操作,请使用 `POST` 方法调用 Azure Blob Storage 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "list", + "data": { + "maxResults": 10, + "prefix": "file", + "marker": "2!108!MDAwMDM1IWZpbGUtMDgtMDctMjAyMS0wOS0zOC01NS03NzgtMjEudHh0ITAwMDAyOCE5OTk5LTEyLTMxVDIzOjU5OjU5Ljk5OTk5OTlaIQ--", + "include": { + "snapshots": false, + "metadata": true, + "uncommittedBlobs": false, + "copy": false, + "deleted": false + } + } +} +``` + +数据参数为: + +- `maxResults` - (可选)指定要返回的最大 blob 数量,包括所有 BlobPrefix 元素。如果请求未指定 maxresults,服务器将返回最多 5,000 个项目。 +- `prefix` - (可选)过滤结果以仅返回名称以指定前缀开头的 blob。 +- `marker` - (可选)一个字符串值,用于标识下一个列表操作要返回的列表部分。如果返回的列表不完整,操作将在响应正文中返回一个标记值。然后可以在后续调用中使用标记值请求下一组列表项。 +- `include` - (可选)指定要在响应中包含的一个或多个数据集: + - snapshots: 指定快照应包含在枚举中。快照在响应中从旧到新列出。默认为:false + - metadata: 指定在响应中返回 blob 元数据。默认为:false + - uncommittedBlobs: 指定应在响应中包含已上传块但未使用 Put Block List 提交的 blob。默认为:false + - copy: 版本 2012-02-12 及更新版本。指定应在响应中包含与任何当前或先前的 Copy Blob 操作相关的元数据。默认为:false + - deleted: 版本 2017-07-29 及更新版本。指定应在响应中包含软删除的 blob。默认为:false + +#### 响应 + +响应正文包含找到的块列表以及以下 HTTP 头: + +`Metadata.marker: 2!108!MDAwMDM1IWZpbGUtMDgtMDctMjAyMS0wOS0zOC0zNC04NjctMTEudHh0ITAwMDAyOCE5OTk5LTEyLTMxVDIzOjU5OjU5Ljk5OTk5OTlaIQ--` +`Metadata.number: 10` + +- `marker` - 下一个标记,可在后续调用中使用以请求下一组列表项。请参阅绑定输入的数据属性上的标记描述。 +- `number` - 找到的 blob 数量 + +blob 列表将作为 JSON 数组返回,格式如下: + +```json +[ + { + "XMLName": { + "Space": "", + "Local": "Blob" + }, + "Name": "file-08-07-2021-09-38-13-776-1.txt", + "Deleted": false, + "Snapshot": "", + "Properties": { + "XMLName": { + "Space": "", + "Local": "Properties" + }, + "CreationTime": "2021-07-08T07:38:16Z", + "LastModified": "2021-07-08T07:38:16Z", + "Etag": "0x8D941E3593C6573", + "ContentLength": 1, + "ContentType": "application/octet-stream", + "ContentEncoding": "", + "ContentLanguage": "", + "ContentMD5": "xMpCOKC5I4INzFCab3WEmw==", + "ContentDisposition": "", + "CacheControl": "", + "BlobSequenceNumber": null, + "BlobType": "BlockBlob", + "LeaseStatus": "unlocked", + "LeaseState": "available", + "LeaseDuration": "", + "CopyID": null, + "CopyStatus": "", + "CopySource": null, + "CopyProgress": null, + "CopyCompletionTime": null, + "CopyStatusDescription": null, + "ServerEncrypted": true, + "IncrementalCopy": null, + "DestinationSnapshot": null, + "DeletedTime": null, + "RemainingRetentionDays": null, + "AccessTier": "Hot", + "AccessTierInferred": true, + "ArchiveStatus": "", + "CustomerProvidedKeySha256": null, + "AccessTierChangeTime": null + }, + "Metadata": null + } +] +``` + +## 元数据信息 + +默认情况下,Azure Blob Storage 输出绑定会自动生成一个 UUID 作为 blob 文件名,并且不会分配任何系统或自定义元数据。可以在消息的元数据属性中进行配置(全部可选)。 + +发布到 Azure Blob Storage 输出绑定的应用程序应发送以下格式的消息: + +```json +{ + "data": "file content", + "metadata": { + "blobName" : "filename.txt", + "contentType" : "text/plain", + "contentMD5" : "vZGKbMRDAnMs4BIwlXaRvQ==", + "contentEncoding" : "UTF-8", + "contentLanguage" : "en-us", + "contentDisposition" : "attachment", + "cacheControl" : "no-cache", + "custom" : "hello-world" + }, + "operation": "create" +} +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/cloudflare-queues.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/cloudflare-queues.md new file mode 100644 index 000000000..d3d229e24 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/cloudflare-queues.md @@ -0,0 +1,250 @@ +--- +type: docs +title: "Cloudflare Queues 绑定规范" +linkTitle: "Cloudflare Queues" +description: "关于 Cloudflare Queues 组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/cloudflare-queues/" + - "/zh-hans/operations/components/setup-bindings/supported-bindings/cfqueues/" +--- + +## 组件格式 + +此 Dapr 输出绑定用于与 [Cloudflare Queues](https://developers.cloudflare.com/queues/) 交互,**发布**新消息。目前,Dapr 还不支持从队列中消费消息。 + +要设置 Cloudflare Queues 绑定,需要创建一个类型为 `bindings.cloudflare.queues` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.cloudflare.queues + version: v1 + # 如果 Dapr 为您管理 Worker,请增加 initTimeout + initTimeout: "120s" + metadata: + # 已存在的 Cloudflare Queue 名称(必需) + - name: queueName + value: "" + # Worker 名称(必需) + - name: workerName + value: "" + # PEM 编码的私有 Ed25519 密钥(必需) + - name: key + value: | + -----BEGIN PRIVATE KEY----- + MC4CAQ... + -----END PRIVATE KEY----- + # Cloudflare 账户 ID(Dapr 管理 Worker 时必需) + - name: cfAccountID + value: "" + # Cloudflare 的 API 令牌(Dapr 管理 Worker 时必需) + - name: cfAPIToken + value: "" + # Worker 的 URL(如果 Worker 是在 Dapr 之外预创建的,则必需) + - name: workerUrl + value: "" +``` + +{{% alert title="警告" color="warning" %}} +上述示例使用明文字符串作为 secret。建议使用 secret 存储来存储 secret,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|-------|--------|---------| +| `queueName` | Y | 输出 | 已存在的 Cloudflare Queue 名称 | `"mydaprqueue"` +| `key` | Y | 输出 | Ed25519 私钥,PEM 编码 | *见上例* +| `cfAccountID` | Y/N | 输出 | Cloudflare 账户 ID。Dapr 管理 Worker 时必需。 | `"456789abcdef8b5588f3d134f74ac"def` +| `cfAPIToken` | Y/N | 输出 | Cloudflare 的 API 令牌。Dapr 管理 Worker 时必需。 | `"secret-key"` +| `workerUrl` | Y/N | 输出 | Worker 的 URL。如果 Worker 是在 Dapr 之外预配置的,则必需。 | `"https://mydaprqueue.mydomain.workers.dev"` + +> 当您配置 Dapr 为您创建 Worker 时,您可能需要为组件的 `initTimeout` 属性设置更长的值,以便为 Worker 脚本的部署留出足够的时间。例如:`initTimeout: "120s"` + +## 绑定支持 + +此组件支持具有以下操作的**输出绑定**: + +- `publish`(别名:`create`):将消息发布到队列。 + 传递给绑定的数据将按原样用于发布到队列的消息体。 + 此操作不接受任何元数据属性。 + +## 创建 Cloudflare Queue + +要使用此组件,您必须在 Cloudflare 账户中创建一个 Cloudflare Queue。 + +您可以通过以下两种方式创建新队列: + + +- 使用 [Cloudflare 仪表板](https://dash.cloudflare.com/) +- 使用 [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/): + + ```sh + # 如果需要,首先使用 `npx wrangler login` 进行身份验证 + npx wrangler queues create + # 例如:`npx wrangler queues create myqueue` + ``` + + +## 配置 Worker + +由于 Cloudflare Queues 只能通过在 Workers 上运行的脚本访问,Dapr 需要通过维护一个 Worker 来与队列通信。 + +Dapr 可以自动为您管理 Worker,或者您可以自行预配置一个 Worker。在 [workerd](https://github.com/cloudflare/workerd) 上运行时,预配置 Worker 是唯一支持的选项。 + +{{% alert title="重要" color="warning" %}} +为每个 Dapr 组件使用单独的 Worker。不要为不同的 Cloudflare Queues 绑定使用相同的 Worker 脚本,也不要为 Dapr 中的不同 Cloudflare 组件(例如 Workers KV 状态存储和 Queues 绑定)使用相同的 Worker 脚本。 +{{% /alert %}} + +{{< tabs "让 Dapr 管理 Worker" "手动预配置 Worker 脚本" >}} + +{{% codetab %}} + + +如果您希望让 Dapr 为您管理 Worker,您需要提供以下 3 个元数据选项: + + +- **`workerName`**:Worker 脚本的名称。这将是您的 Worker URL 的第一部分。例如,如果为您的 Cloudflare 账户配置的 "workers.dev" 域是 `mydomain.workers.dev`,并且您将 `workerName` 设置为 `mydaprqueue`,则 Dapr 部署的 Worker 将可在 `https://mydaprqueue.mydomain.workers.dev` 访问。 +- **`cfAccountID`**:您的 Cloudflare 账户 ID。您可以在登录 [Cloudflare 仪表板](https://dash.cloudflare.com/) 后在浏览器的 URL 栏中找到此 ID,ID 是 `dash.cloudflare.com` 之后的十六进制字符串。例如,如果 URL 是 `https://dash.cloudflare.com/456789abcdef8b5588f3d134f74acdef`,则 `cfAccountID` 的值为 `456789abcdef8b5588f3d134f74acdef`。 +- **`cfAPIToken`**:具有创建和编辑 Workers 权限的 API 令牌。您可以在 Cloudflare 仪表板的 "我的个人资料" 部分的 ["API 令牌" 页面](https://dash.cloudflare.com/profile/api-tokens) 中创建它: + 1. 点击 **"创建令牌"**。 + 1. 选择 **"编辑 Cloudflare Workers"** 模板。 + 1. 按照屏幕上的说明生成新的 API 令牌。 + + +当 Dapr 配置为为您管理 Worker 时,当 Dapr 运行时启动时,它会检查 Worker 是否存在并且是最新的。如果 Worker 不存在,或者使用的是过时版本,Dapr 会自动为您创建或升级它。 + +{{% /codetab %}} + +{{% codetab %}} + + +如果您不希望授予 Dapr 部署 Worker 脚本的权限,您可以手动预配置一个 Worker 供 Dapr 使用。请注意,如果您有多个 Dapr 组件通过 Worker 与 Cloudflare 服务交互,您需要为每个组件创建一个单独的 Worker。 + +要手动预配置 Worker 脚本,您需要在本地计算机上安装 Node.js。 + +1. 创建一个新文件夹以放置 Worker 的源代码,例如:`daprworker`。 +2. 如果尚未进行身份验证,请使用 Wrangler(Cloudflare Workers CLI)进行身份验证:`npx wrangler login`。 +3. 在新创建的文件夹中,创建一个新的 `wrangler.toml` 文件,内容如下,并根据需要填写缺失的信息: + + ```toml + # 您的 Worker 名称,例如 "mydaprqueue" + name = "" + + # 不要更改这些选项 + main = "worker.js" + compatibility_date = "2022-12-09" + usage_model = "bundled" + + [vars] + # 将此设置为 Ed25519 密钥的**公钥**部分,PEM 编码(用 `\n` 替换换行符)。 + # 示例: + # PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\nMCowB...=\n-----END PUBLIC KEY----- + PUBLIC_KEY = "" + # 将此设置为您的 Worker 名称(与上面 "name" 属性的值相同),例如 "mydaprqueue"。 + TOKEN_AUDIENCE = "" + + # 将接下来的两个值设置为您的队列名称,例如 "myqueue"。 + # 请注意,它们都将设置为相同的值。 + [[queues.producers]] + queue = "" + binding = "" + ``` + + > 注意:请参阅下一节了解如何生成 Ed25519 密钥对。确保在部署 Worker 时使用密钥的**公钥**部分! + +4. 将 Worker 的(预编译和最小化的)代码复制到 `worker.js` 文件中。您可以使用以下命令执行此操作: + + ```sh + # 设置为您正在使用的 Dapr 版本 + DAPR_VERSION="release-{{% dapr-latest-version short="true" %}}" + curl -LfO "https://raw.githubusercontent.com/dapr/components-contrib/${DAPR_VERSION}/internal/component/cloudflare/workers/code/worker.js" + ``` + +5. 使用 Wrangler 部署 Worker: + + ```sh + npx wrangler publish + ``` + +一旦您的 Worker 部署完成,您需要使用以下两个元数据选项初始化组件: + +- **`workerName`**:Worker 脚本的名称。这是您在 `wrangler.toml` 文件中设置的 `name` 属性的值。 +- **`workerUrl`**:已部署 Worker 的 URL。`npx wrangler` 命令将向您显示完整的 URL,例如 `https://mydaprqueue.mydomain.workers.dev`。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 生成 Ed25519 密钥对 + +所有 Cloudflare Workers 都在公共互联网监听,因此 Dapr 需要使用额外的身份验证和数据保护措施,以确保没有其他人或应用程序可以与您的 Worker(以及您的 Cloudflare Queue)通信。这些措施包括行业标准措施,例如: + +- Dapr 向 Worker 发出的所有请求都通过一个持有者令牌(技术上是一个 JWT)进行身份验证,该令牌由 Ed25519 密钥签名。 +- Dapr 与您的 Worker 之间的所有通信都通过加密连接进行,使用 TLS(HTTPS)。 +- 持有者令牌在每次请求时生成,并且仅在短时间内有效(目前为一分钟)。 + +为了让 Dapr 发出持有者令牌,并让您的 Worker 验证它们,您需要生成一个新的 Ed25519 密钥对。以下是使用 OpenSSL 或 step CLI 生成密钥对的示例。 + +{{< tabs "使用 OpenSSL 生成" "使用 step CLI 生成" >}} + +{{% codetab %}} + + +> 自 OpenSSL 1.1.0 起支持生成 Ed25519 密钥,因此如果您使用的是旧版本的 OpenSSL,以下命令将无法工作。 + +> Mac 用户注意:在 macOS 上,Apple 提供的 "openssl" 二进制文件实际上基于 LibreSSL,截至撰写本文时不支持 Ed25519 密钥。如果您使用 macOS,可以使用 step CLI,或者从 Homebrew 安装 OpenSSL 3.0,使用 `brew install openssl@3`,然后在以下命令中将 `openssl` 替换为 `$(brew --prefix)/opt/openssl@3/bin/openssl`。 + +您可以使用 OpenSSL 生成新的 Ed25519 密钥对: + +```sh +openssl genpkey -algorithm ed25519 -out private.pem +openssl pkey -in private.pem -pubout -out public.pem +``` + +> 在 macOS 上,使用 Homebrew 的 openssl@3: +> +> ```sh +> $(brew --prefix)/opt/openssl@3/bin/openssl genpkey -algorithm ed25519 -out private.pem +> $(brew --prefix)/opt/openssl@3/bin/openssl pkey -in private.pem -pubout -out public.pem +> ``` + +{{% /codetab %}} + +{{% codetab %}} + + +如果您还没有 step CLI,请按照[官方说明](https://smallstep.com/docs/step-cli/installation)安装它。 + +接下来,您可以使用 step CLI 生成新的 Ed25519 密钥对: + +```sh +step crypto keypair \ + public.pem private.pem \ + --kty OKP --curve Ed25519 \ + --insecure --no-password +``` + +{{% /codetab %}} + +{{< /tabs >}} + +无论您如何生成密钥对,按照上述说明,您将拥有两个文件: + +- `private.pem` 包含密钥的私有部分;使用此文件的内容作为组件元数据的 **`key`** 属性。 +- `public.pem` 包含密钥的公有部分,您仅在手动部署 Worker 时需要它(如上一节中的说明)。 + +{{% alert title="警告" color="warning" %}} +保护密钥的私有部分,并将其视为 secret 值! +{{% /alert %}} + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) +- [Cloudflare Queues 文档](https://developers.cloudflare.com/queues/) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/commercetools.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/commercetools.md new file mode 100644 index 000000000..388b0f11f --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/commercetools.md @@ -0,0 +1,67 @@ +--- +type: docs +title: "commercetools GraphQL 绑定说明" +linkTitle: "commercetools GraphQL" +description: "commercetools GraphQL 绑定组件的详细介绍" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/commercetools/" +--- + +## 组件格式 + +要配置 commercetools GraphQL 绑定,请创建一个类型为 `bindings.commercetools` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.commercetools + version: v1 + metadata: + - name: region # 必需。 + value: "region" + - name: provider # 必需。 + value: "gcp" + - name: projectKey # 必需。 + value: "" + - name: clientID # 必需。 + value: "*****************" + - name: clientSecret # 必需。 + value: "*****************" + - name: scopes # 必需。 + value: "" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中使用了明文字符串作为密钥。建议使用密钥存储来保存这些机密信息,具体方法请参见[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `region` | Y | 输出 | commercetools 项目的区域 | `"europe-west1"` | +| `provider` | Y | 输出 | 云提供商,可以是 gcp 或 aws | `"gcp"`, `"aws"` | +| `projectKey` | Y | 输出 | commercetools 项目密钥 | | +| `clientID` | Y | 输出 | 项目的 commercetools 客户端 ID | | +| `clientSecret` | Y | 输出 | 项目的 commercetools 客户端密钥 | | +| `scopes` | Y | 输出 | 项目的 commercetools 范围 | `"manage_project:project-key"` | + +更多信息请参见 [commercetools - 创建 API 客户端](https://docs.commercetools.com/getting-started/create-api-client#create-an-api-client) 和 [commercetools - 区域](https://docs.commercetools.com/api/general-concepts#regions)。 + +## 绑定支持 + +此组件支持以下操作的**输出绑定**: + +- `create` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [Bindings 构建块]({{< ref bindings >}}) +- [操作指南:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [操作指南:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [Bindings API 参考]({{< ref bindings_api.md >}}) +- [示例应用](https://github.com/dapr/samples/tree/master/commercetools-graphql-sample),利用 commercetools 绑定进行示例 GraphQL 查询 \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/cosmosdb.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/cosmosdb.md new file mode 100644 index 000000000..80e26f302 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/cosmosdb.md @@ -0,0 +1,133 @@ +--- +type: docs +title: "Azure Cosmos DB (SQL API) 绑定说明" +linkTitle: "Azure Cosmos DB (SQL API)" +description: "关于 Azure Cosmos DB (SQL API) 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/cosmosdb/" +--- + +## 组件配置格式 + +要设置 Azure Cosmos DB 绑定,请创建一个类型为 `bindings.azure.cosmosdb` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.azure.cosmosdb + version: v1 + metadata: + - name: url + value: "https://******.documents.azure.com:443/" + - name: masterKey + value: "*****" + - name: database + value: "OrderDb" + - name: collection + value: "Orders" + - name: partitionKey + value: "" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中,secret 以明文字符串形式使用。建议使用 secret 存储来存储 secret,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|--------|---------|---------| +| `url` | Y | 输出 | Cosmos DB 的 URL | `"https://******.documents.azure.com:443/"` | +| `masterKey` | Y | 输出 | Cosmos DB 帐户的主密钥 | `"master-key"` | +| `database` | Y | 输出 | Cosmos DB 数据库的名称 | `"OrderDb"` | +| `collection` | Y | 输出 | 数据库容器的名称。 | `"Orders"` | +| `partitionKey` | Y | 输出 | 从文档负载中提取的分区键的名称。此名称必须与创建 Cosmos DB 容器时指定的分区键一致。 | `"OrderId"`, `"message"` | + +有关更多信息,请参阅 [Azure Cosmos DB 资源模型](https://docs.microsoft.com/azure/cosmos-db/account-databases-containers-items)。 + +### Microsoft Entra 身份认证 + +Azure Cosmos DB 绑定组件支持使用所有 Microsoft Entra 身份认证机制。有关更多信息以及根据选择的 Microsoft Entra 身份认证机制提供的相关组件元数据字段,请参阅[认证到 Azure 的文档]({{< ref authenticating-azure.md >}})。 + +您可以在[下面的部分](#setting-up-cosmos-db-for-authenticating-with-azure-ad)阅读有关使用 Azure AD 认证设置 Cosmos DB 的更多信息。 + +## 绑定支持 + +此组件支持具有以下操作的**输出绑定**: + +- `create` + +## 生产环境最佳实践 + +Azure Cosmos DB 在单个 Azure Cosmos DB 帐户中的所有数据库之间共享严格的元数据请求速率限制。新的 Azure Cosmos DB 连接会占用允许的请求速率限制的大部分。(请参阅 [Cosmos DB 文档](https://docs.microsoft.com/azure/cosmos-db/sql/troubleshoot-request-rate-too-large#recommended-solution-3)) + +因此,必须采取一些策略来避免同时建立新的 Azure Cosmos DB 连接: + +- 确保应用程序的 sidecar 仅在需要时加载 Azure Cosmos DB 组件,以避免不必要的数据库连接。这可以通过[将组件限定到特定应用程序]({{< ref component-scopes.md >}}#application-access-to-components-with-scopes)来实现。 +- 选择按顺序部署或启动应用程序的部署策略,以最大限度地减少对 Azure Cosmos DB 帐户的新连接突发。 +- 避免为不相关的数据库或系统(即使在 Dapr 之外)重用同一个 Azure Cosmos DB 帐户。不同的 Azure Cosmos DB 帐户具有不同的速率限制。 +- 增加 `initTimeout` 值,以允许组件在 sidecar 初始化期间重试连接到 Azure Cosmos DB,最长可达 5 分钟。默认值为 `5s`,应增加。当使用 Kubernetes 时,增加此值可能还需要更新您的[就绪和存活探针](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/)。 + +```yaml +spec: + type: bindings.azure.cosmosdb + version: v1 + initTimeout: 5m + metadata: +``` + +## 数据格式 + +**输出绑定** `create` 操作要求在每个要创建的文档的负载中存在以下键: + +- `id`: 要创建的文档的唯一 ID +- ``: 在组件定义中通过 `spec.partitionKey` 指定的分区键的名称。这也必须与创建 Cosmos DB 容器时指定的分区键一致。 + +## 设置 Cosmos DB 以使用 Azure AD 进行认证 + +使用 Dapr Cosmos DB 绑定并使用 Azure AD 进行认证时,您需要执行一些额外步骤来设置您的环境。 + +先决条件: + +- 您需要根据[认证到 Azure]({{< ref authenticating-azure.md >}})页面中的说明创建一个服务主体。您需要服务主体的 ID 以用于下面的命令(请注意,这与应用程序的客户端 ID 或您在元数据中使用的 `azureClientId` 值不同)。 +- [Azure CLI](https://docs.microsoft.com/cli/azure/install-azure-cli) +- [jq](https://stedolan.github.io/jq/download/) +- 以下脚本针对 bash 或 zsh shell 进行了优化 + +> 使用 Cosmos DB 绑定时,您**不需要**像在 Cosmos DB state 存储的情况下那样创建存储过程。 + +### 授予您的 Azure AD 应用程序访问 Cosmos DB 的权限 + +> 您可以在[官方文档](https://docs.microsoft.com/azure/cosmos-db/how-to-setup-rbac)中找到更多信息,包括分配更细粒度权限的说明。 + +为了授予您的应用程序访问存储在 Cosmos DB 中的数据的权限,您需要为 Cosmos DB 数据平面分配一个自定义角色。在此示例中,您将使用内置角色 "Cosmos DB Built-in Data Contributor",该角色授予您的应用程序对数据的完全读写访问权限;您可以选择按照官方文档中的说明创建自定义的、精细调整的角色。 + +```sh +# 包含您的 Cosmos DB 的资源组的名称 +RESOURCE_GROUP="..." +# 您的 Cosmos DB 帐户的名称 +ACCOUNT_NAME="..." +# 您的服务主体对象的 ID +PRINCIPAL_ID="..." +# "Cosmos DB Built-in Data Contributor" 角色的 ID +# 您也可以使用自定义角色的 ID +ROLE_ID="00000000-0000-0000-0000-000000000002" + +az cosmosdb sql role assignment create \ + --account-name "$ACCOUNT_NAME" \ + --resource-group "$RESOURCE_GROUP" \ + --scope "/" \ + --principal-id "$PRINCIPAL_ID" \ + --role-definition-id "$ROLE_ID" +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/cosmosdbgremlinapi.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/cosmosdbgremlinapi.md new file mode 100644 index 000000000..1aebcba54 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/cosmosdbgremlinapi.md @@ -0,0 +1,66 @@ +--- +type: docs +title: "Azure Cosmos DB (Gremlin API) 绑定组件说明" +linkTitle: "Azure Cosmos DB (Gremlin API)" +description: "关于 Azure Cosmos DB (Gremlin API) 绑定组件的详细文档" +--- + +## 组件格式 + +要配置 Azure Cosmos DB (Gremlin API) 绑定,请创建一个类型为 `bindings.azure.cosmosdb.gremlinapi` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.azure.cosmosdb.gremlinapi + version: v1 + metadata: + - name: url + value: "wss://******.gremlin.cosmos.azure.com:443/" + - name: masterKey + value: "*****" + - name: username + value: "*****" +``` + +{{% alert title="警告" color="warning" %}} +上述示例使用了明文形式的字符串作为密钥。建议使用密钥存储来存储密钥,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 是否必需 | 支持的绑定类型 | 说明 | 示例 | +|--------------------|:--------:|--------|---------|---------| +| `url` | Y | 输出 | Gremlin API 的 Cosmos DB URL | `"wss://******.gremlin.cosmos.azure.com:443/"` | +| `masterKey` | Y | 输出 | Cosmos DB 账户的主密钥 | `"masterKey"` | +| `username` | Y | 输出 | Cosmos DB 数据库的用户名 | `"/dbs//colls/"` | + +更多信息请参见[快速入门:使用 Gremlin 的 Azure Cosmos 图数据库](https://docs.microsoft.com/azure/cosmos-db/graph/create-graph-console)。 + +## 绑定支持 + +此组件支持以下操作的**输出绑定**: + +- `query` + +## 请求示例负载 + +```json +{ + "data": { + "gremlin": "g.V().count()" + }, + "operation": "query" +} +``` + +## 相关文档 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [bindings 构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用bindings与外部资源接口]({{< ref howto-bindings.md >}}) +- [bindings API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/cron.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/cron.md new file mode 100644 index 000000000..2e2efea2a --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/cron.md @@ -0,0 +1,86 @@ +--- +type: docs +title: "Cron 绑定规范" +linkTitle: "Cron" +description: "关于 cron 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/cron/" +--- + +## 组件格式 + +要设置 cron 绑定,需要创建一个类型为 `bindings.cron` 的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.cron + version: v1 + metadata: + - name: schedule + value: "@every 15m" # 有效的 cron 调度 + - name: direction + value: "input" +``` + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|-------|--------|---------| +| `schedule` | Y | 输入| 使用的有效 cron 调度。详见[此处](#schedule-format) | `"@every 15m"` +| `direction` | N | 输入| 绑定的方向 | `"input"` + +### 调度格式 + +Dapr cron 绑定支持以下格式: + +| 字符 | 描述 | 可接受的值 | +|:---------:|-------------------|-----------------------------------------------| +| 1 | 秒 | 0 到 59,或 * | +| 2 | 分 | 0 到 59,或 * | +| 3 | 小时 | 0 到 23,或 * (UTC) | +| 4 | 月中的某天 | 1 到 31,或 * | +| 5 | 月 | 1 到 12,或 * | +| 6 | 星期几 | 0 到 7 (其中 0 和 7 代表星期日),或 * | + +例如: + +* `30 * * * * *` - 每 30 秒执行一次 +* `0 15 * * * *` - 每 15 分钟执行一次 +* `0 30 3-6,20-23 * * *` - 在凌晨 3 点到 6 点和晚上 8 点到 11 点之间,每小时的半点执行一次 +* `CRON_TZ=America/New_York 0 30 04 * * *` - 每天纽约时间凌晨 4:30 执行一次 + +> 您可以在[这里](https://en.wikipedia.org/wiki/Cron)了解更多关于 cron 和支持的格式。 + +为了便于使用,Dapr cron 绑定还支持一些快捷方式: + +* `@every 15s` 其中 `s` 是秒,`m` 是分钟,`h` 是小时 +* `@daily` 或 `@hourly` 从绑定初始化时开始按该周期运行 + +## 监听 cron 绑定 + +设置 cron 绑定后,您只需监听与组件名称匹配的端点。假设 [NAME] 是 `scheduled`。这将作为一个 HTTP `POST` 请求。下面的示例展示了一个简单的 Node.js Express 应用程序如何在 `/scheduled` 端点接收调用并向控制台写入消息。 + +```js +app.post('/scheduled', async function(req, res){ + console.log("scheduled endpoint called", req.body) + res.status(200).send() +}); +``` + +运行此代码时,请注意 `/scheduled` 端点每十五分钟由 Dapr sidecar 调用。 + +## 绑定支持 + +此组件支持**输入**绑定接口。 + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [操作指南:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [操作指南:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/dynamodb.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/dynamodb.md new file mode 100644 index 000000000..e39a1cdbf --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/dynamodb.md @@ -0,0 +1,68 @@ +--- +type: docs +title: "AWS DynamoDB 绑定说明" +linkTitle: "AWS DynamoDB" +description: "关于 AWS DynamoDB 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/dynamodb/" +--- + +## 组件配置格式 + +要配置 AWS DynamoDB 绑定,请创建一个类型为 `bindings.aws.dynamodb` 的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +有关身份验证相关属性的信息,请参阅[身份验证到 AWS]({{< ref authenticating-aws.md >}}) + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.aws.dynamodb + version: v1 + metadata: + - name: table + value: "items" + - name: region + value: "us-west-2" + - name: accessKey + value: "*****************" + - name: secretKey + value: "*****************" + - name: sessionToken + value: "*****************" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中使用了明文字符串作为密钥。建议使用密钥存储来保存密钥,详情请参阅[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `table` | Y | 输出 | DynamoDB 表名 | `"items"` | +| `region` | Y | 输出 | AWS DynamoDB 实例所在的特定 AWS 区域 | `"us-east-1"` | +| `accessKey` | Y | 输出 | 访问此资源的 AWS 访问密钥 | `"key"` | +| `secretKey` | Y | 输出 | 访问此资源的 AWS 秘密访问密钥 | `"secretAccessKey"` | +| `sessionToken` | N | 输出 | 使用的 AWS 会话令牌 | `"sessionToken"` | + +{{% alert title="重要" color="warning" %}} +当在 EKS(AWS Kubernetes)上与应用程序一起运行 Dapr sidecar(daprd)时,如果您使用的节点/Pod 已经附加了定义访问 AWS 资源的 IAM 策略,则**不需要**在组件配置中提供 AWS 访问密钥、秘密密钥和令牌。 +{{% /alert %}} + +## 绑定支持 + +此组件支持具有以下操作的**输出绑定**: + +- `create` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [操作指南:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [操作指南:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) +- [身份验证到 AWS]({{< ref authenticating-aws.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/eventgrid.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/eventgrid.md new file mode 100644 index 000000000..dbed2526a --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/eventgrid.md @@ -0,0 +1,322 @@ +--- +type: docs +title: "Azure Event Grid 绑定规范" +linkTitle: "Azure Event Grid" +description: "关于 Azure Event Grid 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/eventgrid/" +--- + +## 组件格式 + +要设置 Azure Event Grid 绑定,需创建一个类型为 `bindings.azure.eventgrid` 的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +有关 Azure Event Grid 的更多信息,请访问[此处](https://docs.microsoft.com/azure/event-grid/)。 + +```yml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.azure.eventgrid + version: v1 + metadata: + # 必需的输出绑定元数据 + - name: accessKey + value: "[AccessKey]" + - name: topicEndpoint + value: "[TopicEndpoint]" + # 必需的输入绑定元数据 + - name: azureTenantId + value: "[AzureTenantId]" + - name: azureSubscriptionId + value: "[AzureSubscriptionId]" + - name: azureClientId + value: "[ClientId]" + - name: azureClientSecret + value: "[ClientSecret]" + - name: subscriberEndpoint + value: "[SubscriberEndpoint]" + - name: handshakePort + # 确保以字符串形式传递,值需加上引号 + value: "[HandshakePort]" + - name: scope + value: "[Scope]" + # 可选的输入绑定元数据 + - name: eventSubscriptionName + value: "[EventSubscriptionName]" + # 可选元数据 + - name: direction + value: "input, output" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中使用了明文字符串作为密钥。建议使用密钥存储来保护密钥,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `accessKey` | Y | 输出 | 用于向自定义主题发布 Event Grid 事件的访问密钥 | `"accessKey"` | +| `topicEndpoint` | Y | 输出 | 此输出绑定应发布事件的主题端点 | `"topic-endpoint"` | +| `azureTenantId` | Y | 输入 | Event Grid 资源的 Azure 租户 ID | `"tenentID"` | +| `azureSubscriptionId` | Y | 输入 | Event Grid 资源的 Azure 订阅 ID | `"subscriptionId"` | +| `azureClientId` | Y | 输入 | 绑定用于创建或更新 Event Grid 事件订阅并验证传入消息的客户端 ID | `"clientId"` | +| `azureClientSecret` | Y | 输入 | 绑定用于创建或更新 Event Grid 事件订阅并验证传入消息的客户端密钥 | `"clientSecret"` | +| `subscriberEndpoint` | Y | 输入 | Webhook 的 HTTPS 端点,Event Grid 将事件(格式化为 Cloud Events)发送到此处。如果您不在入口处重写 URL,则应采用以下格式:`"https://[YOUR HOSTNAME]/"`
如果在本地计算机上进行测试,可以使用类似 [ngrok](https://ngrok.com) 的工具创建公共端点。 | `"https://[YOUR HOSTNAME]/"` | +| `handshakePort` | Y | 输入 | 输入绑定在接收 Webhook 事件时监听的容器端口 | `"9000"` | +| `scope` | Y | 输入 | 需要创建或更新事件订阅的资源标识符。有关更多详细信息,请参阅[范围部分](#scope) | `"/subscriptions/{subscriptionId}/"` | +| `eventSubscriptionName` | N | 输入 | 事件订阅的名称。事件订阅名称必须在 3 到 64 个字符之间,并且只能使用字母数字字符 | `"name"` | +| `direction` | N | 输入/输出 | 绑定的方向 | `"input"`, `"output"`, `"input, output"` | + +### 范围 + +范围是需要创建或更新事件订阅的资源标识符。范围可以是订阅、资源组、属于资源提供程序命名空间的顶级资源或 Event Grid 主题。例如: + +- `/subscriptions/{subscriptionId}/` 表示一个订阅 +- `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}` 表示一个资源组 +- `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName}` 表示一个资源 +- `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.EventGrid/topics/{topicName}` 表示一个 Event Grid 主题 + +> 大括号 {} 中的值应替换为实际值。 + +## 绑定支持 + +此组件支持 **输入和输出** 绑定接口。 + +此组件支持以下操作的 **输出绑定**: + +- `create`: 在 Event Grid 主题上发布消息 + +## 接收事件 + +您可以使用 Event Grid 绑定从各种来源和操作接收事件。[了解有关与 Event Grid 一起使用的所有可用事件源和处理程序的更多信息。](https://learn.microsoft.com/azure/event-grid/overview) + +在下表中,您可以找到可以引发事件的 Dapr 组件列表。 + +| 事件源 | Dapr 组件 | +| ------------- | --------------- | +| [Azure Blob 存储](https://learn.microsoft.com/azure/storage/blobs/) | [Azure Blob 存储绑定]({{< ref blobstorage.md >}})
[Azure Blob 存储状态存储]({{< ref setup-azure-blobstorage.md >}}) | +| [Azure Redis 缓存](https://learn.microsoft.com/azure/azure-cache-for-redis/cache-overview) | [Redis 绑定]({{< ref redis.md >}})
[Redis pub/sub]({{< ref setup-redis-pubsub.md >}}) | +| [Azure Event Hubs](https://learn.microsoft.com/azure/event-hubs/event-hubs-about) | [Azure Event Hubs pub/sub]({{< ref setup-azure-eventhubs.md >}})
[Azure Event Hubs 绑定]({{< ref eventhubs.md >}}) | +| [Azure IoT Hub](https://learn.microsoft.com/azure/iot-hub/iot-concepts-and-iot-hub) | [Azure Event Hubs pub/sub]({{< ref setup-azure-eventhubs.md >}})
[Azure Event Hubs 绑定]({{< ref eventhubs.md >}}) | +| [Azure Service Bus](https://learn.microsoft.com/azure/service-bus-messaging/service-bus-messaging-overview) | [Azure Service Bus 绑定]({{< ref servicebusqueues.md >}})
[Azure Service Bus pub/sub 主题]({{< ref setup-azure-servicebus-topics.md >}}) 和 [队列]({{< ref setup-azure-servicebus-queues.md >}}) | +| [Azure SignalR 服务](https://learn.microsoft.com/azure/azure-signalr/signalr-overview) | [SignalR 绑定]({{< ref signalr.md >}}) | + +## Microsoft Entra ID 凭据 + +Azure Event Grid 绑定需要 Microsoft Entra ID 应用程序和服务主体,原因有两个: + +- 在 Dapr 启动时创建一个[事件订阅](https://docs.microsoft.com/azure/event-grid/concepts#event-subscriptions)(如果 Dapr 配置更改则更新它) +- 验证 Event Hubs 传递给您应用程序的消息。 + +要求: + +- 安装 [Azure CLI](https://docs.microsoft.com/cli/azure/install-azure-cli)。 +- 安装 [PowerShell 7](https://learn.microsoft.com/powershell/scripting/install/installing-powershell)。 +- 为 PowerShell 安装 [Az 模块](https://learn.microsoft.com/powershell/azure/install-az-ps): + `Install-Module Az -Scope CurrentUser -Repository PSGallery -Force` +- 为 PowerShell 安装 [Microsoft.Graph 模块](https://learn.microsoft.com/powershell/microsoftgraph/installation): + `Install-Module Microsoft.Graph -Scope CurrentUser -Repository PSGallery -Force` + +对于第一个目的,您需要[创建一个 Azure 服务主体](https://learn.microsoft.com/azure/active-directory/develop/howto-create-service-principal-portal)。创建后,记下 Microsoft Entra ID 应用程序的 **clientID**(一个 UUID),并使用 Azure CLI 运行以下脚本: + +```bash +# 设置您创建的应用的客户端 ID +CLIENT_ID="..." +# 资源的范围,通常格式为: +# `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.EventGrid/topics/{topicName}` +SCOPE="..." + +# 首先确保 Azure 资源管理器提供程序已为 Event Grid 注册 +az provider register --namespace "Microsoft.EventGrid" +az provider show --namespace "Microsoft.EventGrid" --query "registrationState" +# 为 SP 授予所需权限,以便它可以为 Event Grid 创建事件订阅 +az role assignment create --assignee "$CLIENT_ID" --role "EventGrid EventSubscription Contributor" --scopes "$SCOPE" +``` + +对于第二个目的,首先下载一个脚本: + +```sh +curl -LO "https://raw.githubusercontent.com/dapr/components-contrib/master/.github/infrastructure/conformance/azure/setup-eventgrid-sp.ps1" +``` + +然后,**使用 PowerShell** (`pwsh`) 运行: + +```powershell +# 设置您创建的应用的客户端 ID +$clientId = "..." + +# 使用 Microsoft Graph 进行身份验证 +# 如果需要,您可能需要在下一个命令中添加 -TenantId 标志 +Connect-MgGraph -Scopes "Application.Read.All","Application.ReadWrite.All" +./setup-eventgrid-sp.ps1 $clientId +``` + +> 注意:如果您的目录没有应用程序 "Microsoft.EventGrid" 的服务主体,您可能需要运行命令 `Connect-MgGraph` 并以 Microsoft Entra ID 租户的管理员身份登录(这与 Microsoft Entra ID 目录的权限有关,而不是 Azure 订阅)。否则,请要求您的租户管理员登录并运行此 PowerShell 命令:`New-MgServicePrincipal -AppId "4962773b-9cdb-44cf-a8bf-237846a00ab7"`(UUID 是一个常量) + +## 本地测试 + +- 安装 [ngrok](https://ngrok.com/download) +- 使用自定义端口在本地运行,例如 `9000`,用于握手 + +```bash +# 以端口 9000 为例 +ngrok http --host-header=localhost 9000 +``` + +- 将 ngrok 的 HTTPS 端点和自定义端口配置为输入绑定元数据 +- 运行 Dapr + +```bash +# 以 .NET core web api 和 Dapr 的默认端口为例 +dapr run --app-id dotnetwebapi --app-port 5000 --dapr-http-port 3500 dotnet run +``` + +## 在 Kubernetes 上测试 + +Azure Event Grid 需要一个有效的 HTTPS 端点用于自定义 webhooks;不接受自签名证书。为了启用从公共互联网到您应用程序的 Dapr sidecar 的流量,您需要启用 Dapr 的入口控制器。关于这个主题有一篇不错的文章:[Kubernetes NGINX ingress controller with Dapr](https://carlos.mendible.com/2020/04/05/kubernetes-nginx-ingress-controller-with-dapr/)。 + +首先,为 Dapr 注解创建一个 `dapr-annotations.yaml` 文件: + +```yaml +controller: + podAnnotations: + dapr.io/enabled: "true" + dapr.io/app-id: "nginx-ingress" + dapr.io/app-port: "80" +``` + +然后使用注解通过 Helm 3 将 NGINX ingress 控制器安装到您的 Kubernetes 集群中: + +```bash +helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx +helm repo update +helm install nginx-ingress ingress-nginx/ingress-nginx -f ./dapr-annotations.yaml -n default +# 获取入口控制器的公共 IP +kubectl get svc -l component=controller -o jsonpath='Public IP is: {.items[0].status.loadBalancer.ingress[0].ip}{"\n"}' +``` + +如果部署到 Azure Kubernetes 服务,您可以按照[官方 Microsoft 文档的其余步骤](https://docs.microsoft.com/azure/aks/ingress-tls): + +- 向您的 DNS 区域添加 A 记录 +- 安装 cert-manager +- 创建 CA 集群颁发者 + +启用 Event Grid 和 Dapr 之间通信的最后一步是定义 `http` 和自定义端口到您应用程序的服务和 Kubernetes 中的 `ingress`。此示例使用 .NET Core web api 和 Dapr 默认端口以及用于握手的自定义端口 9000。 + +```yaml +# dotnetwebapi.yaml +kind: Service +apiVersion: v1 +metadata: + name: dotnetwebapi + labels: + app: dotnetwebapi +spec: + selector: + app: dotnetwebapi + ports: + - name: webapi + protocol: TCP + port: 80 + targetPort: 80 + - name: dapr-eventgrid + protocol: TCP + port: 9000 + targetPort: 9000 + type: ClusterIP + +--- + apiVersion: extensions/v1beta1 + kind: Ingress + metadata: + name: eventgrid-input-rule + annotations: + kubernetes.io/ingress.class: nginx + cert-manager.io/cluster-issuer: letsencrypt + spec: + tls: + - hosts: + - dapr. + secretName: dapr-tls + rules: + - host: dapr. + http: + paths: + - path: /api/events + backend: + serviceName: dotnetwebapi + servicePort: 9000 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dotnetwebapi + labels: + app: dotnetwebapi +spec: + replicas: 1 + selector: + matchLabels: + app: dotnetwebapi + template: + metadata: + labels: + app: dotnetwebapi + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "dotnetwebapi" + dapr.io/app-port: "5000" + spec: + containers: + - name: webapi + image: + ports: + - containerPort: 5000 + imagePullPolicy: Always +``` + +将绑定和应用程序(包括 ingress)部署到 Kubernetes + +```bash +# 部署 Dapr 组件 +kubectl apply -f eventgrid.yaml +# 部署您的应用程序和 Nginx ingress +kubectl apply -f dotnetwebapi.yaml +``` + +> **注意:** 此清单将所有内容部署到 Kubernetes 的默认命名空间。 + +#### 排查 Nginx 控制器可能出现的问题 + +初始部署后,“Dapr 化”的 Nginx 控制器可能会出现故障。要检查日志并修复问题(如果存在),请按照以下步骤操作。 + +```bash +$ kubectl get pods -l app=nginx-ingress + +NAME READY STATUS RESTARTS AGE +nginx-nginx-ingress-controller-649df94867-fp6mg 2/2 Running 0 51m +nginx-nginx-ingress-default-backend-6d96c457f6-4nbj5 1/1 Running 0 55m + +$ kubectl logs nginx-nginx-ingress-controller-649df94867-fp6mg nginx-ingress-controller + +# 如果您看到对 webhook 端点 '/api/events' 的调用记录了 503,请重启 pod +# .."OPTIONS /api/events HTTP/1.1" 503.. + +$ kubectl delete pod nginx-nginx-ingress-controller-649df94867-fp6mg + +# 再次检查日志 - 它应该开始返回 200 +# .."OPTIONS /api/events HTTP/1.1" 200.. +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/eventhubs.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/eventhubs.md new file mode 100644 index 000000000..7cb8ae45d --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/eventhubs.md @@ -0,0 +1,141 @@ +--- +type: docs +title: "Azure Event Hubs 绑定规范" +linkTitle: "Azure Event Hubs" +description: "关于 Azure Event Hubs 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/eventhubs/" +--- + +## 组件格式 + +要配置 Azure Event Hubs 绑定,需要创建一个类型为 `bindings.azure.eventhubs` 的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +请参考[此处](https://docs.microsoft.com/azure/event-hubs/event-hubs-dotnet-framework-getstarted-send)了解如何设置 Event Hub。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.azure.eventhubs + version: v1 + metadata: + # Hub 名称 ("topic") + - name: eventHub + value: "mytopic" + - name: consumerGroup + value: "myapp" + # connectionString 或 eventHubNamespace 必须提供其一 + # 在不使用 Microsoft Entra ID 的情况下,使用 connectionString + - name: connectionString + value: "Endpoint=sb://{EventHubNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key};EntityPath={EventHub}" + # 在使用 Microsoft Entra ID 的情况下,使用 eventHubNamespace + - name: eventHubNamespace + value: "namespace" + - name: enableEntityManagement + value: "false" + - name: enableInOrderMessageDelivery + value: "false" + # 仅当 enableEntityManagement 设置为 true 时需要以下四个属性 + - name: resourceGroupName + value: "test-rg" + - name: subscriptionID + value: "value of Azure subscription ID" + - name: partitionCount + value: "1" + - name: messageRetentionInDays + value: "3" + # 检查点存储属性 + - name: storageAccountName + value: "myeventhubstorage" + - name: storageAccountKey + value: "112233445566778899" + - name: storageContainerName + value: "myeventhubstoragecontainer" + # 传递 storageAccountKey 的替代方法 + - name: storageConnectionString + value: "DefaultEndpointsProtocol=https;AccountName=;AccountKey=" + # 可选元数据 + - name: direction + value: "input, output" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中,secret 以明文字符串形式使用。建议使用 secret 存储,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `eventHub` | Y* | 输入/输出 | Event Hubs hub 的名称 ("topic")。如果使用 Microsoft Entra ID 认证或连接字符串不包含 `EntityPath` 值,则必需 | `mytopic` | +| `connectionString` | Y* | 输入/输出 | Event Hub 或 Event Hub 命名空间的连接字符串。
* 与 `eventHubNamespace` 字段互斥。
* 在不使用 [Microsoft Entra ID 认证]({{< ref "authenticating-azure.md" >}}) 时必需 | `"Endpoint=sb://{EventHubNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key};EntityPath={EventHub}"` 或 `"Endpoint=sb://{EventHubNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key}"` +| `eventHubNamespace` | Y* | 输入/输出 | Event Hub 命名空间名称。
* 与 `connectionString` 字段互斥。
* 在使用 [Microsoft Entra ID 认证]({{< ref "authenticating-azure.md" >}}) 时必需 | `"namespace"` +| `enableEntityManagement` | N | 输入/输出 | 允许管理 EventHub 命名空间和存储账户的布尔值。默认值:`false` | `"true"`, `"false"` +| `enableInOrderMessageDelivery` | N | 输入/输出 | 允许消息按发布顺序传递的布尔值。这假设在发布或发送时设置了 `partitionKey` 以确保跨分区的顺序。默认值:`false` | `"true"`, `"false"` +| `resourceGroupName` | N | 输入/输出 | Event Hub 命名空间所属的资源组名称。启用实体管理时必需 | `"test-rg"` +| `subscriptionID` | N | 输入/输出 | Azure 订阅 ID 值。启用实体管理时必需 | `"azure subscription id"` +| `partitionCount` | N | 输入/输出 | 新 Event Hub 命名空间的分区数量。仅在启用实体管理时使用。默认值:`"1"` | `"2"` +| `messageRetentionInDays` | N | 输入/输出 | 在新创建的 Event Hub 命名空间中保留消息的天数。仅在启用实体管理时使用。默认值:`"1"` | `"90"` +| `consumerGroup` | Y | 输入 | 要监听的 [Event Hubs 消费者组](https://docs.microsoft.com/azure/event-hubs/event-hubs-features#consumer-groups) 的名称 | `"group1"` | +| `storageAccountName` | Y | 输入 | 用于检查点存储的存储账户名称。 |`"myeventhubstorage"` +| `storageAccountKey` | Y* | 输入 | 检查点存储账户的存储账户密钥。
* 使用 Microsoft Entra ID 时,如果服务主体也有权访问存储账户,可以省略此项。 | `"112233445566778899"` +| `storageConnectionString` | Y* | 输入 | 检查点存储的连接字符串,指定 `storageAccountKey` 的替代方法 | `"DefaultEndpointsProtocol=https;AccountName=myeventhubstorage;AccountKey="` +| `storageContainerName` | Y | 输入 | 存储账户名称的存储容器名称。 | `"myeventhubstoragecontainer"` +| `direction` | N | 输入/输出 | 绑定的方向。 | `"input"`, `"output"`, `"input, output"` + +### Microsoft Entra ID 认证 + +Azure Event Hubs pub/sub 组件支持使用所有 Microsoft Entra ID 机制进行认证。有关更多信息以及根据选择的 Microsoft Entra ID 认证机制提供的相关组件元数据字段,请参阅[认证到 Azure 的文档]({{< ref authenticating-azure.md >}})。 + +## 绑定支持 + +此组件支持具有以下操作的**输出绑定**: + +- `create`: 发布新消息到 Azure Event Hubs + +## 输入绑定到 Azure IoT Hub 事件 + +Azure IoT Hub 提供了一个[与 Event Hubs 兼容的端点](https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-messages-read-builtin#read-from-the-built-in-endpoint),因此 Dapr 应用可以创建输入绑定以使用 Event Hubs 绑定组件读取 Azure IoT Hub 事件。 + +由 Azure IoT Hub 设备创建的设备到云事件将包含额外的[IoT Hub 系统属性](https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-messages-construct#system-properties-of-d2c-iot-hub-messages),Dapr 的 Azure Event Hubs 绑定将在响应元数据中返回以下内容: + +| 系统属性名称 | 描述 & 路由查询关键字 | +|----------------------|:------------------------------------| +| `iothub-connection-auth-generation-id` | 发送消息的设备的 **connectionDeviceGenerationId**。请参阅 [IoT Hub 设备身份属性](https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-identity-registry#device-identity-properties)。 | +| `iothub-connection-auth-method` | 用于认证发送消息的设备的 **connectionAuthMethod**。 | +| `iothub-connection-device-id` | 发送消息的设备的 **deviceId**。请参阅 [IoT Hub 设备身份属性](https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-identity-registry#device-identity-properties)。 | +| `iothub-connection-module-id` | 发送消息的设备的 **moduleId**。请参阅 [IoT Hub 设备身份属性](https://docs.microsoft.com/azure/iot-hub/iot-hub-devguide-identity-registry#device-identity-properties)。 | +| `iothub-enqueuedtime` | 设备到云消息被 IoT Hub 接收的 **enqueuedTime**,格式为 RFC3339。 | +| `message-id` | 用户可设置的 AMQP **messageId**。 | + +例如,HTTP `Read()` 响应的头部将包含: + +```js +{ + 'user-agent': 'fasthttp', + 'host': '127.0.0.1:3000', + 'content-type': 'application/json', + 'content-length': '120', + 'iothub-connection-device-id': 'my-test-device', + 'iothub-connection-auth-generation-id': '637618061680407492', + 'iothub-connection-auth-method': '{"scope":"module","type":"sas","issuer":"iothub","acceptingIpFilterRule":null}', + 'iothub-connection-module-id': 'my-test-module-a', + 'iothub-enqueuedtime': '2021-07-13T22:08:09Z', + 'message-id': 'my-custom-message-id', + 'x-opt-sequence-number': '35', + 'x-opt-enqueued-time': '2021-07-13T22:08:09Z', + 'x-opt-offset': '21560', + 'traceparent': '00-4655608164bc48b985b42d39865f3834-ed6cf3697c86e7bd-01' +} +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/gcpbucket.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/gcpbucket.md new file mode 100644 index 000000000..b9d947935 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/gcpbucket.md @@ -0,0 +1,319 @@ +--- +type: docs +title: "GCP 存储桶绑定指南" +linkTitle: "GCP 存储桶" +description: "关于 GCP 存储桶绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/gcpbucket/" +--- + +## 组件格式 + +要配置 GCP 存储桶绑定,请创建一个类型为 `bindings.gcp.bucket` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.gcp.bucket + version: v1 + metadata: + - name: bucket + value: "mybucket" + - name: type + value: "service_account" + - name: project_id + value: "project_111" + - name: private_key_id + value: "*************" + - name: client_email + value: "name@domain.com" + - name: client_id + value: "1111111111111111" + - name: auth_uri + value: "https://accounts.google.com/o/oauth2/auth" + - name: token_uri + value: "https://oauth2.googleapis.com/token" + - name: auth_provider_x509_cert_url + value: "https://www.googleapis.com/oauth2/v1/certs" + - name: client_x509_cert_url + value: "https://www.googleapis.com/robot/v1/metadata/x509/.iam.gserviceaccount.com" + - name: private_key + value: "PRIVATE KEY" + - name: decodeBase64 + value: "" + - name: encodeBase64 + value: "" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中使用了明文字符串来存储密钥。建议使用密钥存储来保护这些信息,具体方法请参阅[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `bucket` | Y | 输出 | 存储桶名称 | `"mybucket"` | +| `type` | Y | 输出 | GCP 凭证类型 | `"service_account"` | +| `project_id` | Y | 输出 | GCP 项目 ID| `projectId` +| `private_key_id` | Y | 输出 | GCP 私钥 ID | `"privateKeyId"` +| `private_key` | Y | 输出 | GCP 凭证私钥。替换为 x509 证书 | `12345-12345` +| `client_email` | Y | 输出 | GCP 客户端邮箱 | `"client@email.com"` +| `client_id` | Y | 输出 | GCP 客户端 ID | `0123456789-0123456789` +| `auth_uri` | Y | 输出 | Google 账户 OAuth 端点 | `https://accounts.google.com/o/oauth2/auth` +| `token_uri` | Y | 输出 | Google 账户令牌 URI | `https://oauth2.googleapis.com/token` +| `auth_provider_x509_cert_url` | Y | 输出 | GCP 凭证证书 URL | `https://www.googleapis.com/oauth2/v1/certs` +| `client_x509_cert_url` | Y | 输出 | GCP 凭证项目 x509 证书 URL | `https://www.googleapis.com/robot/v1/metadata/x509/.iam.gserviceaccount.com` +| `decodeBase64` | N | 输出 | 在保存到存储桶之前解码 base64 文件内容的配置。适用于保存二进制内容的文件。`true` 是唯一允许的正值。其他正值变体如 `"True", "1"` 不可接受。默认为 `false` | `true`, `false` | +| `encodeBase64` | N | 输出 | 在返回内容之前编码 base64 文件内容的配置。适用于打开二进制内容的文件。`true` 是唯一允许的正值。其他正值变体如 `"True", "1"` 不可接受。默认为 `false` | `true`, `false` | + +## 绑定支持 + +此组件支持 **输出绑定**,支持以下操作: + +- `create` : [创建文件](#create-file) +- `get` : [获取文件](#get-file) +- `delete` : [删除文件](#delete-file) +- `list`: [列出文件](#list-files) + +### 创建文件 + +要执行创建操作,请使用 `POST` 方法调用 GCP 存储桶绑定,并使用以下 JSON 正文: + +> 注意:默认情况下,会生成一个随机 UUID。请参阅下文的元数据支持以设置名称 + +```json +{ + "operation": "create", + "data": "YOUR_CONTENT" +} +``` +元数据参数为: +- `key` - (可选)对象的名称 +- `decodeBase64` - (可选)在保存到存储之前解码 base64 文件内容的配置 + +#### 示例 +##### 将文本保存到随机生成的 UUID 文件 + +{{< tabs Windows Linux >}} + {{% codetab %}} + 在 Windows 上,使用 cmd 提示符(PowerShell 有不同的转义机制) + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"Hello World\" }" http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "Hello World" }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 将文本保存到特定文件 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"Hello World\", \"metadata\": { \"key\": \"my-test-file.txt\" } }" \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "Hello World", "metadata": { "key": "my-test-file.txt" } }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 上传文件 + +要上传文件,请将文件内容作为数据负载传递;您可能需要对其进行编码,例如 Base64 以处理二进制内容。 + +然后您可以像往常一样上传它: + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"(YOUR_FILE_CONTENTS)\", \"metadata\": { \"key\": \"my-test-file.jpg\" } }" http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "$(cat my-test-file.jpg)", "metadata": { "key": "my-test-file.jpg" } }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} +#### 响应 + +响应正文将包含以下 JSON: + +```json +{ + "objectURL":"https://storage.googleapis.com//", +} +``` + +### 获取对象 + +要执行获取文件操作,请使用 `POST` 方法调用 GCP 存储桶绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "get", + "metadata": { + "key": "my-test-file.txt" + } +} +``` + +元数据参数为: + +- `key` - 对象的名称 +- `encodeBase64` - (可选)在返回内容之前编码 base64 文件内容的配置。 + +#### 示例 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"get\", \"metadata\": { \"key\": \"my-test-file.txt\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "get", "metadata": { "key": "my-test-file.txt" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文包含存储在对象中的值。 + +### 删除对象 + +要执行删除对象操作,请使用 `POST` 方法调用 GCP 存储桶绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "delete", + "metadata": { + "key": "my-test-file.txt" + } +} +``` + +元数据参数为: + +- `key` - 对象的名称 + +#### 示例 + +##### 删除对象 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"delete\", \"metadata\": { \"key\": \"my-test-file.txt\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "delete", "metadata": { "key": "my-test-file.txt" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 +如果成功,将返回 HTTP 204(无内容)和空正文。 + +### 列出对象 + +要执行列出对象操作,请使用 `POST` 方法调用 S3 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "list", + "data": { + "maxResults": 10, + "prefix": "file", + "delimiter": "i0FvxAn2EOEL6" + } +} +``` + +数据参数为: + +- `maxResults` - (可选)设置响应中返回的最大键数。默认情况下,操作最多返回 1,000 个键名。响应可能包含更少的键,但绝不会包含更多。 +- `prefix` - (可选)可用于过滤以 prefix 开头的对象。 +- `delimiter` - (可选)可用于限制结果仅限于给定“目录”中的对象。没有分隔符,前缀下的整个树都会返回。 + +#### 响应 + +响应正文包含找到的对象列表。 + +对象列表将作为 JSON 数组返回,格式如下: + +```json +[ + { + "Bucket": "", + "Name": "02WGzEdsUWNlQ", + "ContentType": "image/png", + "ContentLanguage": "", + "CacheControl": "", + "EventBasedHold": false, + "TemporaryHold": false, + "RetentionExpirationTime": "0001-01-01T00:00:00Z", + "ACL": null, + "PredefinedACL": "", + "Owner": "", + "Size": 5187, + "ContentEncoding": "", + "ContentDisposition": "", + "MD5": "aQdLBCYV0BxA51jUaxc3pQ==", + "CRC32C": 1058633505, + "MediaLink": "https://storage.googleapis.com/download/storage/v1/b//o/02WGzEdsUWNlQ?generation=1631553155678071&alt=media", + "Metadata": null, + "Generation": 1631553155678071, + "Metageneration": 1, + "StorageClass": "STANDARD", + "Created": "2021-09-13T17:12:35.679Z", + "Deleted": "0001-01-01T00:00:00Z", + "Updated": "2021-09-13T17:12:35.679Z", + "CustomerKeySHA256": "", + "KMSKeyName": "", + "Prefix": "", + "Etag": "CPf+mpK5/PICEAE=" + } +] +``` +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/gcppubsub.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/gcppubsub.md new file mode 100644 index 000000000..f0c46bf7e --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/gcppubsub.md @@ -0,0 +1,86 @@ +--- +type: docs +title: "GCP Pub/Sub 绑定规范" +linkTitle: "GCP Pub/Sub" +description: "关于 GCP Pub/Sub 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/gcppubsub/" +--- + +## 组件格式 + +要设置 GCP Pub/Sub 绑定,您需要创建一个类型为 `bindings.gcp.pubsub` 的组件。有关如何创建和应用绑定配置的信息,请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.gcp.pubsub + version: v1 + metadata: + - name: topic + value: "topic1" + - name: subscription + value: "subscription1" + - name: type + value: "service_account" + - name: project_id + value: "project_111" + - name: private_key_id + value: "*************" + - name: client_email + value: "name@domain.com" + - name: client_id + value: "1111111111111111" + - name: auth_uri + value: "https://accounts.google.com/o/oauth2/auth" + - name: token_uri + value: "https://oauth2.googleapis.com/token" + - name: auth_provider_x509_cert_url + value: "https://www.googleapis.com/oauth2/v1/certs" + - name: client_x509_cert_url + value: "https://www.googleapis.com/robot/v1/metadata/x509/.iam.gserviceaccount.com" + - name: private_key + value: "PRIVATE KEY" + - name: direction + value: "input, output" +``` +{{% alert title="警告" color="warning" %}} +上述示例使用了明文字符串作为密钥。建议使用密钥存储来保护这些信息,详情请参阅[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|-----------| -----|---------| +| `topic` | Y | 输出 | GCP Pub/Sub 主题名称 | `"topic1"` | +| `subscription` | N | GCP Pub/Sub 订阅名称 | `"name1"` | +| `type` | Y | 输出 | GCP 凭证类型 | `service_account` +| `project_id` | Y | 输出 | GCP 项目 ID| `projectId` +| `private_key_id` | N | 输出 | GCP 私钥 ID | `"privateKeyId"` +| `private_key` | Y | 输出 | GCP 凭证私钥。可以替换为 x509 证书 | `12345-12345` +| `client_email` | Y | 输出 | GCP 客户端邮箱 | `"client@email.com"` +| `client_id` | N | 输出 | GCP 客户端 ID | `0123456789-0123456789` +| `auth_uri` | N | 输出 | Google 账户 OAuth 端点 | `https://accounts.google.com/o/oauth2/auth` +| `token_uri` | N | 输出 | Google 账户令牌 URI | `https://oauth2.googleapis.com/token` +| `auth_provider_x509_cert_url` | N | 输出 |GCP 凭证证书 URL | `https://www.googleapis.com/oauth2/v1/certs` +| `client_x509_cert_url` | N | 输出 | GCP 凭证项目 x509 证书 URL | `https://www.googleapis.com/robot/v1/metadata/x509/.iam.gserviceaccount.com` +| `direction` | N |输入/输出 | 绑定的方向。 | `"input"`, `"output"`, `"input, output"` + +## 绑定支持 + +此组件支持 **输入和输出** 绑定接口。 + +此组件支持以下操作的 **输出绑定**: + +- `create` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/graghql.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/graghql.md new file mode 100644 index 000000000..00d5e9051 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/graghql.md @@ -0,0 +1,86 @@ +--- +type: docs +title: "GraphQL 绑定说明" +linkTitle: "GraphQL" +description: "GraphQL 绑定组件的详细说明文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/graphql/" +--- + +## 组件格式 + +要配置 GraphQL 绑定,请创建一个类型为 `bindings.graphql` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。为了区分普通配置(如 endpoint)和 headers,header 名称前需加上 "header:" 前缀。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: example.bindings.graphql +spec: + type: bindings.graphql + version: v1 + metadata: + - name: endpoint + value: "http://localhost:8080/v1/graphql" + - name: header:x-hasura-access-key + value: "adminkey" + - name: header:Cache-Control + value: "no-cache" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中使用了明文字符串来存储 secret。建议使用 secret 存储来保护 secret,详情请参阅[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `endpoint` | Y | 输出 | GraphQL endpoint 字符串,详情见[此处](#url-format) | `"http://localhost:4000/graphql/graphql"` | +| `header:[HEADERKEY]` | N | 输出 | GraphQL header。在 `name` 中指定 header 键,在 `value` 中指定 header 值。 | `"no-cache"` (见上文) | +| `variable:[VARIABLEKEY]` | N | 输出 | GraphQL 查询变量。在 `name` 中指定变量名,在 `value` 中指定变量值。 | `"123"` (见下文) | + +### Endpoint 和 Header 格式 + +GraphQL 绑定内部使用 [GraphQL 客户端](https://github.com/machinebox/graphql)。 + +## 绑定支持 + +此组件支持以下操作的**输出绑定**: + +- `query` +- `mutation` + +### query + +`query` 操作用于执行查询语句,返回的结果包含元数据和数据,以行值数组的形式呈现。 + +**请求** + +```golang +in := &dapr.InvokeBindingRequest{ +Name: "example.bindings.graphql", +Operation: "query", +Metadata: map[string]string{ "query": `query { users { name } }`}, +} +``` + +如果 `query` 需要[查询变量](https://graphql.org/learn/queries/#variables),请在 `metadata` 映射中添加键值对,每个查询变量的键需以 `variable:` 为前缀。 + +```golang +in := &dapr.InvokeBindingRequest{ +Name: "example.bindings.graphql", +Operation: "query", +Metadata: map[string]string{ + "query": `query HeroNameAndFriends($episode: string!) { hero(episode: $episode) { name } }`, + "variable:episode": "JEDI", +} +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/http.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/http.md new file mode 100644 index 000000000..c84d146de --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/http.md @@ -0,0 +1,386 @@ +--- +type: docs +title: "HTTP 绑定规范" +linkTitle: "HTTP" +description: "关于 HTTP 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/http/" +--- + +## 替代方法 + +[服务调用 API]({{< ref service_invocation_api.md >}}) 允许调用非 Dapr 的 HTTP 端点,并且是推荐的方法。阅读 ["如何:使用 HTTP 调用非 Dapr 端点"]({{< ref howto-invoke-non-dapr-endpoints.md >}}) 以获取更多信息。 + +## 设置 Dapr 组件 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.http + version: v1 + metadata: + - name: url + value: "http://something.com" + #- name: maxResponseBodySize + # value: "100Mi" # 可选,最大读取响应数据量 + #- name: MTLSRootCA + # value: "/Users/somepath/root.pem" # 可选,根 CA 或 PEM 编码字符串的路径 + #- name: MTLSClientCert + # value: "/Users/somepath/client.pem" # 可选,客户端证书或 PEM 编码字符串的路径 + #- name: MTLSClientKey + # value: "/Users/somepath/client.key" # 可选,客户端密钥或 PEM 编码字符串的路径 + #- name: MTLSRenegotiation + # value: "RenegotiateOnceAsClient" # 可选,选项之一:RenegotiateNever, RenegotiateOnceAsClient, RenegotiateFreelyAsClient + #- name: securityToken # 可选,<在 HTTP 请求中作为头部包含的令牌> + # secretKeyRef: + # name: mysecret + # key: "mytoken" + #- name: securityTokenHeader + # value: "Authorization: Bearer" # 可选,<安全令牌的头部名称> + #- name: errorIfNot2XX + # value: "false" # 可选 +``` + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|--------|--------|---------| +| `url` | 是 | 输出 | 要调用的 HTTP 端点的基本 URL | `http://host:port/path`, `http://myservice:8000/customers` | +| `maxResponseBodySize`| 否 | 输出 | 要读取的响应的最大长度。整数被解释为字节;可以添加 `Ki, Mi, Gi` (SI) 或 `k | M | G` (十进制) 单位以方便使用。默认值为 `100Mi` | "1Gi", "100Mi", "20Ki", "200" (字节) | +| `MTLSRootCA` | 否 | 输出 | 根 CA 证书或 PEM 编码字符串的路径 | +| `MTLSClientCert` | 否 | 输出 | 客户端证书或 PEM 编码字符串的路径 | +| `MTLSClientKey` | 否 | 输出 | 客户端私钥或 PEM 编码字符串的路径 | +| `MTLSRenegotiation` | 否 | 输出 | 要使用的 mTLS 重新协商类型 | `RenegotiateOnceAsClient` +| `securityToken` | 否 | 输出 | 要作为头部添加到 HTTP 请求中的令牌值。与 `securityTokenHeader` 一起使用 | +| `securityTokenHeader` | 否 | 输出 | HTTP 请求中 `securityToken` 的头部名称 | +| `errorIfNot2XX` | 否 | 输出 | 当响应不在 2xx 范围内时是否抛出绑定错误。默认为 `true` | + +**MTLSRootCA**、**MTLSClientCert** 和 **MTLSClientKey** 的值可以通过三种方式提供: + +- Secret 存储引用: + + ```yaml + apiVersion: dapr.io/v1alpha1 + kind: Component + metadata: + name: + spec: + type: bindings.http + version: v1 + metadata: + - name: url + value: http://something.com + - name: MTLSRootCA + secretKeyRef: + name: mysecret + key: myrootca + auth: + secretStore: + ``` + +- 文件路径:可以将文件的绝对路径作为字段的值提供。 +- PEM 编码字符串:也可以将 PEM 编码字符串作为字段的值提供。 + +{{% alert title="注意" color="primary" %}} +元数据字段 **MTLSRootCA**、**MTLSClientCert** 和 **MTLSClientKey** 用于配置 (m)TLS 认证。 +使用 mTLS 认证时,必须提供这三个字段。有关更多详细信息,请参阅 [mTLS]({{< ref "#using-mtls-or-enabling-client-tls-authentication-along-with-https" >}})。您也可以仅提供 **MTLSRootCA**,以启用与自定义 CA 签名证书的 **HTTPS** 连接。有关更多详细信息,请参阅 [HTTPS]({{< ref "#install-the-ssl-certificate-in-the-sidecar" >}}) 部分。 +{{% /alert %}} + +## 绑定支持 + +此组件支持具有以下 [HTTP 方法/动词](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) 的 **输出绑定**: + +- `create` : 为了向后兼容,视作 post +- `get` : 读取数据/记录 +- `head` : 与 get 相同,但服务器不返回响应体 +- `post` : 通常用于创建记录或发送命令 +- `put` : 更新数据/记录 +- `patch` : 有时用于更新记录的部分字段 +- `delete` : 删除数据/记录 +- `options` : 请求有关可用通信选项的信息(不常用) +- `trace` : 用于调用请求消息的远程应用层回环(不常用) + +### 请求 + +#### 操作元数据字段 + +上述所有操作都支持以下元数据字段 + +| 字段 | 必需 | 详情 | 示例 | +|--------------------|:--------:|---------|---------| +| `path` | 否 | 要附加到基本 URL 的路径。用于访问特定 URI。 | `"/1234"`, `"/search?lastName=Jones"` +| 首字母大写的字段 | 否 | 任何首字母大写的字段都作为请求头发送 | `"Content-Type"`, `"Accept"` + +#### 检索数据 + +要从 HTTP 端点检索数据,请使用 `GET` 方法调用 HTTP 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "get" +} +``` + +可以选择指定路径以与资源 URI 交互: + +```json +{ + "operation": "get", + "metadata": { + "path": "/things/1234" + } +} +``` + +### 响应 + +响应体包含 HTTP 端点返回的数据。`data` 字段包含 HTTP 响应体,作为字节切片(通过 curl 进行 Base64 编码)。`metadata` 字段包含: + +| 字段 | 必需 | 详情 | 示例 | +|--------------------|:--------:|---------|---------| +| `statusCode` | 是 | [HTTP 状态码](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) | `200`, `404`, `503` | +| `status` | 是 | 状态描述 | `"200 OK"`, `"201 Created"` | +| 首字母大写的字段 | 否 | 任何首字母大写的字段都作为请求头发送 | `"Content-Type"` | + +#### 示例 + +**请求基本 URL** + +{{< tabs Windows Linux >}} + +{{% codetab %}} +```bash +curl -d "{ \"operation\": \"get\" }" \ + http://localhost:/v1.0/bindings/ +``` +{{% /codetab %}} + +{{% codetab %}} +```bash +curl -d '{ "operation": "get" }' \ + http://localhost:/v1.0/bindings/ +``` +{{% /codetab %}} + +{{< /tabs >}} + +**请求特定路径** + +{{< tabs Windows Linux >}} + +{{% codetab %}} +```sh +curl -d "{ \"operation\": \"get\", \"metadata\": { \"path\": \"/things/1234\" } }" \ + http://localhost:/v1.0/bindings/ +``` +{{% /codetab %}} + +{{% codetab %}} +```sh +curl -d '{ "operation": "get", "metadata": { "path": "/things/1234" } }' \ + http://localhost:/v1.0/bindings/ +``` +{{% /codetab %}} + +{{< /tabs >}} + +### 发送和更新数据 + +要向 HTTP 端点发送数据,请使用 `POST`、`PUT` 或 `PATCH` 方法调用 HTTP 绑定,并使用以下 JSON 正文: + +{{% alert title="注意" color="primary" %}} +任何以大写字母开头的元数据字段都作为请求头传递。 +例如,默认内容类型是 `application/json; charset=utf-8`。可以通过设置 `Content-Type` 元数据字段来覆盖此设置。 +{{% /alert %}} + +```json +{ + "operation": "post", + "data": "content (default is JSON)", + "metadata": { + "path": "/things", + "Content-Type": "application/json; charset=utf-8" + } +} +``` + +#### 示例 + +**发布新记录** + +{{< tabs Windows Linux >}} + +{{% codetab %}} +```sh +curl -d "{ \"operation\": \"post\", \"data\": \"YOUR_BASE_64_CONTENT\", \"metadata\": { \"path\": \"/things\" } }" \ + http://localhost:/v1.0/bindings/ +``` +{{% /codetab %}} + +{{% codetab %}} +```sh +curl -d '{ "operation": "post", "data": "YOUR_BASE_64_CONTENT", "metadata": { "path": "/things" } }' \ + http://localhost:/v1.0/bindings/ +``` +{{% /codetab %}} + +{{< /tabs >}} + +## 使用 HTTPS + +通过配置 Dapr sidecar 信任服务器的 SSL 证书,HTTP 绑定也可以与 HTTPS 端点一起使用。 + +1. 将绑定 URL 更新为使用 `https` 而不是 `http`。 +1. 如果需要添加自定义 TLS 证书,请参考 [如何:在 Dapr sidecar 中安装证书]({{< ref install-certificates >}}),在 sidecar 中安装 TLS 证书。 + +### 示例 + +#### 更新绑定组件 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: + namespace: +spec: + type: bindings.http + version: v1 + metadata: + - name: url + value: https://my-secured-website.com # 使用 HTTPS +``` + +#### 在 sidecar 中安装 TLS 证书 + +{{< tabs Self-Hosted Kubernetes >}} + +{{% codetab %}} +当 sidecar 未在容器内运行时,可以直接在主机操作系统上安装 TLS 证书。 + +以下是 sidecar 作为容器运行时的示例。SSL 证书位于主机计算机的 `/tmp/ssl/cert.pem`。 + +```yaml +version: '3' +services: + my-app: + # ... + dapr-sidecar: + image: "daprio/daprd:1.8.0" + command: [ + "./daprd", + "-app-id", "myapp", + "-app-port", "3000", + ] + volumes: + - "./components/:/components" + - "/tmp/ssl/:/certificates" # 将证书文件夹挂载到 sidecar 容器的 /certificates + environment: + - "SSL_CERT_DIR=/certificates" # 将环境变量设置为证书文件夹的路径 + depends_on: + - my-app +``` + +{{% /codetab %}} + +{{% codetab %}} + +sidecar 可以从多种来源读取 TLS 证书。请参阅 [如何:将 Pod 卷挂载到 Dapr sidecar]({{< ref kubernetes-volume-mounts >}}) 以了解更多信息。在此示例中,我们将 TLS 证书存储为 Kubernetes secret。 + +```bash +kubectl create secret generic myapp-cert --from-file /tmp/ssl/cert.pem +``` + +下面的 YAML 是一个 Kubernetes 部署示例,将上述 secret 挂载到 sidecar 并设置 `SSL_CERT_DIR` 以安装证书。 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: myapp + namespace: default + labels: + app: myapp +spec: + replicas: 1 + selector: + matchLabels: + app: myapp + template: + metadata: + labels: + app: myapp + annotations: + dapr.io/enabled: "true" + dapr.io/app-id: "myapp" + dapr.io/app-port: "8000" + dapr.io/volume-mounts: "cert-vol:/certificates" # 将证书文件夹挂载到 sidecar 容器的 /certificates + dapr.io/env: "SSL_CERT_DIR=/certificates" # 将环境变量设置为证书文件夹的路径 + spec: + volumes: + - name: cert-vol + secret: + secretName: myapp-cert +... +``` + +{{% /codetab %}} + +{{< /tabs >}} + +#### 安全地调用绑定 + +{{< tabs Windows Linux >}} + +{{% codetab %}} +```bash +curl -d "{ \"operation\": \"get\" }" \ + https://localhost:/v1.0/bindings/ +``` +{{% /codetab %}} + +{{% codetab %}} +```bash +curl -d '{ "operation": "get" }' \ + https://localhost:/v1.0/bindings/ +``` +{{% /codetab %}} + +{{< /tabs >}} + +{{% alert title="注意" color="primary" %}} +HTTPS 绑定支持也可以通过 **MTLSRootCA** 元数据选项进行配置。这将把指定的证书添加到绑定的受信任证书列表中。两种方法没有特定的偏好。虽然 **MTLSRootCA** 选项易于使用且不需要对 sidecar 进行任何更改,但它仅接受一个证书。如果您需要信任多个证书,则需要 [按照上述步骤在 sidecar 中安装它们]({{< ref "#install-the-ssl-certificate-in-the-sidecar" >}})。 +{{% /alert %}} + +## 使用 mTLS 或启用客户端 TLS 认证以及 HTTPS + +您可以通过在绑定组件中提供 `MTLSRootCA`、`MTLSClientCert` 和 `MTLSClientKey` 元数据字段来配置 HTTP 绑定以使用 mTLS 或客户端 TLS 认证以及 HTTPS。 + +这些字段可以作为文件路径或 pem 编码字符串传递: + +- 如果提供了文件路径,则读取文件并使用其内容。 +- 如果提供了 PEM 编码字符串,则直接使用该字符串。 + +当这些字段被配置时,Dapr sidecar 在 TLS 握手过程中使用提供的证书来认证自己。 + +如果远程服务器强制执行 TLS 重新协商,您还需要设置元数据字段 `MTLSRenegotiation`。此字段接受以下选项之一: + +- `RenegotiateNever` +- `RenegotiateOnceAsClient` +- `RenegotiateFreelyAsClient` + +有关更多详细信息,请参阅 [Go `RenegotiationSupport` 文档](https://pkg.go.dev/crypto/tls#RenegotiationSupport)。 + +当服务器需要 mTLS 或客户端 TLS 认证时,可以使用此功能。 + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) +- [如何:在 Dapr sidecar 中安装证书]({{< ref install-certificates >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/huawei-obs.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/huawei-obs.md new file mode 100644 index 000000000..65a8eef00 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/huawei-obs.md @@ -0,0 +1,293 @@ +--- +type: docs +title: "华为 OBS 绑定规范" +linkTitle: "华为 OBS" +description: "关于华为 OBS 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/huawei-obs/" +--- + +## 组件格式 + +要配置华为对象存储服务(OBS)的输出绑定,创建一个类型为 `bindings.huawei.obs` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})以了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.huawei.obs + version: v1 + metadata: + - name: bucket + value: "" + - name: endpoint + value: "" + - name: accessKey + value: "" + - name: secretKey + value: "" + # 可选字段 + - name: region + value: "" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中,secret 使用了明文字符串。建议使用 secret 存储来存储 secret,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `bucket` | Y | 输出 | 要写入的华为 OBS 存储桶名称 | `"My-OBS-Bucket"` | +| `endpoint` | Y | 输出 | 特定的华为 OBS 端点 | `"obs.cn-north-4.myhuaweicloud.com"` | +| `accessKey` | Y | 输出 | 访问此资源的华为访问密钥(AK) | `"************"` | +| `secretKey` | Y | 输出 | 访问此资源的华为密钥(SK) | `"************"` | +| `region` | N | 输出 | 存储桶的特定华为区域 | `"cn-north-4"` | + +## 绑定功能 + +此组件支持以下**输出绑定**操作: + +- `create` : [创建文件](#create-file) +- `upload` : [上传文件](#upload-file) +- `get` : [获取文件](#get-file) +- `delete` : [删除文件](#delete-file) +- `list`: [列出文件](#list-files) + +### 创建文件 + +要执行创建操作,请使用 `POST` 方法调用华为 OBS 绑定,并使用以下 JSON 正文: + +> 注意:默认情况下,会生成一个随机 UUID。请参阅下面的元数据支持以设置目标文件名 + +```json +{ + "operation": "create", + "data": "YOUR_CONTENT" +} +``` + +#### 示例 +##### 将文本保存到随机生成的 UUID 文件 + +{{< tabs Windows Linux >}} + {{% codetab %}} + 在 Windows 上,使用 cmd 提示符(PowerShell 有不同的转义机制) + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"Hello World\" }" http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "Hello World" }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 将文本保存到特定文件 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"Hello World\", \"metadata\": { \"key\": \"my-test-file.txt\" } }" \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "Hello World", "metadata": { "key": "my-test-file.txt" } }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应 JSON 正文包含 `statusCode` 和 `versionId` 字段。只有在启用存储桶版本控制时,`versionId` 才会返回值,否则为空字符串。 + +### 上传文件 + +要上传二进制文件(例如,_.jpg_,_.zip_),请使用 `POST` 方法调用华为 OBS 绑定,并使用以下 JSON 正文: + +> 注意:默认情况下,会生成一个随机 UUID,如果您不指定 `key`。请参阅下面的示例以获取元数据支持以设置目标文件名。此 API 可用于上传常规文件,例如纯文本文件。 + +```json +{ + "operation": "upload", + "metadata": { + "key": "DESTINATION_FILE_NAME" + }, + "data": { + "sourceFile": "PATH_TO_YOUR_SOURCE_FILE" + } +} +``` + +#### 示例 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d "{ \"operation\": \"upload\", \"data\": { \"sourceFile\": \".\my-test-file.jpg\" }, \"metadata\": { \"key\": \"my-test-file.jpg\" } }" \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "upload", "data": { "sourceFile": "./my-test-file.jpg" }, "metadata": { "key": "my-test-file.jpg" } }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应 JSON 正文包含 `statusCode` 和 `versionId` 字段。只有在启用存储桶版本控制时,`versionId` 才会返回值,否则为空字符串。 + +### 获取对象 + +要执行获取文件操作,请使用 `POST` 方法调用华为 OBS 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "get", + "metadata": { + "key": "my-test-file.txt" + } +} +``` + +元数据参数为: + +- `key` - 对象的名称 + +#### 示例 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"get\", \"metadata\": { \"key\": \"my-test-file.txt\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "get", "metadata": { "key": "my-test-file.txt" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文包含存储在对象中的值。 + +### 删除对象 + +要执行删除对象操作,请使用 `POST` 方法调用华为 OBS 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "delete", + "metadata": { + "key": "my-test-file.txt" + } +} +``` + +元数据参数为: + +- `key` - 对象的名称 + +#### 示例 + +##### 删除对象 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"delete\", \"metadata\": { \"key\": \"my-test-file.txt\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "delete", "metadata": { "key": "my-test-file.txt" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +如果成功,将返回 HTTP 204(无内容)和空正文。 + +### 列出对象 + +要执行列出对象操作,请使用 `POST` 方法调用华为 OBS 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "list", + "data": { + "maxResults": 5, + "prefix": "dapr-", + "marker": "obstest", + "delimiter": "jpg" + } +} +``` + +数据参数为: + +- `maxResults` - (可选)设置响应中返回的最大键数。默认情况下,操作最多返回 1,000 个键名。响应可能包含更少的键,但绝不会包含更多。 +- `prefix` - (可选)限制响应为以指定前缀开头的键。 +- `marker` - (可选)标记是您希望华为 OBS 开始列出的位置。华为 OBS 从此指定键之后开始列出。标记可以是存储桶中的任何键。然后可以在后续调用中使用标记值来请求下一组列表项。 +- `delimiter` - (可选)分隔符是您用来分组键的字符。它返回对象/文件,其对象键与分隔符模式指定的不同。 + +#### 示例 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"list\", \"data\": { \"maxResults\": 5, \"prefix\": \"dapr-\", \"marker\": \"obstest\", \"delimiter\": \"jpg\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "list", "data": { "maxResults": 5, "prefix": "dapr-", "marker": "obstest", "delimiter": "jpg" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文包含找到的对象列表。 + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/influxdb.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/influxdb.md new file mode 100644 index 000000000..77b1579c6 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/influxdb.md @@ -0,0 +1,74 @@ +--- +type: docs +title: "InfluxDB 绑定规范" +linkTitle: "InfluxDB" +description: "关于 InfluxDB 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/influxdb/" +--- + +## 组件格式 + +为了设置 InfluxDB 绑定,请创建一个类型为 `bindings.influx` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.influx + version: v1 + metadata: + - name: url # 必需 + value: "" + - name: token # 必需 + value: "" + - name: org # 必需 + value: "" + - name: bucket # 必需 + value: "" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中,secret 使用了明文字符串。建议使用 secret 存储来保护这些信息,具体方法请参见[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `url` | Y | 输出 | InfluxDB 实例的 URL | `"http://localhost:8086"` | +| `token` | Y | 输出 | InfluxDB 的授权令牌 | `"mytoken"` | +| `org` | Y | 输出 | InfluxDB 组织 | `"myorg"` | +| `bucket` | Y | 输出 | 要写入的桶名称 | `"mybucket"` | + +## 绑定功能 + +此组件支持以下**输出绑定**操作: + +- `create` +- `query` + +### 查询 + +要查询 InfluxDB,请使用 `query` 操作,并在调用的元数据中使用 `raw` 键,将查询语句作为其值: + +``` +curl -X POST http://localhost:3500/v1.0/bindings/myInfluxBinding \ + -H "Content-Type: application/json" \ + -d "{ + \"metadata\": { + \"raw\": "SELECT * FROM 'sith_lords'" + }, + \"operation\": \"query\" + }" +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kafka.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kafka.md new file mode 100644 index 000000000..9f1dedd1a --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kafka.md @@ -0,0 +1,152 @@ +--- +type: docs +title: "Kafka 绑定规范" +linkTitle: "Kafka" +description: "关于 Kafka 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/kafka/" +--- + +## 组件格式 + +要配置 Kafka 绑定,需创建一个 `bindings.kafka` 类型的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。有关使用 `secretKeyRef` 的详细信息,请查看[如何在组件中引用 secret]({{< ref component-secrets.md >}})的指南。 + +所有组件的元数据字段值可以使用[模板化的元数据值]({{< ref "component-schema.md#templated-metadata-values" >}}),这些值会在 Dapr sidecar 启动时进行解析。例如,您可以选择使用 `{namespace}` 作为 `consumerGroup`,以便在不同命名空间中使用相同的 `appId` 和主题,如[本文]({{< ref "howto-namespace.md#with-namespace-consumer-groups">}})中所述。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: kafka-binding +spec: + type: bindings.kafka + version: v1 + metadata: + - name: topics # 可选。用于输入绑定。 + value: "topic1,topic2" + - name: brokers # 必需。 + value: "localhost:9092,localhost:9093" + - name: consumerGroup # 可选。用于输入绑定。 + value: "group1" + - name: publishTopic # 可选。用于输出绑定。 + value: "topic3" + - name: authRequired # 必需。 + value: "true" + - name: saslUsername # 如果 authRequired 为 `true`,则必需。 + value: "user" + - name: saslPassword # 如果 authRequired 为 `true`,则必需。 + secretKeyRef: + name: kafka-secrets + key: "saslPasswordSecret" + - name: saslMechanism + value: "SHA-512" + - name: initialOffset # 可选。用于输入绑定。 + value: "newest" + - name: maxMessageBytes # 可选。 + value: "1024" + - name: heartbeatInterval # 可选。 + value: 5s + - name: sessionTimeout # 可选。 + value: 15s + - name: version # 可选。 + value: "2.0.0" + - name: direction + value: "input, output" + - name: schemaRegistryURL # 可选。当使用 Schema Registry Avro 序列化/反序列化时。Schema Registry URL。 + value: http://localhost:8081 + - name: schemaRegistryAPIKey # 可选。当使用 Schema Registry Avro 序列化/反序列化时。Schema Registry API Key。 + value: XYAXXAZ + - name: schemaRegistryAPISecret # 可选。当使用 Schema Registry Avro 序列化/反序列化时。Schema Registry 凭证 API Secret。 + value: "ABCDEFGMEADFF" + - name: schemaCachingEnabled # 可选。当使用 Schema Registry Avro 序列化/反序列化时。启用 schema 缓存。 + value: true + - name: schemaLatestVersionCacheTTL # 可选。当使用 Schema Registry Avro 序列化/反序列化时。发布消息时使用最新 schema 的缓存 TTL。 + value: 5m + - name: escapeHeaders # 可选。 + value: false +``` + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `topics` | N | 输入 | 逗号分隔的主题字符串。 | `"mytopic1,topic2"` | +| `brokers` | Y | 输入/输出 | 逗号分隔的 Kafka brokers 字符串。 | `"localhost:9092,dapr-kafka.myapp.svc.cluster.local:9093"` | +| `clientID` | N | 输入/输出 | 用户提供的字符串,随每个请求发送到 Kafka brokers 以用于日志记录、调试和审计。 | `"my-dapr-app"` | +| `consumerGroup` | N | 输入 | 监听的 kafka 消费者组。发布到主题的每条记录都会传递给订阅该主题的每个消费者组中的一个消费者。 | `"group1"` | +| `consumeRetryEnabled` | N | 输入/输出 | 通过设置为 `"true"` 启用消费重试。在 Kafka 绑定组件中默认为 `false`。 | `"true"`, `"false"` | +| `publishTopic` | Y | 输出 | 要发布到的主题。 | `"mytopic"` | +| `authRequired` | N | *已弃用* | 启用与 Kafka brokers 的 [SASL](https://en.wikipedia.org/wiki/Simple_Authentication_and_Security_Layer) 认证。 | `"true"`, `"false"` | +| `authType` | Y | 输入/输出 | 配置或禁用认证。支持的值:`none`、`password`、`mtls` 或 `oidc` | `"password"`, `"none"` | +| `saslUsername` | N | 输入/输出 | 用于认证的 SASL 用户名。仅当 `authRequired` 设置为 `"true"` 时需要。 | `"adminuser"` | +| `saslPassword` | N | 输入/输出 | 用于认证的 SASL 密码。可以是 `secretKeyRef` 以使用[secret 引用]({{< ref component-secrets.md >}})。仅当 `authRequired` 设置为 `"true"` 时需要。 | `""`, `"KeFg23!"` | +| `saslMechanism` | N | 输入/输出 | 您想要使用的 SASL 认证机制。仅当 `authtype` 设置为 `"password"` 时需要。如果未提供,默认为 `PLAINTEXT`,这可能会导致某些服务(如 Amazon Managed Service for Kafka)中断。 | `"SHA-512", "SHA-256", "PLAINTEXT"` | +| `initialOffset` | N | 输入 | 如果之前没有提交偏移量,则使用的初始偏移量。应为 "newest" 或 "oldest"。默认为 "newest"。 | `"oldest"` | +| `maxMessageBytes` | N | 输入/输出 | 单个 Kafka 消息允许的最大字节大小。默认为 1024。 | `"2048"` | +| `oidcTokenEndpoint` | N | 输入/输出 | OAuth2 身份提供者访问令牌端点的完整 URL。当 `authType` 设置为 `oidc` 时需要 | "https://identity.example.com/v1/token" | +| `oidcClientID` | N | 输入/输出 | 在身份提供者中配置的 OAuth2 客户端 ID。当 `authType` 设置为 `oidc` 时需要 | `"dapr-kafka"` | +| `oidcClientSecret` | N | 输入/输出 | 在身份提供者中配置的 OAuth2 客户端 secret:当 `authType` 设置为 `oidc` 时需要 | `"KeFg23!"` | +| `oidcScopes` | N | 输入/输出 | 逗号分隔的 OAuth2/OIDC 范围列表,用于请求访问令牌。当 `authType` 设置为 `oidc` 时推荐。默认为 `"openid"` | `"openid,kafka-prod"` | +| `version` | N | 输入/输出 | Kafka 集群版本。默认为 2.0.0。请注意,对于使用 Kafka 的 EventHubs,必须将其设置为 `1.0.0`。 | `"1.0.0"` | +| `direction` | N | 输入/输出 | 绑定的方向。 | `"input"`, `"output"`, `"input, output"` | +| `oidcExtensions` | N | 输入/输出 | 包含 JSON 编码的 OAuth2/OIDC 扩展字典的字符串,用于请求访问令牌 | `{"cluster":"kafka","poolid":"kafkapool"}` | +| `schemaRegistryURL` | N | 使用 Schema Registry Avro 序列化/反序列化时必需。Schema Registry URL。 | `http://localhost:8081` | +| `schemaRegistryAPIKey` | N | 使用 Schema Registry Avro 序列化/反序列化时。Schema Registry 凭证 API Key。 | `XYAXXAZ` | +| `schemaRegistryAPISecret` | N | 使用 Schema Registry Avro 序列化/反序列化时。Schema Registry 凭证 API Secret。 | `ABCDEFGMEADFF` | +| `schemaCachingEnabled` | N | 使用 Schema Registry Avro 序列化/反序列化时。启用 schema 缓存。默认为 `true` | `true` | +| `schemaLatestVersionCacheTTL` | N | 使用 Schema Registry Avro 序列化/反序列化时。发布消息时使用最新 schema 的缓存 TTL。默认为 5 分钟 | `5m` | +| `clientConnectionTopicMetadataRefreshInterval` | N | 输入/输出 | 客户端连接的主题元数据与 broker 刷新的间隔,以 Go 持续时间表示。默认为 `9m`。 | `"4m"` | +| `clientConnectionKeepAliveInterval` | N | 输入/输出 | 客户端连接与 broker 保持活动的最长时间,以 Go 持续时间表示,然后关闭连接。零值(默认)表示无限期保持活动。 | `"4m"` | +| `consumerFetchDefault` | N | 输入/输出 | 每个请求从 broker 获取的默认消息字节数。默认为 `"1048576"` 字节。 | `"2097152"` | +| `heartbeatInterval` | N | 输入 | 向消费者协调器发送心跳的间隔。最多应设置为 `sessionTimeout` 值的 1/3。默认为 `"3s"`。 | `"5s"` | +| `sessionTimeout` | N | 输入 | 使用 Kafka 的组管理功能时用于检测客户端故障的超时时间。如果 broker 在此会话超时之前未收到任何来自消费者的心跳,则消费者将被移除并启动重新平衡。默认为 `"10s"`。 | `"20s"` | +| `escapeHeaders` | N | 输入 | 启用对消费者接收的消息头值的 URL 转义。允许接收通常不允许在 HTTP 头中的特殊字符内容。默认为 `false`。 | `true` | + +#### 注意 +使用 Azure EventHubs 和 Kafka 时,元数据 `version` 必须设置为 `1.0.0`。 + +## 绑定支持 + +此组件支持 **输入和输出** 绑定接口。 + +此组件支持具有以下操作的 **输出绑定**: + +- `create` + +## 认证 + +Kafka 支持多种认证方案,Dapr 支持几种:SASL 密码、mTLS、OIDC/OAuth2。[了解更多关于 Kafka 绑定和 Kafka pub/sub 组件的认证方法]({{< ref "setup-apache-kafka.md#authentication" >}})。 + +## 指定分区键 + +调用 Kafka 绑定时,可以通过请求体中的 `metadata` 部分提供可选的分区键。 + +字段名称为 `partitionKey`。 + +示例: + +```shell +curl -X POST http://localhost:3500/v1.0/bindings/myKafka \ + -H "Content-Type: application/json" \ + -d '{ + "data": { + "message": "Hi" + }, + "metadata": { + "partitionKey": "key1" + }, + "operation": "create" + }' +``` + +### 响应 + +如果成功,将返回 HTTP 204(无内容)和空响应体。 + +## 相关链接 + +- [Dapr 组件的基本 schema]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kinesis.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kinesis.md new file mode 100644 index 000000000..f02072dc0 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kinesis.md @@ -0,0 +1,80 @@ +--- +type: docs +title: "AWS Kinesis 绑定规范" +linkTitle: "AWS Kinesis" +description: "关于 AWS Kinesis 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/kinesis/" +--- + +## 组件格式 + +要设置 AWS Kinesis 绑定,需创建一个类型为 `bindings.aws.kinesis` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})以了解如何创建和应用绑定配置。 + +请参阅[此处](https://aws.amazon.com/kinesis/data-streams/getting-started/)以了解如何设置 AWS Kinesis 数据流。 +请参阅[认证到 AWS]({{< ref authenticating-aws.md >}})以获取与认证相关的属性信息。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.aws.kinesis + version: v1 + metadata: + - name: streamName + value: "KINESIS_STREAM_NAME" # Kinesis 流名称 + - name: consumerName + value: "KINESIS_CONSUMER_NAME" # Kinesis 消费者名称 + - name: mode + value: "shared" # shared - 共享吞吐量或 extended - 扩展/增强扇出 + - name: region + value: "AWS_REGION" # 请替换为实际的 AWS 区域 + - name: accessKey + value: "AWS_ACCESS_KEY" # 请替换为实际的 AWS 访问密钥 + - name: secretKey + value: "AWS_SECRET_KEY" # 请替换为实际的 AWS 秘密访问密钥 + - name: sessionToken + value: "*****************" + - name: direction + value: "input, output" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中使用了明文字符串作为 secret。建议使用 secret 存储来存储 secret,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `mode` | 否 | 输入| Kinesis 流模式。`shared`- 共享吞吐量,`extended` - 扩展/增强扇出方法。更多详情请参阅[此处](https://docs.aws.amazon.com/streams/latest/dev/building-consumers.html)。默认为 `"shared"` | `"shared"`, `"extended"` | +| `streamName` | 是 | 输入/输出 | AWS Kinesis 流名称 | `"stream"` | +| `consumerName` | 是 | 输入 | AWS Kinesis 消费者名称 | `"myconsumer"` | +| `region` | 是 | 输出 | 部署 AWS Kinesis 实例的特定 AWS 区域 | `"us-east-1"` | +| `accessKey` | 是 | 输出 | 访问此资源的 AWS 访问密钥 | `"key"` | +| `secretKey` | 是 | 输出 | 访问此资源的 AWS 秘密访问密钥 | `"secretAccessKey"` | +| `sessionToken` | 否 | 输出 | 使用的 AWS 会话令牌 | `"sessionToken"` | +| `direction` | 否 | 输入/输出 | 绑定的方向 | `"input"`, `"output"`, `"input, output"` | + +{{% alert title="重要" color="warning" %}} +在 EKS(AWS Kubernetes)上运行 Dapr sidecar(daprd)与您的应用程序一起时,如果节点/Pod 已附加了定义访问 AWS 资源的 IAM 策略,则**不应**在组件规范中提供 AWS 访问密钥、秘密密钥和令牌。 +{{% /alert %}} + +## 绑定支持 + +此组件支持**输入和输出**绑定接口。 + +此组件支持具有以下操作的**输出绑定**: + +- `create` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) +- [认证到 AWS]({{< ref authenticating-aws.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kitex.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kitex.md new file mode 100644 index 000000000..fa71aae61 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kitex.md @@ -0,0 +1,90 @@ +--- +type: docs +title: "Kitex" +linkTitle: "Kitex" +description: "Kitex 绑定组件的详细文档" +aliases: +- "/zh-hans/operations/components/setup-bindings/supported-bindings/kitex/" +--- + +## 概述 + +Kitex 绑定主要利用其通用调用功能。可以从官方文档中了解更多关于 [Kitex 通用调用的详细信息](https://www.cloudwego.io/docs/kitex/tutorials/advanced-feature/generic-call/)。 +目前,Kitex 仅支持 Thrift 通用调用。集成到 [components-contrib](https://github.com/dapr/components-contrib/tree/master/bindings/kitex) 的实现采用了二进制通用调用方式。 + +## 组件格式 + +要设置 Kitex 绑定,创建一个类型为 `bindings.kitex` 的组件。请参阅[如何:使用输出绑定与外部资源接口]({{< ref "howto-bindings.md#1-create-a-binding" >}})指南,了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: bindings.kitex +spec: + type: bindings.kitex + version: v1 + metadata: + - name: hostPorts + value: "127.0.0.1:8888" + - name: destService + value: "echo" + - name: methodName + value: "echo" + - name: version + value: "0.5.0" +``` + +## 元数据字段说明 + +`bindings.kitex` 的 `InvokeRequest.Metadata` 要求客户端在调用时填写以下四个必需项: + +- `hostPorts` +- `destService` +- `methodName` +- `version` + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|-------------|:----:|--------|-----------------------------------------------------------------------------------------------------|--------------------| +| `hostPorts` | 是 | 输出 | Kitex 服务器(Thrift)的 IP 地址和端口信息 | `"127.0.0.1:8888"` | +| `destService` | 是 | 输出 | Kitex 服务器(Thrift)的服务名称 | `"echo"` | +| `methodName` | 是 | 输出 | Kitex 服务器(Thrift)中某个服务名称下的方法名称 | `"echo"` | +| `version` | 是 | 输出 | Kitex 的版本号 | `"0.5.0"` | + +## 绑定支持 + +此组件支持具有以下操作的**输出绑定**: + +- `get` + +## 示例 + +使用 Kitex 绑定时: +- 客户端需要传入经过 Thrift 编码的二进制数据 +- 服务器需要是一个 Thrift 服务器。 + +可以参考 [kitex_output_test](https://github.com/dapr/components-contrib/blob/master/bindings/kitex/kitex_output_test.go)。 +例如,变量 `reqData` 需要在发送前通过 Thrift 协议进行编码,返回的数据需要通过 Thrift 协议进行解码。 + +**请求** + +```json +{ + "operation": "get", + "metadata": { + "hostPorts": "127.0.0.1:8888", + "destService": "echo", + "methodName": "echo", + "version":"0.5.0" + }, + "data": reqdata +} +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kubemq.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kubemq.md new file mode 100644 index 000000000..030083c3c --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kubemq.md @@ -0,0 +1,118 @@ +--- +type: docs +title: "KubeMQ 绑定规范" +linkTitle: "KubeMQ" +description: "关于 KubeMQ 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/kubemq/" +--- + +## 组件格式 + +要设置 KubeMQ 绑定,需创建一个类型为 `bindings.kubemq` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: binding-topic +spec: + type: bindings.kubemq + version: v1 + metadata: + - name: address + value: "localhost:50000" + - name: channel + value: "queue1" + - name: direction + value: "input, output" +``` + +## 规范元数据字段 + +| 字段 | 必需 | 详情 | 示例 | +|--------------------|:----:|---------------------------------------------------------------------------------------------------------------------------|-------------------------------------| +| `address` | Y | KubeMQ 服务器的地址 | `"localhost:50000"` | +| `channel` | Y | 队列通道名称 | `"queue1"` | +| `authToken` | N | 连接的 Auth JWT 令牌。请参阅 [KubeMQ 认证](https://docs.kubemq.io/learn/access-control/authentication) | `"ew..."` | +| `autoAcknowledged` | N | 设置是否自动确认接收到的队列消息 | `"true"` 或 `"false"` (默认是 `"false"`) | +| `pollMaxItems` | N | 设置每次连接轮询的消息数量 | `"1"` | +| `pollTimeoutSeconds` | N | 设置每个轮询间隔的时间(秒) | `"3600"` | +| `direction` | N | 绑定的方向 | `"input"`, `"output"`, `"input, output"` | + +## 绑定支持 + +该组件支持 **输入和输出** 绑定接口。 + +## 创建 KubeMQ 代理 + +{{< tabs "Self-Hosted" "Kubernetes">}} + +{{% codetab %}} +1. [获取 KubeMQ 密钥](https://docs.kubemq.io/getting-started/quick-start#obtain-kubemq-license-key)。 +2. 等待电子邮件确认您的密钥 + +您可以使用 Docker 运行 KubeMQ 代理: + +```bash +docker run -d -p 8080:8080 -p 50000:50000 -p 9090:9090 -e KUBEMQ_TOKEN= kubemq/kubemq +``` +然后,您可以通过客户端端口与服务器交互:`localhost:50000` + +{{% /codetab %}} + +{{% codetab %}} +1. [获取 KubeMQ 密钥](https://docs.kubemq.io/getting-started/quick-start#obtain-kubemq-license-key)。 +2. 等待电子邮件确认您的密钥 + +然后运行以下 kubectl 命令: + +```bash +kubectl apply -f https://deploy.kubemq.io/init +``` + +```bash +kubectl apply -f https://deploy.kubemq.io/key/ +``` +{{% /codetab %}} + +{{< /tabs >}} + +## 安装 KubeMQ CLI +请访问 [KubeMQ CLI](https://github.com/kubemq-io/kubemqctl/releases) 并下载最新版本的 CLI。 + +## 浏览 KubeMQ 仪表板 + +{{< tabs "Self-Hosted" "Kubernetes">}} + +{{% codetab %}} + +打开浏览器并导航到 [http://localhost:8080](http://localhost:8080) + +{{% /codetab %}} + +{{% codetab %}} +安装 KubeMQCTL 后,运行以下命令: + +```bash +kubemqctl get dashboard +``` +或者,安装 kubectl 后,运行端口转发命令: + +```bash +kubectl port-forward svc/kubemq-cluster-api -n kubemq 8080:8080 +``` +{{% /codetab %}} + +{{< /tabs >}} + +## KubeMQ 文档 +访问 [KubeMQ 文档](https://docs.kubemq.io/) 了解更多信息。 + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kubernetes-binding.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kubernetes-binding.md new file mode 100644 index 000000000..3761319a6 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/kubernetes-binding.md @@ -0,0 +1,126 @@ +--- +type: docs +title: "Kubernetes Events 绑定指南" +linkTitle: "Kubernetes Events" +description: "详细介绍 Kubernetes Events 绑定组件的文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/kubernetes-binding/" +--- + +## 组件格式 + +为了配置 Kubernetes Events 绑定,需要创建一个类型为 `bindings.kubernetes` 的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.kubernetes + version: v1 + metadata: + - name: namespace + value: "" + - name: resyncPeriodInSec + value: "" + - name: direction + value: "input" +``` + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `namespace` | 是 | 输入 | 要读取事件的 Kubernetes 命名空间 | `"default"` | +| `resyncPeriodInSec` | 否 | 输入 | 从 Kubernetes API 服务器刷新事件列表的时间间隔,默认为 `"10"` 秒 | `"15"` +| `direction` | 否 | 输入 | 绑定的方向 | `"input"` +| `kubeconfigPath` | 否 | 输入 | kubeconfig 文件的路径。如果未指定,将使用默认的集群内配置 | `"/path/to/kubeconfig"` + +## 绑定支持 + +此组件支持**输入**绑定接口。 + +## 输出格式 + +从绑定接收到的输出格式为 `bindings.ReadResponse`,其中 `Data` 字段包含以下结构: + +```json + { + "event": "", + "oldVal": { + "metadata": { + "name": "hello-node.162c2661c524d095", + "namespace": "kube-events", + "selfLink": "/api/v1/namespaces/kube-events/events/hello-node.162c2661c524d095", + ... + }, + "involvedObject": { + "kind": "Deployment", + "namespace": "kube-events", + ... + }, + "reason": "ScalingReplicaSet", + "message": "Scaled up replica set hello-node-7bf657c596 to 1", + ... + }, + "newVal": { + "metadata": { "creationTimestamp": "null" }, + "involvedObject": {}, + "source": {}, + "firstTimestamp": "null", + "lastTimestamp": "null", + "eventTime": "null", + ... + } + } +``` +事件类型有三种: +- Add : 只有 `newVal` 字段有值,`oldVal` 字段为空的 `v1.Event`,`event` 为 `add` +- Delete : 只有 `oldVal` 字段有值,`newVal` 字段为空的 `v1.Event`,`event` 为 `delete` +- Update : `oldVal` 和 `newVal` 字段都有值,`event` 为 `update` + +## 所需权限 + +要从 Kubernetes 获取 `events`,需要通过 Kubernetes 的 [RBAC 授权] 机制为用户/组/服务账户分配权限。 + +### 角色 + +需要以下形式的规则之一来授予 `get, watch` 和 `list` `events` 的权限。API 组可以根据需要进行限制。 + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: +rules: +- apiGroups: [""] + resources: ["events"] + verbs: ["get", "watch", "list"] +``` + +### 角色绑定 + +```yaml +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: +subjects: +- kind: ServiceAccount + name: default # 或根据需要更改 +roleRef: + kind: Role + name: # 与上面相同 + apiGroup: "" +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [Bindings 构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [Bindings API 参考]({{< ref bindings_api.md >}}) +``` +This translation aims to improve readability and align with Chinese expression habits while maintaining the technical accuracy of the original conte \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/localstorage.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/localstorage.md new file mode 100644 index 000000000..89e767752 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/localstorage.md @@ -0,0 +1,263 @@ +--- +type: docs +title: "本地存储绑定规范" +linkTitle: "本地存储" +description: "关于本地存储绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/localstorage/" +--- + +## 组件格式 + +要配置本地存储绑定,创建一个类型为 `bindings.localstorage` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})以了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.localstorage + version: v1 + metadata: + - name: rootPath + value: "" +``` + +## 元数据字段规范 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|--------|---------|---------| +| `rootPath` | Y | 输出 | 文件可读写的根路径 | `"/temp/files"` | + +## 绑定支持 + +此组件支持**输出绑定**,具有以下操作: + +- `create` : [创建文件](#create-file) +- `get` : [获取文件](#get-file) +- `list` : [列出文件](#list-files) +- `delete` : [删除文件](#delete-file) + +### 创建文件 + +要执行创建文件操作,使用 `POST` 方法调用本地存储绑定,并使用以下 JSON 正文: + +> 注意:默认情况下,会生成一个随机的 UUID 作为文件名。请参阅下文的元数据支持以设置自定义文件名。 + +```json +{ + "operation": "create", + "data": "YOUR_CONTENT" +} +``` + +#### 示例 + +##### 将文本保存到随机生成的 UUID 文件 + +{{< tabs Windows Linux >}} + {{% codetab %}} + 在 Windows 上,使用 cmd 提示符(PowerShell 有不同的转义机制) + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"Hello World\" }" http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "Hello World" }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 将文本保存到特定文件 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"Hello World\", \"metadata\": { \"fileName\": \"my-test-file.txt\" } }" \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "Hello World", "metadata": { "fileName": "my-test-file.txt" } }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 保存二进制文件 + +要上传文件,请将其编码为 Base64。绑定会自动检测 Base64 编码。 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"YOUR_BASE_64_CONTENT\", \"metadata\": { \"fileName\": \"my-test-file.jpg\" } }" http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "YOUR_BASE_64_CONTENT", "metadata": { "fileName": "my-test-file.jpg" } }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文将包含以下 JSON: + +```json +{ + "fileName": "" +} + +``` + +### 获取文件 + +要执行获取文件操作,使用 `POST` 方法调用本地存储绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "get", + "metadata": { + "fileName": "myfile" + } +} +``` + +#### 示例 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"get\", \"metadata\": { \"fileName\": \"myfile\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "get", "metadata": { "fileName": "myfile" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文包含存储在文件中的值。 + +### 列出文件 + +要执行列出文件操作,使用 `POST` 方法调用本地存储绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "list" +} +``` + +如果您只想列出 `rootPath` 下特定目录中的文件,请在元数据中指定相对目录名称作为 `fileName`。 + +```json +{ + "operation": "list", + "metadata": { + "fileName": "my/cool/directory" + } +} +``` + +#### 示例 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"list\", \"metadata\": { \"fileName\": \"my/cool/directory\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "list", "metadata": { "fileName": "my/cool/directory" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应是一个文件名的 JSON 数组。 + +### 删除文件 + +要执行删除文件操作,使用 `POST` 方法调用本地存储绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "delete", + "metadata": { + "fileName": "myfile" + } +} +``` + +#### 示例 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"delete\", \"metadata\": { \"fileName\": \"myfile\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "delete", "metadata": { "fileName": "myfile" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +如果成功,将返回 HTTP 204(无内容)和空正文。 + +## 元数据信息 + +默认情况下,本地存储输出绑定会自动生成一个 UUID 作为文件名。您可以在消息的元数据属性中自定义文件名。 + +```json +{ + "data": "file content", + "metadata": { + "fileName": "filename.txt" + }, + "operation": "create" +} +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/mqtt3.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/mqtt3.md new file mode 100644 index 000000000..33b478432 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/mqtt3.md @@ -0,0 +1,181 @@ +--- +type: docs +title: "MQTT3 绑定规范" +linkTitle: "MQTT3" +description: "关于 MQTT3 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/mqtt3/" + - "/zh-hans/operations/components/setup-bindings/supported-bindings/mqtt/" +--- + +## 组件格式 + +要设置 MQTT3 绑定,需要创建一个类型为 `bindings.mqtt3` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.mqtt3 + version: v1 + metadata: + - name: url + value: "tcp://[username][:password]@host.domain[:port]" + - name: topic + value: "mytopic" + - name: consumerID + value: "myapp" + # 以下字段是可选的: + - name: retain + value: "false" + - name: cleanSession + value: "false" + - name: backOffMaxRetries + value: "0" + - name: direction + value: "input, output" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中,secret 以明文字符串形式使用。建议使用 secret 存储来保护这些信息,具体方法请参见[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|---------|---------|---------| +| `url` | Y | 输入/输出 | MQTT broker 的地址。可以使用 `secretKeyRef` 来引用 secret。
对于非 TLS 通信,使用 **`tcp://`** URI 方案。
对于 TLS 通信,使用 **`ssl://`** URI 方案。 | `"tcp://[username][:password]@host.domain[:port]"` +| `topic` | Y | 输入/输出 | 要监听或发送事件的主题。 | `"mytopic"` | +| `consumerID` | Y | 输入/输出 | 用于连接到 MQTT broker 的客户端 ID。 | `"myMqttClientApp"` +| `retain` | N | 输入/输出 | 定义消息是否由 broker 保存为指定主题的最后已知良好值。默认为 `"false"`。 | `"true"`, `"false"` +| `cleanSession` | N | 输入/输出 | 如果为 `"true"`,则在连接消息中设置 `clean_session` 标志到 MQTT broker。默认为 `"false"`。 | `"true"`, `"false"` +| `caCert` | 使用 TLS 时必需 | 输入/输出 | 用于验证服务器 TLS 证书的 PEM 格式的证书颁发机构 (CA) 证书。 | 见下例 +| `clientCert` | 使用 TLS 时必需 | 输入/输出 | PEM 格式的 TLS 客户端证书。必须与 `clientKey` 一起使用。 | 见下例 +| `clientKey` | 使用 TLS 时必需 | 输入/输出 | PEM 格式的 TLS 客户端密钥。必须与 `clientCert` 一起使用。可以使用 `secretKeyRef` 来引用 secret。 | 见下例 +| `backOffMaxRetries` | N | 输入 | 在返回错误之前处理消息的最大重试次数。默认为 `"0"`,表示不会尝试重试。可以指定 `"-1"` 表示消息应无限期重试,直到成功处理或应用程序关闭。组件将在重试之间等待 5 秒。 | `"3"` +| `direction` | N | 输入/输出 | 绑定的方向 | `"input"`, `"output"`, `"input, output"` + +### 使用 TLS 进行通信 + +要配置使用 TLS 的通信,请确保 MQTT broker(例如 emqx)配置为支持证书,并在组件配置中提供 `caCert`、`clientCert`、`clientKey` 元数据。例如: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: mqtt-binding +spec: + type: bindings.mqtt3 + version: v1 + metadata: + - name: url + value: "ssl://host.domain[:port]" + - name: topic + value: "topic1" + - name: consumerID + value: "myapp" + # TLS 配置 + - name: caCert + value: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + - name: clientCert + value: | + -----BEGIN CERTIFICATE----- + ... + -----END CERTIFICATE----- + - name: clientKey + secretKeyRef: + name: myMqttClientKey + key: myMqttClientKey + # 以下字段是可选的: + - name: retain + value: "false" + - name: cleanSession + value: "false" + - name: backoffMaxRetries + value: "0" +``` + +> 注意,虽然 `caCert` 和 `clientCert` 的值可能不是 secret,但为了方便起见,它们也可以从 Dapr secret 存储中引用。 + +### 消费共享主题 + +在消费共享主题时,每个消费者必须有一个唯一的标识符。如果运行多个应用程序实例,可以在组件的 `consumerID` 元数据中配置一个 `{uuid}` 标签,这将在启动时为每个实例提供一个随机生成的 `consumerID` 值。例如: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: mqtt-binding + namespace: default +spec: + type: bindings.mqtt3 + version: v1 + metadata: + - name: consumerID + value: "{uuid}" + - name: url + value: "tcp://admin:public@localhost:1883" + - name: topic + value: "topic1" + - name: retain + value: "false" + - name: cleanSession + value: "true" + - name: backoffMaxRetries + value: "0" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中,secret 以明文字符串形式使用。建议使用 secret 存储来保护这些信息,具体方法请参见[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +> 在这种情况下,每次 Dapr 重启时,消费者 ID 的值都是随机的,因此您也应该将 `cleanSession` 设置为 `true`。 + +## 绑定支持 + +此组件支持 **输入和输出** 绑定接口。 + +此组件支持以下操作的 **输出绑定**: + +- `create`: 发布新消息 + +## 每次请求设置主题 + +您可以在每次请求时覆盖组件元数据中的主题: + +```json +{ + "operation": "create", + "metadata": { + "topic": "myTopic" + }, + "data": "

测试 Dapr 绑定

这是一个测试。
再见!" +} +``` + +## 每次请求设置保留属性 + +您可以在每次请求时覆盖组件元数据中的保留属性: + +```json +{ + "operation": "create", + "metadata": { + "retain": "true" + }, + "data": "

测试 Dapr 绑定

这是一个测试。
再见!" +} +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/mysql.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/mysql.md new file mode 100644 index 000000000..26c44b8e0 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/mysql.md @@ -0,0 +1,191 @@ +--- +type: docs +title: "MySQL & MariaDB 绑定规范" +linkTitle: "MySQL & MariaDB" +description: "关于 MySQL 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/mysql/" +--- + +## 组件格式 + +MySQL 绑定支持连接 MySQL 和 MariaDB 数据库。在本文档中,"MySQL" 用于指代这两个数据库。 + +要设置 MySQL 绑定,请创建一个类型为 `bindings.mysql` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +MySQL 绑定使用 [Go-MySQL-Driver](https://github.com/go-sql-driver/mysql) 作为内部驱动。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.mysql + version: v1 + metadata: + - name: url # 必需,定义数据库连接的 DSN 格式 + value: "" + - name: pemPath # 可选 + value: "" + - name: maxIdleConns + value: "" + - name: maxOpenConns + value: "" + - name: connMaxLifetime + value: "" + - name: connMaxIdleTime + value: "" +``` + +{{% alert title="警告" color="warning" %}} +上面的示例使用明文字符串作为 secret。建议使用 secret 存储来存储 secret,如[此处]({{< ref component-secrets.md >}})所述。 +请注意,您不能仅为用户名/密码使用 secret。如果使用 secret,必须用于完整的连接字符串。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `url` | Y | 输出 | 以数据源名称 (DSN) 格式表示数据库连接。查看 [此处](#ssl-connection-details) 的 SSL 详情 | `"user:password@tcp(localhost:3306)/dbname"` | +| `pemPath` | Y | 输出 | PEM 文件的路径。用于 SSL 连接 | `"path/to/pem/file"` | +| `maxIdleConns` | N | 输出 | 最大空闲连接数。大于 0 的整数 | `"10"` | +| `maxOpenConns` | N | 输出 | 最大打开连接数。大于 0 的整数 | `"10"` | +| `connMaxLifetime` | N | 输出 | 最大连接生命周期。格式为持续时间字符串,例如 `"12s"` | `"12s"` | +| `connMaxIdleTime` | N | 输出 | 最大连接空闲时间。格式为持续时间字符串,例如 `"12s"` | `"12s"` | + +### SSL 连接 + +如果您的服务器需要 SSL,您的连接字符串必须以 `&tls=custom` 结尾,例如: + +```bash +":@tcp(:3306)/?allowNativePasswords=true&tls=custom" +``` + +> 您必须将 `` 替换为 PEM 文件的完整路径。如果您使用的是 Azure Database for MySQL,请参阅 Azure [关于 SSL 数据库连接的文档](https://learn.microsoft.com/azure/mysql/single-server/how-to-configure-ssl),了解如何下载所需的证书。连接到 MySQL 需要最低 TLS 版本为 1.2。 + +### 多语句 + +默认情况下,[MySQL Go 驱动](https://github.com/go-sql-driver/mysql) 仅支持每个查询/命令一个 SQL 语句。 + +要在一个查询中允许多个语句,您需要在查询字符串中添加 `multiStatements=true`,例如: + +```bash +":@tcp(:3306)/?multiStatements=true" +``` + +虽然这允许批量查询,但也大大增加了 SQL 注入的风险。仅返回第一个查询的结果,所有其他结果将被静默丢弃。 + +## 绑定支持 + +此组件支持具有以下操作的**输出绑定**: + +- `exec` +- `query` +- `close` + +### 参数化查询 + +此绑定支持参数化查询,允许将 SQL 查询本身与用户提供的值分开。强烈建议使用参数化查询以提高安全性,因为它们可以防止 [SQL 注入攻击](https://owasp.org/www-community/attacks/SQL_Injection)。 + +例如: + +```sql +-- ❌ 错误!在查询中包含值,容易受到 SQL 注入攻击。 +SELECT * FROM mytable WHERE user_key = 'something'; + +-- ✅ 好!使用参数化查询。 +-- 这将使用参数 ["something"] 执行 +SELECT * FROM mytable WHERE user_key = ?; +``` + +### exec + +`exec` 操作可用于 DDL 操作(如表创建),以及返回仅元数据的 `INSERT`、`UPDATE`、`DELETE` 操作(例如受影响的行数)。 + +`params` 属性是一个包含 JSON 编码参数数组的字符串。 + +**请求** + +```json +{ + "operation": "exec", + "metadata": { + "sql": "INSERT INTO foo (id, c1, ts) VALUES (?, ?, ?)", + "params": "[1, \"demo\", \"2020-09-24T11:45:05Z07:00\"]" + } +} +``` + +**响应** + +```json +{ + "metadata": { + "operation": "exec", + "duration": "294µs", + "start-time": "2020-09-24T11:13:46.405097Z", + "end-time": "2020-09-24T11:13:46.414519Z", + "rows-affected": "1", + "sql": "INSERT INTO foo (id, c1, ts) VALUES (?, ?, ?)" + } +} +``` + +### query + +`query` 操作用于 `SELECT` 语句,返回元数据以及以行值数组形式的数据。 + +`params` 属性是一个包含 JSON 编码参数数组的字符串。 + +**请求** + +```json +{ + "operation": "query", + "metadata": { + "sql": "SELECT * FROM foo WHERE id < $1", + "params": "[3]" + } +} +``` + +**响应** + +```json +{ + "metadata": { + "operation": "query", + "duration": "432µs", + "start-time": "2020-09-24T11:13:46.405097Z", + "end-time": "2020-09-24T11:13:46.420566Z", + "sql": "SELECT * FROM foo WHERE id < ?" + }, + "data": [ + {column_name: value, column_name: value, ...}, + {column_name: value, column_name: value, ...}, + {column_name: value, column_name: value, ...}, + ] +} +``` + +这里的 column_name 是查询返回的列名,value 是该列的值。请注意,值以字符串或数字(语言特定的数据类型)返回。 + +### close + +`close` 操作可用于显式关闭数据库连接并将其返回到池中。此操作没有任何响应。 + +**请求** + +```json +{ + "operation": "close" +} +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/openai.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/openai.md new file mode 100644 index 000000000..53a32d9b1 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/openai.md @@ -0,0 +1,291 @@ +--- +type: docs +title: "Azure OpenAI 绑定组件规范" +linkTitle: "Azure OpenAI" +description: "关于 Azure OpenAI 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/openai/" +--- + +## 组件格式 + +要设置 Azure OpenAI 绑定组件,请创建一个类型为 `bindings.azure.openai` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 +有关 Azure OpenAI 服务的文档,请参阅[此处](https://learn.microsoft.com/azure/cognitive-services/openai/overview/)。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.azure.openai + version: v1 + metadata: + - name: apiKey # 必需 + value: "1234567890abcdef" + - name: endpoint # 必需 + value: "https://myopenai.openai.azure.com" +``` +{{% alert title="警告" color="warning" %}} +上述示例中,`apiKey` 被直接用作字符串。建议使用密钥存储来保存敏感信息,具体方法请参阅[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|--------|---------|---------| +| `endpoint` | Y | 输出 | Azure OpenAI 服务端点的 URL。 | `"https://myopenai.openai.azure.com"` | +| `apiKey` | Y* | 输出 | Azure OpenAI 服务的访问密钥。仅在不使用 Microsoft Entra ID 认证时需要。 | `"1234567890abcdef"` | +| `azureTenantId` | Y* | 输入 | Azure OpenAI 资源的租户 ID。仅在未提供 `apiKey` 时需要。 | `"tenentID"` | +| `azureClientId` | Y* | 输入 | 用于创建或更新 Azure OpenAI 订阅并认证传入消息的客户端 ID。仅在未提供 `apiKey` 时需要。| `"clientId"` | +| `azureClientSecret` | Y* | 输入 | 用于创建或更新 Azure OpenAI 订阅并认证传入消息的客户端密钥。仅在未提供 `apiKey` 时需要。 | `"clientSecret"` | + +### Microsoft Entra ID 认证 + +Azure OpenAI 绑定组件支持使用所有 Microsoft Entra ID 机制进行认证。有关更多信息以及根据选择的 Microsoft Entra ID 认证机制提供的相关组件元数据字段,请参阅[认证到 Azure 的文档]({{< ref authenticating-azure.md >}})。 + +#### 示例配置 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: component +metadata: + name: +spec: + type: bindings.azure.openai + version: v1 + metadata: + - name: endpoint + value: "https://myopenai.openai.azure.com" + - name: azureTenantId + value: "***" + - name: azureClientId + value: "***" + - name: azureClientSecret + value: "***" +``` +## 绑定功能支持 + +此组件支持以下操作的**输出绑定**: + +- `completion` : [Completion API](#completion-api) +- `chat-completion` : [Chat Completion API](#chat-completion-api) +- `get-embedding` : [Embedding API](#get-embedding-api) + +### Completion API + +要使用提示调用 Completion API,请使用 `POST` 方法调用 Azure OpenAI 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "completion", + "data": { + "deploymentId": "my-model", + "prompt": "A dog is", + "maxTokens":5 + } +} +``` + +数据参数为: + +- `deploymentId` - 指定要使用的模型部署 ID 的字符串。 +- `prompt` - 指定要生成完成的提示的字符串。 +- `maxTokens` - (可选)定义要生成的最大令牌数。Completion API 默认为 16。 +- `temperature` - (可选)定义采样温度,范围为 0 到 2。较高的值如 0.8 使输出更随机,而较低的值如 0.2 使其更集中和确定。Completion API 默认为 1.0。 +- `topP` - (可选)定义采样温度。Completion API 默认为 1.0。 +- `n` - (可选)定义要生成的完成数。Completion API 默认为 1。 +- `presencePenalty` - (可选)介于 -2.0 和 2.0 之间的数字。正值根据它们是否出现在文本中对新令牌进行惩罚,从而增加模型谈论新主题的可能性。Completion API 默认为 0.0。 +- `frequencyPenalty` - (可选)介于 -2.0 和 2.0 之间的数字。正值根据它们在文本中的现有频率对新令牌进行惩罚,从而减少模型逐字重复同一行的可能性。Completion API 默认为 0.0。 + +在 [Azure OpenAI API 文档](https://learn.microsoft.com/azure/ai-services/openai/reference)中阅读更多关于这些参数的重要性和用法。 +#### 示例 + +{{< tabs Linux >}} + {{% codetab %}} + ```bash + curl -d '{ "data": {"deploymentId: "my-model" , "prompt": "A dog is ", "maxTokens":15}, "operation": "completion" }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文包含以下 JSON: + +```json +[ + { + "finish_reason": "length", + "index": 0, + "text": " a pig in a dress.\n\nSun, Oct 20, 2013" + }, + { + "finish_reason": "length", + "index": 1, + "text": " the only thing on earth that loves you\n\nmore than he loves himself.\"\n\n" + } +] + +``` + +### Chat Completion API + +要执行 chat-completion 操作,请使用 `POST` 方法调用 Azure OpenAI 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "chat-completion", + "data": { + "deploymentId": "my-model", + "messages": [ + { + "role": "system", + "message": "You are a bot that gives really short replies" + }, + { + "role": "user", + "message": "Tell me a joke" + } + ], + "n": 2, + "maxTokens": 30, + "temperature": 1.2 + } +} +``` + +数据参数为: + +- `deploymentId` - 指定要使用的模型部署 ID 的字符串。 +- `messages` - 将用于生成聊天完成的消息数组。 +每条消息的格式为: + - `role` - 指定消息角色的字符串。可以是 `user`、`system` 或 `assistant`。 + - `message` - 指定角色的对话消息的字符串。 +- `maxTokens` - (可选)定义要生成的最大令牌数。Chat Completion API 默认为 16。 +- `temperature` - (可选)定义采样温度,范围为 0 到 2。较高的值如 0.8 使输出更随机,而较低的值如 0.2 使其更集中和确定。Chat Completion API 默认为 1.0。 +- `topP` - (可选)定义采样温度。Chat Completion API 默认为 1.0。 +- `n` - (可选)定义要生成的完成数。Chat Completion API 默认为 1。 +- `presencePenalty` - (可选)介于 -2.0 和 2.0 之间的数字。正值根据它们是否出现在文本中对新令牌进行惩罚,从而增加模型谈论新主题的可能性。Chat Completion API 默认为 0.0。 +- `frequencyPenalty` - (可选)介于 -2.0 和 2.0 之间的数字。正值根据它们在文本中的现有频率对新令牌进行惩罚,从而减少模型逐字重复同一行的可能性。Chat Completion API 默认为 0.0。 + +#### 示例 + +{{< tabs Linux >}} + + {{% codetab %}} + ```bash +curl -d '{ + "data": { + "deploymentId": "my-model", + "messages": [ + { + "role": "system", + "message": "You are a bot that gives really short replies" + }, + { + "role": "user", + "message": "Tell me a joke" + } + ], + "n": 2, + "maxTokens": 30, + "temperature": 1.2 + }, + "operation": "chat-completion" +}' \ +http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文包含以下 JSON: + +```json +[ + { + "finish_reason": "stop", + "index": 0, + "message": { + "content": "Why was the math book sad? Because it had too many problems.", + "role": "assistant" + } + }, + { + "finish_reason": "stop", + "index": 1, + "message": { + "content": "Why did the tomato turn red? Because it saw the salad dressing!", + "role": "assistant" + } + } +] + +``` + +### 获取嵌入 API + +`get-embedding` 操作返回给定输入的向量表示,可以被机器学习模型和其他算法轻松使用。 +要执行 `get-embedding` 操作,请使用 `POST` 方法调用 Azure OpenAI 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "get-embedding", + "data": { + "deploymentId": "my-model", + "message": "The capital of France is Paris." + } +} +``` + +数据参数为: + +- `deploymentId` - 指定要使用的模型部署 ID 的字符串。 +- `message` - 指定要嵌入的文本的字符串。 + +#### 示例 + +{{< tabs Linux >}} + +{{% codetab %}} + ```bash +curl -d '{ + "data": { + "deploymentId": "embeddings", + "message": "The capital of France is Paris." + }, + "operation": "get-embedding" +}' \ +http://localhost:/v1.0/bindings/ + ``` +{{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文包含以下 JSON: + +```json +[0.018574921,-0.00023652936,-0.0057790717,.... (1536 floats total for ada)] +``` + +## 了解更多关于 Azure OpenAI 输出绑定的信息 + +观看[以下社区电话演示](https://youtu.be/rTovKpG0rhY?si=g7hZTQSpSEXz4pV1&t=80)以了解更多关于 Azure OpenAI 输出绑定的信息。 + + + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) +- [Azure OpenAI REST 示例](https://learn.microsoft.com/azure/ai-services/openai/reference) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/postgresql.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/postgresql.md new file mode 100644 index 000000000..a72f0587e --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/postgresql.md @@ -0,0 +1,215 @@ +--- +type: docs +title: "PostgreSQL 绑定组件规范" +linkTitle: "PostgreSQL" +description: "关于 PostgreSQL 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/postgresql/" + - "/zh-hans/operations/components/setup-bindings/supported-bindings/postgres/" +--- + +## 组件配置格式 + +要设置 PostgreSQL 绑定,请创建一个类型为 `bindings.postgresql` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.postgresql + version: v1 + metadata: + # 连接字符串 + - name: connectionString + value: "" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中,secret 以明文字符串形式使用。建议使用 secret 存储来保存 secret,具体方法请参见[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 规范元数据字段 + +### 通过连接字符串进行身份验证 + +以下元数据选项是通过连接字符串进行身份验证时**必需**的。 + +| 字段 | 必需 | 详情 | 示例 | +|--------|:--------:|---------|---------| +| `connectionString` | Y | PostgreSQL 数据库的连接字符串。有关如何定义连接字符串的信息,请参阅 PostgreSQL [数据库连接文档](https://www.postgresql.org/docs/current/libpq-connect.html)。 | `"host=localhost user=postgres password=example port=5432 connect_timeout=10 database=my_db"` + +### 通过 Microsoft Entra ID 进行身份验证 + +在 Azure Database for PostgreSQL 中支持通过 Microsoft Entra ID 进行身份验证。Dapr 支持的所有身份验证方法都可以使用,包括客户端凭据("服务主体")和托管身份。 + +| 字段 | 必需 | 详情 | 示例 | +|--------|:--------:|---------|---------| +| `useAzureAD` | Y | 必须设置为 `true` 以使组件能够从 Microsoft Entra ID 检索访问令牌。 | `"true"` | +| `connectionString` | Y | PostgreSQL 数据库的连接字符串。
这必须包含用户,该用户对应于在 PostgreSQL 内部创建的用户的名称,该用户映射到 Microsoft Entra ID 身份;这通常是相应主体的名称(例如,Microsoft Entra ID 应用程序的名称)。此连接字符串不应包含任何密码。 | `"host=mydb.postgres.database.azure.com user=myapplication port=5432 database=my_db sslmode=require"` | +| `azureTenantId` | N | Microsoft Entra ID 租户的 ID | `"cd4b2887-304c-…"` | +| `azureClientId` | N | 客户端 ID(应用程序 ID) | `"c7dd251f-811f-…"` | +| `azureClientSecret` | N | 客户端 secret(应用程序密码) | `"Ecy3X…"` | + +### 通过 AWS IAM 进行身份验证 + +在所有版本的 PostgreSQL 类型组件中支持通过 AWS IAM 进行身份验证。 +连接字符串中指定的用户必须是数据库中已存在的用户,并且是授予 `rds_iam` 数据库角色的 AWS IAM 启用用户。 +身份验证基于 AWS 身份验证配置文件,或提供的 AccessKey/SecretKey。 +AWS 身份验证令牌将在其到期时间之前动态轮换。 + +| 字段 | 必需 | 详情 | 示例 | +|--------|:--------:|---------|---------| +| `useAWSIAM` | Y | 必须设置为 `true` 以使组件能够从 AWS IAM 检索访问令牌。此身份验证方法仅适用于 AWS Relational Database Service for PostgreSQL 数据库。 | `"true"` | +| `connectionString` | Y | PostgreSQL 数据库的连接字符串。
这必须包含一个已存在的用户,该用户对应于在 PostgreSQL 内部创建的用户的名称,该用户映射到 AWS IAM 策略。此连接字符串不应包含任何密码。请注意,数据库名称字段在 AWS 中由 dbname 表示。 | `"host=mydb.postgres.database.aws.com user=myapplication port=5432 dbname=my_db sslmode=require"`| +| `awsRegion` | N | 这保持与现有字段的向后兼容性。它将在 Dapr 1.17 中被弃用。请改用 'region'。AWS Relational Database Service 部署到的 AWS 区域。 | `"us-east-1"` | +| `awsAccessKey` | N | 这保持与现有字段的向后兼容性。它将在 Dapr 1.17 中被弃用。请改用 'accessKey'。与 IAM 账户关联的 AWS 访问密钥 | `"AKIAIOSFODNN7EXAMPLE"` | +| `awsSecretKey` | N | 这保持与现有字段的向后兼容性。它将在 Dapr 1.17 中被弃用。请改用 'secretKey'。与访问密钥关联的 secret 密钥 | `"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"` | +| `awsSessionToken` | N | 这保持与现有字段的向后兼容性。它将在 Dapr 1.17 中被弃用。请改用 'sessionToken'。要使用的 AWS 会话令牌。仅当您使用临时安全凭证时才需要会话令牌。 | `"TOKEN"` | + +### 其他元数据选项 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|-----|---|---------| +| `timeout` | N | 输出 | 数据库操作的超时时间,作为 [Go duration](https://pkg.go.dev/time#ParseDuration)。整数被解释为秒数。默认为 `20s` | `"30s"`, `30` | +| `maxConns` | N | 输出 | 由此组件池化的最大连接数。设置为 0 或更低以使用默认值,该值为 4 或 CPU 数量中的较大者。 | `"4"` | +| `connectionMaxIdleTime` | N | 输出 | 在连接池中未使用的连接被自动关闭之前的最大空闲时间。默认情况下,没有值,这由数据库驱动程序选择。 | `"5m"` | +| `queryExecMode` | N | 输出 | 控制执行查询的默认模式。默认情况下,Dapr 使用扩展协议并自动准备和缓存准备好的语句。然而,这可能与代理如 PGBouncer 不兼容。在这种情况下,可能更适合使用 `exec` 或 `simple_protocol`。 | `"simple_protocol"` | + +### URL 格式 + +PostgreSQL 绑定内部使用 [pgx 连接池](https://github.com/jackc/pgx),因此 `connectionString` 参数可以是任何有效的连接字符串,无论是 `DSN` 还是 `URL` 格式: + +**示例 DSN** + +```shell +user=dapr password=secret host=dapr.example.com port=5432 dbname=my_dapr sslmode=verify-ca +``` + +**示例 URL** + +```shell +postgres://dapr:secret@dapr.example.com:5432/my_dapr?sslmode=verify-ca +``` + +这两种方法还支持连接池配置变量: + +- `pool_min_conns`: 整数 0 或更大 +- `pool_max_conns`: 大于 0 的整数 +- `pool_max_conn_lifetime`: 持续时间字符串 +- `pool_max_conn_idle_time`: 持续时间字符串 +- `pool_health_check_period`: 持续时间字符串 + +## 绑定支持 + +此组件支持具有以下操作的**输出绑定**: + +- `exec` +- `query` +- `close` + +### 参数化查询 + +此绑定支持参数化查询,允许将 SQL 查询本身与用户提供的值分开。**强烈建议**使用参数化查询以确保安全,因为它们可以防止 [SQL 注入攻击](https://owasp.org/www-community/attacks/SQL_Injection)。 + +例如: + +```sql +-- ❌ 错误!在查询中包含值,容易受到 SQL 注入攻击。 +SELECT * FROM mytable WHERE user_key = 'something'; + +-- ✅ 好!使用参数化查询。 +-- 这将使用参数 ["something"] 执行 +SELECT * FROM mytable WHERE user_key = $1; +``` + +### exec + +`exec` 操作可用于 DDL 操作(如表创建),以及返回仅元数据的 `INSERT`、`UPDATE`、`DELETE` 操作(例如,受影响行数)。 + +`params` 属性是一个包含 JSON 编码参数数组的字符串。 + +**请求** + +```json +{ + "operation": "exec", + "metadata": { + "sql": "INSERT INTO foo (id, c1, ts) VALUES ($1, $2, $3)", + "params": "[1, \"demo\", \"2020-09-24T11:45:05Z07:00\"]" + } +} +``` + +**响应** + +```json +{ + "metadata": { + "operation": "exec", + "duration": "294µs", + "start-time": "2020-09-24T11:13:46.405097Z", + "end-time": "2020-09-24T11:13:46.414519Z", + "rows-affected": "1", + "sql": "INSERT INTO foo (id, c1, ts) VALUES ($1, $2, $3)" + } +} +``` + +### query + +`query` 操作用于 `SELECT` 语句,它返回元数据以及以行值数组形式的数据。 + +`params` 属性是一个包含 JSON 编码参数数组的字符串。 + +**请求** + +```json +{ + "operation": "query", + "metadata": { + "sql": "SELECT * FROM foo WHERE id < $1", + "params": "[3]" + } +} +``` + +**响应** + +```json +{ + "metadata": { + "operation": "query", + "duration": "432µs", + "start-time": "2020-09-24T11:13:46.405097Z", + "end-time": "2020-09-24T11:13:46.420566Z", + "sql": "SELECT * FROM foo WHERE id < $1" + }, + "data": "[ + [0,\"test-0\",\"2020-09-24T04:13:46Z\"], + [1,\"test-1\",\"2020-09-24T04:13:46Z\"], + [2,\"test-2\",\"2020-09-24T04:13:46Z\"] + ]" +} +``` + +### close + +`close` 操作可用于显式关闭数据库连接并将其返回到池中。此操作没有任何响应。 + +**请求** + +```json +{ + "operation": "close" +} +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/postmark.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/postmark.md new file mode 100644 index 000000000..3b8e1ce81 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/postmark.md @@ -0,0 +1,78 @@ +--- +type: docs +title: "Postmark 绑定说明" +linkTitle: "Postmark" +description: "关于 Postmark 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/postmark/" +--- + +## 组件格式指南 + +要配置 Postmark 绑定,需创建一个类型为 `bindings.postmark` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: postmark +spec: + type: bindings.postmark + metadata: + - name: accountToken + value: "YOUR_ACCOUNT_TOKEN" # 必需,这是您的 Postmark 账户令牌 + - name: serverToken + value: "YOUR_SERVER_TOKEN" # 必需,这是您的 Postmark 服务器令牌 + - name: emailFrom + value: "testapp@dapr.io" # 可选 + - name: emailTo + value: "dave@dapr.io" # 可选 + - name: subject + value: "Hello!" # 可选 +``` +{{% alert title="警告" color="warning" %}} +上述示例使用明文字符串作为 secret。建议使用 secret 存储来存储 secret,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `accountToken` | Y | 输出 | Postmark 账户令牌,应视为 secret 值 | `"account token"` | +| `serverToken` | Y | 输出 | Postmark 服务器令牌,应视为 secret 值 | `"server token"` | +| `emailFrom` | N | 输出 | 如果设置,则指定电子邮件消息的“发件人”地址 | `"me@exmaple.com"` | +| `emailTo` | N | 输出 | 如果设置,则指定电子邮件消息的“收件人”地址 | `"me@example.com"` | +| `emailCc` | N | 输出 | 如果设置,则指定电子邮件消息的“抄送”地址 | `"me@example.com"` | +| `emailBcc` | N | 输出 | 如果设置,则指定电子邮件消息的“密送”地址 | `"me@example.com"` | +| `subject` | N | 输出 | 如果设置,则指定电子邮件消息的主题 | `"me@example.com"` | + +在输出绑定请求中,您也可以指定任何可选的元数据属性(例如 `emailFrom`、`emailTo`、`subject` 等)。 + +组件配置和请求负载中的可选元数据属性至少应包含 `emailFrom`、`emailTo` 和 `subject` 字段,因为这些字段是成功发送电子邮件所必需的。 + +## 绑定支持 + +此组件支持以下操作的**输出绑定**: + +- `create` + +## 示例请求负载 + +```json +{ + "operation": "create", + "metadata": { + "emailTo": "changeme@example.net", + "subject": "An email from Dapr Postmark binding" + }, + "data": "

Testing Dapr Bindings

This is a test.
Bye!" +} +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [操作指南:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [操作指南:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/rabbitmq.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/rabbitmq.md new file mode 100644 index 000000000..35a72be30 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/rabbitmq.md @@ -0,0 +1,183 @@ +--- +type: docs +title: "RabbitMQ 绑定规范" +linkTitle: "RabbitMQ" +description: "RabbitMQ 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/rabbitmq/" +--- + +## 组件格式 + +要设置 RabbitMQ 绑定,需创建一个类型为 `bindings.rabbitmq` 的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.rabbitmq + version: v1 + metadata: + - name: queueName + value: "queue1" + - name: host + value: "amqp://[username][:password]@host.domain[:port]" + - name: durable + value: "true" + - name: deleteWhenUnused + value: "false" + - name: ttlInSeconds + value: "60" + - name: prefetchCount + value: "0" + - name: exclusive + value: "false" + - name: maxPriority + value: "5" + - name: contentType + value: "text/plain" + - name: reconnectWaitInSeconds + value: "5" + - name: externalSasl + value: "false" + - name: caCert + value: "null" + - name: clientCert + value: "null" + - name: clientKey + value: "null" + - name: direction + value: "input, output" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中,secret 使用了明文字符串。建议使用 secret 存储,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 规范元数据字段 + +> 发布新的 RabbitMQ 消息时,所有关联元数据的值都会添加到消息的头部。 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `queueName` | Y | 输入/输出 | RabbitMQ 队列名称 | `"myqueue"` | +| `host` | Y | 输入/输出 | RabbitMQ 主机地址 | `"amqp://[username][:password]@host.domain[:port]"` 或使用 TLS: `"amqps://[username][:password]@host.domain[:port]"` | +| `durable` | N | 输出 | 指定 RabbitMQ 是否持久化存储消息。默认为 `"false"` | `"true"`, `"false"` | +| `deleteWhenUnused` | N | 输入/输出 | 启用或禁用自动删除。默认为 `"false"` | `"true"`, `"false"` | +| `ttlInSeconds` | N | 输出 | 设置 [RabbitMQ 队列级别的默认消息生存时间](https://www.rabbitmq.com/ttl.html)。如果省略此参数,消息将不会过期,继续存在于队列中直到被处理。另见 [此处](#specifying-a-ttl-per-message) | `60` | +| `prefetchCount` | N | 输入 | 设置 [通道预取设置 (QoS)](https://www.rabbitmq.com/confirms.html#channel-qos-prefetch)。如果省略此参数,QoS 将设置为 0 表示无限制 | `0` | +| `exclusive` | N | 输入/输出 | 确定主题是否为独占主题。默认为 `"false"` | `"true"`, `"false"` | +| `maxPriority`| N | 输入/输出 | 设置 [优先级队列](https://www.rabbitmq.com/priority.html) 的参数。如果省略此参数,队列将被创建为普通队列而不是优先级队列。值在 1 到 255 之间。另见 [此处](#specifying-a-priority-per-message) | `"1"`, `"10"` | +| `contentType` | N | 输入/输出 | 消息的内容类型。默认为 "text/plain"。 | `"text/plain"`, `"application/cloudevent+json"` 等 | +| `reconnectWaitInSeconds` | N | 输入/输出 | 表示客户端在断开连接后尝试重新连接到服务器之前应等待的秒数。默认为 `"5"`。 | `"5"`, `"10"` | +| `externalSasl` | N | 输入/输出 | 使用 TLS 时,用户名是否应从附加字段(例如 CN)中获取。参见 [RabbitMQ 认证机制](https://www.rabbitmq.com/access-control.html#mechanisms)。默认为 `"false"`。 | `"true"`, `"false"` | +| `caCert` | N | 输入/输出 | 用于 TLS 连接的 CA 证书。默认为 `null`。 | `"-----BEGIN CERTIFICATE-----\nMI..."` | +| `clientCert` | N | 输入/输出 | 用于 TLS 连接的客户端证书。默认为 `null`。 | `"-----BEGIN CERTIFICATE-----\nMI..."` | +| `clientKey` | N | 输入/输出 | 用于 TLS 连接的客户端密钥。默认为 `null`。 | `"-----BEGIN PRIVATE KEY-----\nMI..."` | +| `direction` | N | 输入/输出 | 绑定的方向。 | `"input"`, `"output"`, `"input, output"` | + +## 绑定支持 + +此组件支持 **输入和输出** 绑定接口。 + +此组件支持以下操作的 **输出绑定**: + +- `create` + +## 设置每条消息的 TTL + +生存时间可以在队列级别(如上所示)或消息级别定义。在消息级别定义的值将覆盖在队列级别设置的任何值。 + +要在消息级别设置生存时间,请在绑定调用期间使用请求体中的 `metadata` 部分。 + +字段名称为 `ttlInSeconds`。 + +示例: + +{{< tabs Windows Linux >}} +{{% codetab %}} +```shell +curl -X POST http://localhost:3500/v1.0/bindings/myRabbitMQ \ + -H "Content-Type: application/json" \ + -d "{ + \"data\": { + \"message\": \"Hi\" + }, + \"metadata\": { + \"ttlInSeconds\": "60" + }, + \"operation\": \"create\" + }" +``` +{{% /codetab %}} + +{{% codetab %}} +```bash +curl -X POST http://localhost:3500/v1.0/bindings/myRabbitMQ \ + -H "Content-Type: application/json" \ + -d '{ + "data": { + "message": "Hi" + }, + "metadata": { + "ttlInSeconds": "60" + }, + "operation": "create" + }' +``` +{{% /codetab %}} +{{< /tabs >}} + +## 设置每条消息的优先级 + +优先级可以在消息级别定义。如果设置了 `maxPriority` 参数,高优先级消息将优先于其他低优先级消息。 + +要在消息级别设置优先级,请在绑定调用期间使用请求体中的 `metadata` 部分。 + +字段名称为 `priority`。 + +示例: + +{{< tabs Windows Linux >}} +{{% codetab %}} +```shell +curl -X POST http://localhost:3500/v1.0/bindings/myRabbitMQ \ + -H "Content-Type: application/json" \ + -d "{ + \"data\": { + \"message\": \"Hi\" + }, + \"metadata\": { + "priority": \"5\" + }, + \"operation\": \"create\" + }" +``` +{{% /codetab %}} + +{{% codetab %}} +```shell +curl -X POST http://localhost:3500/v1.0/bindings/myRabbitMQ \ + -H "Content-Type: application/json" \ + -d '{ + "data": { + "message": "Hi" + }, + "metadata": { + "priority": "5" + }, + "operation": "create" + }' +``` +{{% /codetab %}} +{{< /tabs >}} + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/redis.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/redis.md new file mode 100644 index 000000000..db9f78866 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/redis.md @@ -0,0 +1,253 @@ +--- +type: docs +title: "Redis 绑定规范" +linkTitle: "Redis" +description: "关于 Redis 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/redis/" +--- + +## 组件格式 + +要设置 Redis 绑定,需创建一个类型为 `bindings.redis` 的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.redis + version: v1 + metadata: + - name: redisHost + value: "
:6379" + - name: redisPassword + value: "**************" + - name: useEntraID + value: "true" + - name: enableTLS + value: "" +``` + +{{% alert title="警告" color="warning" %}} +上述示例使用了明文字符串作为秘密。建议使用秘密存储,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `redisHost` | Y | 输出 | Redis 主机地址 | `"localhost:6379"` | +| `redisPassword` | N | 输出 | Redis 密码 | `"password"` | +| `redisUsername` | N | 输出 | Redis 主机的用户名。默认为空。确保您的 Redis 服务器版本为 6 或更高,并已正确创建 ACL 规则。 | `"username"` | +| `useEntraID` | N | 输出 | 实现 Azure Cache for Redis 的 EntraID 支持。启用此功能之前:
  • 必须以 `"server:port"` 的形式指定 `redisHost` 名称
  • 必须启用 TLS
更多信息请参见[创建 Redis 实例 > Azure Cache for Redis]({{< ref "#create-a-redis-instance" >}})部分。 | `"true"`, `"false"` | +| `enableTLS` | N | 输出 | 如果 Redis 实例支持带有公共证书的 TLS,则可以配置启用或禁用 TLS。默认为 `"false"` | `"true"`, `"false"` | +| `clientCert` | N | 输出 | 客户端证书的内容,用于需要客户端证书的 Redis 实例。必须与 `clientKey` 一起使用,并且 `enableTLS` 必须设置为 true。建议使用秘密存储,如[此处]({{< ref component-secrets.md >}})所述 | `"----BEGIN CERTIFICATE-----\nMIIC..."` | +| `clientKey` | N | 输出 | 客户端私钥的内容,与 `clientCert` 一起用于身份验证。建议使用秘密存储,如[此处]({{< ref component-secrets.md >}})所述 | `"----BEGIN PRIVATE KEY-----\nMIIE..."` | +| `failover` | N | 输出 | 启用故障转移配置的属性。需要设置 sentinalMasterName。默认为 `"false"` | `"true"`, `"false"` +| `sentinelMasterName` | N | 输出 | 哨兵主名称。参见 [Redis Sentinel 文档](https://redis.io/docs/reference/sentinel-clients/) | `""`, `"127.0.0.1:6379"` +| `redeliverInterval` | N | 输出 | 检查待处理消息以重新传递的间隔。默认为 `"60s"`。`"0"` 禁用重新传递。 | `"30s"` +| `processingTimeout` | N | 输出 | 消息在尝试重新传递之前必须挂起的时间。默认为 `"15s"`。`"0"` 禁用重新传递。 | `"30s"` +| `redisType` | N | 输出 | Redis 的类型。有两个有效值,一个是 `"node"` 表示单节点模式,另一个是 `"cluster"` 表示 Redis 集群模式。默认为 `"node"`。 | `"cluster"` +| `redisDB` | N | 输出 | 连接到 Redis 后选择的数据库。如果 `"redisType"` 是 `"cluster"`,则忽略此选项。默认为 `"0"`。 | `"0"` +| `redisMaxRetries` | N | 输出 | 在放弃之前重试命令的最大次数。默认情况下不重试失败的命令。 | `"5"` +| `redisMinRetryInterval` | N | 输出 | 每次重试之间 Redis 命令的最小退避时间。默认为 `"8ms"`;`"-1"` 禁用退避。 | `"8ms"` +| `redisMaxRetryInterval` | N | 输出 | 每次重试之间 Redis 命令的最大退避时间。默认为 `"512ms"`;`"-1"` 禁用退避。 | `"5s"` +| `dialTimeout` | N | 输出 | 建立新连接的拨号超时时间。默认为 `"5s"`。 | `"5s"` +| `readTimeout` | N | 输出 | 套接字读取的超时时间。如果达到,Redis 命令将因超时而失败而不是阻塞。默认为 `"3s"`,`"-1"` 表示无超时。 | `"3s"` +| `writeTimeout` | N | 输出 | 套接字写入的超时时间。如果达到,Redis 命令将因超时而失败而不是阻塞。默认为 readTimeout。 | `"3s"` +| `poolSize` | N | 输出 | 最大套接字连接数。默认是每个 CPU 10 个连接,如 runtime.NumCPU 报告。 | `"20"` +| `poolTimeout` | N | 输出 | 如果所有连接都忙,客户端在返回错误之前等待连接的时间。默认是 readTimeout + 1 秒。 | `"5s"` +| `maxConnAge` | N | 输出 | 客户端在此连接年龄时退役(关闭)连接。默认是不关闭老化连接。 | `"30m"` +| `minIdleConns` | N | 输出 | 为了避免创建新连接的性能下降,保持打开的最小空闲连接数。默认为 `"0"`。 | `"2"` +| `idleCheckFrequency` | N | 输出 | 空闲连接清理器进行空闲检查的频率。默认为 `"1m"`。`"-1"` 禁用空闲连接清理器。 | `"-1"` +| `idleTimeout` | N | 输出 | 客户端关闭空闲连接的时间。应小于服务器的超时时间。默认为 `"5m"`。`"-1"` 禁用空闲超时检查。 | `"10m"` + +## 绑定支持 + +此组件支持具有以下操作的**输出绑定**: + +- `create` +- `get` +- `delete` + +### create + +您可以使用 `create` 操作在 Redis 中存储记录。这会设置一个键来保存一个值。如果键已经存在,则会覆盖该值。 + +#### 请求 + +```json +{ + "operation": "create", + "metadata": { + "key": "key1" + }, + "data": { + "Hello": "World", + "Lorem": "Ipsum" + } +} +``` + +#### 响应 + +如果成功,将返回 HTTP 204(无内容)和空响应体。 + +### get + +您可以使用 `get` 操作在 Redis 中获取记录。这会获取之前设置的键。 + +这需要一个可选参数 `delete`,默认值为 `false`。当设置为 `true` 时,此操作使用 Redis 的 `GETDEL` 操作。例如,它返回之前设置的 `value`,然后删除它。 + +#### 请求 + +```json +{ + "operation": "get", + "metadata": { + "key": "key1" + }, + "data": { + } +} +``` + +#### 响应 + +```json +{ + "data": { + "Hello": "World", + "Lorem": "Ipsum" + } +} +``` + +#### 带删除标志的请求 + +```json +{ + "operation": "get", + "metadata": { + "key": "key1", + "delete": "true" + }, + "data": { + } +} +``` + +### delete + +您可以使用 `delete` 操作在 Redis 中删除记录。无论键是否存在,都会返回成功。 + +#### 请求 + +```json +{ + "operation": "delete", + "metadata": { + "key": "key1" + } +} +``` + +#### 响应 + +如果成功,将返回 HTTP 204(无内容)和空响应体。 + +## 创建 Redis 实例 + +Dapr 可以使用任何 Redis 实例 - 容器化的、在本地开发机器上运行的或托管的云服务,只要 Redis 的版本是 5.0.0 或更高。 + +*注意:Dapr 不支持 Redis >= 7。建议使用 Redis 6* + +{{< tabs "自托管" "Kubernetes" "AWS" "Azure" "GCP" >}} + +{{% codetab %}} +Dapr CLI 将自动为您创建和设置一个 Redis Streams 实例。 +当您运行 `dapr init` 时,Redis 实例将通过 Docker 安装,并且组件文件将创建在默认目录中。(`$HOME/.dapr/components` 目录 (Mac/Linux) 或 `%USERPROFILE%\.dapr\components` 在 Windows 上)。 +{{% /codetab %}} + +{{% codetab %}} +您可以使用 [Helm](https://helm.sh/) 在我们的 Kubernetes 集群中快速创建一个 Redis 实例。此方法需要[安装 Helm](https://github.com/helm/helm#install)。 + +1. 将 Redis 安装到您的集群中。 + ```bash + helm repo add bitnami https://charts.bitnami.com/bitnami + helm install redis bitnami/redis --set image.tag=6.2 + ``` + +2. 运行 `kubectl get pods` 查看现在在您的集群中运行的 Redis 容器。 +3. 在您的 redis.yaml 文件中将 `redis-master:6379` 添加为 `redisHost`。例如: + + ```yaml + metadata: + - name: redisHost + value: redis-master:6379 + ``` + +4. 接下来,我们将获取我们的 Redis 密码,这在我们使用的操作系统上略有不同: + - **Windows**: 运行 `kubectl get secret --namespace default redis -o jsonpath="{.data.redis-password}" > encoded.b64`,这将创建一个包含您编码密码的文件。接下来,运行 `certutil -decode encoded.b64 password.txt`,这将把您的 Redis 密码放入一个名为 `password.txt` 的文本文件中。复制密码并删除这两个文件。 + + - **Linux/MacOS**: 运行 `kubectl get secret --namespace default redis -o jsonpath="{.data.redis-password}" | base64 --decode` 并复制输出的密码。 + + 将此密码作为 `redisPassword` 值添加到您的 redis.yaml 文件中。例如: + + ```yaml + - name: redisPassword + value: "lhDOkwTlp0" + ``` +{{% /codetab %}} + +{{% codetab %}} +[AWS Redis](https://aws.amazon.com/redis/) +{{% /codetab %}} + +{{% codetab %}} +1. [使用官方 Microsoft 文档创建 Azure Cache for Redis 实例。](https://docs.microsoft.com/azure/azure-cache-for-redis/quickstart-create-redis) + +1. 一旦您的实例创建完成,从 Azure 门户获取主机名(FQDN)和您的访问密钥。 + - 对于主机名: + - 导航到资源的**概览**页面。 + - 复制**主机名**值。 + - 对于您的访问密钥: + - 导航到**设置** > **访问密钥**。 + - 复制并保存您的密钥。 + +1. 将您的密钥和主机名添加到 Dapr 可以应用到您集群的 `redis.yaml` 文件中。 + - 如果您正在运行示例,请将主机和密钥添加到提供的 `redis.yaml` 中。 + - 如果您从头开始创建项目,请按照[组件格式部分](#component-format)中指定的创建 `redis.yaml` 文件。 + +1. 将 `redisHost` 键设置为 `[HOST NAME FROM PREVIOUS STEP]:6379`,并将 `redisPassword` 键设置为您之前保存的密钥。 + + **注意:** 在生产级应用程序中,请遵循[秘密管理]({{< ref component-secrets.md >}})说明以安全管理您的秘密。 + +1. 启用 EntraID 支持: + - 在您的 Azure Redis 服务器上启用 Entra ID 身份验证。这可能需要几分钟。 + - 将 `useEntraID` 设置为 `"true"` 以实现 Azure Cache for Redis 的 EntraID 支持。 + +1. 将 `enableTLS` 设置为 `"true"` 以支持 TLS。 + +> **注意:**`useEntraID` 假设您的 UserPrincipal(通过 AzureCLICredential)或 SystemAssigned 托管身份具有 RedisDataOwner 角色权限。如果使用用户分配的身份,[您需要指定 `azureClientID` 属性]({{< ref "howto-mi.md#set-up-identities-in-your-component" >}})。 + +{{% /codetab %}} + +{{% codetab %}} +[GCP Cloud MemoryStore](https://cloud.google.com/memorystore/) +{{% /codetab %}} + +{{< /tabs >}} + +{{% alert title="注意" color="primary" %}} +Dapr CLI 在自托管模式下作为 `dapr init` 命令的一部分自动部署本地 redis 实例。 +{{% /alert %}} + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/rethinkdb.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/rethinkdb.md new file mode 100644 index 000000000..b89ea0934 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/rethinkdb.md @@ -0,0 +1,54 @@ +--- +type: docs +title: "RethinkDB 绑定规范" +linkTitle: "RethinkDB" +description: "关于 RethinkDB 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/rethinkdb/" +--- + +## 组件格式 + +[RethinkDB 状态存储]({{}})支持事务,因此可以用于支持 Dapr actor。Dapr 仅持久化 actor 的当前状态,因此用户无法跟踪 actor 状态随时间的变化。 + +为了让用户能够跟踪 actor 状态的变化,此绑定利用 RethinkDB 内置的功能来监控表和事件的变化,包括 `old` 和 `new` 状态。此绑定在 Dapr 状态表上创建一个订阅,并通过 Dapr 输入绑定接口流式传输这些变化。 + +要设置 RethinkDB 状态变化绑定,请创建一个类型为 `bindings.rethinkdb.statechange` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: changes +spec: + type: bindings.rethinkdb.statechange + version: v1 + metadata: + - name: address + value: "" # 必需,例如 127.0.0.1:28015 或 rethinkdb.default.svc.cluster.local:28015)。 + - name: database + value: "" # 必需,例如 dapr(仅限字母数字) + - name: direction + value: "" +``` + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `address` | Y | 输入 | RethinkDB 服务器地址 | `"27.0.0.1:28015"`,`"rethinkdb.default.svc.cluster.local:28015"` | +| `database` | Y | 输入 | RethinkDB 数据库名称 | `"dapr"` | +| `direction` | N | 输入 | 绑定的方向 | `"input"` | + +## 绑定支持 + +此组件仅支持**输入**绑定接口。 + +## 相关链接 + +- [将此绑定与 Dapr Pub/Sub 结合使用](https://github.com/mchmarny/dapr-state-store-change-handler)以将状态变化流式传输到主题 +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [Bindings 构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [Bindings API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/s3.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/s3.md new file mode 100644 index 000000000..91cd3fd72 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/s3.md @@ -0,0 +1,515 @@ +--- +type: docs +title: "AWS S3 绑定规范" +linkTitle: "AWS S3" +description: "关于 AWS S3 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/s3/" +--- + +## 组件格式 + +要设置 AWS S3 绑定,您需要创建一个类型为 `bindings.aws.s3` 的组件。此绑定可以与其他兼容 S3 的服务一起使用,例如 Minio。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})以了解如何创建和应用绑定配置。 + +有关身份验证相关属性的信息,请参阅[身份验证到 AWS]({{< ref authenticating-aws.md >}})。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.aws.s3 + version: v1 + metadata: + - name: bucket + value: "mybucket" + - name: region + value: "us-west-2" + - name: endpoint + value: "s3.us-west-2.amazonaws.com" + - name: accessKey + value: "*****************" + - name: secretKey + value: "*****************" + - name: sessionToken + value: "mysession" + - name: decodeBase64 + value: "" + - name: encodeBase64 + value: "" + - name: forcePathStyle + value: "" + - name: disableSSL + value: "" + - name: insecureSSL + value: "" + - name: storageClass + value: "" +``` + +{{% alert title="警告" color="warning" %}} +上面的示例中使用了明文字符串作为密钥。建议使用密钥存储来存储密钥,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `bucket` | Y | 输出 | 要写入的 S3 bucket 名称 | `"bucket"` | +| `region` | Y | 输出 | 特定的 AWS 区域 | `"us-east-1"` | +| `endpoint` | N | 输出 | 特定的 AWS 端点 | `"s3.us-east-1.amazonaws.com"` | +| `accessKey` | Y | 输出 | 访问此资源的 AWS 访问密钥 | `"key"` | +| `secretKey` | Y | 输出 | 访问此资源的 AWS secret 访问密钥 | `"secretAccessKey"` | +| `sessionToken` | N | 输出 | 要使用的 AWS 会话令牌 | `"sessionToken"` | +| `forcePathStyle` | N | 输出 | Amazon S3 SDK 支持虚拟主机样式和路径样式访问。`"true"` 表示路径样式格式,如 `"https:////"`。`"false"` 表示主机样式格式,如 `"https://./"`。默认为 `"false"` | `"true"`, `"false"` | +| `decodeBase64` | N | 输出 | 配置在保存到 bucket 存储之前解码 base64 文件内容。(在保存二进制内容文件的情况下)。`"true"` 是唯一允许的正值。其他正值变体如 `"True", "1"` 不可接受。默认为 `false` | `"true"`, `"false"` | +| `encodeBase64` | N | 输出 | 配置在返回内容之前对 base64 文件内容进行编码。(在打开二进制内容文件的情况下)。`"true"` 是唯一允许的正值。其他正值变体如 `"True", "1"` 不可接受。默认为 `"false"` | `"true"`, `"false"` | +| `disableSSL` | N | 输出 | 允许连接到非 `https://` 端点。默认为 `"false"` | `"true"`, `"false"` | +| `insecureSSL` | N | 输出 | 当连接到 `https://` 端点时,接受无效或自签名证书。默认为 `"false"` | `"true"`, `"false"` | +| `storageClass` | N | 输出 | 在创建操作期间对象的所需存储类。[有效的 AWS 存储类类型可以在此处找到](https://aws.amazon.com/s3/storage-classes/) | `STANDARD_IA` | + +{{% alert title="重要" color="warning" %}} +当在 EKS(AWS Kubernetes)上与应用程序一起运行 Dapr sidecar(daprd)时,如果您使用的节点/Pod 已经附加了定义访问 AWS 资源的 IAM 策略,则**不得**在您使用的组件规范定义中提供 AWS 访问密钥、secret 密钥和令牌。 +{{% /alert %}} + +### S3 Bucket 创建 +{{< tabs "Minio" "LocalStack" "AWS" >}} + +{{% codetab %}} +### 使用 Minio + +[Minio](https://min.io/) 是一种将本地存储暴露为兼容 S3 的块存储的服务,尤其在开发环境中是 S3 的流行替代品。您也可以使用 S3 绑定与 Minio 一起使用,只需进行一些配置调整: +1. 将 `endpoint` 设置为 Minio 服务器的地址,包括协议(`http://` 或 `https://`)和末尾的可选端口。例如,`http://minio.local:9000`(值取决于您的环境)。 +2. `forcePathStyle` 必须设置为 `true` +3. `region` 的值不重要;您可以将其设置为 `us-east-1`。 +4. 根据您的环境,如果您使用非安全连接(使用 `http://` 协议)连接到 Minio,可能需要将 `disableSSL` 设置为 `true`。如果您使用安全连接(`https://` 协议)但使用自签名证书,可能需要将 `insecureSSL` 设置为 `true`。 + +{{% /codetab %}} + +{{% codetab %}} +对于本地开发,[LocalStack 项目](https://github.com/localstack/localstack)用于集成 AWS S3。按照[这些说明](https://github.com/localstack/localstack#running)运行 LocalStack。 + +要从命令行使用 Docker 本地运行 LocalStack,请使用类似于以下的 `docker-compose.yaml`: + +```yaml +version: "3.8" + +services: + localstack: + container_name: "cont-aws-s3" + image: localstack/localstack:1.4.0 + ports: + - "127.0.0.1:4566:4566" + environment: + - DEBUG=1 + - DOCKER_HOST=unix:///var/run/docker.sock + volumes: + - "/init-aws.sh:/etc/localstack/init/ready.d/init-aws.sh" # 初始化钩子 + - "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack" + - "/var/run/docker.sock:/var/run/docker.sock" +``` + +要使用 S3 组件,您需要使用现有的 bucket。上面的示例使用 [LocalStack 初始化钩子](https://docs.localstack.cloud/references/init-hooks/)来设置 bucket。 + +要使用 LocalStack 与您的 S3 绑定,您需要在组件元数据中提供 `endpoint` 配置。在针对生产 AWS 运行时,`endpoint` 是不必要的。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: aws-s3 + namespace: default +spec: + type: bindings.aws.s3 + version: v1 + metadata: + - name: bucket + value: conformance-test-docker + - name: endpoint + value: "http://localhost:4566" + - name: accessKey + value: "my-access" + - name: secretKey + value: "my-secret" + - name: region + value: "us-east-1" +``` + +{{% /codetab %}} + +{{% codetab %}} + +要使用 S3 组件,您需要使用现有的 bucket。请按照 [AWS 文档创建 bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/create-bucket-overview.html)。 + +{{% /codetab %}} + +{{< /tabs >}} + +## 绑定支持 + +此组件支持**输出绑定**,具有以下操作: + +- `create` : [创建对象](#create-object) +- `get` : [获取对象](#get-object) +- `delete` : [删除对象](#delete-object) +- `list`: [列出对象](#list-objects) + +### 创建对象 + +要执行创建操作,请使用 `POST` 方法调用 AWS S3 绑定,并使用以下 JSON 正文: + +> 注意:默认情况下,会生成一个随机 UUID。请参阅下面的元数据支持以设置名称 + +```json +{ + "operation": "create", + "data": "YOUR_CONTENT", + "metadata": { + "storageClass": "STANDARD_IA" + } +} +``` + +例如,您可以在使用 `create` 操作时提供存储类,使用 Linux curl 命令 + +```bash +curl -d '{ "operation": "create", "data": "YOUR_BASE_64_CONTENT", "metadata": { "storageClass": "STANDARD_IA" } }' / +http://localhost:/v1.0/bindings/ +``` + +#### 使用预签名 URL 共享对象 + +要使用指定的生存时间预签名对象,请在 `create` 请求中使用 `presignTTL` 元数据键。 +`presignTTL` 的有效值为 [Go 持续时间字符串](https://pkg.go.dev/maze.io/x/duration#:~:text=A%20duration%20string%20is%20a,w%22%2C%20%22y%22)。 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"Hello World\", \"metadata\": { \"presignTTL\": \"15m\" } }" \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "Hello World", "metadata": { "presignTTL": "15m" } }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 响应 + +响应正文包含以下示例 JSON: + +```json +{ + "location":"https://.s3..amazonaws.com/", + "versionID":"", + "presignURL": "https://.s3..amazonaws.com/image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAJJWZ7B6WCRGMKFGQ%2F20180210%2Feu-west-2%2Fs3%2Faws4_request&X-Amz-Date=20180210T171315Z&X-Amz-Expires=1800&X-Amz-Signature=12b74b0788aa036bc7c3d03b3f20c61f1f91cc9ad8873e3314255dc479a25351&X-Amz-SignedHeaders=host" +} +``` + +#### 示例 +##### 将文本保存到随机生成的 UUID 文件 + +{{< tabs Windows Linux >}} + {{% codetab %}} + 在 Windows 上,使用 cmd 提示符(PowerShell 有不同的转义机制) + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"Hello World\" }" http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "Hello World" }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 将文本保存到特定文件 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"Hello World\", \"metadata\": { \"key\": \"my-test-file.txt\" } }" \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "Hello World", "metadata": { "key": "my-test-file.txt" } }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 将文件保存为对象 + +要上传文件,请将其编码为 Base64,并让绑定知道要反序列化它: + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.aws.s3 + version: v1 + metadata: + - name: bucket + value: mybucket + - name: region + value: us-west-2 + - name: endpoint + value: s3.us-west-2.amazonaws.com + - name: accessKey + value: ***************** + - name: secretKey + value: ***************** + - name: sessionToken + value: mysession + - name: decodeBase64 + value: + - name: forcePathStyle + value: +``` + +然后您可以像往常一样上传它: + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"YOUR_BASE_64_CONTENT\", \"metadata\": { \"key\": \"my-test-file.jpg\" } }" http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "YOUR_BASE_64_CONTENT", "metadata": { "key": "my-test-file.jpg" } }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 从文件路径上传 +要从提供的路径(相对或绝对)上传文件,请在包含空 `data` 字段的 `create` 请求中使用 `filepath` 元数据键。 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"create\", \"metadata\": { \"filePath\": \"my-test-file.txt\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "metadata": { "filePath": "my-test-file.txt" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文将包含以下 JSON: + +```json +{ + "location":"https://.s3..amazonaws.com/", + "versionID":"}} + + {{% codetab %}} + ```bash + curl -d "{ \"operation\": \"presign\", \"metadata\": { \"presignTTL\": \"15m\", \"key\": \"my-test-file.txt\" } }" \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "presign", "metadata": { "presignTTL": "15m", "key": "my-test-file.txt" } }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +##### 响应 + +响应正文包含以下示例 JSON: + +```json +{ + "presignURL": "https://.s3..amazonaws.com/image.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAJJWZ7B6WCRGMKFGQ%2F20180210%2Feu-west-2%2Fs3%2Faws4_request&X-Amz-Date=20180210T171315Z&X-Amz-Expires=1800&X-Amz-Signature=12b74b0788aa036bc7c3d03b3f20c61f1f91cc9ad8873e3314255dc479a25351&X-Amz-SignedHeaders=host" +} +``` + +### 获取对象 + +要执行获取文件操作,请使用 `POST` 方法调用 AWS S3 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "get", + "metadata": { + "key": "my-test-file.txt" + } +} +``` + +元数据参数为: + +- `key` - 对象的名称 + +#### 示例 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"get\", \"metadata\": { \"key\": \"my-test-file.txt\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "get", "metadata": { "key": "my-test-file.txt" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文包含存储在对象中的值。 + +### 删除对象 + +要执行删除对象操作,请使用 `POST` 方法调用 AWS S3 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "delete", + "metadata": { + "key": "my-test-file.txt" + } +} +``` + +元数据参数为: + +- `key` - 对象的名称 + +#### 示例 + +##### 删除对象 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"delete\", \"metadata\": { \"key\": \"my-test-file.txt\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "delete", "metadata": { "key": "my-test-file.txt" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +如果成功,将返回 HTTP 204(无内容)和空正文。 + +### 列出对象 + +要执行列出对象操作,请使用 `POST` 方法调用 S3 绑定,并使用以下 JSON 正文: + +```json +{ + "operation": "list", + "data": { + "maxResults": 10, + "prefix": "file", + "marker": "hvlcCQFSOD5TD", + "delimiter": "i0FvxAn2EOEL6" + } +} +``` + +数据参数为: + +- `maxResults` - (可选)设置响应中返回的最大键数。默认情况下,操作返回最多 1,000 个键名。响应可能包含更少的键,但绝不会包含更多。 +- `prefix` - (可选)限制响应为以指定前缀开头的键。 +- `marker` - (可选)标记是您希望 Amazon S3 开始列出的位置。Amazon S3 从此指定键之后开始列出。标记可以是 bucket 中的任何键。标记值可以在后续调用中用于请求下一组列表项。 +- `delimiter` - (可选)分隔符是您用来分组键的字符。 + +#### 响应 + +响应正文包含找到的对象列表。 + +对象列表将作为 JSON 数组返回,格式如下: + +```json +{ + "CommonPrefixes": null, + "Contents": [ + { + "ETag": "\"7e94cc9b0f5226557b05a7c2565dd09f\"", + "Key": "hpNdFUxruNuwm", + "LastModified": "2021-08-16T06:44:14Z", + "Owner": { + "DisplayName": "owner name", + "ID": "owner id" + }, + "Size": 6916, + "StorageClass": "STANDARD" + } + ], + "Delimiter": "", + "EncodingType": null, + "IsTruncated": true, + "Marker": "hvlcCQFSOD5TD", + "MaxKeys": 1, + "Name": "mybucketdapr", + "NextMarker": "hzaUPWjmvyi9W", + "Prefix": "" +} +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) +- [身份验证到 AWS]({{< ref authenticating-aws.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/sendgrid.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/sendgrid.md new file mode 100644 index 000000000..6e36e5c53 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/sendgrid.md @@ -0,0 +1,105 @@ +--- +type: docs +title: "Twilio SendGrid 绑定规范" +linkTitle: "Twilio SendGrid" +description: "关于 Twilio SendGrid 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/sendgrid/" +--- + +## 组件格式 + +要设置 Twilio SendGrid 绑定,您需要创建一个类型为 `bindings.twilio.sendgrid` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: sendgrid +spec: + type: bindings.twilio.sendgrid + version: v1 + metadata: + - name: emailFrom + value: "testapp@dapr.io" # 可选 + - name: emailFromName + value: "test app" # 可选 + - name: emailTo + value: "dave@dapr.io" # 可选 + - name: emailToName + value: "dave" # 可选 + - name: subject + value: "Hello!" # 可选 + - name: emailCc + value: "jill@dapr.io" # 可选 + - name: emailBcc + value: "bob@dapr.io" # 可选 + - name: dynamicTemplateId + value: "d-123456789" # 可选 + - name: dynamicTemplateData + value: '{"customer":{"name":"John Smith"}}' # 可选 + - name: apiKey + value: "YOUR_API_KEY" # 必需,这是您的 SendGrid 密钥 +``` + +{{% alert title="警告" color="warning" %}} +上述示例中使用了明文字符串作为密钥。建议使用密钥存储来保存密钥,具体方法请参见[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `apiKey` | Y | 输出 | SendGrid API 密钥,应视为敏感信息 | `"apikey"` | +| `emailFrom` | N | 输出 | 若设置,指定电子邮件的“发件人”地址。仅允许一个电子邮件地址。可选字段,参见[下文](#example-request-payload) | `"me@example.com"` | +| `emailFromName` | N | 输出 | 若设置,指定电子邮件的“发件人”名称。可选字段,参见[下文](#example-request-payload) | `"me"` | +| `emailTo` | N | 输出 | 若设置,指定电子邮件的“收件人”地址。仅允许一个电子邮件地址。可选字段,参见[下文](#example-request-payload) | `"me@example.com"` | +| `emailToName` | N | 输出 | 若设置,指定电子邮件的“收件人”名称。可选字段,参见[下文](#example-request-payload) | `"me"` | +| `emailCc` | N | 输出 | 若设置,指定电子邮件的“抄送”地址。仅允许一个电子邮件地址。可选字段,参见[下文](#example-request-payload) | `"me@example.com"` | +| `emailBcc` | N | 输出 | 若设置,指定电子邮件的“密件抄送”地址。仅允许一个电子邮件地址。可选字段,参见[下文](#example-request-payload) | `"me@example.com"` | +| `subject` | N | 输出 | 若设置,指定电子邮件的主题。可选字段,参见[下文](#example-request-payload) | `"subject of the email"` | + +## 绑定支持 + +此组件支持以下操作的**输出绑定**: + +- `create` + +## 示例请求负载 + +您也可以在输出绑定请求中指定任何可选的元数据属性(例如 `emailFrom`、`emailTo`、`subject` 等)。 + +```json +{ + "operation": "create", + "metadata": { + "emailTo": "changeme@example.net", + "subject": "An email from Dapr SendGrid binding" + }, + "data": "

Testing Dapr Bindings

This is a test.
Bye!" +} +``` + +## 动态模板 + +如果使用动态模板,您需要提供 `dynamicTemplateId`,并使用 `dynamicTemplateData` 来传递模板数据: + +```json +{ + "operation": "create", + "metadata": { + "emailTo": "changeme@example.net", + "subject": "An template email from Dapr SendGrid binding", + "dynamicTemplateId": "d-123456789", + "dynamicTemplateData": "{\"customer\":{\"name\":\"John Smith\"}}" + } +} +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [操作指南:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [操作指南:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/servicebusqueues.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/servicebusqueues.md new file mode 100644 index 000000000..f8e617ae3 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/servicebusqueues.md @@ -0,0 +1,238 @@ +--- +type: docs +title: "Azure Service Bus Queues 绑定规范" +linkTitle: "Azure Service Bus Queues" +description: "关于 Azure Service Bus Queues 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/servicebusqueues/" +--- + +## 组件格式 + +要设置 Azure Service Bus Queues 绑定,请创建一个类型为 `bindings.azure.servicebusqueues` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +### 连接字符串认证 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.azure.servicebusqueues + version: v1 + metadata: + - name: connectionString # 不使用 Azure 认证时必需。 + value: "Endpoint=sb://{ServiceBusNamespace}.servicebus.windows.net/;SharedAccessKeyName={PolicyName};SharedAccessKey={Key};EntityPath={ServiceBus}" + - name: queueName + value: "queue1" + # - name: timeoutInSec # 可选 + # value: "60" + # - name: handlerTimeoutInSec # 可选 + # value: "60" + # - name: disableEntityManagement # 可选 + # value: "false" + # - name: maxDeliveryCount # 可选 + # value: "3" + # - name: lockDurationInSec # 可选 + # value: "60" + # - name: lockRenewalInSec # 可选 + # value: "20" + # - name: maxActiveMessages # 可选 + # value: "10000" + # - name: maxConcurrentHandlers # 可选 + # value: "10" + # - name: defaultMessageTimeToLiveInSec # 可选 + # value: "10" + # - name: autoDeleteOnIdleInSec # 可选 + # value: "3600" + # - name: minConnectionRecoveryInSec # 可选 + # value: "2" + # - name: maxConnectionRecoveryInSec # 可选 + # value: "300" + # - name: maxRetriableErrorsPerSec # 可选 + # value: "10" + # - name: publishMaxRetries # 可选 + # value: "5" + # - name: publishInitialRetryIntervalInMs # 可选 + # value: "500" + # - name: direction + # value: "input, output" +``` +{{% alert title="警告" color="warning" %}} +上述示例中使用了明文字符串作为密钥。建议使用密钥存储来存储这些敏感信息,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|-----------------|----------|---------| +| `connectionString` | Y | 输入/输出 | Service Bus 的连接字符串。除非使用 Microsoft Entra ID 认证,否则必需。 | `"Endpoint=sb://************"` | +| `queueName` | Y | 输入/输出 | Service Bus 的队列名称。队列名称不区分大小写,并将始终强制为小写。 | `"queuename"` | +| `timeoutInSec` | N | 输入/输出 | 对 Azure Service Bus 端点的所有调用的超时时间,以秒为单位。*注意,此选项影响网络调用,与应用于消息的 TTL 无关*。默认值为 `"60"` | `"60"` | +| `namespaceName`| N | 输入/输出 | 设置 Service Bus 命名空间地址的参数,作为完全限定的域名。使用 Microsoft Entra ID 认证时必需。 | `"namespace.servicebus.windows.net"` | +| `disableEntityManagement` | N | 输入/输出 | 当设置为 true 时,队列和订阅不会自动创建。默认值为 `"false"` | `"true"`, `"false"` +| `lockDurationInSec` | N | 输入/输出 | 定义消息在过期前被锁定的时间长度,以秒为单位。仅在订阅创建期间使用。由服务器设置默认值。 | `"30"` +| `autoDeleteOnIdleInSec` | N | 输入/输出 | 在自动删除空闲订阅之前等待的时间,以秒为单位。仅在订阅创建期间使用。必须为 300 秒或更长。默认值为 `"0"` (禁用) | `"3600"` +| `defaultMessageTimeToLiveInSec` | N | 输入/输出 | 默认消息生存时间,以秒为单位。仅在订阅创建期间使用。 | `"10"` +| `maxDeliveryCount` | N | 输入/输出 | 定义服务器尝试传递消息的次数。仅在订阅创建期间使用。由服务器设置默认值。 | `"10"` +| `minConnectionRecoveryInSec` | N | 输入/输出 | 在连接失败的情况下,尝试重新连接到 Azure Service Bus 之前等待的最小间隔(以秒为单位)。默认值为 `"2"` | `"5"` +| `maxConnectionRecoveryInSec` | N | 输入/输出 | 在连接失败的情况下,尝试重新连接到 Azure Service Bus 之前等待的最大间隔(以秒为单位)。每次尝试后,组件在最小和最大之间等待一个随机秒数,每次增加。默认值为 `"300"` (5 分钟) | `"600"` +| `maxActiveMessages` | N | 定义一次处理或在缓冲区中的最大消息数。此值应至少与最大并发处理程序一样大。默认值为 `"1"` | `"1"` +| `handlerTimeoutInSec`| N | 输入 | 调用应用程序处理程序的超时时间。默认值为 `"0"` (无超时) | `"30"` +| `minConnectionRecoveryInSec` | N | 输入 | 在连接失败的情况下,尝试重新连接到 Azure Service Bus 之前等待的最小间隔(以秒为单位)。默认值为 `"2"` | `"5"` | +| `maxConnectionRecoveryInSec` | N | 输入 | 在连接失败的情况下,尝试重新连接到 Azure Service Bus 之前等待的最大间隔(以秒为单位)。每次尝试后,绑定在最小和最大之间等待一个随机秒数,每次增加。默认值为 `"300"` (5 分钟) | `"600"` | +| `lockRenewalInSec` | N | 输入 | 定义缓冲消息锁将被续订的频率。默认值为 `"20"`。 | `"20"` +| `maxActiveMessages` | N | 输入 | 定义一次处理或在缓冲区中的最大消息数。此值应至少与最大并发处理程序一样大。默认值为 `"1"` | `"2000"` +| `maxConcurrentHandlers` | N | 输入 | 定义最大并发消息处理程序数;设置为 `0` 表示无限制。默认值为 `"1"` | `"10"` +| `maxRetriableErrorsPerSec` | N | 输入 | 每秒处理的最大可重试错误数。如果消息因可重试错误而无法处理,组件会在开始处理另一条消息之前添加延迟,以避免立即重新处理失败的消息。默认值为 `"10"` | `"10"` +| `publishMaxRetries` | N | 输出 | 当 Azure Service Bus 响应“过于繁忙”以限制消息时的最大重试次数。默认值为 `"5"` | `"5"` +| `publishInitialRetryIntervalInMs` | N | 输出 | 当 Azure Service Bus 限制消息时,初始指数退避的时间(以毫秒为单位)。默认值为 `"500"` | `"500"` +| `direction` | N | 输入/输出 | 绑定的方向 | `"input"`, `"output"`, `"input, output"` + +### Microsoft Entra ID 认证 + +Azure Service Bus Queues 绑定组件支持使用所有 Microsoft Entra ID 机制进行认证,包括托管身份。有关更多信息以及根据选择的 Microsoft Entra ID 认证机制提供的相关组件元数据字段,请参阅[认证到 Azure 的文档]({{< ref authenticating-azure.md >}})。 + +#### 示例配置 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.azure.servicebusqueues + version: v1 + metadata: + - name: azureTenantId + value: "***" + - name: azureClientId + value: "***" + - name: azureClientSecret + value: "***" + - name: namespaceName + # 使用 Azure 认证时必需。 + # 必须是完全限定的域名 + value: "servicebusnamespace.servicebus.windows.net" + - name: queueName + value: queue1 + - name: ttlInSeconds + value: 60 +``` + +## 绑定支持 + +此组件支持 **输入和输出** 绑定功能。 + +此组件支持具有以下操作的 **输出绑定**: + +- `create`: 将消息发布到指定队列 + +## 消息元数据 + +Azure Service Bus 消息通过附加上下文元数据扩展了 Dapr 消息格式。一些元数据字段由 Azure Service Bus 本身设置(只读),其他字段可以在通过 `Invoke` 绑定调用使用 `create` 操作发布消息时由客户端设置。 + +### 发送带有元数据的消息 + +要在发送消息时设置 Azure Service Bus 元数据,请在 HTTP 请求或 gRPC 元数据上设置查询参数,如[此处]({{< ref "bindings_api.md" >}})所述。 + +- `metadata.MessageId` +- `metadata.CorrelationId` +- `metadata.SessionId` +- `metadata.Label` +- `metadata.ReplyTo` +- `metadata.PartitionKey` +- `metadata.To` +- `metadata.ContentType` +- `metadata.ScheduledEnqueueTimeUtc` +- `metadata.ReplyToSessionId` + +{{% alert title="注意" color="primary" %}} +- `metadata.MessageId` 属性不会设置 Dapr 返回的云事件的 `id` 属性,应单独处理。 +- `metadata.ScheduledEnqueueTimeUtc` 属性支持 [RFC1123](https://www.rfc-editor.org/rfc/rfc1123) 和 [RFC3339](https://www.rfc-editor.org/rfc/rfc3339) 时间戳格式。 +{{% /alert %}} + +### 接收带有元数据的消息 + +当 Dapr 调用您的应用程序时,它使用 HTTP 头或 gRPC 元数据将 Azure Service Bus 消息元数据附加到请求中。 +除了[上述可设置的元数据](#sending-a-message-with-metadata)外,您还可以访问以下只读消息元数据。 + +- `metadata.DeliveryCount` +- `metadata.LockedUntilUtc` +- `metadata.LockToken` +- `metadata.EnqueuedTimeUtc` +- `metadata.SequenceNumber` + +要了解这些元数据属性的目的的更多详细信息,请参阅[官方 Azure Service Bus 文档](https://docs.microsoft.com/rest/api/servicebus/message-headers-and-properties#message-headers)。 + +此外,原始 Azure Service Bus 消息的所有 `ApplicationProperties` 条目都作为 `metadata.` 附加。 + +{{% alert title="注意" color="primary" %}} +所有时间均由服务器设置,并未调整时钟偏差。 +{{% /alert %}} + +## 为每条消息指定 TTL + +生存时间可以在队列级别(如上所示)或消息级别进行定义。在消息级别定义的值将覆盖在队列级别设置的任何值。 + +要在消息级别设置生存时间,请在绑定调用期间使用请求体中的 `metadata` 部分:字段名称为 `ttlInSeconds`。 + +{{< tabs "Linux">}} + +{{% codetab %}} + +```shell +curl -X POST http://localhost:3500/v1.0/bindings/myServiceBusQueue \ + -H "Content-Type: application/json" \ + -d '{ + "data": { + "message": "Hi" + }, + "metadata": { + "ttlInSeconds": "60" + }, + "operation": "create" + }' +``` +{{% /codetab %}} + +{{< /tabs >}} + +## 调度消息 + +可以调度消息以进行延迟处理。 + +要调度消息,请在绑定调用期间使用请求体中的 `metadata` 部分:字段名称为 `ScheduledEnqueueTimeUtc`。 + +支持的时间戳格式为 [RFC1123](https://www.rfc-editor.org/rfc/rfc1123) 和 [RFC3339](https://www.rfc-editor.org/rfc/rfc3339)。 + +{{< tabs "Linux">}} + +{{% codetab %}} + +```shell +curl -X POST http://localhost:3500/v1.0/bindings/myServiceBusQueue \ + -H "Content-Type: application/json" \ + -d '{ + "data": { + "message": "Hi" + }, + "metadata": { + "ScheduledEnqueueTimeUtc": "Tue, 02 Jan 2024 15:04:05 GMT" + }, + "operation": "create" + }' +``` + +{{% /codetab %}} + +{{< /tabs >}} + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/ses.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/ses.md new file mode 100644 index 000000000..0e778c79c --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/ses.md @@ -0,0 +1,107 @@ +--- +type: docs +title: "AWS SES 绑定说明" +linkTitle: "AWS SES" +description: "AWS SES 绑定组件的详细介绍" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/ses/" +--- + +## 组件格式 + +要配置 AWS 绑定,请创建一个类型为 `bindings.aws.ses` 的组件。有关如何创建和应用绑定配置的详细信息,请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})。 + +关于身份验证的更多信息,请参阅[身份验证到 AWS]({{< ref authenticating-aws.md >}})。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: ses +spec: + type: bindings.aws.ses + version: v1 + metadata: + - name: accessKey + value: ***************** + - name: secretKey + value: ***************** + - name: region + value: "eu-west-1" + - name: sessionToken + value: mysession + - name: emailFrom + value: "sender@example.com" + - name: emailTo + value: "receiver@example.com" + - name: emailCc + value: "cc@example.com" + - name: emailBcc + value: "bcc@example.com" + - name: subject + value: "subject" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中使用了明文字符串作为密钥。建议使用密钥存储来保存密钥,详情请参阅[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `region` | 否 | 输出 | AWS 区域 | `"eu-west-1"` | +| `accessKey` | 否 | 输出 | 访问资源的 AWS 访问密钥 | `"key"` | +| `secretKey` | 否 | 输出 | 访问资源的 AWS 秘密访问密钥 | `"secretAccessKey"` | +| `sessionToken` | 否 | 输出 | 使用的 AWS 会话令牌 | `"sessionToken"` | +| `emailFrom` | 否 | 输出 | 发件人的电子邮件地址 | `"me@example.com"` | +| `emailTo` | 否 | 输出 | 收件人的电子邮件地址 | `"me@example.com"` | +| `emailCc` | 否 | 输出 | 抄送的电子邮件地址 | `"me@example.com"` | +| `emailBcc` | 否 | 输出 | 密送的电子邮件地址 | `"me@example.com"` | +| `subject` | 否 | 输出 | 电子邮件的主题 | `"subject of mail"` | + +{{% alert title="重要" color="warning" %}} +在 EKS(AWS Kubernetes)上运行 Dapr sidecar(daprd)时,如果节点/Pod 已附加了访问 AWS 资源的 IAM 策略,则**不应**在组件规范中提供 AWS 访问密钥、秘密密钥和令牌。 +{{% /alert %}} + +## 绑定支持 + +此组件支持以下操作的**输出绑定**: + +- `create` + +## 示例请求 + +在每个请求中,您可以指定以下任意可选元数据属性: + +- `emailFrom` +- `emailTo` +- `emailCc` +- `emailBcc` +- `subject` + +发送电子邮件时,配置中的元数据和请求中的元数据将合并。合并后的元数据集必须至少包含 `emailFrom`、`emailTo`、`emailCc`、`emailBcc` 和 `subject` 字段。 + +`emailTo`、`emailCc` 和 `emailBcc` 字段可以包含多个用分号分隔的电子邮件地址。 + +示例: +```json +{ + "operation": "create", + "metadata": { + "emailTo": "dapr-smtp-binding@example.net", + "emailCc": "cc1@example.net", + "subject": "Email subject" + }, + "data": "Testing Dapr SMTP Binding" +} +``` +`emailTo`、`emailCc` 和 `emailBcc` 字段可以包含多个用分号分隔的电子邮件地址。 + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/sftp.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/sftp.md new file mode 100644 index 000000000..5828bdd61 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/sftp.md @@ -0,0 +1,230 @@ +--- +type: docs +title: "SFTP 绑定规范" +linkTitle: "SFTP" +description: "关于安全文件传输协议(SFTP)绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/sftp/" +--- + +## 组件格式 + +要配置 SFTP 绑定,创建一个类型为 `bindings.sftp` 的组件。请参阅[本指南]({{ ref bindings-overview.md }})以了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.sftp + version: v1 + metadata: + - name: rootPath + value: "" + - name: address + value: "" + - name: username + value: "" + - name: password + value: "*****************" + - name: privateKey + value: "*****************" + - name: privateKeyPassphrase + value: "*****************" + - name: hostPublicKey + value: "*****************" + - name: knownHostsFile + value: "" + - name: insecureIgnoreHostKey + value: "" +``` + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `rootPath` | Y | 输出 | 默认工作目录的根路径 | `"/path"` | +| `address` | Y | 输出 | SFTP 服务器地址 | `"localhost:22"` | +| `username` | Y | 输出 | 用于身份验证的用户名 | `"username"` | +| `password` | N | 输出 | 用户名/密码身份验证的密码 | `"password"` | +| `privateKey` | N | 输出 | 公钥身份验证的私钥 |
"\|-
-----BEGIN OPENSSH PRIVATE KEY-----
*****************
-----END OPENSSH PRIVATE KEY-----"
| +| `privateKeyPassphrase` | N | 输出 | 公钥身份验证的私钥密码 | `"passphrase"` | +| `hostPublicKey` | N | 输出 | 主机验证的主机公钥 | `"ecdsa-sha2-nistp256 *** root@openssh-server"` | +| `knownHostsFile` | N | 输出 | 主机验证的已知主机文件 | `"/path/file"` | +| `insecureIgnoreHostKey` | N | 输出 | 允许跳过主机验证。默认为 `"false"` | `"true"`, `"false"` | + +## 绑定功能支持 + +此组件支持以下操作的**输出绑定**: + +- `create` : [创建文件](#create-file) +- `get` : [获取文件](#get-file) +- `list` : [列出文件](#list-files) +- `delete` : [删除文件](#delete-file) + +### 创建文件 + +要执行创建文件操作,请使用 `POST` 方法调用 SFTP 绑定,并提供以下 JSON 正文: + +```json +{ + "operation": "create", + "data": "", + "metadata": { + "fileName": "" + } +} +``` + +#### 示例 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d "{ \"operation\": \"create\", \"data\": \"YOUR_BASE_64_CONTENT\", \"metadata\": { \"fileName\": \"my-test-file.jpg\" } }" http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "create", "data": "YOUR_BASE_64_CONTENT", "metadata": { "fileName": "my-test-file.jpg" } }' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文将返回以下 JSON: + +```json +{ + "fileName": "" +} +``` + +### 获取文件 + +要执行获取文件操作,请使用 `POST` 方法调用 SFTP 绑定,并提供以下 JSON 正文: + +```json +{ + "operation": "get", + "metadata": { + "fileName": "" + } +} +``` + +#### 示例 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"get\", \"metadata\": { \"fileName\": \"filename\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "get", "metadata": { "fileName": "filename" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应正文将包含文件中的内容。 + +### 列出文件 + +要执行列出文件操作,请使用 `POST` 方法调用 SFTP 绑定,并提供以下 JSON 正文: + +```json +{ + "operation": "list" +} +``` + +如果您只想列出 `rootPath` 下某个特定目录中的文件,请在元数据中指定该目录的相对路径作为 `fileName`。 + +```json +{ + "operation": "list", + "metadata": { + "fileName": "my/cool/directory" + } +} +``` + +#### 示例 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"list\", \"metadata\": { \"fileName\": \"my/cool/directory\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "list", "metadata": { "fileName": "my/cool/directory" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +响应将是一个包含文件名的 JSON 数组。 + +### 删除文件 + +要执行删除文件操作,请使用 `POST` 方法调用 SFTP 绑定,并提供以下 JSON 正文: + +```json +{ + "operation": "delete", + "metadata": { + "fileName": "myfile" + } +} +``` + +#### 示例 + +{{< tabs Windows Linux >}} + + {{% codetab %}} + ```bash + curl -d '{ \"operation\": \"delete\", \"metadata\": { \"fileName\": \"myfile\" }}' http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + + {{% codetab %}} + ```bash + curl -d '{ "operation": "delete", "metadata": { "fileName": "myfile" }}' \ + http://localhost:/v1.0/bindings/ + ``` + {{% /codetab %}} + +{{< /tabs >}} + +#### 响应 + +如果成功,将返回 HTTP 204(无内容)和空响应正文。 + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/signalr.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/signalr.md new file mode 100644 index 000000000..c00b061ba --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/signalr.md @@ -0,0 +1,98 @@ +--- +type: docs +title: "Azure SignalR 绑定规范" +linkTitle: "Azure SignalR" +description: "关于 Azure SignalR 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/signalr/" +--- + +## 组件格式 + +要配置 Azure SignalR 绑定,请创建一个类型为 `bindings.azure.signalr` 的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.azure.signalr + version: v1 + metadata: + - name: connectionString + value: "Endpoint=https://.service.signalr.net;AccessKey=;Version=1.0;" + - name: hub # 可选 + value: "" +``` + +{{% alert title="警告" color="warning" %}} +上述示例使用了明文字符串作为 secret。建议使用 secret 存储来存储 secret,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `connectionString` | Y | 输出 | Azure SignalR 连接字符串 | `"Endpoint=https://.service.signalr.net;AccessKey=;Version=1.0;"` | +| `hub` | N | 输出 | 定义消息将发送到的 hub。hub 可以在发布到输出绑定时动态定义为元数据值(键为 "hub") | `"myhub"` | +| `endpoint` | N | 输出 | Azure SignalR 的端点;如果未包含在 `connectionString` 中或使用 Microsoft Entra ID,则必需 | `"https://.service.signalr.net"` +| `accessKey` | N | 输出 | 访问密钥 | `"your-access-key"` + +### Microsoft Entra ID 认证 + +Azure SignalR 绑定组件支持所有 Microsoft Entra ID 认证机制。请参考[认证到 Azure 的文档]({{< ref authenticating-azure.md >}})以了解更多关于根据您选择的 Microsoft Entra ID 认证机制的相关组件元数据字段。 + +您可以通过以下两种方式使用 Microsoft Entra ID 认证此组件: + +- 提供单独的元数据键: + - `endpoint` 用于端点 + - 如有需要:`azureClientId`、`azureTenantId` 和 `azureClientSecret` +- 提供带有 `AuthType=aad` 指定的连接字符串: + - 系统分配的托管身份:`Endpoint=https://.service.signalr.net;AuthType=aad;Version=1.0;` + - 用户分配的托管身份:`Endpoint=https://.service.signalr.net;AuthType=aad;ClientId=;Version=1.0;` + - Microsoft Entra ID 应用程序:`Endpoint=https://.service.signalr.net;AuthType=aad;ClientId=;ClientSecret=;TenantId=;Version=1.0;` + 请注意,如果您的应用程序的 ClientSecret 包含 `;` 字符,则无法使用连接字符串。 + +## 绑定支持 + +此组件支持具有以下操作的**输出绑定**: + +- `create` + +## 附加信息 + +默认情况下,Azure SignalR 输出绑定会向所有连接的用户广播消息。要缩小消息的接收范围,可以在消息的 Metadata 属性中配置以下选项: + +- group:将消息发送到特定的 Azure SignalR 组 +- user:将消息发送到特定的 Azure SignalR 用户 + +发布到 Azure SignalR 输出绑定的应用程序应发送具有以下格式的消息: + +```json +{ + "data": { + "Target": "", + "Arguments": [ + { + "sender": "dapr", + "text": "Message from dapr output binding" + } + ] + }, + "metadata": { + "group": "chat123" + }, + "operation": "create" +} +``` + +有关将 Azure SignalR 集成到解决方案中的更多信息,请查看[文档](https://docs.microsoft.com/azure/azure-signalr/) + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [Bindings 构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [Bindings API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/smtp.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/smtp.md new file mode 100644 index 000000000..e0e1244a6 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/smtp.md @@ -0,0 +1,108 @@ +--- +type: docs +title: "SMTP 绑定规范" +linkTitle: "SMTP" +description: "关于 SMTP 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/smtp/" +--- + +## 组件格式 + +要设置 SMTP 绑定,您需要创建一个类型为 `bindings.smtp` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: smtp +spec: + type: bindings.smtp + version: v1 + metadata: + - name: host + value: "smtp host" + - name: port + value: "smtp port" + - name: user + value: "username" + - name: password + value: "password" + - name: skipTLSVerify + value: true|false + - name: emailFrom + value: "sender@example.com" + - name: emailTo + value: "receiver@example.com" + - name: emailCC + value: "cc@example.com" + - name: emailBCC + value: "bcc@example.com" + - name: subject + value: "subject" + - name: priority + value: "[value 1-5]" +``` + +{{% alert title="警告" color="warning" %}} +上面的示例配置中包含了明文形式的用户名和密码。建议使用 secret 存储来保护这些信息,详情请参阅[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `host` | Y | 输出 | SMTP 服务器的主机地址 | `"smtphost"` | +| `port` | Y | 输出 | SMTP 服务器的端口号 | `"9999"` | +| `user` | Y | 输出 | 用于认证的用户名 | `"user"` | +| `password` | Y | 输出 | 用户的密码 | `"password"` | +| `skipTLSVerify` | N | 输出 | 如果设置为 true,将跳过对 SMTP 服务器 TLS 证书的验证。默认为 `"false"` | `"true"`, `"false"` | +| `emailFrom` | N | 输出 | 如果设置,将指定发件人的电子邮件地址。参见[示例请求](#example-request) | `"me@example.com"` | +| `emailTo` | N | 输出 | 如果设置,将指定收件人的电子邮件地址。参见[示例请求](#example-request) | `"me@example.com"` | +| `emailCc` | N | 输出 | 如果设置,将指定抄送的电子邮件地址。参见[示例请求](#example-request) | `"me@example.com"` | +| `emailBcc` | N | 输出 | 如果设置,将指定密送的电子邮件地址。参见[示例请求](#example-request) | `"me@example.com"` | +| `subject` | N | 输出 | 如果设置,将指定电子邮件的主题。参见[示例请求](#example-request) | `"subject of mail"` | +| `priority` | N | 输出 | 如果设置,将指定电子邮件的优先级 (X-Priority),范围从 1(最低)到 5(最高)(默认值:3)。参见[示例请求](#example-request) | `"1"` | + +## 绑定支持 + +此组件支持**输出绑定**,可执行以下操作: + +- `create` + +## 示例请求 + +在每个请求中,您可以指定以下任意可选元数据属性: + +- `emailFrom` +- `emailTo` +- `emailCC` +- `emailBCC` +- `subject` +- `priority` + +发送电子邮件时,配置中的元数据和请求中的元数据将被合并。合并后的元数据集必须至少包含 `emailFrom`、`emailTo` 和 `subject` 字段。 + +`emailTo`、`emailCC` 和 `emailBCC` 字段可以包含多个用分号分隔的电子邮件地址。 + +示例: +```json +{ + "operation": "create", + "metadata": { + "emailTo": "dapr-smtp-binding@example.net", + "emailCC": "cc1@example.net; cc2@example.net", + "subject": "Email subject", + "priority": "1" + }, + "data": "Testing Dapr SMTP Binding" +} +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [操作指南:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [操作指南:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/sns.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/sns.md new file mode 100644 index 000000000..26e3e4a0d --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/sns.md @@ -0,0 +1,71 @@ +--- +type: docs +title: "AWS SNS 绑定组件规范" +linkTitle: "AWS SNS" +description: "AWS SNS 绑定组件的详细说明文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/sns/" +--- + +## 组件格式 + +要配置 AWS SNS 绑定,请创建一个类型为 `bindings.aws.sns` 的组件。有关如何创建和应用绑定配置的详细信息,请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})。 + +有关身份验证的详细信息,请参阅[身份验证到 AWS]({{< ref authenticating-aws.md >}})。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.aws.sns + version: v1 + metadata: + - name: topicArn + value: "mytopic" + - name: region + value: "us-west-2" + - name: endpoint + value: "sns.us-west-2.amazonaws.com" + - name: accessKey + value: "*****************" + - name: secretKey + value: "*****************" + - name: sessionToken + value: "*****************" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中使用了明文字符串来表示密钥。建议使用密钥存储来管理这些密钥,详情请参阅[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `topicArn` | 是 | 输出绑定 | SNS 主题的 ARN(Amazon Resource Name) | `"arn:::topicarn"` | +| `region` | 是 | 输出绑定 | AWS 的特定区域 | `"us-east-1"` | +| `endpoint` | 否 | 输出绑定 | AWS 的特定端点 | `"sns.us-east-1.amazonaws.com"` | +| `accessKey` | 是 | 输出绑定 | 访问资源的 AWS 访问密钥 | `"key"` | +| `secretKey` | 是 | 输出绑定 | 访问资源的 AWS 秘密访问密钥 | `"secretAccessKey"` | +| `sessionToken` | 否 | 输出绑定 | 使用的 AWS 会话令牌 | `"sessionToken"` | + +{{% alert title="重要" color="warning" %}} +在 EKS(AWS Kubernetes)上与应用程序一起运行 Dapr sidecar(daprd)时,如果节点/Pod 已附加了访问 AWS 资源的 IAM 策略,则**不应**在组件规范中提供 AWS 访问密钥、秘密密钥和令牌。 +{{% /alert %}} + +## 绑定支持 + +此组件支持以下操作的**输出绑定**: + +- `create` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [bindings 构建块]({{< ref bindings >}}) +- [操作指南:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [操作指南:使用bindings与外部资源接口]({{< ref howto-bindings.md >}}) +- [bindings API 参考]({{< ref bindings_api.md >}}) +- [身份验证到 AWS]({{< ref authenticating-aws.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/sqs.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/sqs.md new file mode 100644 index 000000000..d57629f01 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/sqs.md @@ -0,0 +1,73 @@ +--- +type: docs +title: "AWS SQS 绑定规范" +linkTitle: "AWS SQS" +description: "关于 AWS SQS 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/sqs/" +--- + +## 组件格式 + +要设置 AWS SQS 绑定,您需要创建一个类型为 `bindings.aws.sqs` 的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +关于身份验证相关属性的信息,请参阅[身份验证到 AWS]({{< ref authenticating-aws.md >}})。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.aws.sqs + version: v1 + metadata: + - name: queueName + value: "items" + - name: region + value: "us-west-2" + - name: accessKey + value: "*****************" + - name: secretKey + value: "*****************" + - name: sessionToken + value: "*****************" + - name: direction + value: "input, output" +``` + +{{% alert title="警告" color="warning" %}} +上述示例使用明文字符串作为密钥。建议使用密钥存储来保存密钥,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 规范元数据字段 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `queueName` | Y | 输入/输出 | SQS 队列名称 | `"myqueue"` | +| `region` | Y | 输入/输出 | 特定的 AWS 区域 | `"us-east-1"` | +| `accessKey` | Y | 输入/输出 | 访问此资源的 AWS 访问密钥 | `"key"` | +| `secretKey` | Y | 输入/输出 | 访问此资源的 AWS 秘密访问密钥 | `"secretAccessKey"` | +| `sessionToken` | N | 输入/输出 | 要使用的 AWS 会话令牌 | `"sessionToken"` | +| `direction` | N | 输入/输出 | 绑定的方向 | `"input"`, `"output"`, `"input, output"` | + +{{% alert title="重要" color="warning" %}} +在 EKS(AWS Kubernetes)上与应用程序一起运行 Dapr sidecar(daprd)时,如果您使用的节点/Pod 已经附加了定义访问 AWS 资源的 IAM 策略,则**不应**在组件规范中提供 AWS 访问密钥、秘密密钥和令牌。 +{{% /alert %}} + +## 绑定支持 + +此组件支持**输入和输出**绑定接口。 + +此组件支持以下操作的**输出绑定**: + +- `create` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [操作指南:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [操作指南:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) +- [身份验证到 AWS]({{< ref authenticating-aws.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/storagequeues.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/storagequeues.md new file mode 100644 index 000000000..d6a228d54 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/storagequeues.md @@ -0,0 +1,106 @@ +--- +type: docs +title: "Azure Storage Queues 绑定规范" +linkTitle: "Azure Storage Queues" +description: "关于 Azure Storage Queues 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/storagequeues/" +--- + +## 组件格式 + +要配置 Azure Storage Queues 绑定,需创建一个类型为 `bindings.azure.storagequeues` 的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.azure.storagequeues + version: v1 + metadata: + - name: accountName + value: "account1" + - name: accountKey + value: "***********" + - name: queueName + value: "myqueue" +# - name: pollingInterval +# value: "30s" +# - name: ttlInSeconds +# value: "60" +# - name: decodeBase64 +# value: "false" +# - name: encodeBase64 +# value: "false" +# - name: endpoint +# value: "http://127.0.0.1:10001" +# - name: visibilityTimeout +# value: "30s" +# - name: direction +# value: "input, output" +``` + +{{% alert title="警告" color="warning" %}} +上述示例中,secret 使用了明文字符串。建议使用 secret 存储,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `accountName` | Y | 输入/输出 | Azure Storage 帐户的名称 | `"account1"` | +| `accountKey` | Y* | 输入/输出 | Azure Storage 帐户的访问密钥。仅在不使用 Microsoft Entra ID 身份验证时需要。 | `"access-key"` | +| `queueName` | Y | 输入/输出 | Azure Storage 队列的名称 | `"myqueue"` | +| `pollingInterval` | N | 输出 | 设置轮询 Azure Storage Queues 以获取新消息的间隔,作为 Go 持续时间值。默认值:`"10s"` | `"30s"` | +| `ttlInSeconds` | N | 输出 | 设置默认消息生存时间的参数。如果省略此参数,消息将在 10 分钟后过期。参见[此处](#specifying-a-ttl-per-message) | `"60"` | +| `decodeBase64` | N | 输入 | 配置将从 Storage Queue 接收到的 base64 内容解码为字符串。默认为 `false` | `true`, `false` | +| `encodeBase64` | N | 输出 | 如果启用,则在上传到 Azure storage queues 之前对数据负载进行 base64 编码。默认 `false`。 | `true`, `false` | +| `endpoint` | N | 输入/输出 | 可选的自定义端点 URL。这在使用 [Azurite 模拟器](https://github.com/Azure/azurite)或使用 Azure Storage 的自定义域时很有用(尽管这不是官方支持的)。端点必须是完整的基本 URL,包括协议(`http://` 或 `https://`)、IP 或 FQDN,以及可选端口。 | `"http://127.0.0.1:10001"` 或 `"https://accountName.queue.example.com"` | +| `visibilityTimeout` | N | 输入 | 允许设置自定义队列可见性超时,以避免最近失败消息的立即重试。默认为 30 秒。 | `"100s"` | +| `direction` | N | 输入/输出 | 绑定的方向。 | `"input"`, `"output"`, `"input, output"` | + +### Microsoft Entra ID 身份验证 + +Azure Storage Queue 绑定组件支持使用所有 Microsoft Entra ID 机制进行身份验证。请参阅[Azure 身份验证文档]({{< ref authenticating-azure.md >}})以了解有关根据您选择的 Microsoft Entra ID 身份验证机制的相关组件元数据字段的更多信息。 + +## 绑定支持 + +此组件支持 **输入和输出** 绑定接口。 + +此组件支持具有以下操作的 **输出绑定**: + +- `create` + +## 为每条消息指定 TTL + +生存时间可以在队列级别(如上所示)或消息级别定义。在消息级别定义的值将覆盖在队列级别设置的任何值。 + +要在消息级别设置生存时间,请在绑定调用期间使用请求体中的 `metadata` 部分。 + +字段名称为 `ttlInSeconds`。 + +示例: + +```shell +curl -X POST http://localhost:3500/v1.0/bindings/myStorageQueue \ + -H "Content-Type: application/json" \ + -d '{ + "data": { + "message": "Hi" + }, + "metadata": { + "ttlInSeconds": "60" + }, + "operation": "create" + }' +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [bindings 构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用 bindings 与外部资源接口]({{< ref howto-bindings.md >}}) +- [bindings API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/twilio.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/twilio.md new file mode 100644 index 000000000..2a7b1a191 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/twilio.md @@ -0,0 +1,57 @@ +--- +type: docs +title: "Twilio SMS 绑定说明" +linkTitle: "Twilio SMS" +description: "关于 Twilio SMS 绑定组件的详细文档" +aliases: + - "/zh-hans/operations/components/setup-bindings/supported-bindings/twilio/" +--- + +## 组件格式指南 + +要配置 Twilio SMS 绑定组件,请创建一个类型为 `bindings.twilio.sms` 的组件。有关如何创建和应用绑定配置的详细信息,请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.twilio.sms + version: v1 + metadata: + - name: toNumber # 必需。 + value: "111-111-1111" + - name: fromNumber # 必需。 + value: "222-222-2222" + - name: accountSid # 必需。 + value: "*****************" + - name: authToken # 必需。 + value: "*****************" +``` +{{% alert title="警告" color="warning" %}} +上述示例中,secret 以明文字符串形式使用。建议使用 secret 存储来存储 secret,如[此处]({{< ref component-secrets.md >}})所述。 +{{% /alert %}} + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|--------------------|:--------:|------------|-----|---------| +| `toNumber` | Y | 输出 | 发送短信的目标号码 | `"111-111-1111"` | +| `fromNumber` | Y | 输出 | 发送者的电话号码 | `"222-222-2222"` | +| `accountSid` | Y | 输出 | Twilio 账户 SID | `"account sid"` | +| `authToken` | Y | 输出 | Twilio 认证令牌 | `"auth token"` | + +## 支持的绑定功能 + +此组件支持以下**输出绑定**操作: + +- `create` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [操作指南:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [操作指南:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/wasm.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/wasm.md new file mode 100644 index 000000000..26778d36b --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/wasm.md @@ -0,0 +1,115 @@ +--- +type: docs +title: "Wasm" +linkTitle: "Wasm" +description: "关于 WebAssembly 绑定组件的详细文档" +aliases: +- "/zh-hans/operations/components/setup-bindings/supported-bindings/wasm/" +--- + +## 概述 + +使用 WebAssembly,您可以安全地运行用其他语言编写并编译的代码。运行时执行 WebAssembly 模块(Wasm),这些模块通常是带有 `.wasm` 扩展名的二进制文件。 + +Wasm 绑定允许您通过传递命令行参数或环境变量来调用编译为 Wasm 的程序,就像使用普通子进程一样。例如,即使 Dapr 是用 Go 编写的并运行在没有安装 Python 的平台上,您也可以使用 Python 满足调用需求! + +Wasm 二进制文件必须是使用 WebAssembly 系统接口(WASI)编译的程序。二进制文件可以是您编写的程序,例如用 Go 编写的,或者是您用来运行内联脚本的解释器,例如 Python。 + +至少,您需要指定一个使用标准 WASI 版本 `wasi_snapshot_preview1`(又名 `wasip1`)编译的 Wasm 二进制文件,通常缩写为 `wasi`。 + +> **注意:** 如果在 Go 1.21+ 中编译,这是 `GOOS=wasip1 GOARCH=wasm`。在 TinyGo、Rust 和 Zig 中,这是目标 `wasm32-wasi`。 + +您还可以重用现有的二进制文件。例如,[Wasm 语言运行时](https://github.com/vmware-labs/webassembly-language-runtimes)分发已经编译为 WASI 的解释器(包括 PHP、Python 和 Ruby)。 + +Wasm 二进制文件可以从 URL 加载。例如,URL `file://rewrite.wasm` 会从进程的当前目录加载 `rewrite.wasm`。在 Kubernetes 上,请参阅[如何:将 Pod 卷挂载到 Dapr sidecar]({{< ref kubernetes-volume-mounts.md >}})以配置可以包含 Wasm 二进制文件的文件系统挂载。也可以从远程 URL 获取 Wasm 二进制文件。在这种情况下,URL 必须准确指向一个 Wasm 二进制文件。例如: +- `http://example.com/rewrite.wasm`,或 +- `https://example.com/rewrite.wasm`。 + +Dapr 使用 [wazero](https://wazero.io) 来运行这些二进制文件,因为它没有依赖项。这允许使用 WebAssembly 而无需安装过程,除了 Dapr 本身。 + +Wasm 输出绑定支持使用 [wasi-http](https://github.com/WebAssembly/wasi-http) 规范进行 HTTP 客户端调用。您可以在此处找到用多种语言进行 HTTP 调用的示例代码: +* [Golang](https://github.com/dev-wasm/dev-wasm-go/tree/main/http) +* [C](https://github.com/dev-wasm/dev-wasm-c/tree/main/http) +* [.NET](https://github.com/dev-wasm/dev-wasm-dotnet/tree/main/http) +* [TypeScript](https://github.com/dev-wasm/dev-wasm-ts/tree/main/http) + +{{% alert title="注意" color="primary" %}} +如果您只想进行 HTTP 调用,使用 [service-invocation API]({{< ref howto-invoke-non-dapr-endpoints.md >}}) 更简单。然而,如果您需要添加自己的逻辑 - 例如,过滤或调用多个 API 端点 - 请考虑使用 Wasm。 +{{% /alert %}} + +## 组件格式 + +要配置 Wasm 绑定,请创建一个类型为 `bindings.wasm` 的组件。请参阅[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: wasm +spec: + type: bindings.wasm + version: v1 + metadata: + - name: url + value: "file://uppercase.wasm" +``` + +## 规范元数据字段 + +| 字段 | 详情 | 必需 | 示例 | +|-------|----------------------------------------------------------------|----------|----------------| +| `url` | 包含要实例化的 Wasm 二进制文件的资源 URL。支持的方案包括 `file://`、`http://` 和 `https://`。`file://` URL 的路径相对于 Dapr 进程,除非它以 `/` 开头。 | true | `file://hello.wasm`, `https://example.com/hello.wasm` | + +## 绑定支持 + +此组件支持具有以下操作的**输出绑定**: + +- `execute` + +## 示例请求 + +如果存在,`data` 字段将是程序的 STDIN。您可以选择性地为每个请求传递元数据属性: + +- `args` 任何 CLI 参数,逗号分隔。这不包括程序名称。 + +例如,考虑将 `url` 绑定到 Ruby 解释器,例如来自 [webassembly-language-runtimes](https://github.com/vmware-labs/webassembly-language-runtimes/releases/tag/ruby%2F3.2.0%2B20230215-1349da9): + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: wasm +spec: + type: bindings.wasm + version: v1 + metadata: + - name: url + value: "https://github.com/vmware-labs/webassembly-language-runtimes/releases/download/ruby%2F3.2.0%2B20230215-1349da9/ruby-3.2.0-slim.wasm" +``` + +假设您想在端口 3500 启动 Dapr 并使用 Wasm 绑定,您可以运行: + +``` +$ dapr run --app-id wasm --dapr-http-port 3500 --resources-path components +``` + +以下请求响应 `Hello "salaboy"`: + +```sh +$ curl -X POST http://localhost:3500/v1.0/bindings/wasm -d' +{ + "operation": "execute", + "metadata": { + "args": "-ne,print \"Hello \"; print" + }, + "data": "salaboy" +}' +``` + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [bindings 构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [bindings API 参考]({{< ref bindings_api.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/zeebe-command.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/zeebe-command.md new file mode 100644 index 000000000..5a98680c9 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/zeebe-command.md @@ -0,0 +1,672 @@ +--- +type: docs +title: "Zeebe 命令绑定说明" +linkTitle: "Zeebe 命令" +description: "关于 Zeebe 命令绑定组件的详细文档" +--- + +## 组件格式说明 + +要配置 Zeebe 命令绑定,请创建一个类型为 `bindings.zeebe.command` 的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +有关 Zeebe 的更多信息,请查看[此处](https://docs.camunda.io/docs/components/zeebe/zeebe-overview/)的文档。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.zeebe.command + version: v1 + metadata: + - name: gatewayAddr + value: ":" + - name: gatewayKeepAlive + value: "45s" + - name: usePlainTextConnection + value: "true" + - name: caCertificatePath + value: "/path/to/ca-cert" +``` + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|-------------------------|:--------:|------------|-----|---------| +| `gatewayAddr` | Y | 输出 | Zeebe 网关地址 | `"localhost:26500"` | +| `gatewayKeepAlive` | N | 输出 | 设置发送到网关的保活消息的频率。默认为 45 秒 | `"45s"` | +| `usePlainTextConnection` | N | 输出 | 是否使用纯文本连接 | `"true"`, `"false"` | +| `caCertificatePath` | N | 输出 | CA 证书的路径 | `"/path/to/ca-cert"` | + +## 绑定支持 + +此组件支持以下操作的**输出绑定**: + +- `topology` +- `deploy-process` +- `deploy-resource` +- `create-instance` +- `cancel-instance` +- `set-variables` +- `resolve-incident` +- `publish-message` +- `activate-jobs` +- `complete-job` +- `fail-job` +- `update-job-retries` +- `throw-error` + +### 输出绑定 + +Zeebe 在此绑定中使用的客户端底层依赖 gRPC。请查阅 [gRPC API 参考](https://docs.camunda.io/docs/apis-clients/grpc/)以获取更多信息。 + +#### topology + +`topology` 操作用于获取网关所属集群的当前拓扑。 + +要执行 `topology` 操作,请通过 `POST` 方法调用 Zeebe 命令绑定,并使用以下 JSON 正文: + +```json +{ + "data": {}, + "operation": "topology" +} +``` + +##### 响应 + +绑定返回一个包含以下信息的 JSON: + +```json +{ + "brokers": [ + { + "nodeId": null, + "host": "172.18.0.5", + "port": 26501, + "partitions": [ + { + "partitionId": 1, + "role": null, + "health": null + } + ], + "version": "0.26.0" + } + ], + "clusterSize": 1, + "partitionsCount": 1, + "replicationFactor": 1, + "gatewayVersion": "0.26.0" +} +``` + +响应值为: + +- `brokers` - 集群中的 broker 列表 + - `nodeId` - broker 的唯一节点 ID + - `host` - broker 的主机名 + - `port` - broker 的端口 + - `partitions` - 此 broker 管理或复制的分区列表 + - `partitionId` - 分区的唯一 ID + - `role` - broker 在此分区中的角色 + - `health` - 分区的健康状况 + - `version` - broker 版本 +- `clusterSize` - 集群中的节点数量 +- `partitionsCount` - 集群中分布的分区数量 +- `replicationFactor` - 集群配置的复制因子 +- `gatewayVersion` - 网关版本 + +#### deploy-process + +`deploy-process` 的弃用别名为 'deploy-resource'。 + +#### deploy-resource + +`deploy-resource` 操作用于将单个资源部署到 Zeebe。资源可以是流程(BPMN)或决策和决策需求(DMN)。 + +要执行 `deploy-resource` 操作,请通过 `POST` 方法调用 Zeebe 命令绑定,并使用以下 JSON 正文: + +```json +{ + "data": "YOUR_FILE_CONTENT", + "metadata": { + "fileName": "products-process.bpmn" + }, + "operation": "deploy-resource" +} +``` + +元数据参数为: + +- `fileName` - 资源文件的名称 + +##### 响应 + +绑定返回一个包含以下信息的 JSON: + +{{< tabs "BPMN" "DMN" >}} + +{{% codetab %}} + +```json +{ + "key": 2251799813685252, + "deployments": [ + { + "Metadata": { + "Process": { + "bpmnProcessId": "products-process", + "version": 2, + "processDefinitionKey": 2251799813685251, + "resourceName": "products-process.bpmn" + } + } + } + ] +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```json +{ + "key": 2251799813685253, + "deployments": [ + { + "Metadata": { + "Decision": { + "dmnDecisionId": "products-approval", + "dmnDecisionName": "Products approval", + "version": 1, + "decisionKey": 2251799813685252, + "dmnDecisionRequirementsId": "Definitions_0c98xne", + "decisionRequirementsKey": 2251799813685251 + } + } + }, + { + "Metadata": { + "DecisionRequirements": { + "dmnDecisionRequirementsId": "Definitions_0c98xne", + "dmnDecisionRequirementsName": "DRD", + "version": 1, + "decisionRequirementsKey": 2251799813685251, + "resourceName": "products-approval.dmn" + } + } + } + ] +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +响应值为: + +- `key` - 部署的唯一标识键 +- `deployments` - 已部署资源的列表,例如流程 + - `metadata` - 部署元数据,每个部署只有一个元数据 + - `process`- 已部署流程的元数据 + - `bpmnProcessId` - 部署期间解析的 bpmn 流程 ID;与版本一起构成特定流程定义的唯一标识符 + - `version` - 分配的流程版本 + - `processDefinitionKey` - 分配的键,作为此流程的唯一标识符 + - `resourceName` - 解析此流程的资源名称 + - `decision` - 已部署决策的元数据 + - `dmnDecisionId` - 部署期间解析的 dmn 决策 ID;与版本一起构成特定决策的唯一标识符 + - `dmnDecisionName` - 部署期间解析的决策的 dmn 名称 + - `version` - 分配的决策版本 + - `decisionKey` - 分配的决策键,作为此决策的唯一标识符 + - `dmnDecisionRequirementsId` - 部署期间解析的决策需求图的 dmn ID,此决策是其一部分 + - `decisionRequirementsKey` - 此决策所属的决策需求图的分配键 + - `decisionRequirements` - 已部署决策需求的元数据 + - `dmnDecisionRequirementsId` - 部署期间解析的 dmn 决策需求 ID;与版本一起构成特定决策的唯一标识符 + - `dmnDecisionRequirementsName` - 部署期间解析的决策需求的 dmn 名称 + - `version` - 分配的决策需求版本 + - `decisionRequirementsKey` - 分配的决策需求键,作为此决策需求的唯一标识符 + - `resourceName` - 解析此决策需求的资源名称 + +#### create-instance + +`create-instance` 操作用于创建并启动指定流程的实例。可以使用其唯一键(由 `deploy-process` 操作返回)或使用 BPMN 流程 ID 和版本来指定要用于创建实例的流程定义。 + +请注意,只有具有无启动事件的流程才能通过此命令启动。 + +通常,流程创建和执行是解耦的。这意味着命令创建一个新的流程实例并立即响应流程实例 ID。流程的执行在响应发送后发生。然而,有些用例需要在流程执行完成时收集结果。通过定义 `withResult` 属性,命令允许“同步”执行流程并通过一组变量接收结果。响应在流程执行完成时发送。 + +有关更多信息,请访问[官方文档](https://docs.camunda.io/docs/components/concepts/process-instance-creation/)。 + +要执行 `create-instance` 操作,请通过 `POST` 方法调用 Zeebe 命令绑定,并使用以下 JSON 正文: + +{{< tabs "通过 BPMN 流程 ID" "通过流程定义键" "同步执行" >}} + +{{% codetab %}} + +```json +{ + "data": { + "bpmnProcessId": "products-process", + "variables": { + "productId": "some-product-id", + "productName": "some-product-name", + "productKey": "some-product-key" + } + }, + "operation": "create-instance" +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```json +{ + "data": { + "processDefinitionKey": 2251799813685895, + "variables": { + "productId": "some-product-id", + "productName": "some-product-name", + "productKey": "some-product-key" + } + }, + "operation": "create-instance" +} +``` + +{{% /codetab %}} + +{{% codetab %}} + +```json +{ + "data": { + "bpmnProcessId": "products-process", + "variables": { + "productId": "some-product-id", + "productName": "some-product-name", + "productKey": "some-product-key" + }, + "withResult": true, + "requestTimeout": "30s", + "fetchVariables": ["productId"] + }, + "operation": "create-instance" +} +``` + +{{% /codetab %}} + +{{< /tabs >}} + +数据参数为: + +- `bpmnProcessId` - 要实例化的流程定义的 BPMN 流程 ID +- `processDefinitionKey` - 要实例化的流程定义的唯一键 +- `version` - (可选,默认:最新版本)要实例化的流程版本 +- `variables` - (可选)JSON 文档,将为流程实例的根变量范围实例化变量;它必须是一个 JSON 对象,因为变量将以键值对的方式映射。例如,{ "a": 1, "b": 2 } 将创建两个变量,分别命名为 "a" 和 "b",并具有其关联的值。[{ "a": 1, "b": 2 }] 将不是有效参数,因为 JSON 文档的根是一个数组而不是对象 +- `withResult` - (可选,默认:false)如果设置为 true,流程将被同步实例化和执行 +- `requestTimeout` - (可选,仅在 withResult=true 时使用)如果流程在 requestTimeout 之前未完成,请求将被关闭。如果 requestTimeout = 0,则使用网关中配置的通用 requestTimeout。 +- `fetchVariables` - (可选,仅在 withResult=true 时使用)要包含在响应的 `variables` 属性中的变量名称列表。如果为空,将返回根范围内的所有可见变量。 + +##### 响应 + +绑定返回一个包含以下信息的 JSON: + +```json +{ + "processDefinitionKey": 2251799813685895, + "bpmnProcessId": "products-process", + "version": 3, + "processInstanceKey": 2251799813687851, + "variables": "{\"productId\":\"some-product-id\"}" +} +``` + +响应值为: + +- `processDefinitionKey` - 用于创建流程实例的流程定义的键 +- `bpmnProcessId` - 用于创建流程实例的流程定义的 BPMN 流程 ID +- `version` - 用于创建流程实例的流程定义的版本 +- `processInstanceKey` - 创建的流程实例的唯一标识符 +- `variables` - (可选,仅在请求中使用了 withResult=true 时)JSON 文档,由根范围内的可见变量组成;作为序列化的 JSON 文档返回 + +#### cancel-instance + +`cancel-instance` 操作用于取消正在运行的流程实例。 + +要执行 `cancel-instance` 操作,请通过 `POST` 方法调用 Zeebe 命令绑定,并使用以下 JSON 正文: + +```json +{ + "data": { + "processInstanceKey": 2251799813687851 + }, + "operation": "cancel-instance" +} +``` + +数据参数为: + +- `processInstanceKey` - 流程实例键 + +##### 响应 + +绑定不返回响应正文。 + +#### set-variables + +`set-variables` 操作用于为元素实例(例如流程实例、流程元素实例)创建或更新变量。 + +要执行 `set-variables` 操作,请通过 `POST` 方法调用 Zeebe 命令绑定,并使用以下 JSON 正文: + +```json +{ + "data": { + "elementInstanceKey": 2251799813687880, + "variables": { + "productId": "some-product-id", + "productName": "some-product-name", + "productKey": "some-product-key" + } + }, + "operation": "set-variables" +} +``` + +数据参数为: + +- `elementInstanceKey` - 特定元素的唯一标识符;可以是流程实例键(在实例创建期间获得),或给定元素,例如服务任务(请参阅 job 消息上的 elementInstanceKey) +- `local` - (可选,默认:`false`)如果为 true,变量将严格合并到本地范围(由 elementInstanceKey 指示);这意味着变量不会传播到上层范围。 + 例如,假设我们有两个范围,'1' 和 '2',每个范围的有效变量为: + 1 => `{ "foo" : 2 }`,和 2 => `{ "bar" : 1 }`。如果我们发送一个更新请求,elementInstanceKey = 2,变量 `{ "foo" : 5 }`,并且 local 为 true,那么范围 1 将保持不变,范围 2 将变为 `{ "bar" : 1, "foo" 5 }`。然而,如果 local 为 false,那么范围 1 将为 `{ "foo": 5 }`,范围 2 将为 `{ "bar" : 1 }` +- `variables` - 描述变量的键值对的 JSON 序列化文档;文档的根必须是一个对象 + +##### 响应 + +绑定返回一个包含以下信息的 JSON: + +```json +{ + "key": 2251799813687896 +} +``` + +响应值为: + +- `key` - 设置变量命令的唯一键 + +#### resolve-incident + +`resolve-incident` 操作用于解决一个事件。 + +要执行 `resolve-incident` 操作,请通过 `POST` 方法调用 Zeebe 命令绑定,并使用以下 JSON 正文: + +```json +{ + "data": { + "incidentKey": 2251799813686123 + }, + "operation": "resolve-incident" +} +``` + +数据参数为: + +- `incidentKey` - 要解决的事件的唯一 ID + +##### 响应 + +绑定不返回响应正文。 + +#### publish-message + +`publish-message` 操作用于发布一条消息。消息发布到从其关联键计算出的特定分区。 + +要执行 `publish-message` 操作,请通过 `POST` 方法调用 Zeebe 命令绑定,并使用以下 JSON 正文: + +```json +{ + "data": { + "messageName": "product-message", + "correlationKey": "2", + "timeToLive": "1m", + "variables": { + "productId": "some-product-id", + "productName": "some-product-name", + "productKey": "some-product-key" + }, + }, + "operation": "publish-message" +} +``` + +数据参数为: + +- `messageName` - 消息的名称 +- `correlationKey` - (可选)消息的关联键 +- `timeToLive` - (可选)消息在 broker 上缓冲的时间 +- `messageId` - (可选)消息的唯一 ID;可以省略。仅用于确保在其生命周期内只有一条具有给定 ID 的消息会被发布 +- `variables` - (可选)消息变量作为 JSON 文档;要有效,文档的根必须是一个对象,例如 { "a": "foo" }。[ "foo" ] 将不是有效的 + +##### 响应 + +绑定返回一个包含以下信息的 JSON: + +```json +{ + "key": 2251799813688225 +} +``` + +响应值为: + +- `key` - 发布的消息的唯一 ID + +#### activate-jobs + +`activate-jobs` 操作以轮询方式遍历所有已知分区并激活最多请求的最大数量,并在激活时将其流式传输回客户端。 + +要执行 `activate-jobs` 操作,请通过 `POST` 方法调用 Zeebe 命令绑定,并使用以下 JSON 正文: + +```json +{ + "data": { + "jobType": "fetch-products", + "maxJobsToActivate": 5, + "timeout": "5m", + "workerName": "products-worker", + "fetchVariables": [ + "productId", + "productName", + "productKey" + ], + "requestTimeout": "30s" + }, + "operation": "activate-jobs" +} +``` + +数据参数为: + +- `jobType` - 作业类型,如 BPMN 流程中定义的(例如 ``) +- `maxJobsToActivate` - 此请求要激活的最大作业数 +- `timeout` - (可选,默认:5 分钟)此调用返回的作业在超时之前不会被另一个调用激活 +- `workerName` - (可选,默认:`default`)激活作业的工作者的名称,主要用于日志记录目的 +- `fetchVariables` - (可选)要作为作业变量获取的变量列表;如果为空,将返回作业范围内激活时的所有可见变量 +- `requestTimeout` - (可选)请求将在至少一个作业被激活或在 requestTimeout 之后完成。如果 requestTimeout = 0,则使用默认超时。如果 requestTimeout < 0,则禁用长轮询,并且请求立即完成,即使没有作业被激活。 + +##### 响应 + +绑定返回一个包含以下信息的 JSON: + +```json +[ + { + "key": 2251799813685267, + "type": "fetch-products", + "processInstanceKey": 2251799813685260, + "bpmnProcessId": "products", + "processDefinitionVersion": 1, + "processDefinitionKey": 2251799813685249, + "elementId": "Activity_test", + "elementInstanceKey": 2251799813685266, + "customHeaders": "{\"process-header-1\":\"1\",\"process-header-2\":\"2\"}", + "worker": "test", + "retries": 1, + "deadline": 1694091934039, + "variables":"{\"productId\":\"some-product-id\"}" + } +] +``` + +响应值为: + +- `key` - 作业的键,作业的唯一标识符 +- `type` - 作业的类型(应与请求的类型匹配) +- `processInstanceKey` - 作业的流程实例键 +- `bpmnProcessId` - 作业流程定义的 bpmn 流程 ID +- `processDefinitionVersion` - 作业流程定义的版本 +- `processDefinitionKey` - 作业流程定义的键 +- `elementId` - 关联的任务元素 ID +- `elementInstanceKey` - 唯一标识关联任务的唯一键,在流程实例范围内唯一 +- `customHeaders` - 在建模期间定义的一组自定义头;作为序列化的 JSON 文档返回 +- `worker` - 激活此作业的工作者的名称 +- `retries` - 此作业剩余的重试次数(应始终为正) +- `deadline` - 作业可以再次激活的时间,以 UNIX 纪元时间戳发送 +- `variables` - 在激活时计算,由任务范围内的所有可见变量组成;作为序列化的 JSON 文档返回 + +#### complete-job + +`complete-job` 操作使用给定的负载完成作业,从而允许完成关联的服务任务。 + +要执行 `complete-job` 操作,请通过 `POST` 方法调用 Zeebe 命令绑定,并使用以下 JSON 正文: + +```json +{ + "data": { + "jobKey": 2251799813686172, + "variables": { + "productId": "some-product-id", + "productName": "some-product-name", + "productKey": "some-product-key" + } + }, + "operation": "complete-job" +} +``` + +数据参数为: + +- `jobKey` - 唯一的作业标识符,从激活作业响应中获得 +- `variables` - (可选)表示当前任务范围内变量的 JSON 文档 + +##### 响应 + +绑定不返回响应正文。 + +#### fail-job + +`fail-job` 操作将作业标记为失败;如果重试参数为正,则作业将立即可再次激活,并且工作者可以再次尝试处理它。然而,如果为零或负数,则会引发事件,并标记为给定的错误消息,并且作业在事件解决之前不会被激活。 + +要执行 `fail-job` 操作,请通过 `POST` 方法调用 Zeebe 命令绑定,并使用以下 JSON 正文: + +```json +{ + "data": { + "jobKey": 2251799813685739, + "retries": 5, + "errorMessage": "some error occurred", + "retryBackOff": "30s", + "variables": { + "productId": "some-product-id", + "productName": "some-product-name", + "productKey": "some-product-key" + } + }, + "operation": "fail-job" +} +``` + +数据参数为: + +- `jobKey` - 激活作业时获得的唯一作业标识符 +- `retries` - 作业应剩余的重试次数 +- `errorMessage ` - (可选)描述作业失败原因的消息,这在作业用尽重试次数并引发事件时特别有用,因为此消息可以帮助解释为什么引发事件 +- `retryBackOff` - (可选)下次重试的回退超时 +- `variables` - (可选)JSON 文档,将在作业关联任务的本地范围内实例化变量;它必须是一个 JSON 对象,因为变量将以键值对的方式映射。例如,{ "a": 1, "b": 2 } 将创建两个变量,分别命名为 "a" 和 "b",并具有其关联的值。[{ "a": 1, "b": 2 }] 将不是有效参数,因为 JSON 文档的根是一个数组而不是对象。 + +##### 响应 + +绑定不返回响应正文。 + +#### update-job-retries + +`update-job-retries` 操作用于更新作业剩余的重试次数。这对于作业用尽重试次数的情况特别有用,假设底层问题已解决。 + +要执行 `update-job-retries` 操作,请通过 `POST` 方法调用 Zeebe 命令绑定,并使用以下 JSON 正文: + +```json +{ + "data": { + "jobKey": 2251799813686172, + "retries": 10 + }, + "operation": "update-job-retries" +} +``` + +数据参数为: + +- `jobKey` - 通过 activate-jobs 操作获得的唯一作业标识符 +- `retries` - 作业的新重试次数;必须为正 + +##### 响应 + +绑定不返回响应正文。 + +#### throw-error + +`throw-error` 操作用于抛出一个错误,以指示在处理作业时发生了业务错误。错误由错误代码标识,并由流程中具有相同错误代码的错误捕获事件处理。 + +要执行 `throw-error` 操作,请通过 `POST` 方法调用 Zeebe 命令绑定,并使用以下 JSON 正文: + +```json +{ + "data": { + "jobKey": 2251799813686172, + "errorCode": "product-fetch-error", + "errorMessage": "The product could not be fetched", + "variables": { + "productId": "some-product-id", + "productName": "some-product-name", + "productKey": "some-product-key" + } + }, + "operation": "throw-error" +} +``` + +数据参数为: + +- `jobKey` - 激活作业时获得的唯一作业标识符 +- `errorCode` - 将与错误捕获事件匹配的错误代码 +- `errorMessage` - (可选)提供附加上下文的错误消息 +- `variables` - (可选)JSON 文档,将在作业关联任务的本地范围内实例化变量;它必须是一个 JSON 对象,因为变量将以键值对的方式映射。例如,{ "a": 1, "b": 2 } 将创建两个变量,分别命名为 "a" 和 "b",并具有其关联的值。[{ "a": 1, "b": 2 }] 将不是有效参数,因为 JSON 文档的根是一个数组而不是对象。 + +##### 响应 + +绑定不返回响应正文。 + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [Bindings 构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [Bindings API 参考]({{< ref bindings_api.md >}}) \ No newline at end of file diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/zeebe-jobworker.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/zeebe-jobworker.md new file mode 100644 index 000000000..425a2e2c1 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-bindings/zeebe-jobworker.md @@ -0,0 +1,127 @@ +--- +type: docs +title: "Zeebe JobWorker 绑定说明" +linkTitle: "Zeebe JobWorker" +description: "关于 Zeebe JobWorker 绑定组件的详细文档" +--- + +## 组件配置格式 + +要配置 Zeebe JobWorker 绑定,请创建一个类型为 `bindings.zeebe.jobworker` 的组件。请参考[本指南]({{< ref "howto-bindings.md#1-create-a-binding" >}})了解如何创建和应用绑定配置。 + +有关 Zeebe JobWorker 的详细文档,请查看[此处](https://docs.camunda.io/docs/components/concepts/job-workers/)。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: bindings.zeebe.jobworker + version: v1 + metadata: + - name: gatewayAddr + value: ":" + - name: gatewayKeepAlive + value: "45s" + - name: usePlainTextConnection + value: "true" + - name: caCertificatePath + value: "/path/to/ca-cert" + - name: workerName + value: "products-worker" + - name: workerTimeout + value: "5m" + - name: requestTimeout + value: "15s" + - name: jobType + value: "fetch-products" + - name: maxJobsActive + value: "32" + - name: concurrency + value: "4" + - name: pollInterval + value: "100ms" + - name: pollThreshold + value: "0.3" + - name: fetchVariables + value: "productId, productName, productKey" + - name: autocomplete + value: "true" + - name: retryBackOff + value: "30s" + - name: direction + value: "input" +``` + +## 元数据字段说明 + +| 字段 | 必需 | 绑定支持 | 详情 | 示例 | +|-------------------------|:--------:|------------|-----|---------| +| `gatewayAddr` | Y | 输入 | Zeebe 网关地址 | `"localhost:26500"` | +| `gatewayKeepAlive` | N | 输入 | 设置发送到网关的保活消息频率,默认为 45 秒 | `"45s"` | +| `usePlainTextConnection` | N | 输入 | 是否使用纯文本连接 | `"true"`, `"false"` | +| `caCertificatePath` | N | 输入 | CA 证书的路径 | `"/path/to/ca-cert"` | +| `workerName` | N | 输入 | 激活作业的 worker 名称,主要用于日志记录 | `"products-worker"` | +| `workerTimeout` | N | 输入 | 在此调用后返回的作业在超时之前不会被另一个调用激活,默认为 5 分钟 | `"5m"` | +| `requestTimeout` | N | 输入 | 请求将在至少一个作业被激活或达到 requestTimeout 后完成。如果 requestTimeout = 0,则使用默认超时。如果 requestTimeout < 0,则禁用长轮询,即使没有作业被激活,请求也会立即完成。默认为 10 秒 | `"30s"` | +| `jobType` | Y | 输入 | 在 BPMN 流程中定义的作业类型(例如 ``) | `"fetch-products"` | +| `maxJobsActive` | N | 输入 | 设置此 worker 同时激活的最大作业数,默认为 32 | `"32"` | +| `concurrency` | N | 输入 | 完成作业的最大并发 goroutines 数量,默认为 4 | `"4"` | +| `pollInterval` | N | 输入 | 设置轮询新作业的最大间隔,默认为 100 毫秒 | `"100ms"` | +| `pollThreshold` | N | 输入 | 设置缓冲激活作业的阈值以便轮询新作业,即阈值 * maxJobsActive,默认为 0.3 | `"0.3"` | +| `fetchVariables` | N | 输入 | 要获取的作业变量列表;如果为空,则在作业激活时返回作用域内的所有可见变量 | `"productId"`, `"productName"`, `"productKey"` | +| `autocomplete` | N | 输入 | 指示作业是否应自动完成。如果未设置,默认情况下所有作业将自动完成。如果 worker 应手动完成或因业务错误或事件而失败作业,请禁用此选项 | `"true"`, `"false"` | +| `retryBackOff` | N | 输入 | 作业失败时下次重试的回退超时 | `15s` | +| `direction` | N | 输入 | 绑定的方向 | `"input"` | + +## 绑定支持 + +此组件支持**输入**绑定接口。 + +### 输入绑定 + +#### 变量 + +Zeebe 流程引擎处理流程状态,并可以在流程实例化时传递或在流程执行期间更新或创建流程变量。这些变量可以通过在 `fetchVariables` 元数据字段中定义变量名称的逗号分隔列表传递给注册的作业 worker。然后,流程引擎将这些变量及其当前值传递给作业 worker 实现。 + +如果绑定注册了三个变量 `productId`、`productName` 和 `productKey`,则 worker 将接收到以下 JSON 主体: + +```json +{ + "productId": "some-product-id", + "productName": "some-product-name", + "productKey": "some-product-key" +} +``` + +注意:如果未传递 `fetchVariables` 元数据字段,则所有流程变量将传递给 worker。 + +#### 头信息 + +Zeebe 流程引擎能够将自定义任务头信息传递给作业 worker。这些头信息可以为每个[服务任务](https://docs.camunda.io/docs/components/best-practices/development/service-integration-patterns/#service-task)定义。任务头信息将作为元数据(HTTP 头信息)由绑定传递给作业 worker。 + +绑定还将以下与作业相关的变量作为元数据传递。值将作为字符串传递。表格中还包含原始数据类型,以便可以在 worker 使用的编程语言中转换回等效数据类型。 + +| 元数据 | 数据类型 | 描述 | +|------------------------------------|-----------|-------------------------------------------------------------------------------------------------| +| X-Zeebe-Job-Key | int64 | 作业的键,一个唯一标识符 | +| X-Zeebe-Job-Type | string | 作业的类型(应与请求的类型匹配) | +| X-Zeebe-Process-Instance-Key | int64 | 作业的流程实例键 | +| X-Zeebe-Bpmn-Process-Id | string | 作业流程定义的 bpmn 流程 ID | +| X-Zeebe-Process-Definition-Version | int32 | 作业流程定义的版本 | +| X-Zeebe-Process-Definition-Key | int64 | 作业流程定义的键 | +| X-Zeebe-Element-Id | string | 关联任务元素 ID | +| X-Zeebe-Element-Instance-Key | int64 | 唯一标识关联任务的唯一键,在流程实例范围内唯一 | +| X-Zeebe-Worker | string | 激活此作业的 worker 名称 | +| X-Zeebe-Retries | int32 | 此作业剩余的重试次数(应始终为正) | +| X-Zeebe-Deadline | int64 | 作业可以再次激活的时间,以 UNIX 纪元时间戳发送 | +| X-Zeebe-Autocomplete | bool | 在绑定元数据中定义的自动完成状态 | + +## 相关链接 + +- [Dapr 组件的基本架构]({{< ref component-schema >}}) +- [绑定构建块]({{< ref bindings >}}) +- [如何:使用输入绑定触发应用程序]({{< ref howto-triggers.md >}}) +- [如何:使用绑定与外部资源接口]({{< ref howto-bindings.md >}}) +- [绑定 API 参考]({{< ref bindings_api.md >}}) diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-configuration-stores/_index.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-configuration-stores/_index.md new file mode 100644 index 000000000..7d67d3f35 --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-configuration-stores/_index.md @@ -0,0 +1,14 @@ +--- +type: docs +title: "配置存储组件说明" +linkTitle: "配置存储" +weight: 6000 +description: 与Dapr接口的支持配置存储 +aliases: + - "/zh-hans/operations/components/setup-configuration-store/supported-configuration-stores/" +no_list: true +--- + +{{< partial "components/description.html" >}} + +{{< partial "components/configuration-stores.html" >}} diff --git a/src/translated_content/zh_CN/docs/reference/components-reference/supported-configuration-stores/azure-appconfig-configuration-store.md b/src/translated_content/zh_CN/docs/reference/components-reference/supported-configuration-stores/azure-appconfig-configuration-store.md new file mode 100644 index 000000000..231ecfacb --- /dev/null +++ b/src/translated_content/zh_CN/docs/reference/components-reference/supported-configuration-stores/azure-appconfig-configuration-store.md @@ -0,0 +1,108 @@ +--- +type: docs +title: "Azure 应用配置" +linkTitle: "Azure 应用配置" +description: 详细介绍 Azure 应用配置组件 +aliases: + - "/zh-hans/operations/components/setup-configuration-store/supported-configuration-stores/setup-azure-appconfig/" +--- + +## 组件格式 + +要设置 Azure 应用配置,需创建一个类型为 `configuration.azure.appconfig` 的组件。 + +```yaml +apiVersion: dapr.io/v1alpha1 +kind: Component +metadata: + name: +spec: + type: configuration.azure.appconfig + version: v1 + metadata: + - name: host # 使用 Azure 身份验证时应使用此项。 + value: + - name: connectionString # 使用 Azure 身份验证时不应使用此项。 + value: + - name: maxRetries + value: # 可选 + - name: retryDelay + value: # 可选 + - name: maxRetryDelay + value: # 可选 + - name: azureEnvironment # 可选,默认为 AZUREPUBLICCLOUD + value: "AZUREPUBLICCLOUD" + # 请参阅下方的身份验证部分以了解所有选项 + - name: azureTenantId # 可选 + value: "[your_service_principal_tenant_id]" + - name: azureClientId # 可选 + value: "[your_service_principal_app_id]" + - name: azureCertificateFile # 可选 + value : "[pfx_certificate_file_fully_qualified_local_path]" + - name: subscribePollInterval # 可选 + value: #可选 [格式示例 - 24h] + +``` + +{{% alert title="警告" color="warning" %}} +上述示例中,secret 以明文字符串形式使用。建议使用 secret 存储来存储 secret,详见[此处]({{< ref component-secrets.md >}})。 +{{% /alert %}} + +## 规格元数据字段 + +| 字段 | 必需 | 详情 | 示例 | +|----------------------------|:--------:|---------|---------| +| connectionString | Y* | Azure 应用配置实例的连接字符串。无默认值。可以使用 `secretKeyRef` 引用 secret。*与 host 字段互斥。*在使用 [Azure 身份验证](https://docs.dapr.io/developing-applications/integrations/azure/azure-authentication/authenticating-azure/) 时不使用 | `Endpoint=https://foo.azconfig.io;Id=osOX-l9-s0:sig;Secret=00000000000000000000000000000000000000000000` +| host | N* | Azure 应用配置实例的端点。无默认值。*与 connectionString 字段互斥。*在使用 [Azure 身份验证](https://docs.dapr.io/developing-applications/integrations/azure/azure-authentication/authenticating-azure/) 时使用 | `https://dapr.azconfig.io` +| maxRetries | N | 最大重试次数,默认为 `3` | `5`, `10` +| retryDelay | N | 初始重试延迟时间,默认为 `4` 秒;`"-1"` 禁用重试延迟。延迟会随着每次重试呈指数增长,直到达到 maxRetryDelay 指定的最大值。 | `4s` +| maxRetryDelay | N | 允许的最大重试延迟时间,通常大于或等于 retryDelay。默认为 `120` 秒;`"-1"` 禁用限制 | `120s` +| subscribePollInterval | N | 轮询订阅键以检测更改的间隔时间(以纳秒为单位)。未来将更新为 Go 时间格式。默认间隔为 `24` 小时。 | `24h` + +**注意**:必须指定 `host` 或 `connectionString`。 + +## 使用连接字符串进行身份验证 + +通过连接字符串访问应用配置实例,该字符串可在 Azure 门户中获取。由于连接字符串包含敏感信息,建议将其视为 secret 并[使用 secret 存储]({{< ref component-secrets.md >}})。 + +## 使用 Microsoft Entra ID 进行身份验证 + +Azure 应用配置组件还支持使用 Microsoft Entra ID 进行身份验证。在启用此组件之前: +- 阅读[Azure 身份验证]({{< ref authenticating-azure.md >}})文档。 +- 创建一个 Microsoft Entra ID 应用程序(也称为服务主体)。 +- 或者,为您的应用程序平台创建托管身份。 + +## 设置 Azure 应用配置 + +您需要一个 Azure 订阅来设置 Azure 应用配置。 + +1. [启动 Azure 应用配置创建流程](https://ms.portal.azure.com/#create/Microsoft.Azconfig)。如有必要,请登录。 +1. 点击 **创建** 以启动 Azure 应用配置实例的部署。 +1. 创建实例后,获取 **端点** 或 **连接字符串**: + - 对于端点:导航到资源的 **概览** 并复制 **端点**。 + - 对于连接字符串:导航到 **设置** > **访问密钥** 并复制连接字符串。 +1. 将端点或连接字符串添加到 Dapr 的 `azappconfig.yaml` 文件中。 + + 将 `host` 键设置为 `[Endpoint]` 或将 `connectionString` 键设置为您之前保存的值。 + + {{% alert title="注意" color="primary" %}} + 在生产环境中,请遵循[秘密管理]({{< ref component-secrets.md >}})说明以安全管理您的 secret。 + {{% /alert %}} + +## Azure 应用配置请求元数据 + +在 Azure 应用配置中,您可以为同一键定义不同标签的值。例如,您可以为开发和生产环境定义不同的值。您可以指定在连接到应用配置时要加载的标签。 + +Azure 应用配置组件支持以下可选的 `label` 元数据属性: + +`label`:要检索的配置的标签。如果不存在,配置存储将返回指定键和空标签的配置。 + +标签可以通过请求 URL 中的查询参数指定: + +```bash +GET curl http://localhost:/v1.0/configuration/?key=&metadata.label=