最近 Issue 8698 有用户说容器启动和清理都偏慢,尤其多个 Pod 同时启动时现象特别明显。之前有过类似的问题: containerd 启动容器前,它需要临时挂载 rootfs 来读取 uid/gid 信息。因为挂载的是可写属性的 overlayfs,卸载时内核会强制刷盘。当系统大量的脏页数据需要回写时,这个刷盘动作容易造成系统卡顿。 oci: use readonly mount to read user/group info 已经解决读取 uid/gid 的性能问题了...| Posts on Fu, Wei
之前和苦总/Ace 维护 pouch-container/containerd 的时候,我们遇到比较多的问题是资源泄漏,比如节点负载太高以至于无法 umount 容器根目录(容器 bundle 目录残留),内核 pidns 死锁问题导致容器进程僵尸态( cgroup 残留),还有进程重启导致 CNI 网络资源泄漏等等。对于内核死锁等问题,重启可能是唯一的解决方案;而那些因为短期高负载或者进程重启导致的资源泄漏,它们需要从系...| Posts on Fu, Wei
从 HELM Chart 成功对接容器镜像仓库开始,到近两年 OCI 社区 artifacts 标准化的落地推广,现在 OCI Registry as Storage 已经是事实标准,不同业务场景的数据存储都可以对接 OCI registry 的分发协议。同时,这几年容器镜像的安全供应链需求徒增,以及各大云厂商对容器镜像 lazy-loading 探索力度在加大,OCI 社区在 artifacts 标准的基础上为容器镜像引入 referrers 定义:在保证前后兼容的情...| Posts on Fu, Wei
containerd 1.7 版本有比较多的实验特性。在这里,我会介绍 containerd 对 UserNamespace Stateless Pod 支持的情况,算是个人对 containerd 1.7 版本特性介绍系列的开篇。 1. UserNamespace 安全特性 Linux 内核是基于进程的 credentials(7) 凭证来做访问控制,比如进程的拥有者标识 UID/GID 和用于系统资源访问控制判定的 Effective UID/GID 等凭证。而 user_namespace(7) 提供了安全隔离特性。在不同的 user namespa...| Posts on Fu, Wei
背景 在 Linux 平台上,大部分情况下会使用 OverlayFS 文件系统来管理容器镜像存储,而 OverlayFS 文件的特点也比较符合容器场景使用:它不仅可以将多个目录合并成统一的访问视图,还能做到读写分离。 mount -t overlay overlay \ -olowerdir=/lower1:/lower2:/lower3,upperdir=/upper,workdir=/work \ /merged 如上面的挂载命令所示, lowerdir 代表着容器镜像层解压后的目录。从 OCI Image 标准 定义来看,容器...| Posts on Fu, Wei
在 containerd 自定义插件 embedshim 项目里,我借助了 Linux 内核里的 trace_sched_process_exit 观测能力,并利用 eBPF Map 记录和持久化容器进程退出事件。 这类观测能力依赖内核在关键代码路径上提前定义好钩子,它属于静态观测技术,任何变化都需要重新编译 Linux 内核。 如果我们想观测内核中的某一个关键函数或者某一行关键代码时,我们可以选择 kprobe 或者 ftrace 这类动态观测技...| Posts on Fu, Wei
在 2019 年的时候,当时所在的团队正在开始大规模使用 containerD,我们初期遇到较多 containerd-shim 的死锁等稳定性问题,我们不得不去思考去除 containerd-shim 进程的可能性。由于当时技术选型上的限制,containerd-shim 必须作为容器 subreaper 而存在。直到去年才留意到 pidfd pollable,我才发现 containerd-shim 管控面其实是可以被移除。我顺着这个思路作出了 embedshim 这个 containerD 第三方...| Posts on Fu, Wei
在上一篇 eBPF Loader 中介绍了 eBPF 加载器的工作原理。Compile-Once Run-Everywhere (CO-RE) 是目前社区的发力方向,但它要求内核版本支持 CONFIG_DEBUG_INFO_BTF=y 特性。除了 REHL 等商业公司会回合高版本特性到当前支持的商业版本之外,大部分社区免费版本都要求 >= 5.5 版本的内核。为了能在当前主流的 4.14, 4.15, 4.18, 4.19 内核版本上支持 eBPF CO-RE 特性, Aqua Security 的工程师在 2021 Linux Plumber...| Posts on Fu, Wei
Linux Kernel 提供 Semaphore/Mutex 来实现线程间的同步机制,可保证在同一个时间段 只有少量的线程可以访问同一块资源(也称为进入临界区域)。 线程之间要通过竞争来获得访问权限,一旦竞争失败,线程会进入到阻塞状态; 而阻塞的线程只能等待离开临界区域被内核唤醒。 go runtime 提供的 sync.Mutex 并不是采用内核级别的同步机制。 作为执行单元的线程一旦阻塞,意味该线程...| Posts on Fu, Wei
写过 Go 代码的同学都知道,在程序内启动多个 goroutine 处理任务是很常见的事情, 启动一个 goroutine 要比启动一个线程简单的多。当多个 goroutine 同时处理同一份数据时, 我们应该在代码中加入同步机制,保证多个 goroutine 按照一定顺序来访问数据, 不然就会出现 data race。 最常见的例子如下,同时写操作 map 数据会导致程序 panic,即使操作的是不同 key: // example 1 package main ...| Posts on Fu, Wei
想当初,为了看 Operating Systems: Three Easy Pieces 和 A Philosophy of Software Design 原版技术书,还特别麻烦了朋友从国外人肉带回来,成本极高。 但如果等国内出版社引进,就会出现时间跨度太大没法尝鲜;加上翻译水平参差不齐,等待中文版的路子基本上行不通。 为了解决这个尴尬问题,最近找到了一个比较实惠看国外原版书籍的方式:ACM Professional Membership。 ACM Professional Membership...| Posts on Fu, Wei
前段时间因为 KubeCon 演讲去了趟西班牙-巴塞罗那,忙里偷闲,感受了下西方文化。 不再是「白本」 5.18 号从杭州出发,途径香港转机到巴塞罗那。飞机上的娱乐设施还算丰富,「海王」、「绿皮书」等新片都可以观看到。十几个小时的飞机总不能一直看电影,还得兼顾倒时差的任务。 之前没有调整时差的经验,加上平时作息比较规律,十三个小时的飞行过程里相对属于清...| Posts on Fu, Wei
不知不觉就过了三年,但是我还能很清楚地记得当时签卖身契的场景,只能说毕业之后时间过的飞起。这三年没写过什么年度总结,今天打算矫情一把,记下流水账。 Vimer 有一次参加罗老师开发环境的分享会后,我就开始迷上 vim,并结束了 IDE/Sublime 之间的摇摆。从实用角度看,IDE 有着开箱即用的特点,这的确让人无法抗拒。但在平时的工作里,不同语言之间切换是常有的...| Posts on Fu, Wei
Goroutine 是 Golang 世界里的 Lightweight Thread 。 Golang 在语言层面支持多线程,代码可以通过 go 关键字来启动 Goroutine ,调用者不需要关心调用栈的大小,函数上下文等等信息就可以完成并发或者并行操作,加快了我们的开发速度。 分析 Goroutine 调度有利于了解和分析 go binary 的工作状况,所以接下来的内容将分析 runtime 中关于 Goroutine 调度的逻辑。 以下内容涉及到的代码是基于 g...| Posts on Fu, Wei
Protobuf 是 G 厂开源的序列化数据的方法,可用来通信或者存储数据。它采用 IDL 描述数据接口,使得不同语言编写的程序可以根据同一接口通信。不同编程语言也可以根据 IDL 的描述来生成对应数据结构,该数据结构用来编解码。为此,G 厂为主流开发语言都提供代码生成器(即 protoc )。 为了更好地了解一些细节,本文将主要描述 Protobuf 3.0 的编码规则。 Protobuf 里面主要采...| Posts on Fu, Wei
Go 不需要像 Java 那样显式地使用 implement 说明某一数据类型实现了 interface,只要某一数据类型实现了 interface 所定义的方法名签,那么就称该数据类型实现了 interface。interface 的语言特性可以容易地做到接口定义和具体实现解耦分离,并将注意力转移到如何使用 interface ,而不是方法的具体实现,我们也称这种程序设计为 Duck Typing。文本将描述 Go 是如何通过 interface 来实现 Duck...| Posts on Fu, Wei
刚开始接触 shell 脚本的时候,最痛苦的地方在于出了问题,却不容易定位问题。 shell 脚本遇到错误,“大部分” 情况下都会继续执行剩下的命令,最后返回 Zero Exit Code 并不代表着结果正确。 这让人很难发现问题,它不像其他脚本语言,遇到 语法错误 和 typo 等错误时便会立即退出。 如果想要写出容易维护、容易 debug 的 shell 脚本,我们就需要让 shell 脚本变得可控。 set -e ...| Posts on Fu, Wei
写脚本的时候通常会在脚本的开头加上 shebang, 系统会将这段内容作为解释器指令,比如 bash shell 脚本。 $> cat example #!/usr/bin/bash echo "HaHa" $> chmod +x ./example $> ./example HaHa 只要为脚本添加了可执行的属性,那么内核在执行脚本的时候,会调用 shebang 描述的解释器来执行脚本。 ./exmaple 其实等价于 /usr/bin/bash ./example。shebang 描述的解释器需要写其绝对路径或者相对路径,因为内核并...| Posts on Fu, Wei
在 GO 1.23 版本中,GO Linker 将来会限制 //go:linkname 直接引用标准库中不可访问的对象。 看到这个消息后,我立刻用 GO 1.23.0 编译了 containerd,发现即使不加 -checklinkname=0 也能正常工作。 之前为了支持 ID-mapped mount, 我在 containerd 项目里使用了 GO runtime 的隐藏功能,算是语言层面的灵活运用。 现在可倒好,GO 团队直接在代码里把 containerd 列为 Hall of shame 成员。 这种强行拉入群的...| Fu, Wei
etcd-io/etcd#17615| fuweid