工作流(Workflow)是一个通过自动化来实现特定结果的、已定义的步骤序列。它是一个可复用、可版本化的 “配方”,用于将输入转化为行动。
更多阅读:Elasticsearch:使用 Elastic Workflows 构建自动化 - 9.3
为什么要使用工作流
仅仅洞察数据还不够。真正的价值在于行动和结果。工作流完成了从数据到洞察再到自动化结果的完整路径。你的关键运维数据已经存在于 Elastic 集群中:安全事件、基础设施指标、应用日志以及业务上下文。工作流让你可以在数据所在的位置直接实现端到端流程自动化,而无需依赖外部自动化工具。
工作流解决了常见的运维挑战,例如:
- 告警疲劳:通过自动化响应来减少人工分流和排查。
- 人手不足:让团队用更少的资源完成更多工作。
- 手动、重复性工作:一致地自动化日常任务。
- 工具碎片化:无需再引入外部自动化工具。
工作流可以处理各种任务,从简单、可重复的步骤,到复杂的流程。
谁应该使用工作流
如果你希望减少人工工作量、加快响应时间,并确保重复出现的情况得到一致处理,那么工作流适合你。
关键概念
在使用工作流时需要理解的一些关键概念:
- 触发器/triggers:启动工作流的事件或条件。参考 Triggers 了解更多。
- 步骤/Steps:构成工作流的单个逻辑或操作单元。参考 Steps 了解更多。
- 数据/Data:数据在工作流中的流转方式,包括输入、常量、上下文变量、步骤输出,以及用于动态值的 Liquid 模板。参考 Data 和错误处理了解更多。
工作流结构
工作流使用 YAML 定义。在 YAML 编辑器中描述工作流应该执行的内容,平台会负责执行。
`
1. # ═══════════════════════════════════════════════════════════════
2. # METADATA - Identifies and describes the workflow
3. # ═══════════════════════════════════════════════════════════════
4. name: My Workflow # 1
5. description: What this workflow does # 2
6. enabled: true # 3
7. tags: ["demo", "production"] # 4
9. # ═══════════════════════════════════════════════════════════════
10. # CONSTANTS - Reusable values defined once, used throughout
11. # ═══════════════════════════════════════════════════════════════
12. consts:
13. indexName: "my-index"
14. environment: "production"
15. alertThreshold: 100
16. endpoints: # Can be objects/arrays
17. api: "https://api.example.com"
18. backup: "https://backup.example.com"
20. # ═══════════════════════════════════════════════════════════════
21. # INPUTS - Parameters passed when the workflow is triggered
22. # ═══════════════════════════════════════════════════════════════
23. inputs:
24. - name: environment
25. type: string
26. required: true
27. default: "staging"
28. description: "Target environment"
29. - name: dryRun
30. type: boolean
31. default: true
33. # ═══════════════════════════════════════════════════════════════
34. # TRIGGERS - How/when the workflow starts
35. # ═══════════════════════════════════════════════════════════════
36. triggers:
37. - type: manual # 5
38. # - type: scheduled # 6
39. # with:
40. every: 1d
41. # - type: alert # 7
43. # ═══════════════════════════════════════════════════════════════
44. # STEPS - The actual workflow logic (executed in order)
45. # ═══════════════════════════════════════════════════════════════
46. steps:
47. - name: step_one
48. type: elasticsearch.search
49. with:
50. index: "{{consts.indexName}}"
51. query:
52. match_all: {}
54. - name: step_two
55. type: console
56. with:
57. message: |
58. Environment: {{inputs.environment}} # 9
59. Found: {{steps.step_one.output.hits.total.value}} # 10
`AI写代码收起代码块
- 必填:唯一标识符
- 可选:在 UI 中显示
- 可选:启用或禁用执行
- 可选:用于组织工作流
- 用户点击 Run 按钮
- 按计划运行
- 由告警触发
- 引用常量
- 引用输入
- 引用步骤输出
运行你的第一个 workflow
在本教程中,你将创建一个工作流,用于对国家公园数据进行索引和搜索。在这个过程中,你将学习工作流的核心概念和能力。
前提条件
要使用 工作流,请开启 Elastic Workflows(workflows:ui:enabled)高级设置。
上面的显示是 Elastic Serverless 上的。正对自托管的 Elastic Stack 安装,界面虽然有所不同,但应该是是同一个开关。你可以安装最新的 Elastic Stack 9.3:
你必须具备相应的订阅。请参考 www.elastic.co/cn/subscrip… 的订阅页面,了解可用功能及其对应的订阅级别。
对工作流的访问由 Kibana 权限控制。请确保你的角色在 Analytics > Workflows 下拥有 All 权限,这样你就可以创建、编辑、运行和管理工作流。
教程
要访问 Workflows 页面,请在导航菜单中找到 Workflows:
定义你的工作流
删除占位内容,并将以下 YAML 复制并粘贴到编辑器中:
`
1. name: 🏔️ National Parks Demo1
2. description: Creates an Elasticsearch index, loads sample national park data using bulk operations, searches for parks by category, and displays the results.
3. enabled: true
4. tags: ["demo", "getting-started"]
5. consts:
6. indexName: national-parks
7. triggers:
8. - type: manual
9. steps:
10. - name: get_index
11. type: elasticsearch.indices.exists
12. with:
13. index: "{{ consts.indexName }}"
14. - name: check_if_index_exists
15. type: if
16. condition: 'steps.get_index.output : true'
17. steps:
18. - name: index_already_exists
19. type: console
20. with:
21. message: "index: {{ consts.indexName }} already exists. Will proceed to delete it and re-create"
22. - name: delete_index
23. type: elasticsearch.indices.delete
24. with:
25. index: "{{ consts.indexName }}"
26. else:
27. - name: no_index_found
28. type: console
29. with:
30. message: "index: {{ consts.indexName }} Not found. Will proceed to create"
32. - name: create_parks_index
33. type: elasticsearch.indices.create
34. with:
35. index: "{{ consts.indexName }}"
36. mappings:
37. properties:
38. name: { type: text }
39. category: { type: keyword }
40. description: { type: text }
41. - name: bulk_index_park_data
42. type: elasticsearch.request
43. with:
44. method: POST
45. path: /{{ consts.indexName }}/_bulk?refresh=wait_for
46. headers:
47. Content-Type: application/x-ndjson
48. body: |
49. {"index":{}}
50. {"name": "Yellowstone National Park", "category": "geothermal", "description": "America's first national park, established in 1872, famous for Old Faithful geyser and diverse wildlife including grizzly bears, wolves, and herds of bison and elk."}
51. {"index":{}}
52. {"name": "Grand Canyon National Park", "category": "canyon", "description": "Home to the immense Grand Canyon, a mile deep gorge carved by the Colorado River, revealing millions of years of geological history in its colorful rock layers."}
53. {"index":{}}
54. {"name": "Yosemite National Park", "category": "mountain", "description": "Known for its granite cliffs, waterfalls, clear streams, giant sequoia groves, and biological diversity. El Capitan and Half Dome are iconic rock formations."}
55. {"index":{}}
56. {"name": "Zion National Park", "category": "canyon", "description": "Utah's first national park featuring cream, pink, and red sandstone cliffs soaring into a blue sky. Famous for the Narrows wade through the Virgin River."}
57. {"index":{}}
58. {"name": "Rocky Mountain National Park", "category": "mountain", "description": "Features mountain environments, from wooded forests to mountain tundra, with over 150 riparian lakes and diverse wildlife at various elevations."}
59. - name: search_park_data
60. type: elasticsearch.search
61. with:
62. index: "{{ consts.indexName }}"
63. size: 5
64. query:
65. term:
66. category: canyon
67. - name: log_results
68. type: console
69. with:
70. message: |-
71. Found {{ steps.search_park_data.output.hits.total.value }} parks in category "canyon".
72. - name: loop_over_results
73. type: foreach
74. foreach: "{{steps.search_park_data.output.hits.hits | json}}"
75. steps:
76. - name: process-item
77. type: console
78. with:
79. message: "{{foreach.item._source.name}}"
`AI写代码收起代码块
点击 Save 按钮:
保存完毕后,我们可以看到 Workflow 的名称已经被修改。
运行工作流
监控执行
当你的工作流运行时,执行日志会显示在工作流旁边的一个面板 中。在该 面板中,你可以看到:
- 实时执行日志:每个步骤在执行时都会显示。
- 工作流状态指示器:绿色表示成功,红色表示失败,并显示持续时间的时间戳。
- 可展开的步骤详情:点击任意步骤可查看 输入、输出和时间线。
查看执行历史
要检查过去的执行记录:
- 点击 Executions 选项卡。
- 查看所有工作流运行的列表(包括 pending 和 in progress 的运行),以及它们的状态和完成时间。
- 点击任意一次执行以查看其详细日志。
理解发生了什么
让我们检查工作流的每个部分,以理解它是如何工作的。
1)工作流元数据
`
1. name: 🏔️ National Parks Demo
2. description: Creates an Elasticsearch index, loads sample national park data using bulk operations, searches for parks by category, and displays the results.
3. enabled: true
4. tags: ["demo", "getting-started"]
`AI写代码
- name:你的工作流的唯一标识符。
- description:解释工作流的用途。
- enabled:控制工作流是否可以运行。
- tags:用于组织和查找工作流的标签。
2)Constants
`
1. consts:
2. indexName: national-parks-data
`AI写代码
- consts:定义可在整个工作流中引用的可复用值。
- 使用 template syntax 访问:{{ consts.indexName }}。这有助于保持一致性,并使工作流更易于维护。
3)Triggers
`
1. triggers:
2. - type: manual
`AI写代码
- triggers:定义工作流如何启动。
- type:指定触发器类型。 Manual 触发器需要用户显式操作(点击 Run icon )来启动工作流。
4)创建索引
`
1. - name: create_parks_index
2. type: elasticsearch.indices.create
3. with:
4. index: "{{ consts.indexName }}"
5. settings:
6. number_of_shards: 1
7. number_of_replicas: 0
8. mappings:
9. properties:
10. name: { type: text }
11. category: { type: keyword }
12. description: { type: text }
`AI写代码
- Step type:这是一个直接与 Elasticsearch 交互的 action 步骤。
- Step purpose:建立公园信息的数据结构,确保字段被正确类型化,便于搜索和聚合。
- Key elements:
- 使用 elasticsearch.indices.create,这是一个内置 action,对应 Elasticsearch Create Index API。
- 定义 mappings 来控制数据如何被索引(text 用于全文搜索,keyword 用于精确匹配)。
- 引用常量 indexName 以保持一致性。
- 为此 demo 设置索引 settings 以获得最佳性能。
5)批量索引文档
`1. - name: bulk_index_park_data
2. type: elasticsearch.request
3. with:
4. method: POST
5. path: /{{ consts.indexName }}/_bulk?refresh=wait_for
6. headers:
7. Content-Type: application/x-ndjson
8. body: |
9. {"index":{}}
10. {"name": "Yellowstone National Park", "category": "geothermal", "description": "America's first national park, established in 1872, famous for Old Faithful geyser and diverse wildlife including grizzly bears, wolves, and herds of bison and elk."}
11. # ... additional parks`AI写代码
- Step type: 使用 Elasticsearch 的 bulk API 的另一个内部 action step
- Steup purpose: 高效地在单次操作中加载多个 documents,向 index 填充示例数据
- 关键元素:
- operations 数组包含要索引的 documents
- 每个 document 都会成为 Elasticsearch 中可搜索的记录
- 使用 mappings 中定义的字段名 (name, category, description)
- 每个 document 都会成为具有一致字段结构的可搜索记录
- 此步骤演示了如何在 workflows 中处理批量操作
6)搜索 Parks
`
1. - name: search_park_data
2. type: elasticsearch.search
3. with:
4. index: "{{ consts.indexName }}"
5. size: 5
6. query:
7. term:
8. category: "canyon"
`AI写代码
- Step type: 用于查询 Elasticsearch 的内部 action step
- Step purpose: 根据条件检索特定数据,演示 workflows 如何基于数据做出决策
- 关键元素:
- 搜索 category 为 "canyon" 的 parks(会找到 Grand Canyon 和 Zion)
- steps.search_park_data.output 的结果会自动提供给后续 steps 使用
- 将结果限制为 5 个 documents 以保持输出可管理
- 演示 workflows 如何动态筛选和处理数据
7)记录结果
`
1. - name: log_results
2. type: console
3. with:
4. message: |-
5. Found {{ steps.search_park_data.output.hits.total.value }} parks in category "canyon".
6. Top results: {{ steps.search_park_data.output.hits.hits | json(2) }}
`AI写代码
- Step type: 用于输出和调试的 console step
- Step purpose: 以人类可读的格式展示结果,演示如何访问和格式化前一步的数据
- 关键元素:
- 模板变量访问搜索结果: {{ steps.search_park_data.output }}
- | json(2) filter 用于带缩进格式化 JSON 输出
- 使用精确的 step 名称 search_park_data 来引用前一步输出
- 演示数据如何在 workflow 中流动并可以被转换
演示的关键概念
此 workflow 介绍了几个基本概念:
- Action steps: 与 Elasticsearch 和 Kibana APIs 交互的内置 steps
- Data flow: 信息如何通过 outputs 和模板变量从一步流向下一步
- Constants: 可重用的值,使 workflows 更易维护
- Template syntax: {{ }} 表示动态值的语法
- Step chaining: 每个 step 如何基于前一步构建以完成整个流程