Windmill 监控指南:用 Prometheus 与 Pushgateway 采集 Server/Worker 指标与 Job 业务指标
【免费下载链接】windmillOpen-source developer platform to power your entire infra and turn scripts into webhooks, workflows and UIs. Fastest workflow engine (13x vs Airflow). Open-source alternative to Retool and Temporal.项目地址: https://gitcode.com/GitHub_Trending/wi/windmill
本文以 Windmill 开源仓库中的 job-monitoring-prometheus 部署示例 为主体,讲解如何搭建一套完整的监控栈:通过 Prometheus 抓取 Windmill server 与 worker 暴露的指标,并借助 Prometheus Pushgateway 让短暂运行的 Job 也能推送自己的业务指标,最终在 Grafana 中统一可视化。读完本文,你将掌握 Windmill 指标开关的底层原理、docker-compose 下的服务发现配置,以及规避 Pushgateway "指标残留" 陷阱的实战技巧。
一、整体监控架构
Windmill 的监控分为两个层面,对应两种截然不同的采集模型:
| 采集对象 | 数据产生方式 | 采集模型 | 适用指标 |
|---|---|---|---|
| Windmill server / worker 进程 | 常驻进程,持续暴露/metrics端点 | Prometheus 主动拉取(scrape) | 队列长度、运行中的 Job 数、Worker 心跳、API 延迟等进程级指标 |
| 单个 Windmill Job(脚本/流程) | Job 生命周期极短,Prometheus 来不及抓取 | Job 主动推送(push)到 Pushgateway | job_records_processed这类业务指标 |
Windmill 服务器和 worker 都会产生可供 Prometheus 抓取的指标;而单个 Job 由于临时性(ephemeral)本质,往往在 Prometheus 完成一次抓取之前就已经结束,因此需要借助 Prometheus 官方推荐的 Pushgateway 模型来完成指标上报。本示例正是围绕这两条链路设计的。
完整的监控栈由四类服务组成:
- Windmill:一个 PostgreSQL 数据库、一个 server、至少一个 worker(示例中部署了 3 个 worker 副本);
- Prometheus:负责抓取 server/worker 指标,以及抓取 Pushgateway 中 Job 推送的指标;
- Prometheus Pushgateway:接收 Job 推送的指标并暂存;
- Grafana:可视化以上所有指标(可选)。
二、一键启动整套监控栈
仓库中的 docker-compose.yml 已经把所有服务组装完毕,直接运行:
docker compose up -d启动完成后各服务访问地址如下:
| 服务 | 地址 | 说明 |
|---|---|---|
| Windmill | http://localhost:8000 | 主控制台 |
| Prometheus | http://localhost:9090 | 抓取与查询 |
| Grafana | http://localhost:3000 | 可视化(compose 中实际映射为 3030) |
| Pushgateway 指标端点 | http://localhost:9091/metrics | 可被 Prometheus 抓取 |
| Pushgateway 管理界面 | http://localhost:9091 | 管理 metric group |
Grafana 的默认管理员账号密码定义在 grafana/grafana.ini 中(admin_user = windmill,admin_password = changeme),Prometheus 数据源则通过 grafana/datasource.yml 自动预置,指向http://prometheus:9090。
compose 文件中几个值得注意的细节:
- Pushgateway 使用了
--persistence.file=/data/persistence.dat将推送的指标持久化到卷中,重启后指标不会丢失; - Prometheus 设置了
--storage.tsdb.retention.time=365d的长期保留策略; - Windmill server 与 worker 均通过
depends_on等待 PostgreSQL 健康检查通过后再启动; - 数据库密码为示例用的
changeme,生产环境务必替换。
启动后,你可以在 Prometheus 的 Status 页面(http://localhost:9090/targets)直接确认各抓取目标是否在线。
三、监控 Windmill Server 与 Worker
3.1 开启指标端点:METRICS_ADDR 的底层原理
Windmill 的指标功能默认关闭,需要通过环境变量METRICS_ADDR开启(该功能属于 Windmill Enterprise Edition)。开启后进程会在8001端口(默认值)暴露/metrics端点。
从源码看,该变量的解析逻辑位于 backend/windmill-common/src/lib.rs:
pub static ref METRICS_PORT: u16 = std::env::var("METRICS_PORT") .ok().and_then(|s| s.parse::<u16>().ok()) .unwrap_or(8001); pub static ref METRICS_ADDR: SocketAddr = std::env::var("METRICS_ADDR") .ok().map(|s| { s.parse::<bool>() .map(|b| b.then(|| SocketAddr::from(([0, 0, 0, 0], *METRICS_PORT)))) .or_else(|_| s.parse::<SocketAddr>().map(Some)) }) ... .unwrap_or_else(|| SocketAddr::from(([0, 0, 0, 0], *METRICS_PORT))); pub static ref METRICS_ENABLED: AtomicBool = AtomicBool::new( std::env::var("METRICS_PORT").is_ok() || std::env::var("METRICS_ADDR").is_ok() );由此可以提炼出三种配置方式及其行为:
| 配置方式 | 行为 |
|---|---|
METRICS_ADDR=1(或true) | 在默认端口8001的0.0.0.0上监听/metrics,即 README 与 compose 示例的用法 |
METRICS_ADDR=0.0.0.0:9100(SocketAddr 形式) | 解析为完整地址,覆盖默认端口,按指定地址监听 |
METRICS_PORT=9100(单独设置) | 仅指定端口,同样会触发METRICS_ENABLED为 true,在0.0.0.0:9100监听 |
也就是说,METRICS_ENABLED只要检测到这两个环境变量中任意一个存在即为 true,监听地址默认绑定0.0.0.0以便容器外部访问。
除了环境变量,也可以在 Windmill 实例设置(instance settings → core)中打开 "Expose Metrics" 开关,其对应的全局设置项为expose_metrics(源码见 backend/src/monitor.rs 的apply_metrics_enabled,测试覆盖见 backend/tests/instance_config.rs)。此外,实例设置 → debug 菜单还可以开启额外的 "debug-level" 指标。
3.2 让 Prometheus 通过 Docker 服务发现找到 Windmill
在 docker-compose 部署方式下,需要做四处调整才能让 Prometheus 自动发现并抓取 Windmill 容器:
- 暴露指标端口:给
windmill_server和windmill_worker两个服务的expose块加入8001(默认指标端口),使服务发现能确定抓取哪个端口; - 打标签区分角色:为容器添加
prometheus-job=windmill_server与prometheus-job=windmill_worker标签,便于服务发现按角色过滤; - 挂载 Docker socket:Prometheus 容器需要以
user: root运行,并把宿主机的/var/run/docker.sock只读挂载进去(compose 中对应- /var/run/docker.sock:/var/run/docker.sock:ro # for service discovery); - 配置 scrape_configs:在 prometheus/prometheus.yml 中添加如下抓取配置:
scrape_configs: - job_name: "windmill_server" docker_sd_configs: - host: unix:///var/run/docker.sock relabel_configs: - source_labels: [__meta_docker_container_label_prometheus_job] regex: windmill_server action: keep scrape_interval: 1s - job_name: "windmill_worker" docker_sd_configs: - host: unix:///var/run/docker.sock relabel_configs: - source_labels: [__meta_docker_container_label_prometheus_job] regex: windmill_worker action: keep scrape_interval: 1s这里docker_sd_configs负责从 Docker socket 发现容器,relabel_configs中的action: keep则按容器标签prometheus-job的值过滤,只保留 server 或 worker。抓取间隔设为1s,能够获得更细腻的时序数据(windmill server 与 worker 指标对实时性要求较高)。
3.3 多 Docker daemon 场景
如果 Windmill 容器分散在多个 Docker daemon 上,上述方案依然成立:无需修改 relabel 逻辑,只需把 Prometheus 的docker_sd_configs中的host从本地 socket 改为远程 daemon 的 HTTP(S) 地址,例如http://remote_docker_daemon:2375,并且可以在数组中列出多个远程 daemon 地址。
3.4 查看监控结果
配置就绪后,server 与 worker 的指标会持续被 Prometheus 抓取,可在 Grafana 中可视化。仓库在 grafana/dashboards/ 下提供了现成的仪表盘(windmill_monitoring_dashboard.json),展示最核心的进程级指标:
Windmill 监控仪表盘
四、让单个 Job 产生自己的指标
4.1 为什么需要 Pushgateway
Job 是临时进程:一个 Job 可能只运行几百毫秒就结束,Prometheus 按固定间隔抓取时很可能错过它。Pushgateway 的模型是"作业主动把指标推到网关,Prometheus 再从网关拉取",正好解决这一问题。
4.2 用 Python 脚本推送指标
在 Windmill 中新建一个 Python 脚本(教程中命名为u/admin/random_number_metric_script),内容如下:
import os import random from prometheus_client import CollectorRegistry, Gauge, push_to_gateway PROMETHEUS_GATEWAY_URL = "prometheus_gateway:9091" def main(): job_path = os.environ.get("WM_JOB_PATH") registry = CollectorRegistry() gauge = Gauge( "job_records_processed", "Number of records processed for {}".format(job_path), registry=registry, ) val = random.randint(0, 100) print("Storing metrics value: ", val) gauge.set(val) push_to_gateway(PROMETHEUS_GATEWAY_URL, job=job_path, registry=registry)这段脚本的核心逻辑:
- 使用
prometheus-client库的CollectorRegistry创建独立 registry,避免与默认 registry 冲突; - 定义了一个名为
job_records_processed的 Gauge 指标; - 关键设计:通过
os.environ.get("WM_JOB_PATH")读取 Windmill 注入的环境变量(即脚本路径),并将其作为 Pushgateway 的job标签。这样该脚本的所有运行都会推送到同一个指标分组,便于跨多次运行观察趋势; push_to_gateway还支持grouping_key参数,如需按 Job ID 等更细粒度区分,可传入额外的分组标签。
脚本所需的依赖(prometheus-client)可在 Windmill 脚本的"依赖"一栏中声明。若不想用 Python,官方还提供了 Golang(prometheus/client_golang)、TypeScript(prom-client)等客户端,bash 场景则可以直接用 CURL 命令向 Pushgateway 推送。
脚本创建完成后,为它配置一个每 5 秒运行一次的调度(schedule),即可持续向 Pushgateway 推送新值。
4.3 在 Prometheus UI 中直接查询
如果不使用 Grafana,可以直接在 Prometheus 的 Graph 页面(http://localhost:9090/graph)输入如下 PromQL 查看原始指标:
job_records_processed{exported_job="u/admin/random_number_metric_script"}注意这里使用了exported_job标签:因为 Prometheus 会用自己的job标签(即抓取配置中的job_name,此处为prometheus_gateway)覆盖被抓取数据中的job标签,原job标签会被改名为exported_job保留下来:
Prometheus UI 中查看 Job 指标
五、Grafana 可视化与 Pushgateway 陷阱
仓库在 grafana/dashboards/ 提供了job_metric_dashboard.json,可直接导入 Grafana 使用。该仪表盘包含两个面板,第二个面板正是为了演示 Pushgateway 的一个关键陷阱。
5.1 面板一:原始指标
第一个面板是job_records_processed的简单时间序列展示。由于 Job 每 5 秒运行一次,面板的Min Step被调整为 5 秒,以便尽可能显示全部测量点:
job_records_processed 原始指标
5.2 面板二:Pushgateway 的"指标残留"问题与解法
问题:Pushgateway 中被推送的值会一直保留,直到有新的值推入。这意味着如果调度被意外停止、或脚本开始报错不再推送,旧值依然停留在仪表盘上保持不变——这掩盖了故障,不利于发现异常行为。
解法:理想情况下指标应在无新数据时回落到默认值(如0)。Pushgateway 内置了一个指标push_time_seconds,记录每次成功推送的时间戳(按指标与标签分组)。将业务指标与push_time_seconds的irate相乘,就能得到一个"瞬时"表示:一旦推送停止,irate迅速归零,乘积也随之归零。
第二个面板的实现思路如下:
job_records_processed{exported_job="u/admin/random_number_metric_script"} * irate(push_time_seconds{job="prometheus_gateway", exported_job="u/admin/random_number_metric_script"}[1m])其中Min Step需设为1s,irate才能正常工作(irate计算的是相邻两个样本间的瞬时变化率,抓取间隔为 1s 时其数值才准确反映"此刻是否仍在推送")。
该面板的即时值显示效果:
job_records_processed 瞬时表示
5.3 最终效果
两个面板组合后的仪表盘如下。图中两条浅蓝色竖线之间,作者手动停止了 Windmill 的调度:可以看到上方的原始指标保持不变(残留值),而下方的瞬时表示立即跌到 0——这正是上述技巧的价值所在:
Grafana 双面板仪表盘
六、小结与生产实践建议
回到示例的核心链路:Windmill server/worker 通过METRICS_ADDR暴露/metrics端点供 Prometheus 拉取;短暂运行的 Job 通过prometheus-client的push_to_gateway把业务指标推给 Pushgateway 再由 Prometheus 拉取;Grafana 统一呈现。落地到生产环境时,建议关注以下几点:
- 务必处理 Pushgateway 的残留问题:结合
push_time_seconds的irate构造瞬时指标,或在脚本中显式处理失败/停止场景,否则告警会失效; - 合理设置抓取间隔:本示例为了演示将
scrape_interval设为1s,生产环境应按指标重要性与资源开销权衡; - 安全性:挂载 Docker socket、以 root 运行 Prometheus 均需在可信环境中使用;Pushgateway 默认无鉴权,部署在公网前应增加访问控制;
- 版本前提:
METRICS_ADDR指标开关属于 Enterprise Edition 能力,社区版(CE)部署时请以实际版本文档为准。
更多配套资源可继续查阅:完整部署 compose 文件、Prometheus 抓取配置、Grafana 仪表盘定义。
【免费下载链接】windmillOpen-source developer platform to power your entire infra and turn scripts into webhooks, workflows and UIs. Fastest workflow engine (13x vs Airflow). Open-source alternative to Retool and Temporal.项目地址: https://gitcode.com/GitHub_Trending/wi/windmill
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考