news 2026/10/13 1:59:48

Docker 事件系统完全指南:`docker events` 命令的时间过滤、过滤器与自定义格式实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker 事件系统完全指南:`docker events` 命令的时间过滤、过滤器与自定义格式实战
  • 容器运行时
  • 云原生

【免费下载链接】docker-ce

:warning: This repository is deprecated and will be archived (Docker CE itself is NOT deprecated) see the https://github.com/docker/docker-ce/blob/master/README.md :warning:

项目地址:https://gitcode.com/gh_mirrors/do/docker-ce
点击查看免费下载

docker events是 Docker CLI 中用于从 Docker daemon 获取事件信息的核心命令,既能回溯历史事件,也能实时跟踪新事件。本文以本仓库中 man 手册源文档 为骨架,结合 CLI 与 Engine 两侧的源码实现,系统讲解事件类型体系、--since/--until时间参数、--filter过滤语义、--format自定义模板,以及事件从 daemon 发布到客户端渲染的完整链路,帮助你把这个命令真正用成排障与自动化的利器。

一、docker events能告诉你什么

docker events从 Docker daemon 获取事件信息,信息既包括历史数据(historical information),也包括实时数据(real-time information)。它本质上是 Docker 守护进程内置的一套发布/订阅(pub/sub)事件总线,凡是容器、镜像、卷、网络等对象发生状态变化,都会以事件的形式广播给订阅者。

在 CLI 命令定义 中,命令的使用方式是docker events [OPTIONS],不接受位置参数(Args: cli.NoArgs),支持以下四个选项:

选项短写说明
--filter-f基于给定条件过滤输出,可多次传递
--format—使用给定的 Go 模板格式化输出
--since—仅显示自该时间戳以来产生的事件
--until—持续流式传输事件直到该时间戳

1.1 各对象类型上报的事件

根据 man 源文档 与仓库中更完整的 参考文档,不同 Docker 对象上报的事件集合如下:

容器(containers)

attach、commit、copy、create、destroy、detach、die、exec_create、exec_detach、exec_die、exec_start、export、health_status、kill、oom、pause、rename、resize、restart、start、stop、top、unpause、update

镜像(images)

delete、import、load、pull、push、save、tag、untag

卷(volumes)

create、mount、unmount、destroy

网络(networks)

create、connect、disconnect、destroy、remove

插件(plugins)

enable、disable、install、remove

守护进程(daemons)

reload

服务、节点、Secret、Config(Swarm 范畴)

  • service:create、remove、update
  • node:create、remove、update
  • secret:create、remove、update
  • config:create、remove、update

在 事件类型常量定义 中可以看到完整的类型枚举:builder、config、container、daemon、image、network、node、plugin、secret、service、volume,它们与上述对象一一对应。

1.2 本地作用域与 Swarm 作用域

不同事件类型具有不同的作用域(scope)。根据参考文档:本地作用域(local)的事件只在事件发生的节点上可见,而 Swarm 作用域(swarm)的事件在所有 manager 节点上可见。从源码看,daemon 通过 daemon/events/events.go 中的Log方法发布本地事件时固定填充Scope: "local";而 Swarm 集群事件则由daemon.ProcessClusterNotifications从 swarmkit 的 watch 流转换而来,最终在 daemon/events.go 中通过generateClusterEvent分发。

二、时间窗口:--since与--until详解

--since和--until是docker events最常用的两个参数。二者支持三类输入格式:

  1. Unix 时间戳:秒[.纳秒],其中秒是从 1970 年 1 月 1 日(UTC/GMT 午夜)起经过的秒数,不含闰秒(即 Unix epoch / Unix time);可选的.nanoseconds是秒的小数部分,最多 9 位。
  2. 日期格式化时间戳:支持 RFC3339Nano、RFC3339、2006-01-02T15:04:05、2006-01-02T15:04:05.999999999、2006-01-02Z07:00、2006-01-02。
  3. Go duration 字符串:如10m、1h30m,相对于客户端机器当前时间向前推算。

需要注意的规则:

  • 如果时间戳末尾没有Z或+-00:00时区偏移,则使用客户端的本地时区解析。
  • 如果不提供--since,命令只返回新的(new)和/或实时(live)事件。
  • 提供--until时,daemon 会校验until不能早于since(见下文服务端实现);若until已是过去时间,则只返回历史缓冲事件后立即结束。

