Dagu 日常运维手册
Dagu 2.21.0 日常运维闭环实测:六步巡检(服务/端口/UI-API/执行历史/日志异常/磁盘水位)、失败告警最小实现(Webhook 对接钉钉企微机器人 + 邮件通知 + 外部拨测)、备份恢复、升级回滚 SOP 与六则故障排查(附实测原始报错)。
Dagu 日常运维手册
目标:为已上线的 Dagu 2.21.0 服务建立日常巡检闭环(服务状态/端口探活/UI 可用性/DAG 执行历史/日志异常/磁盘水位)、失败告警最小实现(Webhook 告警 + 邮件通知)、备份与恢复、升级回滚与故障排查手册。全文命令与回显均在 Ubuntu 22.04 + Dagu 2.21.0 生产形态环境逐条实测通过,所有报错均为实测原始输出。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64),内核
6.8.0-138-generic。 - Dagu:2.21.0,systemd 服务
dagu.service托管(ExecStart=/usr/local/bin/dagu start-all,Restart=always)。 - 数据目录:
/var/lib/dagu/(dags 工作流、logs 日志、data 状态);配置:/etc/dagu/dagu.env(DAGU_HOST=0.0.0.0、DAGU_PORT=8114)。 - 服务端口:Admin UI 与 API 同端口 8114(默认 8080,本机 8080 已被占用故改 8114)。
- 管理员账号:
admin(内置用户体系,API 认证为 Bearer JWT)。 - 资源基准(实测):二进制
/usr/local/bin/dagu约 173MB;单进程常驻 RSS 约 130MB;空载时logs/52KB、data/320KB。
二、日常巡检
日常巡检按「服务 → 端口 → UI/API → 执行历史 → 日志异常 → 磁盘水位」六步走,每步给出命令与实测回显,可整段写进巡检脚本。
2.1 服务状态
systemctl is-active dagu && systemctl is-enabled dagu
实测回显:
active
enabled
active 为运行中;failed/inactive 时先 systemctl status dagu -n 30 看最近日志。服务异常退出时 systemd 会在 10 秒后自动拉起(单元文件 Restart=always, RestartSec=10),频繁重启说明存在持续故障,用启动次数辅助判断:
systemctl show dagu -p NRestarts
实测回显:
NRestarts=0
2.2 端口探活
ss -ltn | grep 8114
实测回显:
LISTEN 0 4096 0.0.0.0:8114 0.0.0.0:*
要点:监听地址必须是 0.0.0.0(远程可访问);若显示 127.0.0.1:8114 则远程全部不通,检查 /etc/dagu/dagu.env 的 DAGU_HOST(详见第七章 Q2 的还原事故)。
2.3 UI 与 API 可用性
curl -s -o /dev/null -w "UI: %{http_code}\n" http://127.0.0.1:8114/
实测回显:
UI: 200
API 层探活(带认证,返回 DAG 数量即业务面健康):
TOKEN=$(curl -s -X POST -H 'Content-Type: application/json' \
-d '{"username":"admin","password":"q1w2e3r4"}' \
http://127.0.0.1:8114/api/v1/auth/login | python3 -c "import json,sys; print(json.load(sys.stdin)['token'])")
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:8114/api/v1/dags | python3 -c "
import json,sys
d=json.load(sys.stdin)
print('dags:', len(d['dags']))
for x in d['dags']:
lr=x['latestDAGRun']
print(x['dag']['name'],'|',lr['statusLabel'])
"
实测回显(节选):
dags: 10
c1-fail-demo | failed
c1-retry-demo | succeeded
c1-schedule-demo | not_started
d2-check-demo | succeeded
d2-webhook-demo | failed
example-01-basic-sequential | not_started
...
巡检关注点:failed 状态的 DAG 需结合 2.4 的执行历史确认是「历史失败已处理」还是「新失败待处理」;not_started 且配置了 schedule 的 DAG 若长期未触发,检查调度器状态(2.5)。
2.4 DAG 执行历史检查
export DAGU_HOME=/var/lib/dagu
dagu history /var/lib/dagu/dags/d2-check-demo.yaml
实测回显:
DAG NAME RUN ID STATUS STARTED (UTC) DURATION PARAMS
d2-check-demo 034iRy7RoVhAwP9JvM919c Succeeded 2026-10-19 05:14:07 < 1s -
多看几条历史时加 --limit;单个 run 的细粒度状态用 dagu status /var/lib/dagu/dags/<名>.yaml --run-id <RUNID>。定时任务重点核对「最近一次计划触发时间」与历史里最新一条的差值——超过 1~2 个周期未跑即为异常。
2.5 服务日志异常检查
journalctl -u dagu --since "24 hours ago" --no-pager | grep -c "level=ERROR"
journalctl -u dagu --since "24 hours ago" --no-pager | grep "level=ERROR" | tail -5
实测回显(历史遗留错误的典型形态):
13
Oct 19 05:07:40 ubuntu dagu[2871]: time=2026-10-19T05:07:40.245Z level=ERROR msg="DAG load failed" err="[1:14] mapping value is not allowed in this context\n> 1 | description: \"C1 failure handler test\"..." file=/var/lib/dagu/dags/c1-fail-demo.yaml
判定口径:总数只作趋势参考(本例 13 条均为修复前的历史记录,时间戳在修复点之前即无需处理);重点关注时间戳持续前移的 ERROR。最常见的两类:DAG load failed(YAML 语法错,工作流作者修文件)与下载/网络类错误。调度器健康标志(启动日志中应存在):
msg="Updated scheduler status to active"
msg="Scheduler started"
msg="Started zombie detector" interval=45s
zombie detector(僵尸进程检测,45 秒一轮)与 retry scanner(30 秒一轮失败自动重试扫描)是两个常驻自愈组件,日志中消失说明调度面异常。
2.6 磁盘水位
df -h /var/lib/dagu | tail -1
du -sh /var/lib/dagu/logs /var/lib/dagu/data
实测回显:
overlay 786G 262G 490G 35% /
52K /var/lib/dagu/logs
320K /var/lib/dagu/data
水位口径:数据盘使用率超 80% 触发清理;日志增长主力是高频 DAG 的 per-run 目录(每次运行一个 dag-run_*/),保留期由 base.yaml hist_retention_days: 30(或 hist_retention_runs)自动控制,临时收紧可手动清理:
dagu rm --help # 查看清理子命令用法
dagu cleanup --help # 旧版清理命令(官方标记 deprecated,功能并入 rm --history)
三、监控告警
Dagu 的失败感知有三层:步骤/DAG 重试(自愈)、通知(邮件/Webhook,人感知)、外部拨测(UI 可用性,服务级感知)。本节落地后两层的最小实现。
3.1 Webhook 失败告警(衔接钉钉/企微机器人)
思路:利用 DAG 级 handler_on.failure 钩子,在失败时向钉钉/企微群机器人 Webhook 地址 POST 一条文本消息,格式与《钉钉机器人 webhook 告警接入指南》生态完全兼容。实测 DAG($DAGU_HOME/dags/d2-webhook-demo.yaml):
description: "D2 webhook alert test (DingTalk-style)"
handler_on:
failure:
run: |
curl -s -X POST -H 'Content-Type: application/json' \
-d '{"msgtype":"text","text":{"content":"[Dagu] d2-webhook-demo 执行失败,请排查"}}' \
http://127.0.0.1:1026/dingtalk
steps:
- id: broken_job
run: sh -c "exit 7"
生产使用时把 http://127.0.0.1:1026/dingtalk 替换为真实机器人地址(钉钉:https://oapi.dingtalk.com/robot/send?access_token=xxx;企微:https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx)。执行实测(dagu start /var/lib/dagu/dags/d2-webhook-demo.yaml):
├─broken_job (0s) [failed]
│ ├─sh -c "exit 7"
│ │
│ └─error: exit status 7
│
└─onFailure (0s) [succeeded]
└─stdout: /var/lib/dagu/logs/d2-webhook-demo/dag-run_20261019_050954Z_034iRriexAo3VlBGrArMNX/run_20261019_050954Z_525342/onFailure.20261019.050954.804.034iRrie.out
{"errcode":0,"errmsg":"ok"}
Result: Failed
接收端实测原始报文(群机器人收到的 JSON):
WEBHOOK-HIT path=/dingtalk content-type=application/json body={"msgtype":"text","text":{"content":"[Dagu] d2-webhook-demo 执行失败,请排查"}}
要点:钩子 stdout 里落了机器人响应 {"errcode":0,"errmsg":"ok"},告警是否送达可直接从日志判断;钉钉机器人若开启「自定义关键词」风控,文案里带上 [Dagu] 关键词即可。多 DAG 复用时把该钩子块写进 base.yaml 的 handler_on(全局继承,官方支持),消息文案中用固定字样区分来源。
💡 技术拓展:Webhook 接收格式主流三派——钉钉/企微的
{"msgtype":"text","text":{"content":"..."}}文本消息体、通用 JSON 自由体(自建接收器)、以及标准化事件订阅(如 Slack Events 的 challenge 握手)。本文因目标端是钉钉/企微机器人,采用 msgtype 文本体;对接自有告警平台时改 POST 自由 JSON 即可,钩子内 curl 参数同步调整。
3.2 邮件失败通知
全局 SMTP 配置(写入 /var/lib/dagu/base.yaml,所有 DAG 继承):
smtp:
host: smtp.example.com
port: "587"
error_mail:
from: dagu@example.com
to: ops@example.com
prefix: "[DAGU]"
attach_logs: true
mail_on:
failure: true
实测回显(本环境 SMTP 调试服务器收到失败邮件的原始头):
b'To: ops@example.com'
b'From: dagu@example.com'
b'Subject: [DAGU] c1-fail-demo (failed)'
b'Content-Type: text/html; charset=UTF-8'
主题规则 {prefix} {DAG名} ({状态});attach_logs: true 时附步骤日志。字段逐项说明与 OAuth(Microsoft 365/Google)配置见 《Dagu 2.21.0 配置参数详解》5.6 节。
3.3 服务级拨测(UI 可用性)
服务挂了但 DAG 都没跑时,前面两层告警都不会响(钩子随进程一起死)。补一个外部拨测(crontab 或其他监控平台执行):
curl -s -o /dev/null -m 5 -w "%{http_code}" http://<服务器IP>:8114/ | grep -q 200 || echo "Dagu UI DOWN" | mail -s "[ALERT] dagu down" ops@example.com
200 之外的状态(000 连接失败、502 代理失败)即触发。本例实测正常返回 200。
四、备份与恢复
Dagu 状态全部落盘,备份即打包两个目录:/var/lib/dagu(工作流定义+日志+执行历史+用户)与 /etc/dagu(服务端环境变量)。实测打包:
tar -czf /root/dagu-backup-$(date +%Y%m%d).tar.gz -C / var/lib/dagu /etc/dagu
ls -la /root/dagu-backup-*.tar.gz
实测回显:
tar: Removing leading `/' from member names
-rw-r--r-- 1 root root 18968 Oct 19 05:23 /root/dagu-backup-20261019.tar.gz
tar -tzf /root/dagu-backup-20261019.tar.gz | head -5
实测回显(节选):
var/lib/dagu/
var/lib/dagu/data/
var/lib/dagu/data/service-registry/
var/lib/dagu/data/notifications/
var/lib/dagu/dags/
备份策略建议:每日一次全量(空载约 20KB数 MB,成本可忽略),保留 730 天;只需保工作流定义时单独打包 /var/lib/dagu/dags/ 即可。恢复(在装好 Dagu 的机器上):
systemctl stop dagu
tar -xzf /root/dagu-backup-20261019.tar.gz -C /
systemctl start dagu
systemctl is-active dagu
实测回显:
active
恢复后用 2.3 的 API 探活确认 DAG 列表完整。迁移到新服务器 = 安装 Dagu(见《Ubuntu 22.04 安装 Dagu 2.21.0 指南》)+ 恢复备份 + 复核 dagu.env 中的监听地址与端口。
五、部署形态与扩容缩容
Dagu 无传统「扩容缩容」概念,按规模选形态(官方 Deployment Models 文档口径):
| 形态 | 适用规模 | 说明 |
|---|---|---|
| 单机单进程(本文形态) | 数十~数百个工作流 | start-all 一进程含 UI+调度器,文件状态 |
| 多机共享卷 | 多台服务器共管 DAG | 调度器部署在 NFS/EFS/CephFS 上可感知其他主机的 DAG 变更(v2.21 起秒级同步) |
| 分布式 worker | 单机算力不足 | dagu coordinator + 多台 dagu worker,按 workerSelector 分发(v2.21 支持按 run 选择 worker 与 worker 从零扩容等待) |
纵向扩容一般不需要:单进程 RSS 实测 130MB 起步,max_active_steps(默认 10)是首要并发旋钮;横向扩容走 worker 形态,配合 base.yaml 的 queue 做跨 DAG 并发分组。缩容即反向操作,单机形态无状态外移负担。
六、升级与回滚
升级走安装器原地覆盖(实测记录与完整命令见《Ubuntu 22.04 安装 Dagu 2.21.0 指南》第七章),运维侧流程与校验:
# 1. 备份(升级前必做,见第四章)
tar -czf /root/dagu-backup-preupgrade-$(date +%Y%m%d).tar.gz -C / var/lib/dagu /etc/dagu
# 2. 升级(安装器;或手动替换二进制)
# 3. 复核被安装器重写的配置
grep -E 'DAGU_HOST|DAGU_PORT' /etc/dagu/dagu.env
# 4. 服务与版本确认
systemctl is-active dagu && dagu version
# 5. 业务确认:DAG 列表与最近执行历史
dagu ls
实测回显(升级后复核发现配置被还原的原始形态):
DAGU_HOST='127.0.0.1'
DAGU_PORT='8080'
按需改回 0.0.0.0/8114 并 systemctl restart dagu。回滚 = 装回旧版二进制(安装器 --version v2.20.1 实测可降级,服务自动重启);执行历史数据格式小版本间兼容,跨大版本回滚前以升级前备份恢复数据目录。
七、故障排查手册
以下均为实测原始报错与定位路径。
7.1 DAG 定义错误(DAG load failed)
现象:DAG 不出现在 UI/dagu ls,服务日志报错。实测原始报错:
time=2026-10-19T05:07:40.245Z level=ERROR msg="DAG load failed" err="[1:14] mapping value is not allowed in this context\n> 1 | description: \"C1 failure handler test\"\n..." file=/var/lib/dagu/dags/c1-fail-demo.yaml
定位:报错含「行:列」精确位置([1:14]),多为值含冒号/特殊字符未加引号。修复:dagu validate <文件> 通过后再触发;保存后日志出现 msg="DAG added/updated" 即加载成功。
7.2 远程访问 404/拒绝(DAGU_HOST 被还原)
现象:升级后宿主侧 curl http://<IP>:8114/ 实测返回 000(连接失败)。定位三步:
ss -ltn | grep 8114 # 实测仅见 127.0.0.1:8114 → 监听地址问题
grep DAGU_HOST /etc/dagu/dagu.env # 实测 DAGU_HOST='127.0.0.1'(安装器重写还原)
sed -i "s/DAGU_HOST='127.0.0.1'/DAGU_HOST='0.0.0.0'/" /etc/dagu/dagu.env && systemctl restart dagu
修复后实测 curl 返回 200。该问题源于官方安装器每次重跑都重写 dagu.env,升级 SOP 中必须保留复核步骤(见第六章)。
7.3 API 401(认证方式不符)
现象:curl -u admin:q1w2e3r4 http://127.0.0.1:8114/api/v1/dags 返回 401。实测响应头:
HTTP/1.1 401 Unauthorized
Www-Authenticate: Bearer realm="restricted"
原因:2.x 内置用户体系用 Bearer JWT,不接受 Basic Auth。修复:先 POST /api/v1/auth/login 取 token(登录体 {"username":"admin","password":"q1w2e3r4"}),再带 Authorization: Bearer <token> 调用(完整命令见 2.3)。
7.4 步骤失败定位(exit status N)
现象:DAG 状态 failed。定位路径:UI 的 run 详情页查看步骤 stderr,或命令行直读日志文件:
grep -r "Step execution failed" /var/lib/dagu/logs/<DAG名>/ | tail -3
cat /var/lib/dagu/logs/<DAG名>/dag-run_*/run_*/<步骤名>.*.err
实测原始记录:
time=2026-10-19T05:06:53.537Z level=INFO msg="Step execution failed; retrying" step=flaky err="exit status 1" retry=0 exit-code=1
exit status 3、exit status 7 等即脚本退出码;retry=N 显示已重试次数,超过 retry_policy.limit 后最终失败并触发 onFailure 钩子。
7.5 服务反复重启/起不来
systemctl status dagu -n 50
journalctl -u dagu -b --no-pager | grep -E "ERROR|panic|Fatal" | tail -10
常见根因:/etc/dagu/dagu.env 语法错误(EnvironmentFile 解析失败)、DAGU_HOME 目录权限不足(User=root 时通常无此问题)、端口被占(v2.21 起端口被占时进程直接退出,日志含明确提示,改 DAGU_PORT 或释放端口)。
7.6 安装/升级下载失败(网络类)
实测原始报错:
curl: (56) OpenSSL SSL_read: Connection reset by peer, errno 104
curl: (7) Failed to connect to github.com port 443 after 21053 ms: Connection refused
处理:走代理(export http_proxy=http://192.168.1.62:7897 https_proxy=http://192.168.1.62:7897)重试,或手动下载二进制后替换(离线方案见安装篇第五章)。
八、常见问题(FAQ)
Q1:日志和历史会无限膨胀吗?
不会。base.yaml hist_retention_days(默认 30 天)/hist_retention_runs 自动清理过期 run;巡检 2.6 监控磁盘水位即可,异常膨胀通常是高频 DAG + 大 stdout,调低 max_output_size 或缩短保留期。
Q2:重试会不会造成重复副作用?
会。重试对幂等任务(备份覆盖写、状态上报)安全;非幂等任务(下单、发消息)在 DAG 或步骤级显式关闭重试(retry_policy.limit: 0),失败走人工介入。
Q3:worker 挂了正在跑的任务怎么办?
单机形态任务随进程消失,systemd 会拉起服务但该次 run 标记中断,可在 UI 手动 retry(同 run-ID 重放);分布式形态由 coordinator 的 worker 等待/重派机制处理(v2.21 的 worker_wait_timeout,默认 2m)。
Q4:升级会丢执行历史吗?
不会。历史在 /var/lib/dagu 与二进制无关;但升级 SOP 必须含「备份 + 复核 dagu.env」两步(实测安装器会重写该文件,见第六章)。
Q5:多个 DAG 需要统一并发上限?
用 base.yaml 的 queue 字段把相关 DAG 归入同一命名队列,队列内并发由调度器统一控制(官方注释:Assign DAGs to a named queue for concurrency control across DAGs)。
九、参考链接
- 官方运维相关文档:https://docs.dagu.sh/overview/console-monitoring 、https://docs.dagu.sh/web-ui/notifications
- 部署形态:https://docs.dagu.sh/overview/deployment-models
- CLI 参考(history/status/rm/retry 等):
dagu --help与 https://docs.dagu.sh/ - 本站安装篇:《Ubuntu 22.04 安装 Dagu 2.21.0 指南》
- 本站配置篇:《Dagu 2.21.0 配置参数详解》
- 本站选型篇:《Dagu 2.21.0 介绍与选型指南》