- 容器运行时
- 云原生
【免费下载链接】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:
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最常用的两个参数。二者支持三类输入格式:
- Unix 时间戳:
秒[.纳秒],其中秒是从 1970 年 1 月 1 日(UTC/GMT 午夜)起经过的秒数,不含闰秒(即 Unix epoch / Unix time);可选的.nanoseconds是秒的小数部分,最多 9 位。 - 日期格式化时间戳:支持 RFC3339Nano、RFC3339、
2006-01-02T15:04:05、2006-01-02T15:04:05.999999999、2006-01-02Z07:00、2006-01-02。 - 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中:
- 用 ParseTimestamps 把
since/until字符串解析为time.Time; - 校验
until.Before(since)时返回invalidRequestError; - 若
until晚于当前时间,则启动一个定时器(time.NewTimer(dur)),到点后结束流; - 若
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 源文档给出的全部支持键如下(来自 参考文档 的完整列表):
| 过滤键 | 匹配对象 | 说明 |
|---|---|---|
config | config | 名称或 ID |
container | container | 名称或 ID |
daemon | daemon | 名称或 ID |
event | 事件动作 | 如stop、start |
image | 镜像 | repository 或 tag |
label | 标签 | label=<key>或label=<key>=<value> |
network | network | 名称或 ID |
node | node | ID |
plugin | plugin | 名称或 ID |
scope | 作用域 | local或swarm |
secret | secret | 名称或 ID |
service | service | 名称或 ID |
type | 对象类型 | container、image、volume、network、daemon、plugin、service、node、secret、config |
volume | volume | 名称 |
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=2ee349dac409e97974ce8d01b70d250b85e0ba8189299c126a87812311951e264.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 渲染默认格式。其输出依次为:
- 时间戳:优先
TimeNano,其次Time,统一按rfc3339NanoFixed(2006-01-02T15:04:05.000000000Z07:00)格式输出,纳秒零填充以保持固定宽度; 类型 动作 ActorID;- 若 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:
相关推荐
Docker `events` 命令完全指南:实时事件流、过滤与格式化实战
Docker events 命令完全指南:实时事件流、过滤与格式化实战 导读 docker events 是 Docker CLI 中用于实时获取引擎(daem
容器运行时云原生Docker CLI 事件监控指南:`docker events` 命令的实时事件流、过滤器与格式化详解
Docker CLI 事件监控指南: docker events 命令的实时事件流、过滤器与格式化详解 导读 docker events 是 Docker CL
CLI开发工具Docker CLI `docker plugin ls` 命令完全指南:插件列表、过滤与自定义格式化输出
Docker CLI docker plugin ls 命令完全指南:插件列表、过滤与自定义格式化输出 导读 docker plugin ls 是 Docker
CLI开发工具
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考