2.1 客户端侧的解析逻辑

--since/--until字符串的实际解析发生在两个地方。首先是 CLI 的 engine/client/events.go 中buildEventsQueryParams:它把since、until交给 GetTimestamp 转成 Unix 纳秒字符串,作为 HTTP 查询参数传给/events接口。

GetTimestamp的解析优先级为:先尝试 Go duration,再尝试 RFC3339 系列日期格式,最后才是 Unix 时间戳。其内部细节值得注意:

  • 若输入不含zZ+且连字符个数不等于 3,则判定为“本地时区解析”(ParseInLocation),使用time.FixedZone(reference.Zone())作为时区基准;
  • 根据输入中是否含.、T以及冒号个数,选择rFC3339NanoLocal、rFC3339Local、time.RFC3339、dateWithZone、dateLocal等不同布局;
  • 对纯数字输入(如1483283804),直接原样透传,因为客户端无需转换即可发给服务端;
  • 最终输出格式统一为%d.%09d(秒.纳秒)。

2.2 服务端侧的处理流程

服务端在 system_routes.go 的getEvents中:

  1. 用 ParseTimestamps 把since/until字符串解析为time.Time;
  2. 校验until.Before(since)时返回invalidRequestError;
  3. 若until晚于当前时间,则启动一个定时器(time.NewTimer(dur)),到点后结束流;
  4. 若until是过去时间(onlyPastEvents),则输出完历史缓冲事件后直接返回。

历史事件的缓冲读取由 daemon/events/events.go 的loadBufferedEvents完成:它逆序遍历内存中的事件环形缓冲,TimeNano < since时中断,TimeNano > until时跳过,并对满足条件的消息执行 topic 过滤函数。

2.3 实战示例

监听实时事件,然后另开终端启动/停止容器(用CTRL+C退出监听):

$ docker events 2017-01-05T00:35:58.859401177+08:00 container create 0fdb...ff37 (image=alpine:latest, name=test) 2017-01-05T00:36:04.703631903+08:00 network connect e2e1...29e2 (container=0fdb...ff37, name=bridge, type=bridge) 2017-01-05T00:36:04.795031609+08:00 container start 0fdb...ff37 (image=alpine:latest, name=test) 2017-01-05T00:36:09.840186338+08:00 container die 0fdb...ff37 (exitCode=143, image=alpine:latest, name=test) 2017-01-05T00:36:09.890214053+08:00 container stop 0fdb...ff37 (image=alpine:latest, name=test)

按时间过滤(绝对时间戳、日期、相对时长、时间区间均可):

# Unix 时间戳 $ docker events --since 1483283804 # 仅日期(当日 00:00:00 起,本地时区) $ docker events --since '2017-01-05' # RFC3339 局部格式 $ docker events --since '2017-01-05T00:35:30' --until '2017-01-05T00:36:05' # 相对时长:最近 10 分钟 $ docker events --since '10m' # 相对时长组合:最近 1 小时 30 分 $ docker events --since '1h30m'

三、过滤器:--filter的语义与全部可用键

过滤标志的格式是key=value;多个过滤器通过多次传递--filter指定(如--filter "foo=bar" --filter "bif=baz")。

过滤语义遵循两条规则:

  • 同一键多次使用 = OR:例如--filter container=588a23dac085 --filter container=a8f7720b8c22会显示两个容器中任意一个的事件。
  • 不同键组合使用 = AND:例如--filter container=588a23dac085 --filter event=start只显示该容器的start事件。

man 源文档给出的全部支持键如下(来自 参考文档 的完整列表):

过滤键匹配对象说明
configconfig名称或 ID
containercontainer名称或 ID
daemondaemon名称或 ID
event事件动作如stop、start
image镜像repository 或 tag
label标签label=<key>或label=<key>=<value>
networknetwork名称或 ID
nodenodeID
pluginplugin名称或 ID
scope作用域local或swarm
secretsecret名称或 ID
serviceservice名称或 ID
type对象类型container、image、volume、network、daemon、plugin、service、node、secret、config
volumevolume名称

3.1 过滤器在服务端的实现

CLI 端把过滤器参数序列化进filters查询参数(见 client/events.go,filters.ToParamWithVersion),服务端在 system_routes.go 中通过filters.FromJSON还原,并传入backend.SubscribeToEvents。

