Kubernetes 1.19.3
OS: CentOS 7.9.2009
Kernel: 5.4.94-1.el7.elrepo.x86_64
Docker: 20.10.6
先说结论,runc v1.0.0-rc93 有 bug,会导致 docker hang 住。
发现问题
线上告警提示集群中存在 2-3 个 K8s 节点处于 NotReady 的状态,并且 NotReady 状态一直持续。
- kubectl describe node,有 NotReady 相关事件。
-
登录问题机器后,查看节点负载情况,一切正常。
-
查看 kubelet 日志,发现 PLEG 时间过长,导致节点被标记为 NotReady。
-
docker ps 正常。
-
执行 ps 查看进程,发现存在几个 runc init 的进程。runc 是 containerd 启动容器时调用的 OCI Runtime 程序。初步怀疑是 docker hang 住了。
要解决这个问题可以通过两种方法,首先来看一下 A 方案。
解决方案 A
针对 docker hang 住这样的现象,通过搜索资料后发现了以下两篇文章里也遇到了相似的问题:
-
docker hang 问题排查[https://www.likakuli.com/posts/docker-hang/]
-
Docker hung 住问题解析系列(一):pipe 容量不够[https://juejin.cn/post/6891559762320703495]
这两篇文章都提到了是由于 pipe 容量不够导致 runc init 往 pipe 写入卡住了,将 /proc/sys/fs/pipe-user-pages-soft 的限制放开,就能解决问题。
于是,查看问题主机上 /proc/sys/fs/pipe-user-pages-soft 设置的是 16384。所以将它放大 10 倍 echo 163840 > /proc/sys/fs/pipe-user-pages-soft,然而 kubelet 还是没有恢复正常,pleg 报错日志还在持续,runc init 程序也没有退出。
考虑到 runc init 是 kubelet 调用 CRI 接口创建的,可能需要将 runc init 退出才能使 kubelet 退出。而根据文章中的说明,只需要将对应的 pipe 中的内容读取掉,runc init 就能退出。因为读取 pipe 的内容可以利用「UNIX/Linux 一切皆文件」的原则,通过 lsof -p 查看 runc init 打开的句柄信息,获取写入类型的 pipe 对应的编号(可能存在多个),依次执行 cat /proc/