dagucloud/dagu · 上手攻略
- 仓库:dagucloud/dagu
- 链接:https://github.com/dagucloud/dagu
- 分类:database / app(自托管工作流编排引擎)
- 作者:spark
- 更新:2026-10-22
一句话结论
如果你有一堆能跑的脚本和 cron 任务,想要依赖关系、重试、历史和 Web UI,但不想为此运维 Airflow 那六个服务——Dagu 是当下最直接的答案;团队要 SSO/RBAC/审计时先确认授权边界,见坑 6。
它是什么
Dagu 是一个 local-first 的工作流引擎,用 Go 写成,卖点是「单个二进制 + 内置 Web UI + 不需要外部数据库或消息队列」,跑在 Linux、macOS、Windows 上。工作流用声明式 YAML 定义 DAG,原生支持 shell 命令、Docker 容器、Kubernetes Job、SSH 远程命令,还可以通过 Dagu Actions 扩展到 SQL、HTTP 等任意工具。
它的设计哲学写在 README 里很直白:编排不是你的主要工作。传统编排器要你运维 Web Server、Scheduler、Worker、PostgreSQL、Redis/RabbitMQ、Python Runtime 六个组件,并且你的任务会被重写成 @dag/@task 框架代码;Temporal 则把业务逻辑塞进它的 SDK。Dagu 的立场是「工作流结构是配置,不是代码」——顺序、依赖、重试、调度、人工任务都在脚本旁边的一个 YAML 文件里,而执行引擎是一个进程。
关键约束值得单独说:你的脚本永远不会 import 编排器。删掉 YAML,脚本照常运行;留着 YAML,每次运行都能得到依赖图、重试、逐步日志、历史和 Web UI。
⚠️ 版本状态:README 提到 Dagu Console 监控「free for one server on Dagu v2.19.2 or later」,openalternative 抓取显示 last commit 为 v2.19.0。许可 GPL-3.0(仓库内另有 LICENSING.md,涉及嵌入式 API 与商业嵌入说明——⚠️ 具体条款本文未展开,见坑 6)。约 4.4k stars。
解决什么问题
三个替代方案各自的代价,README 概括得相当准:
- cron 能跑命令,但没依赖、没重试、没历史。
- Airflow 能编排,但你要养一个平台,而且任务被改写成框架代码。
- Temporal 提供持久化执行,但业务逻辑要搬进它的 SDK 和编程模型。
而这些工具的真实结果是:「你本来只想给几个任务定时,结果现在要运维第二套系统,而且编排器住进了本该被它服务的代码里。」
快速安装
六种方式,按场景挑:
# macOS / Linux:引导式安装向导(可加 PATH、注册后台服务、建管理员账号)
curl -fsSL https://raw.githubusercontent.com/dagucloud/dagu/main/scripts/installer.sh | bash
# Homebrew / npm(无向导)
brew install dagu
npm install -g --ignore-scripts=false @dagucloud/dagu
# Docker
docker run --rm -v ~/.dagu:/var/lib/dagu -p 8080:8080 ghcr.io/dagucloud/dagu:latest dagu start-all
# Kubernetes(Helm,注意 StorageClass 必须支持 ReadWriteMany)
helm repo add dagu https://dagucloud.github.io/dagu
helm repo update
helm install dagu dagu/dagu --set persistence.storageClass=<your-rwx-storage-class>
Windows PowerShell:irm https://raw.githubusercontent.com/dagucloud/dagu/main/scripts/installer.ps1 | iex。
只跑脚本安装器(shell / PowerShell)才有引导向导;Homebrew、npm、Docker、Helm 没有。
核心用法
最小工作流——在空目录建 hello.yaml:
steps:
- id: hello
run: echo "hello from Dagu"
dagu start hello.yaml # 跑一次
dagu start-all --dags . # 起服务 + 调度器 + 执行器
# 打开 http://localhost:8080
依赖与并行:
steps:
- id: extract
run: ./extract.sh
- id: transform_a
run: ./transform_a.sh
depends: extract
- id: transform_b
run: ./transform_b.sh
depends: extract
- id: load
run: ./load.sh
depends: [transform_a, transform_b]
重试与容错:
steps:
- name: flaky-api-call
run: curl -f https://api.example.com/data
retry_policy:
limit: 3
interval_sec: 10
continue_on:
failure: true # 失败也继续往下走
调度(cron 语法 + 重叠策略 + 补偿窗口):
schedule:
- "0 */6 * * *" # 每 6 小时
overlap_policy: skip # 上一次还在跑就跳过
catchup_window: "5h" # 调度器宕机 5 小时内可补跑
timeout_sec: 3600
handler_on:
failure:
run: notify-team.sh
exit:
run: cleanup.sh
带类型参数的表单(params 会在 Web UI 渲染成类型化输入表单):
params:
- name: customer_id
type: string
description: Customer or account identifier
- name: change_scope
type: string
enum: [metadata_only, permissions, full_account]
default: metadata_only
- name: dry_run
type: boolean
default: true
steps:
- id: extract
run: >-
./scripts/extract.sh
--customer "${params.customer_id}"
--scope "${params.change_scope}"
--dry-run="${params.dry_run}"
SSH 步骤与 Sub-DAG 并行:
# 父 DAG:对多个目标并行调同一个子 DAG,限并发
steps:
- id: patch
action: dag.run
with:
dag: patch-host
params:
host: ${ITEM}
parallel:
items: [web-1.internal, web-2.internal, db-1.internal]
max_concurrent: 2
---
# 子 DAG
name: patch-host
params:
- name: host
type: string
ssh:
user: deploy
host: ${params.host}
steps:
- id: apply
run: apt-get update -q && apt-get upgrade -y
Docker 步骤(直接透传 docker run 选项):
resources:
limits:
cpu: 500m
memory: 512Mi
steps:
- id: report
action: docker.run
with:
image: ghcr.io/acme/reporting:1.4.2
pull: always
platform: linux/amd64
working_dir: /work
volumes: ["~/orders:/work/data"]
auto_remove: true
command: python generate_report.py --input /work/data/orders.csv
Build workflow(缓存复用)——命令和文件都没变就复用上一步结果,Dagu 还能从匹配的路径推断依赖:
type: build
working_dir: .
steps:
- id: uppercase
inputs:
- name: source
path: source.txt
outputs:
- name: result
path: uppercase.txt
run: |
#!/bin/sh
tr '[:lower:]' '[:upper:]' < "${inputs.source}" > "${outputs.result}"
再跑一次会复用 uppercase.txt;改了 source.txt 才重跑。
部署拓扑三选一:单服务(dagu start-all,开发/单机/边缘)、临时 worker(Cloud Run Jobs / K8s Job / CI 每次起一个 dagu start,跑完销毁,状态写共享卷)、分布式 worker(常驻 worker 通过 gRPC 轮询协调器,按 label 路由)。CI 或纯 CLI 环境用 DAGU_HEADLESS=true 关掉 Web UI。
典型适用场景
README 列的场景我挑几个最有代表性的:
- ETL 与数据运维:把已有的抽取脚本、SQL、dbt 命令变成可观测的流水线。
- 遗留脚本与定时任务:把互相依赖的 cron 脚本变成有 UI、有日志、有重试、有通知的 DAG。
- 媒体转码:ffmpeg 批处理,文件态状态让 worker 并行跑而不需要外部数据库。
- 基础设施自动化:通过 SSH 在远端服务器跑命令,日志和结果集中一处。
- GitHub 驱动的自动化:用 GitHub 事件触发工作流,在私有基础设施上跑自动化,不用把服务器暴露到公网。
- 客服自助运维:给非工程团队提供自助工作流做诊断、查库、常规操作。
- IoT / 边缘:传感器轮询、本地推理、备份、离线同步,仍有 Web UI 可见性。
坑与注意
- Docker socket 是权限逃逸面。现象:想让 Dagu 跑
container:或action: docker.run步骤,于是挂载宿主 Docker socket。影响:挂载 socket 等于把宿主 daemon 的控制权交给工作流,等同于把宿主 root 权限开放。修复:README 的 Docker 安装命令故意不暴露 host daemon;若确实需要容器步骤,按官方 container-step Docker setup 单独配置并评估风险,不要图省事直接-v /var/run/docker.sock。 - Helm 必须用 ReadWriteMany 的 StorageClass。现象:
helm install后 Pod 起不来或状态不持久。影响:工作流状态丢失。修复:--set persistence.storageClass=<rwx-storage-class>,先确认集群有支持 RWX 的 StorageClass。 - Docker 部署需要额外步骤才能用容器步骤。现象:官方 docker run 命令起来了,但容器步骤报错。影响:以为 Dagu 坏了。修复:README 明确说该命令不暴露 host daemon,容器步骤需按专门文档配置。
- 升级缺少明确迁移说明。现象:直接换二进制就升级。影响:状态存在本地文件里,格式若变更可能读不了历史。修复:README 未描述跨版本正式迁移路径,升级前务必读 release notes;重要环境先备份数据目录。
- 文件态存储的容量边界。现象:以为能无限扩展。影响:磁盘成为瓶颈。修复:README 称单机每天可跑数千次 workflow run,但明确「实际容量取决于 CPU、内存、磁盘和工作流形态」。用队列、并发上限和资源限制控制负载;大规模走 worker 横向扩展。⚠️ 官方未给出量化上限,务必按自己的工作流压测。
- 许可边界要看清。现象:以为所有功能都免费。影响:合规风险。修复:GPL-3.0(另有
LICENSING.md说明嵌入式 API 与商业嵌入);功能上分两档——Community self-host 不要 license key,SSO、RBAC、审计日志、incident SaaS 集成属于 self-host license(付费)。⚠️ 具体条款本文未逐条核实,商用前请自行读 LICENSE 与 LICENSING.md。 - 开启监控即出网。现象:打开了 Dagu Console 监控。影响:元数据离开你的环境。修复:README 说得很明确——opt-in(需管理员在 Plan & features 开启或设
cloud.report: runs),仅出站(HTTPS 每 60 秒上报,免费档每 5 分钟),仅元数据(运行状态、耗时、失败的 step 名;日志、输出、参数和 secrets 永不外发,且服务器会显示最后一次上报的确切 JSON)。监控处于 beta;单台服务器免费需 Dagu v2.19.2 及以上。 continue_on: failure: true会吞掉失败。现象:某步失败但流程「成功」了。影响:以为全绿其实漏了数据。修复:只在明确可容忍失败的步骤上开,并配handler_on: failure通知。- catchup 窗口会造成补偿风暴。现象:调度器宕机数小时后恢复。影响:
catchup_window: "5h"内的错过的运行被批量补跑,瞬间打满资源。修复:窗口按业务容忍度设,并配合并发上限。 - 脚本安装器才有引导向导。现象:想当然以为 brew/npm 装完能直接开 UI 看到管理员账号流程。影响:困惑。修复:Homebrew、npm、Docker、Helm 均无向导,需自行首次启动时创建管理员账号。
brew install dagu装的版本可能落后于上游 release,注意版本对齐。
与同类对比
- vs cron:Dagu 严格是超集。cron 能做的 Dagu 都能做,且多了依赖、重试、历史和 UI。差别只是多引入一个二进制——如果你只有三五个无关紧要的任务,cron 仍然更省。
- vs Airflow:README 的对比逻辑成立——Airflow 要你养 6+ 个服务,且任务被改写成
@dag/@task代码。Dagu 是 1 个进程、配置与逻辑分离。代价是你失去了 Airflow 的成熟生态、丰富的 operator 库和大规模调度经验。Dagu 明确把自己定位为 Airflow / Cron / Job Scheduler 的替代品,而非同量级平台。 - vs Temporal:Temporal 的优势是持久化执行的强语义保证,代价是业务逻辑要进 SDK。Dagu 是「薄编排」——执行仍由你的 shell/容器负责,编排器不接管重试语义到编程模型层面。
- vs Mage-ai(第三方对比 ⚠️ 非官方数据):两者都属编排类,仓库年龄都约 4 年;差异是 Mage 侧重 ETL 与数据集成、许可是 Apache-2.0,Dagu 侧重通用自动化编排、许可是 GPL-3.0。GPL 对闭源商业集成的约束明显更紧,这点要先想清楚。
- vs n8n / Node-RED:那两个是可视化节点编辑器,面向集成与业务连接;Dagu 是 YAML 声明式 + 运维取向,面向已有脚本与批处理。Dagu 有 Web UI 但主打观测与运维,不是拖拽编排画布。
不确定处
- 版本:README 引用「v2.19.2 or later」用于 Console 免费档,openalternative 抓取为 v2.19.0,mise 版本列表最新可见 2.16.5(1 个月前)。⚠️ 核查于 2026-10-22,各数据源不一致,具体最新版请以 GitHub Releases 页面为准。
- GPL-3.0 已确认(仓库卡、第三方多源一致);但
LICENSING.md中关于嵌入式 API 与商业嵌入的条款本文未读取,商业使用前需自行核实。 - self-host license 的定价与具体功能边界未核实(见 dagu.sh/pricing)。
- 「单机每天数千次 run」为 README 自述,未找到压测数据支撑。
- Dagu Console 处于 beta,其稳定性与上报行为的长期一致性未核实。
- 本文未 clone、未运行任何命令;所有 YAML 与命令均直接摘自 README。