2. 容器运行时基础:Docker 与 containerd 运行时架构对比
在自动化流水线中,容器运行时是事件监听与触发的核心执行层。理解 Docker 与 containerd 的架构差异,有助于精准设计事件源、Hook 挂载点以及触发链路。本章从组件分层、进程模型、事件机制三个维度进行对比。
2.1 架构演进:从单体到分层
Docker 1.11 之前采用单体运行时架构,所有容器操作由 dockerd 进程直接调用底层 Linux 系统接口。从 1.11 开始,Docker 引入 containerd 作为容器生命周期管理中间层,形成三层解耦架构:
- Docker CLI / API:用户交互与编排入口。
- dockerd:镜像构建、网络、存储卷、Swarm 编排等上层逻辑。
- containerd:容器生命周期管理(创建、启动、停止、删除)、镜像拉取与存储。
- runc:OCI 运行时规范实现,负责实际创建容器进程。
关键认知: containerd 是 Docker 生态中的核心组件,但也可以独立运行,被 Kubernetes 通过 CRI(Container Runtime Interface)直接调用。当前主流 Kubernetes 集群默认使用 containerd 作为运行时。
2.2 架构对比:Docker 与 containerd
以下表格从组件、进程模型、事件接口、适用场景四个维度进行对比:
| 对比维度 | Docker 运行时 | containerd 运行时 |
|---|---|---|
| 核心进程 | dockerd(守护进程)+ containerd + containerd-shim + runc | containerd(守护进程)+ containerd-shim + runc |
| 组件数量 | 4 层(CLI → dockerd → containerd → runc) | 3 层(ctr/CRI → containerd → runc) |
| 事件接口 | Docker Events API(/events 端点) | containerd Event Service(gRPC + 命名空间隔离) |
| 镜像管理 | dockerd 负责镜像拉取、构建、推送 | containerd 内置镜像拉取与快照管理 |
| 网络与存储 | dockerd 通过 libnetwork 管理网络,通过 volume driver 管理存储 | 不直接管理网络与存储,由上层(Kubernetes 或 Docker)通过 CNI/CSI 接入 |
| 事件粒度 | 容器、镜像、网络、卷、插件等全量事件 | 容器生命周期事件(创建、启动、退出、删除)+ 任务事件 |
| 适用场景 | 开发环境、单机编排、Docker Compose、Swarm | 生产级 Kubernetes 集群、边缘计算、嵌入式容器 |
2.3 进程模型与事件链路
下图展示了 Docker 与 containerd 在事件监听链路中的进程关系:
事件监听建议: 在 containerd 环境中,事件订阅通过
containerd.WithEventService() 客户端选项建立 gRPC 流式连接,事件类型包括 container/create、container/start、container/exit 等。Docker 环境则使用 docker events --filter 命令或 SDK 的 client.Events() 方法。
2.4 事件订阅方式对比
两种运行时的事件订阅在接口协议、过滤能力、性能表现上存在显著差异:
| 特性 | Docker Events | containerd Events |
|---|---|---|
| 协议 | HTTP Streaming(Chunked Transfer) | gRPC Server-Side Streaming |
| 事件格式 | JSON 对象(含 Type、Action、Actor) | protobuf 序列化(Event 结构体) |
| 过滤方式 | URL 参数:--filter 'event=start' |
gRPC 元数据 + 服务端过滤器 |
| 命名空间 | 无原生命名空间隔离 | 支持多命名空间(Kubernetes 按 Pod 隔离) |
| 事件持久化 | 默认不持久化,断开后丢失 | 可配置事件存储后端(如 BoltDB) |
| 订阅示例 | curl -N --unix-socket /var/run/docker.sock http://v1.41/events |
ctr events 或 gRPC 客户端订阅 |
2.5 事件触发场景对比
在自动化流水线中,不同运行时的事件触发能力直接影响监听方案设计:
- 容器启动事件:Docker 通过
start动作触发;containerd 通过container/start主题触发。 - 容器退出事件:Docker 通过
die动作(含退出码);containerd 通过container/exit事件(含退出码与时间戳)。 - 镜像拉取事件:Docker 通过
pull动作;containerd 通过images/create事件。 - 健康检查事件:Docker 通过
health_status动作;containerd 不直接提供,需上层应用实现。
注意: containerd 的事件主题命名采用
<资源类型>/<动作> 格式(如 container/create、task/start),而 Docker 使用扁平化的动作名称(如 create、start)。在编写事件监听适配层时,需要做主题映射转换。
2.6 选择建议
根据流水线部署环境选择运行时:
| 环境类型 | 推荐运行时 | 理由 |
|---|---|---|
| Kubernetes 集群(生产) | containerd | CRI 原生支持、事件命名空间隔离、资源占用更低 |
| Docker Compose 开发环境 | Docker | 生态完善、调试方便、事件类型丰富 |
| 边缘计算 / IoT | containerd | 组件精简、内存占用小、适合资源受限设备 |
| 混合架构(K8s + 传统 Docker) | 双运行时适配 | 事件监听层需要抽象统一接口,屏蔽底层差异 |