Kestra 2.0.6 快速入门与 Flow 编排示例
Kestra 2.0.6 快速入门:Flow YAML 结构、API 导入与版本演进、执行状态轮询、If 分支与 Parallel 并行编排示例、flow dot 依赖图与常见 422 报错排障的完整实测记录。
Kestra 2.0.6 快速入门与 Flow 编排示例
目标:通过 API 完成 Flow 创建、触发执行、版本演进与分支并行编排的快速入门。已在 Ubuntu 22.04 实测通过。
本文档所有命令与回显均来自 Ubuntu 22.04 实机实测(Kestra 2.0.6 单二进制安装 + systemd 托管实例,2026-10-17),可逐条复现。安装与认证配置见《Kestra 2.0.6 Ubuntu 22.04 安装指南》。
一、环境信息
- 操作系统:Ubuntu 22.04
- Kestra 版本:2.0.6(单二进制安装 + systemd 托管实例)
- 端口:8080(Web/API,
http://localhost:8080) - 认证:已配置 Basic 认证(
admin@example.com/q1w2E3r4) - 数据目录:插件自动下载到
/opt/kestra/data/plugins - 部署形态:单机单二进制实例(安装与 systemd 托管见《Kestra 2.0.6 Ubuntu 22.04 安装指南》)
二、核心概念
| 概念 | 说明 |
|---|---|
| Flow | 一个 YAML 定义的工作流,含 id、namespace 与 tasks 列表,是最小部署单元 |
| Namespace | Flow 的命名空间(如 tutorial、prod),用于隔离与权限分组 |
| Task | Flow 中的单个任务,用插件类的全限定名(type)标识 |
| Trigger | 触发器(如定时 Schedule、文件监听),附加在 Flow 上按条件自动触发执行 |
| Execution | 一次 Flow 运行实例,含全局唯一执行 ID 与逐任务状态 |
💡 技术拓展:Kestra 的任务类型(
type)由插件提供——io.kestra.plugin.core.*为内置核心任务(Log、Return、If、Parallel、http.Request 等),随主程序发布;io.kestra.plugin.scripts.shell.*等脚本类任务在首次使用时自动下载到插件目录(/opt/kestra/data/plugins),实测首次执行会先下载插件再运行。存储后端(H2/PostgreSQL/MySQL)与队列实现的选择见《Kestra 2.0.6 配置参数详解》。
三、准备:确认服务与认证
按安装指南部署的实例监听 8080,已配置 Basic 认证(admin@example.com / q1w2E3r4)。验证服务可用:
curl -s -o /dev/null -w "ping=%{http_code}\n" http://localhost:8080/ping
curl -s -o /dev/null -w "configs_auth=%{http_code}\n" -u admin@example.com:q1w2E3r4 http://localhost:8080/api/v1/configs
回显:
ping=200
configs_auth=200
后续所有 curl 命令都通过 -u admin@example.com:q1w2E3r4 携带凭证(文中简写为 $AUTH)。
⚠️ 排障实录:不带凭证访问业务 API 返回 401 与
{"message":"Unauthorized","_embedded":{"errors":[{"message":"Unauthorized"}]}},属预期的认证拦截,不是服务故障。
四、第一个 Flow:创建
4.1 Flow YAML 结构
创建 /tmp/hello-world.yaml:
cat > /tmp/hello-world.yaml <<'EOF'
id: hello_world
namespace: tutorial
description: 第一个示例 Flow:日志 + 返回值 + Shell
tasks:
- id: hello
type: io.kestra.plugin.core.log.Log
message: "Hello Kestra 2.0.6"
- id: shell_date
type: io.kestra.plugin.scripts.shell.Commands
taskRunner:
type: io.kestra.plugin.core.runner.Process
commands:
- echo "hello from $(hostname) at $(date +%F_%T)"
EOF
字段说明:
id+namespace唯一标识一个 Flow;tasks列表内任务顺序执行(依赖关系即定义顺序);Log任务写日志,message支持 Pebble 模板(双花括号表达式);Commands任务跑 Shell 命令,taskRunner.type: io.kestra.plugin.core.runner.Process表示直接在本机进程内执行(默认的 task runner 需要拉起执行环境,单机 Process 模式最轻量)。
4.2 通过 API 导入
curl -s -u admin@example.com:q1w2E3r4 -X POST \
-H "Content-Type: application/x-yaml" \
--data-binary @/tmp/hello-world.yaml \
http://localhost:8080/api/v1/flows
回显(单行 JSON,已折行展示):
{"id":"hello_world","namespace":"tutorial","revision":1,"description":"第一个示例 Flow:日志 + 返回值 + Shell","disabled":false,"deleted":false,"draft":false,"tasks":[{"id":"hello","type":"io.kestra.plugin.core.log.Log","message":"Hello Kestra 2.0.6"},...
返回体中 revision: 1 表示这是该 Flow 的第 1 个版本。
⚠️ 排障实录:
--data-binary @文件路径的路径不存在时,curl 不发送任何请求体,服务端返回 422:{"type":"https://kestra.io/docs/api-reference/problems/invalid-request-body","title":"Invalid request body","status":422,"detail":"Required Body [flow] not specified","instance":"/api/v1/flows"}看到
Required Body [flow] not specified先检查文件路径与当前目录。
五、触发执行与状态轮询
5.1 触发
curl -s -u admin@example.com:q1w2E3r4 -X POST \
http://localhost:8080/api/v1/executions/tutorial/deps_demo
回显(节选):
{"id":"H39Je5BBKUaA16jEMNHoM","namespace":"tutorial",...
URL 规则:POST /api/v1/executions/{namespace}/{flow_id}。hello_world 触发方式相同,返回体同构(执行 ID 如 28YgS7P3N8jiwMvuC0EYAR)。
5.2 查询执行状态
curl -s -u admin@example.com:q1w2E3r4 \
http://localhost:8080/api/v1/executions/28YgS7P3N8jiwMvuC0EYAR
回显(节选):
{"tenantId":"main","id":"28YgS7P3N8jiwMvuC0EYAR","namespace":"tutorial","flowId":"hello_world","flowRevision":2,"taskRunList":[{"id":"G862ZOnahWYX4KOrcOPTP","taskId":"hello","attempts":[{"state":{"current":"SUCCESS","histories":[{"state":"CREATED","date":"2026-10-17T01:30:12.669732Z"},{"state":"RUNN...
单任务的状态机为 CREATED → RUNNING → SUCCESS(或 FAILED)。实测一次完整执行的 prepare 任务(deps_demo,见第七章)状态记录:
"taskId":"prepare","attempts":[{"state":{"current":"SUCCESS","histories":[{"state":"CREATED","date":"2026-10-17T01:28:59.370695Z"},{"state":"RUNNING","date":"2026-10-17T01:28:59.370697Z"},{"state":"SUCCESS","date":"2026-10-17T01:28:59.412991Z"}],"duration":"PT0.042296S","startDate":"2026-10-17T01:28:59.370695Z","endDate":"2026-10-17T01:28:59.4129...
💡 技术拓展:执行 API 的默认响应不含任务的
outputs字段;任务输出值(如 Return 任务的返回内容、命令的标准输出)在 Web UI 执行详情的 Outputs 标签页查看。Return任务的format支持{{ execution.id }}等 Pebble 表达式,实测渲染正常。
六、Flow 版本演进(PUT 更新)
修改 YAML(加入 Return 任务)后用 PUT 更新:
cat > /tmp/hello-v2.yaml <<'EOF'
id: hello_world
namespace: tutorial
description: 第一个示例 Flow:日志 + 返回值 + Shell
tasks:
- id: hello
type: io.kestra.plugin.core.log.Log
message: "Hello Kestra 2.0.6"
- id: say_hi
type: io.kestra.plugin.core.debug.Return
format: "来自 {{ execution.id }} 的问候"
- id: shell_date
type: io.kestra.plugin.scripts.shell.Commands
taskRunner:
type: io.kestra.plugin.core.runner.Process
commands:
- echo "hello from $(hostname) at $(date +%F_%T)"
EOF
curl -s -u admin@example.com:q1w2E3r4 -X PUT \
-H "Content-Type: application/x-yaml" \
--data-binary @/tmp/hello-v2.yaml \
http://localhost:8080/api/v1/flows/tutorial/hello_world
回显(节选):
"revision":2
Kestra 对同一 id + namespace 的更新自动递增 revision,历史版本保留可回溯。列出命名空间下全部 Flow 验证:
curl -s -u admin@example.com:q1w2E3r4 http://localhost:8080/api/v1/flows/tutorial
回显(节选,三个 Flow 的版本信息):
"id":"deps_demo","namespace":"tutorial","revision":1
"id":"hello_world","namespace":"tutorial","revision":2
"id":"http_demo","namespace":"tutorial","revision":1
七、分支与并行编排示例
7.1 Flow 定义
创建 /tmp/deps-demo.yaml,演示 If 条件分支、Parallel 并行与任务依赖顺序:
cat > /tmp/deps-demo.yaml <<'EOF'
id: deps_demo
namespace: tutorial
tasks:
- id: prepare
type: io.kestra.plugin.scripts.shell.Commands
taskRunner:
type: io.kestra.plugin.core.runner.Process
commands:
- echo "准备阶段:生成随机数"
- echo "::{\"outputs\":{\"n\":\"7\"}}::"
- id: branch
type: io.kestra.plugin.core.flow.If
condition: "{{ outputs.prepare.vars.n == \"7\" }}"
then:
- id: match
type: io.kestra.plugin.scripts.shell.Commands
taskRunner:
type: io.kestra.plugin.core.runner.Process
commands:
- echo "n 等于 7,走 then 分支"
else:
- id: not_match
type: io.kestra.plugin.scripts.shell.Commands
taskRunner:
type: io.kestra.plugin.core.runner.Process
commands:
- echo "n 不等于 7,走 else 分支"
- id: fanout
type: io.kestra.plugin.core.flow.Parallel
tasks:
- id: p1
type: io.kestra.plugin.scripts.shell.Commands
taskRunner:
type: io.kestra.plugin.core.runner.Process
commands:
- echo "并行任务 p1"
- id: p2
type: io.kestra.plugin.scripts.shell.Commands
taskRunner:
type: io.kestra.plugin.core.runner.Process
commands:
- sleep 1
- echo "并行任务 p2"
- id: report
type: io.kestra.plugin.scripts.shell.Commands
taskRunner:
type: io.kestra.plugin.core.runner.Process
commands:
- echo "全部依赖完成,输出汇总"
EOF
要点:
prepare用::{"outputs":{"n":"7"}}::协议向下游输出变量outputs.prepare.vars.n;If任务按condition选择then或else子分支执行;Parallel子任务并行跑,全部完成后 Flow 才进入下一个任务report。
7.2 导入、触发与结果验证
curl -s -u admin@example.com:q1w2E3r4 -X POST \
-H "Content-Type: application/x-yaml" \
--data-binary @/tmp/deps-demo.yaml \
http://localhost:8080/api/v1/flows
回显(节选):
"id":"deps_demo"
"revision":1
curl -s -u admin@example.com:q1w2E3r4 -X POST \
http://localhost:8080/api/v1/executions/tutorial/deps_demo
回显(节选):
{"id":"H39Je5BBKUaA16jEMNHoM","namespace":"tutorial",...
等待约 25 秒(含插件首次下载)后查询 http://localhost:8080/api/v1/executions/H39Je5BBKUaA16jEMNHoM,实测结果:
- 整体状态
SUCCESS; taskRunList中出现了 7 个任务(prepare、branch、match、fanout、p1、p2、report)——没有not_match:If的条件成立,else分支未产生任何任务运行,分支语义实测符合预期;p1/p2在Parallel内并行执行,report在两者全部结束后才开始。
八、依赖图可视化(flow dot)
kestra flow dot 可把 Flow 定义输出为 Graphviz DOT 格式(直接保存为 .dot 文件后可用 dot -Tsvg 转 SVG):
/opt/kestra/kestra-2.0.6 flow dot /tmp/dot-demo.yaml > /tmp/dot.out 2>&1
head -30 /tmp/dot.out
回显(前置日志两行后为 DOT 内容,节选):
01:32:52.049 WARN main i.m.p.PrometheusMeterRegistry The meter (MeterId{name='netty.alloc.arena.allocation.count', ...}) registration has failed: ...
01:32:53.674 INFO dot i.kestra.core.plugins.PluginScanner Registered 81 core plugins (scan done in 240ms)
digraph G {
layout=dot;
"root.root-6YnHLdohA0MUpwxhNO519a"[shape=point];
"root.end-4go63TKhiLe8KeSESYMWIN"[shape=point];
"root.prepare"[shape=box];
subgraph "cluster_cluster_root.branch"{
label = "cluster_root.branch";
"root.branch.root-KdVrEhI5sL7qryDwRsU35"[shape=point];
"root.branch.end-5sCNuqpIPV33G5s0cwzchM"[shape=point];
"root.branch"[shape=box];
"root.branch.match"[shape=box];
"root.branch.not_match"[shape=box];
"root.branch.root-KdVrEhI5sL7qryDwRsU35" -> "root.branch" ;
"root.branch" -> "root.branch.match" ;
"root.branch" -> "root.branch.not_match" ;
"root.branch.not_match" -> "root.branch.end-5sCNuqpIPV33G5s0cwzchM" ;
"root.branch.match" -> "root.branch.end-5sCNuqpIPV33G5s0cwzchM" ;
}
结尾的连线(节选)体现了并行与顺序依赖:
"root.fanout.p1" -> "root.fanout.end-3gWjArBdeaML9GjQUkIwZo" ;
"root.fanout.p2" -> "root.fanout.end-3gWjArBdeaML9GjQUkIwZo" ;
"root.fanout" -> "root.fanout.p2" ;
"root.fanout" -> "root.fanout.p1" ;
"root.fanout.root-vbHLwfYazaemR1GBhGj40" -> "root.fanout" ;
}
"root.branch.end-5sCNuqpIPV33G5s0cwzchM" -> "root.fanout.root-vbHLwfYazaemR1GBhGj40" ;
"root.root-6YnHLdohA0MUpwxhNO519a" -> "root.prepare" ;
"root.report" -> "root.end-4go63TKhiLe8KeSESYMWIN" ;
"root.fanout.end-3gWjArBdeaML9GjQUkIwZo" -> "root.report" ;
If 的 then/else 双子任务都出现在图中(运行时只会走其一),Parallel 的 p1/p2 汇聚到同一个结束点。
⚠️ 排障实录:
flow dot只加载 jar 内置的 81 个核心插件。Flow 里若引用了外部插件任务(如io.kestra.plugin.scripts.shell.Commands),CLI 会报Invalid type类错误;实测加-p /opt/kestra/data/plugins指定插件目录也无效。需要看这类 Flow 的依赖图时,直接用 Web UI 的 Topology 视图。
九、HTTP 任务示例(含 422 排障实录)
9.1 第一次尝试:字段名写错
让 Flow 调用本机 Kestra API(带认证的 HTTP GET)。先故意使用想当然的字段名 basicAuthUser/basicAuthPassword:
cat > /tmp/http-broken.yaml <<'EOF'
id: http_demo
namespace: tutorial
description: 调用本机 Kestra API 的 HTTP 任务示例
tasks:
- id: fetch
type: io.kestra.plugin.core.http.Request
uri: http://localhost:8080/api/v1/configs
method: GET
options:
basicAuthUser: admin@example.com
basicAuthPassword: q1w2E3r4
EOF
curl -s -u admin@example.com:q1w2E3r4 -X POST \
-H "Content-Type: application/x-yaml" \
--data-binary @/tmp/http-broken.yaml \
http://localhost:8080/api/v1/flows
实测回显(422,报错明确列出了全部合法字段):
{"type":"https://kestra.io/docs/api-reference/problems/validation-failed","title":"Validation failed","status":422,"detail":"Unrecognized field \"basicAuthUser\" (class io.kestra.core.http.client.configurations.HttpConfiguration$HttpConfigurationBuilder), not marked as ignorable (14 known properties: \"timeout\", \"retryOnStatusCodesByMethod\", \"allowFailed\", \"auth\", \"defaultCharset\", \"ssl\", \"retryOnStatusCodes\", \"proxy\", \"logs\", \"allowedResponseCodes\", \"followRedirects\", \"retry\", \"enabledTcpExtendedKeepAlive\", \"retryableTransportFailureMethods\")","instance":"/api/v1/flows","errors":[{"detail":"Unrecognized field \"basicAuthUser\" ...","pointer":"/io/kestra/core/models/flows/FlowWithSource/\"tasks\"/->java/util/ArrayList/0/->io/kestra/plugin/core/http/Request/\"options\"/->io/kestra/core/http/client/configurations/HttpConfiguration$HttpConfigurationBuilder/\"basicAuthUser\"","path":"io.kestra.core.models.flows.FlowWithSource[\"tasks\"]->java.util.ArrayList[0]->io.kestra.plugin.core.http.Request[\"options\"]->io.kestra.core.http.client.configurations.HttpConfiguration$HttpConfigurationBuilder[\"basicAuthUser\"]"}]}
9.2 修正:auth 使用对象结构
按报错提示改用 options.auth(type: BASIC + 用户名/密码):
cat > /tmp/http-demo.yaml <<'EOF'
id: http_demo
namespace: tutorial
description: 调用本机 Kestra API 的 HTTP 任务示例
tasks:
- id: fetch
type: io.kestra.plugin.core.http.Request
uri: http://localhost:8080/api/v1/configs
method: GET
options:
auth:
type: BASIC
username: admin@example.com
password: q1w2E3r4
EOF
curl -s -u admin@example.com:q1w2E3r4 -X POST \
-H "Content-Type: application/x-yaml" \
--data-binary @/tmp/http-demo.yaml \
http://localhost:8080/api/v1/flows
回显(节选):
"id":"http_demo"
"revision":1
触发执行(执行 ID 实测 4SER9Md1WBGyXwBjYY2iWo),查询后整体状态:
"current":"SUCCESS"
十、常见问题(FAQ)
10.1 提交 Flow 报 422 Required Body [flow] not specified
--data-binary @路径 的文件不存在或为空,curl 静默发送了空请求体。先 ls -la 确认文件存在再重试。
10.2 提交 Flow 报 422 Validation failed
字段名或结构不符合插件定义(如 9.1 的 basicAuthUser)。422 报错的 detail 会列出全部合法字段名与报错字段的 JSON pointer,照着改即可。
10.3 执行一直停在 RUNNING
单机 Process 模式下脚本任务首次运行要先下载插件(/opt/kestra/data/plugins),实测首次执行 deps_demo 花费约 25 秒,之后同插件任务秒级完成。网络不畅时插件下载慢是 RUNNING 停留的最常见原因,可 journalctl -u kestra -f 观察下载日志。
10.4 脚本任务的 outputFiles 未产生文件
实测在 taskRunner: io.kestra.plugin.core.runner.Process 模式下,outputFiles 声明后执行成功但内部存储目录未生成对应产物(两次实测一致)。Process runner 对 outputFiles 的处理与隔离型 task runner 不同,产物可直接在命令中 cat/落盘到本地路径使用;确需 Internal Storage 产物时换用隔离 runner 或改写文件到指定目录。
10.5 API 401
见第三章:所有业务 API 都需要 Basic 认证(已配置时),或先在 Web UI 登录后使用会话。密码需满足"至少 8 位 + 大写字母 + 数字",弱密码配置后认证也会 401。