news 2026/9/13 16:23:00

containerd 2017-03-17 开发报告解读:首个端到端镜像拉取与容器 Prometheus 指标的诞生

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
containerd 2017-03-17 开发报告解读:首个端到端镜像拉取与容器 Prometheus 指标的诞生

containerd 2017-03-17 开发报告解读:首个端到端镜像拉取与容器 Prometheus 指标的诞生

【免费下载链接】containerdAn open and reliable container runtime项目地址: https://gitcode.com/GitHub_Trending/co/containerd

这篇技术文章基于 containerd 历史开发报告 docs/historical/reports/2017-03-17.md,完整梳理 containerd 2017 年 3 月 17 日周报中记录的四项里程碑:多平台测试计划、Windows 运行时移植启动、基于 Prometheus 的容器级指标导出,以及首个"端到端镜像拉取"概念验证(dist pull/dist images/ctr run)。文章同时对照当前仓库中的源码(如 core/metrics/cgroups/cgroups.go、cmd/ctr/commands/images/pull.go、client/pull.go),说明 2017 年埋下的这些能力如何在今天的 containerd 中落地演化,帮助读者理解 containerd 从"理论架构"走向"可运行系统"的关键转折点。

一、背景:containerd 周报体系与这份报告的地位

containerd 在 2017 年上半年以双周开发报告(Development Report)的形式记录进展,完整系列保存在 docs/historical/reports/ 目录下(从 2017-01-13 到 2017-06-23 共 14 份)。2017-03-17 这一期之所以关键,是因为它标志着 containerd 从"各子系统分别开发"进入了"子系统端到端串联"阶段——报告原文明确指出:

Up to this point, the relationship between subsystems has been somewhat theoretical.

(此前,各子系统之间的关系还多少停留在理论层面。)

而这份报告中的 Image Pull 章节,第一次让 fetching(内容拉取)、snapshot drivers(快照驱动)、rootfs service(根文件系统服务)、image metadata(镜像元数据)与 execution service(执行服务)五个部分在一条真实命令链中被同时调用,验证了 containerd 提出的整体模型。

二、Testing Plan:面向 ARM、Windows、Linux、Power 的 CI 战略

报告开头讨论的是测试计划(Testing Plan)。作者感谢 @gianarb 发起了 containerd 测试与 CI 计划的讨论,核心动机是让用户能够"安心地依赖 containerd"(feel secure depending on containerd)。

报告点出了 containerd 测试的特殊困难:它需要覆盖的系统平台非常多,当时已列出的支持平台包括ARM、Windows、Linux、Power,以及更多变体。这与 containerd 作为"底层容器运行时"的定位一致——它不像应用框架可以选择性地支持操作系统,而是必须跟随 OCI 生态覆盖几乎所有主流架构。报告中提到的测试计划讨论在 containerd 社区的 issue #634 中进行(原文以外链给出,此处不复述),社区贡献者可围绕 CI 平台矩阵持续补充。

从当前仓库结构看,多平台支持至今仍是主线:构建系统按平台拆分为 Makefile.linux、Makefile.darwin、Makefile.freebsd、Makefile.windows,默认路径逻辑也按平台拆分在 defaults/defaults_linux.go、defaults/defaults_darwin.go、defaults/defaults_windows.go 等文件中,印证了 2017 年"平台矩阵"这一测试难题的长期性。

三、Windows Runtime:执行代码移植启动

报告确认 Windows 运行时的执行代码移植(porting over the Windows execution code)已经启动,移植完成后还有大量测试要做,PR 即将提交。

这一条对应的是 containerd 早期"先 Linux 后 Windows"的演进路线。从源码结构看,当前仓库中 Windows 相关能力已相当完整:执行层有 pkg/cio/io_windows.go(Windows 控制台/管道 IO 处理)、pkg/os/ 下的 Windows 实现、挂载层有 core/mount/mount_windows.go、core/diff/stream_windows.go,集成测试目录中也存在 integration/client/client_windows_test.go、integration/sandbox_clean_remove_windows_test.go 等 Windows 专项用例。可以说,2017-03 这次"移植启动"的 PR 正是后来这些 Windows 实现的起点。

四、Metrics:容器级指标首次通过 Prometheus 导出

这是本报告信息量最大的部分。2017 年 3 月,团队启动了"将容器级指标通过 Prometheus 导出"的工作,报告贴出了当时的完整初始输出(以id="test"的容器为例):

