核心概念
整套系统围绕三层结构组织,理解这三层就能看懂画布上的任意编排。
流水线 · 阶段 · 任务
| 层级 | 说明 |
|---|---|
| 流水线(Pipeline) | 一张证书的完整生命周期,包含申请、部署与通知;支持启用 / 停用、分组、批量操作与定时触发 |
| 阶段(Stage) | 流水线中的一个环节,例如「申请证书」「部署证书」「通知」;阶段之间按顺序执行 |
| 任务(Task) | 阶段内的最小执行单元,例如 CertApply、DeployToNginx、Notify;每个任务可以单独启停 |
执行顺序只由「阶段顺序 + 阶段内顺序」决定,连线表达的是「接入 / 失败后跳转」,不是自由拓扑。
一条最小可用的流水线长这样:
json
{
"stages": [
{
"id": "s1",
"title": "申请证书",
"tasks": [
{
"id": "t1",
"type": "CertApply",
"input": {
"domains": ["example.com", "*.example.com"],
"provider": "letsencrypt",
"email": "admin@example.com",
"challengeType": "dns",
"dnsAccessId": 1,
"keyType": "ec256",
"renewDays": 20
}
}
]
},
{
"id": "s2",
"title": "部署证书",
"tasks": [
{
"id": "t2",
"type": "DeployToNginx",
"input": {
"accessId": 2,
"certPath": "/etc/nginx/ssl/{{cert.domain}}.crt",
"keyPath": "/etc/nginx/ssl/{{cert.domain}}.key",
"reloadCmd": "nginx -s reload"
}
}
]
}
],
"triggers": [{ "id": "tr1", "type": "timer", "cron": "0 3 * * *", "enabled": true }]
}画布操作

- 阶段横排、任务竖排。每个阶段底部有「添加任务」,单阶段最多 5 个任务。
- 每张任务卡右侧两个出口:绿色「成功」接下一个任务,橙色「失败」按「失败后跳转」连到目标。
- 新任务默认不接入(虚线卡片 + 「未接入」徽标):不参与执行链、画布也不连线。要接入就打开任务配置里的「接入流程」开关,或直接从绿色出口拖一条线过去。
- 可以手动拖线:从绿色出口拖到后面的任务 = 接入执行链;从橙色出口拖到后面的任务 = 设置「失败后跳转」。落点吸到卡片即可,不用精确对准锚点。
- 点连线可以删:点顺序线 = 断开接入(之后不执行);点「失败后」线 = 清掉跳转。都会先弹确认。
- 失败后跳转只允许指向后面的任务(避免成环),并且一个任务最多只有一条「失败后」入边。
- 阶段可以拖动摆位:拖动阶段标题条整块移动,松手后吸附到 16px 网格;落点重叠会自动推开,坐标写回
content.layout.stages。 - 画布 / 列表两种视图,选择记在浏览器里;批量核对参数用列表视图更省事。
Ctrl/Cmd+S保存。有未保存改动时,右上角主按钮会从「运行」变成「保存并运行」。- 右键菜单:任务卡 = 配置 / 复制 / 日志 / 启停 / 删除;阶段 = 添加任务 / 单独运行 / 本段日志 / 重命名 / 启停 / 删除;空白处 = 添加阶段。
阶段级操作
hover 阶段标题会出现「单独运行本阶段 / 查看本阶段日志 / 重命名 / 删除」;hover 任务卡会出现「查看该任务日志」。日志弹窗只显示这一次执行里属于该阶段(按 ===== 阶段:X ===== 切段)或该任务(按 [任务名] 前缀过滤)的行。
变量引用
CertApply 的输出可以被后续任务引用,写法是 {{ cert.xxx }}:
| 变量 | 含义 |
|---|---|
{{cert.domain}} | 主域名 |
{{cert.crt}} | 证书链 PEM |
{{cert.key}} | 私钥 PEM |
{{cert.expiresTime}} | 到期时间 |
部署插件的路径参数支持这些变量,例如:
text
/etc/nginx/ssl/{{cert.domain}}.crt
/etc/nginx/ssl/{{cert.domain}}.key触发方式
| 方式 | 说明 |
|---|---|
| 手动 | 详情页右上角「运行」;列表页也能直接点运行 |
| 定时 | 「定时任务」按钮按日历选(每天 / 每周 / 每月 1 日 / 自定义 cron),按钮上直接显示人话时间 |
| 批量 | 列表页勾选多行后「运行 / 启用 / 停用 / 定时 / 通知 / 删除」,走 POST /api/pipeline/batch,逐条执行、单条失败不影响其余 |
| 开放接口 | 用 API 密钥调 POST /api/open/v1/pipelines/{id}/run,见 架构与目录 |
改定时或启停后,服务端会立即重算下次运行时间,不用等调度器下一轮 tick。
关于 renewDays
证书任务里有个「提前续期天数」(renewDays,默认 20 天)。没到续期时间时会自动跳过签发,直接复用证书库里现有的证书 —— 这是为了避免每天定时跑都去申请一次,触发 CA 的限流。
执行历史与实时日志
- 点「运行」时,后端先建历史记录再提交线程池,直接返回
historyId,前端拿到 id 立刻订阅日志,不用轮询猜哪条是新记录。 - 日志通过 SSE(
GET /api/history/{id}/stream)逐行推送,并额外推event: tasks任务进度快照、event: status/event: end状态与结束信号。 - 跑完的记录频道保留 5 分钟;更早的记录直接回放数据库里的日志 —— 「看历史」和「看实时」是同一个组件、同一条接口。
- 「停止」是协作式停止:在任务之间、以及 ACME 轮询的每一轮检查标志位,正在飞的单次 HTTP 请求不会被打断。
- 进程被强杀会留下
status=running的记录,启动时cleanup_stale_runs()会把它们标成failed并在日志末尾补一句「服务重启,本次执行已中断」。
日志高亮
时间戳、===== 阶段 =====、[任务名] 前缀、URL / 域名 / IP、PEM 标记各用一种颜色;「成功 / 完成」绿、「失败 / 错误」红、「警告 / 跳过」黄。日志全部按文本节点渲染,不会被当成 HTML 执行。
流水线模板
GET /api/pipeline/templates 返回 8 套模板骨架:
- Let's Encrypt + Nginx
- Let's Encrypt + SSH 主机
- Let's Encrypt + 阿里云 CDN
- Let's Encrypt + 腾讯云 CDN
- Let's Encrypt + HTTP 验证
- 火山引擎免费证书 + CDN
- 仅申请(不部署)
- 自签测试
模板只提供结构,不含任何凭据(accessId 一律为空)—— 授权是每个账号私有的,硬编码没有意义。
