Kestra 2.0.6 快速入门与 Flow 编排示例

Kestra 2.0.6 快速入门:Flow YAML 结构、API 导入与版本演进、执行状态轮询、If 分支与 Parallel 并行编排示例、flow dot 依赖图与常见 422 报错排障的完整实测记录。

KestraKestraLinux工作流编排Java2026/10/17

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 列表,是最小部署单元
NamespaceFlow 的命名空间(如 tutorial、prod),用于隔离与权限分组
TaskFlow 中的单个任务,用插件类的全限定名(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。

十一、参考链接