containerd_container_blkio_io_service_bytes_recursive_bytes{id="test",major="8",minor="0",op="Async"} 958464 containerd_container_blkio_io_service_bytes_recursive_bytes{id="test",major="8",minor="0",op="Read"} 958464 containerd_container_blkio_io_service_bytes_recursive_bytes{id="test",major="8",minor="0",op="Sync"} 0 containerd_container_blkio_io_service_bytes_recursive_bytes{id="test",major="8",minor="0",op="Total"} 958464 containerd_container_blkio_io_service_bytes_recursive_bytes{id="test",major="8",minor="0",op="Write"} 0 containerd_container_blkio_io_serviced_recursive_total{id="test",major="8",minor="0",op="Async"} 17 containerd_container_blkio_io_serviced_recursive_total{id="test",major="8",minor="0",op="Read"} 17 containerd_container_blkio_io_serviced_recursive_total{id="test",major="8",minor="0",op="Sync"} 0 containerd_container_blkio_io_serviced_recursive_total{id="test",major="8",minor="0",op="Total"} 17 containerd_container_blkio_io_serviced_recursive_total{id="test",major="8",minor="0",op="Write"} 0 containerd_container_cpu_kernel_nanoseconds{id="test"} 1e+07 containerd_container_cpu_throttle_periods_total{id="test"} 0 containerd_container_cpu_throttled_periods_total{id="test"} 0 containerd_container_cpu_throttled_time_nanoseconds{id="test"} 0 containerd_container_cpu_total_nanoseconds{id="test"} 2.1428791e+07 containerd_container_cpu_user_nanoseconds{id="test"} 0 containerd_container_hugetlb_failcnt_total{id="test",page="1GB"} 0 containerd_container_hugetlb_failcnt_total{id="test",page="2MB"} 0 containerd_container_hugetlb_max_bytes{id="test",page="1GB"} 0 containerd_container_hugetlb_max_bytes{id="test",page="2MB"} 0 containerd_container_hugetlb_usage_bytes{id="test",page="1GB"} 0 containerd_container_hugetlb_usage_bytes{id="test",page="2MB"} 0 containerd_container_memory_active_anon_bytes{id="test"} 0 containerd_container_memory_active_file_bytes{id="test"} 659456 containerd_container_memory_cache_bytes{id="test"} 925696 containerd_container_memory_dirty_bytes{id="test"} 0 containerd_container_memory_hierarchical_memory_limit_bytes{id="test"} 9.223372036854772e+18 containerd_container_memory_hierarchical_memsw_limit_bytes{id="test"} 9.223372036854772e+18 containerd_container_memory_inactive_anon_bytes{id="test"} 73728 containerd_container_memory_inactive_file_bytes{id="test"} 266240 containerd_container_memory_kernel_failcnt_total{id="test"} 0 containerd_container_memory_kernel_limit_bytes{id="test"} 9.223372036854772e+18 containerd_container_memory_kernel_max_bytes{id="test"} 0 containerd_container_memory_kernel_usage_bytes{id="test"} 0 containerd_container_memory_kerneltcp_failcnt_total{id="test"} 0 containerd_container_memory_kerneltcp_limit_bytes{id="test"} 9.223372036854772e+18 containerd_container_memory_kerneltcp_max_bytes{id="test"} 0 containerd_container_memory_kerneltcp_usage_bytes{id="test"} 0 containerd_container_memory_mapped_file_bytes{id="test"} 577536 containerd_container_memory_oom_total{id="test"} 0 containerd_container_memory_pgfault_bytes{id="test"} 770 containerd_container_memory_pgmajfault_bytes{id="test"} 6 containerd_container_memory_pgpgin_bytes{id="test"} 651 containerd_container_memory_pgpgout_bytes{id="test"} 407 containerd_container_memory_rss_bytes{id="test"} 73728 containerd_container_memory_rss_huge_bytes{id="test"} 0 containerd_container_memory_swap_failcnt_total{id="test"} 0 containerd_container_memory_swap_limit_bytes{id="test"} 9.223372036854772e+18 containerd_container_memory_swap_max_bytes{id="test"} 1.527808e+06 containerd_container_memory_swap_usage_bytes{id="test"} 999424 containerd_container_memory_total_active_anon_bytes{id="test"} 0 containerd_container_memory_total_active_file_bytes{id="test"} 659456 containerd_container_memory_total_cache_bytes{id="test"} 925696 containerd_container_memory_total_dirty_bytes{id="test"} 0 containerd_container_memory_total_inactive_anon_bytes{id="test"} 73728 containerd_container_memory_total_inactive_file_bytes{id="test"} 266240 containerd_container_memory_total_mapped_file_bytes{id="test"} 577536 containerd_container_memory_total_pgfault_bytes{id="test"} 770 containerd_container_memory_total_pgmajfault_bytes{id="test"} 6 containerd_container_memory_total_pgpgin_bytes{id="test"} 651 containerd_container_memory_total_pgpgout_bytes{id="test"} 407 containerd_container_memory_total_rss_bytes{id="test"} 73728 containerd_container_memory_total_rss_huge_bytes{id="test"} 0 containerd_container_memory_total_unevictable_bytes{id="test"} 0 containerd_container_memory_total_writeback_bytes{id="test"} 0 containerd_container_memory_unevictable_bytes{id="test"} 0 containerd_container_memory_usage_failcnt_total{id="test"} 0 containerd_container_memory_usage_limit_bytes{id="test"} 9.223372036854772e+18 containerd_container_memory_usage_max_bytes{id="test"} 1.527808e+06 containerd_container_memory_usage_usage_bytes{id="test"} 999424 containerd_container_memory_writeback_bytes{id="test"} 0 containerd_container_per_cpu_nanoseconds{cpu="0",id="test"} 7.530139e+06 containerd_container_per_cpu_nanoseconds{cpu="1",id="test"} 4.586408e+06 containerd_container_per_cpu_nanoseconds{cpu="2",id="test"} 5.076059e+06 containerd_container_per_cpu_nanoseconds{cpu="3",id="test"} 4.236185e+06 containerd_container_pids_current{id="test"} 1 containerd_container_pids_limit{id="test"} 0

