k8s-运行时:cgroup内存泄漏
1.背景
kubelet误报内存压力(实际内存使用率很小)->节点被打污点->节点上pod处于驱逐状态->重启kubelet会恢复
;kubelet 和message是有这个错
1.2.2 日志
kubelet日志:
日志中搜索memory:
SLUB日志:
1.2.3 日志
kubelet日志:
"mkdir /svs/fs/caroun/memorv/kubepods/<pod>/<容器>: cannot allocate memory "
2.cgroup
在当前内核版本下,开启了kmem accounting功能,会导致memory cgroup的条目泄漏无法回收。
2.1 cgroup泄漏
内核对于每个cgroup子系统的的条目数是有限制的,限制的大小定义在kernel/cgroup.c(#L139 )。
当pod的yaml中存在request/limit,为pod在cgroup创建一个子目录,条目数加1。
因为开启了kmem accounting功能,删除POD时,虽然删除对应cgroup子目录,但是条目没有回收。最终,条目数量达到上限,导致无法创建cgroup。
2.2 查看当前已使用的cgroup条目
cat /proc/cgroups |awk {if($1~"memory") print $3}
3.解决方案-1
在kubelet层面和docker层面均关闭kmem accounting。
3.1 针对kubelet方面
1)代码中已关闭kmem
/kubernetes/vendor/
func (kl *Kubelet) initializeRuntimeDependentModules() -》 func (cm *containerManagerImpl) Start() → func (cm *containerManagerImpl) setupNode()
--
func ensureSystemCgroups(rootCgroupPath string, manager cgroups.Manager)
func ensureProcessInContainerWithOOMScore(pid int, oomScoreAdj int, manager cgroups.Manager)
-
func (m *manager) Apply(pid int)
func (s *MemoryGroup) Apply()
2) 检查
预期:以下文件不存在
/sys/fs/cgroup/memory/memory.kmem.slabinfo
/sys/fs/cgroup/memory/kubepods/memory.kmem.slabinfo
3.2 针对docker[runc]方面
1)runc编译时,关闭kmem
仓库地址:
commit:425e105d
编译方法:[cent os]
yum install libseccomp-devel
make BUILDTAGS=seccomp apparmor nokmem selinux // ubuntu需要apparmor
增加执行权限:chmod 777
结果:
3) 检查
memory.kmem.slabinfo文件:
注意:检查YAML文件中request、limit的POD中的容器。例如:service-controller。
检查(预期:以下文件夹不存在memory.kmem.slabinfo):
/sys/fs/cgroup/memory/kubepods/pod<ID>/<容器ID>
/sys/fs/cgroup/memory/kubepods/besteffort/pod<ID>/<容器ID>
/sys/fs/cgroup/memory/kubepods/burstable/pod<ID>/<容器ID>
查找容器对应的memory.kmem.slabinfo文件:
find /sys/fs/cgroup/memory -name "memory.kmem.slabinfo" | grep 容器 id,得到slabinfo的路径,直接 cat看结果
4.解决方案-2
升级系统内核至4.0以上
推荐添加Tlinux 2.4。
存量系统升级:
5.修复操作
采用方案1。
仅需处理centos系统,ubuntu内核版本较高无需处理。
1)存量集群的存量节点[仅处理cent os节点]
1.替换/usr/bin中的runc
2.chmod 777 runc
3.针对cent OS:
yum -y install libseccomp.x86_64
4.注意事项:
替换完成后,不需要重启,之后在该节点运行的容器将不会开启kmem。针对存量的POD,可以重建来关闭kmem。
如果节点已经发生OOM,则需要reboot节点(内存已经发生泄漏,需要重启解决)。
2)新增集群/存量集群的新节点
会直接使用新的runc,无需额外操作。
参考文献:
1.
2.