同步近期 containerd 的高频问题

August 13, 2023

最近 Issue 8698 有用户说容器启动和清理都偏慢,尤其多个 Pod 同时启动时现象特别明显。之前有过类似的问题: containerd 启动容器前,它需要临时挂载 rootfs 来读取 uid/gid 信息。因为挂载的是可写属性的 overlayfs,卸载时内核会强制刷盘。当系统大量的脏页数据需要回写时,这个刷盘动作容易造成系统卡顿。 oci: use readonly mount to read user/group info 已经解决读取 uid/gid 的性能问题了,但这一次是 Pod Init-container 带来的 。

Init-container rootfs 大部分都是可写模式的 overlayfs,如果 Init-container 是做数据预下载的话,那么 containerd 在删除 Init-container 时,内核一定会刷盘。在大部分场景下,同一个节点上的 Pod 共享同一块数据盘,这种不预期的刷盘很容易把系统打崩。还有 Issue 8647 用户说,他的系统一开始还好好的,跑几天就不稳定了。后来查看他提供的日志,发现有几个 Pod 一直启动失败,相当于每隔几秒都要去刷盘,导致整个系统不稳定。

这个问题的最佳解决方案应该是做好 Pod 的存储隔离,但显然这成本确要高不少。然而 Kubernetes 场景下的容器并不会重启,即使在「失败后无限重启」的策略下,kubelet 依然是删除重建,这也意味着容器 rootfs 并不需要持久化。个人觉得,成本最低的解决方案应该是使用 overlayfs-volatile-mount,它需要 Linux Kernel ≥ 5.10。以下是个人目前了解到的情况,大部分云厂家都支持了 overlayfs-volatile。

除此之外,还有 Issue 7496 Issue 8931 用户报告说 umount 刷盘耗时太长导致 containerd-shim 泄露。其实这个问题的根因并不在于 umount,而是 containerd 清理 shim 的流程忽略了一些关键错误,导致上层调用者 (比如 CRI 插件) 没有重试机会,进而出现了 shim 泄露问题。PR 8954 仅修复 umount 超时带来的泄露,但可能会出现因 shim.Shutdown 超时带来的泄露。要完全修复 shim 泄露问题,containerd 应该让上层调用者发起删除,而不是通过异步来做清理。这里涉及到 containerd event 的可靠性以及上游 moby/moby 使用的调整,估计要讨论上一段时间,所以 PR 8954 也仅是降低泄露风险。

如果有遇到该问题的朋友,可以关注下 Cherry-pick: [overlay] add configurable mount options to overlay snapshotter ,尽量使用 volatile 来避免刷盘带来的影响。

containerd v1.7 系列文章的最后一篇被我鸽了,考虑到最近华为云提议的 Sandbox: make sandbox controller plugin 特性还在讨论阶段,等到 v2.0 在补一篇好了。下次一定!