这些指标覆盖了四个 cgroup 资源域:

  • blkio:块设备 IO 的服务字节数与请求次数,按 major/minor 设备和 op(Async/Read/Sync/Total/Write)维度打标;
  • cpu:内核态/用户态/总 CPU 时间(纳秒)、CFS 配额限流计数(throttle_periods、throttled_time)、按核的 per_cpu_nanoseconds;
  • memory:匿名页/文件页的 active/inactive 状态、cache、dirty、mapped_file、page fault/PGIN/PGOUT、RSS、swap 用量与限额、hugetlb(2MB/1GB 大页)用量、OOM 计数等;
  • pids:当前进程数与进程数上限。

报告给出了两条关键设计决策:

  1. id标签即容器 ID,用户可据此过滤只关心的容器;
  2. 采集频率完全由 Prometheus 抓取周期决定。每次/metricsAPI 被命中时才采集容器指标,containerd 内部没有定时器——"If you never ask for metrics the collection never happens"(从不请求就从不采集)。这是一种典型的"按需付费"(pay only when you ask)设计,避免了常驻采集线程的固定开销。

报告同时预告了 PR 即将提交,以便社区讨论指标与标签命名。

在今天的源码中:TaskMonitor 插件与no_prometheus开关

2017 年这次"初始输出"对应的设计,如今已沉淀为正式的 cgroups 监控插件。在 core/metrics/cgroups/cgroups.go 中可以看到:

  • 插件以TaskMonitorPlugin类型、IDcgroups注册,并依赖EventPlugin(通过容器 create/delete 事件决定监控的 cgroup 生命周期);
  • 配置只有一个开关NoPrometheus(TOML 键no_prometheus):为 false 时创建metrics.NewNamespace("container", ...)并注册到全局指标表,为 true 时仅采集不上报——这正是对"按需付费"理念的配置化体现;
  • 实现按 cgroup 版本分流:cgroups.Mode() == cgroups.Unified时选择 core/metrics/cgroups/v2 的NewTaskMonitor,否则使用 v1 版本,分别读取 cgroup v1/v2 的 cgroupfs 统计文件。

另一个细节是命名空间:core/metrics/metrics.go 的init()中注册了containerd命名空间,并暴露build_info计数器(含 version、revision 两个 label),同时定义了ShimStatsRequestTimeoutio.containerd.timeout.metrics.shimstats,默认 2 秒)这个超时键——从源码结构看,这意味着当前的指标体系除了 cgroup 统计,还包含向 shim 发起 Stats RPC 的路径,这是 2017 年"直接读 cgroupfs"阶段之后的自然扩展。

需要注意一个演进差异:2017 年报告中的指标名以containerd_container_开头(如containerd_container_cpu_total_nanoseconds),而当前插件创建的命名空间前缀是container(即container_cpu_*这类名字);从源码结构看,这反映了多年间指标命名规范的调整,直接引用旧文档指标名的既有监控规则需要重新核对。

五、Image Pull:首个端到端拉取的概念验证

