docker stats –no-stream:让容器资源快照能被脚本安全调用
docker stats 默认每两秒重绘一次,Ctrl+C 才停。人盯着看没问题,被脚本、日志采集或定时任务调用时就会永远阻塞。典型场景:容器 CPU 突然跑满,要在故障窗口留一份“此刻各容器占用”的快照;或巡检脚本每五分钟追加一条记录。
先看现象
docker stats | tee /tmp/stats.log
tee 会一直等,脚本卡在这一行。放进 cron 里,任务会堆积——上一次没结束,下一次又起来了。
机制:一次采样后主动退出
--no-stream 关闭循环刷新,只做一次数据采集,打印表头和数据行后返回。它不改变采集内容,改变的是生命周期:
docker stats --no-stream
输出第一行是表头,之后每个运行中的容器一行,命令返回后 shell 提示符立刻回来,可以安全接管道、重定向、写进 cron。
针对单个容器:
docker stats --no-stream web-1
web-1 是 docker ps 里 NAMES 列的值,不是镜像名。名字写错时命令不会报错退出,而是打印表头后结束,容易误判成“容器没占用资源”。先用 docker ps --filter name=web-1 确认。
在 DSH 里落地
DSH 的定时任务用 schedule 能力建立,固定时刻把提示词投给会话。采集端命令保持无交互:
docker stats --no-stream --format '{{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}'
--format 用 Go 模板,字段名来自 docker stats 的列定义,\t 在单引号里原样传给 Docker,输出制表符分隔,方便 awk 或入库。--format 与 --no-stream 可同时用,前者只改输出形态,不改变采样次数。
采集结果要落到会话可见的位置。会话记录在 下的 session.v4.jsonl.zstd,是压缩归档,不适合当实时日志追加。更直接的是走本地投递接口:
curl -s -X POST http://127.0.0.1:3080/api/dsh-im/delivery/messages \
-H 'Content-Type: application/json' \
-d '{"botId":"ops","targetId":"alert-room","text":"web-1 CPU 92%","format":"plain"}'
format 只接受 plain 或 markdown,传其他值会被拒绝。接口只监听回环地址,不需要额外鉴权,返回 {"sent": true} 表示受理,不代表对方已读。投递目标要先在 的 deliveryTargets 里登记,targetId 与其中条目对应;没登记时请求不会成功受理。
判断哪一步失败
- 命令卡住不返回:漏了
--no-stream,或管道下游没读完。 - 只有表头没有数据行:容器名写错,或容器已退出(stats 只统计运行中的容器)。
curl返回非{"sent": true}:检查botId、targetId是否与deliveryTargets一致,format是否拼错。- 定时任务重复执行:多半是上一次采集阻塞未退出,DSH 重启后会补发最近一次,叠加起来更明显。
边界
--no-stream 拿到的是单点采样,CPU % 是两次采样间的瞬时值,短命进程的尖峰可能采不到;要看趋势得自己按固定间隔多次调用并记录时间戳。容器数量多时单次采集有延迟,几十个以内影响不大。它不替代 cAdvisor、Prometheus 这类持续采集方案,只适合留证和轻量巡检。