真正的匹配逻辑在 daemon/events/filter.go 的Include方法中,一次事件要经过一长串 AND 条件的逐项检查:event、type、scope、daemon、container、plugin、volume、network、image、node、service、secret、config、label。几个实现细节非常值得注意:

  • event匹配对health_status、exec_create、exec_start使用FuzzyMatch(模糊匹配)而非精确匹配,以兼容旧格式事件(源码注释引用了 issue #25798);
  • container/network/plugin/volume等通过fuzzyMatchName同时匹配事件的Actor.ID与Actor.Attributes["name"],因此既可按 ID 也可按名称过滤;
  • image过滤对事件 ID、image属性名、以及用 reference.ParseNormalizedNamed 去 tag 后的仓库名进行四重精确匹配,确保“从某镜像创建的容器”也能被该镜像过滤器命中。

3.2 过滤实战示例

# 只显示 stop 事件 $ docker events --filter 'event=stop' # 按镜像过滤(容器事件中的 image 属性也会命中) $ docker events --filter 'image=alpine' # 按容器名/ID 过滤 $ docker events --filter 'container=test' # 多个同键过滤 = OR $ docker events --filter 'container=test' --filter 'container=d9cdb1525ea8' # 不同键组合 = AND $ docker events --filter 'container=test' --filter 'event=stop' # 按类型过滤:卷 $ docker events --filter 'type=volume' 2015-12-23T21:05:28.136212689Z volume create test-event-volume-local (driver=local) 2015-12-23T21:05:28.383462717Z volume mount test-event-volume-local (read/write=true, container=562f...5025, destination=/foo, driver=local, propagation=rprivate) 2015-12-23T21:05:28.650314265Z volume unmount test-event-volume-local (container=562f...5025, driver=local) 2015-12-23T21:05:28.716218405Z volume destroy test-event-volume-local (driver=local) # 按类型过滤:网络 $ docker events --filter 'type=network' 2015-12-23T21:38:24.705709133Z network create 8b11...2c5b (name=test-event-network-local, type=bridge) 2015-12-23T21:38:25.119625123Z network connect 8b11...2c5b (name=test-event-network-local, container=b4be...c54e, type=bridge) # 按类型过滤:插件 $ docker events --filter 'type=plugin' 2016-07-25T17:30:14.825557616Z plugin pull ec7b87f2ce84330fe076e666f17dfc049d2d7ae0b8190763de94e1f2d105993f (name=tiborvass/sample-volume-plugin:latest) 2016-07-25T17:30:14.888127370Z plugin enable ec7b87f2ce84330fe076e666f17dfc049d2d7ae0b8190763de94e1f2d105993f (name=tiborvass/sample-volume-plugin:latest) # Swarm 作用域事件 $ docker events --filter 'scope=swarm' 2017-07-10T07:46:50.250024503Z service create m8qcxu8081woyof7w3jaax6gk (name=affectionate_wilson)

四、自定义输出格式:--format与 JSON Lines

如果指定了--format,给定的模板将替代默认格式执行。模板语法由 Go 标准库的text/template包定义(全部细节见该包文档)。

4.1 模板字段

每条事件消息的结构定义在 api/types/events/events.go 中,模板可访问的主要字段为:

  • {{.Type}}:事件类型,如container、image、network
  • {{.Action}}:事件动作,如create、start、die(容器事件中对应的旧字段是{{.Status}})
  • {{.ID}}:Actor ID(旧字段,对应新结构中的{{.Actor.ID}})
  • {{.Actor}}:Actor 结构体,包含ID与Attributes(map 类型)
  • {{.Scope}}:local或swarm
  • {{.Time}}/{{.TimeNano}}:事件发生时间

CLI 端在 system/events.go 的makeTemplate中解析模板,并通过一次“空消息执行”预校验非法模板(如{{.badFieldString}}),解析失败会返回状态码 64 的StatusError(Error parsing format: ...)。

4.2 示例:自定义模板

$ docker events --filter 'type=container' --format 'Type={{.Type}} Status={{.Status}} ID={{.ID}}' Type=container Status=create ID=2ee349dac409e97974ce8d01b70d250b85e0ba8189299c126a87812311951e26 Type=container Status=attach ID=2ee349dac409e97974ce8d01b70d250b85e0ba8189299c126a87812311951e26 Type=container Status=start ID=2ee349dac409e97974ce8d01b70d250b85e0ba8189299c126a87812311951e26 Type=container Status=resize ID=2ee349dac409e97974ce8d01b70d250b85e0ba8189299c126a87812311951e26 Type=container Status=die ID=2ee349dac409e97974ce8d01b70d250b85e0ba8189299c126a87812311951e26 Type=container Status=destroy ID=2ee349dac409e97974ce8d01b70d250b85e0ba8189299c126a87812311951e26

4.3 输出 JSON Lines

如果--format设置为{{json .}},事件将以JSON Lines(每行一个合法 JSON 对象)的形式流式输出,非常适合交给 jq 等工具做机器化处理:

$ docker events --format '{{json .}}' {"status":"create","id":"196016a57679bf42424484918746a9474cd905dd993c4d0f4.. {"status":"attach","id":"196016a57679bf42424484918746a9474cd905dd993c4d0f4.. {"Type":"network","Action":"connect","Actor":{"ID":"1b50a5bf755f6021dfa78e.. {"status":"start","id":"196016a57679bf42424484918746a9474cd905dd993c4d0f42..

注意示例输出中同时出现了新旧两种字段形态:容器事件同时填充status/id/from等 Deprecated 字段与Type/Action/Actor新字段。这一点在 daemon 端 events.go 的Log方法中可以看到:仅对ContainerEventType与ImageEventType额外填充旧字段(jm.ID = actor.ID、jm.Status = action、jm.From = actor.Attributes["image"]),以保证旧版客户端兼容。

五、事件消息的默认输出格式

不指定--format时,CLI 使用 prettyPrintEvent 渲染默认格式。其输出依次为:

  1. 时间戳:优先TimeNano,其次Time,统一按rfc3339NanoFixed(2006-01-02T15:04:05.000000000Z07:00)格式输出,纳秒零填充以保持固定宽度;
  2. 类型 动作 ActorID;
  3. 若 Actor 存在属性(Attributes),按键名排序后以(key=value, key=value)形式追加在行尾。

例如:

2017-01-05T00:36:09.840186338+08:00 container die 0fdb...ff37 (exitCode=143, image=alpine:latest, name=test)

属性中常见的键包括image(镜像名)、name(对象名)、exitCode(容器退出码)、signal(kill 信号)、driver(卷驱动)、type(网络类型)、read/write、destination、propagation、container(卷/网络关联的容器)等。

六、事件链路源码走读:从发布到渲染

理解docker events的关键在于整条事件管线。以本仓库实现为准,链路如下:

1. 客户端发起订阅

CLI 的runEvents(system/events.go)把 CLI 选项组装成types.EventsOptions,调用dockerCli.Client().Events(ctx, eventOptions)。客户端 API(client/events.go)通过cli.get(ctx, "/events", query, nil)请求 daemon 的 HTTP 接口,用 JSON Decoder 逐条解码事件,送入messageschannel;errschannel 负责传输错误(流读完后会收到io.EOF)。

2. daemon 端订阅与缓冲回放

服务端 getEvents 调用backend.SubscribeToEvents(since, until, ef),返回的buffered切片是历史事件,随后循环enc.Encode(ev)输出到响应流,之后继续从 pub/sub channel 转发新事件,并对响应启用 WriteFlusher 实现实时推送。

SubscribeToEvents的底层实现位于 daemon/events/events.go:loadBufferedEvents从内存环形缓冲取出[since, until]窗口内的历史事件,同时根据过滤器生成 topic 函数,选择pub.Subscribe()或pub.SubscribeTopic(topic)。这里的 pub/sub 基础设施来自pkg/pubsub。

3. 事件产生与广播

daemon 各模块通过 daemon/events.go 中的LogContainerEvent、LogVolumeEvent、LogNetworkEvent、LogPluginEvent、LogDaemonEventWithAttributes等方法,把对象状态变化写入daemon.EventsService。例如容器事件会附带镜像与标签属性(attributes["image"]、container.Config.Labels)。EventsService.Log(daemon/events/events.go)构造带Scope: "local"、Time、TimeNano的events.Message并PublishMessage广播。

4. 缓冲与背压

PublishMessage(daemon/events/events.go)先把事件写入环形缓冲(容量为常量eventsLimit = 256,满员时丢弃最旧事件),再广播给订阅者。pub 通道的发送缓冲为bufferSize = 1024,每个订阅者有 100ms 的接收时限,超时事件会被跳过——这正是事件流“尽力而为”语义的体现。相关行为在 events_test.go 中有TestEventsLog、TestEventsLogTimeout等测试用例覆盖。

5. 客户端渲染

CLI 侧 runEvents 用select同时监听事件 channel 与错误 channel:收到事件就交给handleEvent(模板为空走prettyPrintEvent,否则走formatEvent),收到io.EOF则正常返回结束。

6.1 面向扩展:EventHandler 抽象

CLI 还提供了可复用的 EventHandler 接口:通过InitEventHandler()创建处理器,Handle(action, h)注册特定动作的回调,Watch(ch)消费事件 channel 并异步执行回调。该抽象被docker stats等命令复用(见 container/stats.go 中的command.InitEventHandler()调用),说明事件机制在 CLI 内部也是跨命令共享的基础设施。

七、常见问题与排障建议

  • 为什么docker events没有输出历史事件?不指定--since时只返回订阅时刻之后的新事件;要看历史需给出--since。且 daemon 仅保留内存环形缓冲(本仓库实现中eventsLimit = 256),早于缓冲窗口的历史事件无法回溯。
  • 为什么某些事件丢了?pub/sub 通道缓冲有限(bufferSize = 1024)、每个订阅者 100ms 接收超时即跳过;高事件量场景下订阅处理不及时会丢事件,请优先用--since/--until窗口化拉取。
  • 时区问题:时间戳不带Z或+-00:00偏移时按客户端本地时区解析;跨机器排障时建议显式携带时区偏移或统一使用 UTC。
  • until早于since报错:服务端会返回since time (...) cannot be after until time (...)的 invalidRequestError,需检查两个参数的大小关系。
  • 模板报错Error parsing format:CLI 在 makeTemplate 中会对空消息预执行模板,引用不存在的字段会在命令启动时立即暴露。

八、参考资源

  • 本文骨架来源:man 手册源文档
  • 更完整的官方参考:commandline/events.md
  • CLI 命令实现:system/events.go
  • 客户端 API:client/events.go
  • 时间戳解析:api/types/time/timestamp.go
  • 事件消息结构:api/types/events/events.go
  • daemon 事件服务与过滤:daemon/events/events.go、daemon/events/filter.go
  • 服务端路由:system_routes.go
  • 事件测试用例:daemon/events/events_test.go
  • 容器运行时
  • 云原生

【免费下载链接】docker-ce

:warning: This repository is deprecated and will be archived (Docker CE itself is NOT deprecated) see the https://github.com/docker/docker-ce/blob/master/README.md :warning:

项目地址:https://gitcode.com/gh_mirrors/do/docker-ce
点击查看免费下载
上一篇:msmarco-MiniLM-L-6-v3:快速上手指南 - 如何在5分钟内开始使用这个强大的句子嵌入模型
下一篇:LogicStack-LeetCode 题解精讲:1710. 卡车上的最大单元数——排序 + 贪心的一维容量最优化范式

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 1:59:28

Open-Code-Review实战:构建可自建、可定制的代码评审机制

1. 为什么"代码评审"这件事值得单独拿出来做第一次听到"open-code-review"这个说法&#xff0c;很多人会以为又是一个套壳的代码格式化工具。但真正在团队里做过代码评审的人都知道&#xff0c;评审这件事的痛点从来不在"格式化"上&#xff0c;而…

作者头像 李华
网站建设 2026/10/13 1:59:25

darktable 免费 RAW 处理教程:从导入到导出的完整指南

darktable 免费 RAW 处理教程&#xff1a;从导入到导出的完整指南 【免费下载链接】darktable darktable is an open source photography workflow application and raw developer 项目地址: https://gitcode.com/GitHub_Trending/da/darktable 如果你拍 RAW 却不愿为商…

作者头像 李华
网站建设 2026/10/13 1:59:01

疾病诊断机器学习实战:从数据处理到模型评估的完整避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 1:58:58

直线型一阶倒立摆软件设计:从状态采集到LQR控制的工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华