报告后半部分是 PR #640 带来的成果:containerd 首次实现了端到端拉取的 proof of concept。它串联了 fetching、snapshot 驱动、rootfs 服务、镜像元数据与执行服务,验证了 containerd 的子系统模型;报告也坦承存在若干待办,例如需要将部分访问逻辑移入 gRPC service。

5.1dist pull:完整拉取并展开根文件系统

dist pull是当时docker pull/git pull的对应物:对一个镜像执行完整的资源拉取,并把根文件系统展开进 snapshot 驱动。报告给出的原始输出:

$ sudo ./bin/dist pull docker.io/library/redis:latest docker.io/library/redis:latest: resolved |++++++++++++++++++++++++++++++++++++++| manifest-sha256:4c8fb09e8d634ab823b1c125e64f0e1ceaf216025aa38283ea1b42997f1e8059: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:3b281f2bcae3b25c701d53a219924fffe79bdb74385340b73a539ed4020999c4: done |++++++++++++++++++++++++++++++++++++++| config-sha256:e4a35914679d05d25e2fccfd310fde1aa59ffbbf1b0b9d36f7b03db5ca0311b0: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:4b7726832aec75f0a742266c7190c4d2217492722dfd603406208eaa902648d8: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:338a7133395941c85087522582af182d2f6477dbf54ba769cb24ec4fd91d728f: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:83f12ff60ff1132d1e59845e26c41968406b4176c1a85a50506c954696b21570: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:693502eb7dfbc6b94964ae66ebc72d3e32facd981c72995b09794f1e87bac184: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:622732cddc347afc9360b4b04b46c6f758191a1dc73d007f95548658847ee67e: done |++++++++++++++++++++++++++++++++++++++| layer-sha256:19a7e34366a6f558336c364693df538c38307484b729a36fede76432789f084f: done |++++++++++++++++++++++++++++++++++++++| elapsed: 1.6 s total: 0.0 B (0.0 B/s) INFO[0001] unpacking rootfs

输出中每行对应一个 OCI 内容对象:先resolved镜像引用,再依次完成 manifest、config blob 与 6 个 layer 的下载,最后一行unpacking rootfs表明根文件系统正在展开到快照驱动——报告指出当时展开进度尚未并入状态输出,但整体已经"差不多就是今天 docker 的样子"。

5.2dist images:镜像元数据视图

拉取完成后,用dist images查看结果:

$ sudo ./bin/dist images REF TYPE DIGEST SIZE docker.io/library/redis:latest application/vnd.docker.distribution.manifest.v2+json sha256:4c8fb09e8d634ab823b1c125e64f0e1ceaf216025aa38283ea1b42997f1e8059 1.8 kB

表格四列分别是引用名(REF)、镜像清单类型(TYPE)、摘要(DIGEST)与大小(SIZE)。报告特别说明:此时 SIZE 显示的是 manifest 的大小而非整个镜像的大小,后续可按需补充;同时预告了命名模型的几个待完善点——例如希望同时按 hash 限定名和 tag 版本索引同一个镜像,这些工作将在元数据存储(metadata store)开发中推进。

5.3ctr run:第一次真正跑起 redis

拉下来的镜像名可直接用于运行容器:

$ sudo ./bin/ctr run --id foo docker.io/library/redis:latest /usr/local/bin/redis-server 1:C 17 Mar 17:20:25.316 # Warning: no config file specified, using the default config. In order to specify a config file use /usr/local/bin/redis-server /path/to/redis.conf 1:M 17 Mar 17:20:25.317 * Increased maximum number of open files to 10032 (it was originally set to 1024). ... Redis 3.2.8 (00000000/0) 64 bit ... 1:M 17 Mar 17:20:25.326 * The server is now ready to accept connections on port 6379

(中间的 ASCII 艺术 banner 已省略,完整输出见原文 docs/historical/reports/2017-03-17.md。)

报告对此的定性是:"So, now we are running redis!"——一个真实的 redis 3.2.8 进程以 PID 1 的身份在容器里监听 6379 端口。同时报告诚实地指出了 PoC 的局限:必须在ctr run参数里显式写出容器命令,因为当时还没有从镜像 config(config.cmd)读取命令并转换为 OCI runtime config 的逻辑;报告判断"基础已经打好,补上这个功能应该很直接"。

5.4 对照当前代码:ctr image pull的三步语义没有变

今天对应dist pull的是ctr image pull,其命令定义在 cmd/ctr/commands/images/pull.go。命令描述中明确的三步流程——"1. Fetch all resources into containerd. 2. Prepare the snapshot filesystem with the pulled resources. 3. Register metadata for the image."——与 2017 年报告对dist pull的描述(拉取全部资源 + 展开 rootfs 到 snapshot 驱动 + 记录镜像元数据)一脉相承。

从源码看,当前实现比 2017 年的 PoC 更完整的地方包括:

  • 拉取路径可选:默认走 server 端的 transfer service(client.Transfer),--local则退回客户端本地拉取(content.Fetch),两条路径分别对应 client/pull.go 中Client.Pull与 transfer 服务的协作;
  • 平台选择:支持--platform--all-platforms--skip-metadata,解决 2017 年报告里"命名与索引模型待完善"的遗留问题——现在可以按平台精确拉取内容与元数据;
  • 下载控制--max-concurrent-downloads通过 client/pull.go 中的transfer.WithMaxConcurrentDownloads作用于 resolver,提供并发限制;
  • 进度输出ProgressHandler(cmd/ctr/commands/images/pull.go)按父子节点构建进度树并调用DisplayHierarchy渲染层级化进度条——这正是 2017 年那种"逐项 done + 进度条"输出形态的现代化版本;
  • 展开参数--sync-fs透传给diff.WithSyncFs,在 unpack 时同步文件系统,--print-chainid则打印快照链 chain ID 用于校验。

而 2017 年 PoC 的"已知局限"(不读镜像 config、部分能力未进 gRPC service)在今天的仓库中都已兑现:ctr run相关能力由 client/task.go 与 client/container.go 承担,镜像与内容的访问全部通过 gRPC service(api/services/ 下定义)暴露给远端客户端。

六、小结:一份周报如何映射出 containerd 的演进主线

2017-03-17 这份开发报告的四个章节,恰好对应 containerd 的四条长期主线,且在当前仓库中都能找到延续:

2017-03-17 报告条目当年状态当前仓库中的延续
Testing Plan(多平台 CI)讨论启动按平台拆分的 Makefile 与集成测试(Makefile.linux、integration/client/)
Windows Runtime移植启动pkg/cio/io_windows.go、core/mount/mount_windows.go 等完整 Windows 实现
Prometheus 容器指标初始输出 + 按需采集core/metrics/cgroups/cgroups.go TaskMonitor 插件(cgroup v1/v2、no_prometheus开关)、core/metrics/metrics.go
端到端 Image Pull PoCdist pull/dist images/ctr run跑通 rediscmd/ctr/commands/images/pull.go 的三步 pull 语义、client/pull.go 的 transfer 化实现

阅读这份历史报告的最大价值在于:它展示了 containerd 早期"先验证模型、再逐步产品化"的工程节奏——2017 年 3 月用一条dist pull+ctr run命令链证明架构可行,随后几年再把指标、Windows、元数据、gRPC 化这些报告中的"待办"逐项兑现为今天 core/ 与 client/ 下的正式模块。

【免费下载链接】containerdAn open and reliable container runtime项目地址: https://gitcode.com/GitHub_Trending/co/containerd

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

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

SSM图书馆座位预约系统:五态状态机与事务原子性实现

简介:这是一套面向计算机专业本科生的高分毕业设计实战资源,聚焦图书馆自习室座位数字化管理痛点,提供从需求分析到部署上线的完整解决方案。资源包含1130个文件,涵盖103个Java后端业务逻辑文件、154个JS与123个Vue前端交互脚本、…

作者头像 李华
网站建设 2026/9/13 16:21:02

SpringBoot+MyBatis+Vue学生请假系统设计与全栈实现

简介:这是一套基于Spring Boot的学生网上请假系统完整代码,面向计算机、电子信息等专业的学习者,尤其适合需要完成毕业设计、课程设计或期末大作业的同学。项目采用B/S架构与MVC分层,集成Mybatis、Vue、Ajax等主流技术&#xff0c…

作者头像 李华
网站建设 2026/9/13 16:17:04

MATLAB生成高斯随机粗糙表面:频域滤波原理与参数校准

简介:面向工程与科研场景的 MATLAB 表面粗糙度分析源码包,聚焦基于高斯分布模型的表面形貌数值模拟与参数计算。资源共 4 个 .m 文件,压缩包仅 2KB,核心脚本 zaihe.m 覆盖从数据读取、去噪预处理到高斯拟合及粗糙度参数求解的完整…

作者头像 李华
网站建设 2026/9/13 16:13:30

量化交易入门:Python回测脚手架搭建与MA策略解析

简介:本资源是面向零基础入门者的量化交易Python实践教学包,聚焦数据获取、清洗、分析、策略构建与回测全流程,帮助初学者通过可运行代码理解量化逻辑并动手搭建简易交易系统。压缩包共139个文件,含43个Python脚本(覆盖…

作者头像 李华