前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Cgroup泄露1

Cgroup泄露1

作者头像
李鹤
发布2023-03-28 11:07:58
2510
发布2023-03-28 11:07:58
举报
文章被收录于专栏:k-cloud-labs

背景

线上k8s节点创建容器时提示"no space left on device",为已知问题,参考

https://tencentcloudcontainerteam.github.io/2018/12/29/cgroup-leaking/

http://www.linuxfly.org/kubernetes-19-conflict-with-centos7/?from=groupmessage

解决方案

按照上述链接中的提示,首先看runc部分,docker用的从opencontainers/runc项目fork出来的docker/runc项目,目前线上用的docker版本为1.13.1,对应的docker-runc的commit为 9df8b306d01f59d3a8029be411de015b7304dd8f,查看其相关代码

代码语言:javascript
复制
func (s *MemoryGroup) Apply(d *cgroupData) (err error) {
   path, err := d.path("memory")
   if err != nil && !cgroups.IsNotFound(err) {
      return err
   }
   if memoryAssigned(d.config) {
      if path != "" {
         if err := os.MkdirAll(path, 0755); err != nil {
            return err
         }
      }
          // 默认关闭
      if d.config.KernelMemory != 0 {
         if err := EnableKernelMemoryAccounting(path); err != nil {
            return err
         }
      }
   }
   defer func() {
      if err != nil {
         os.RemoveAll(path)
      }
   }()
 
   // We need to join memory cgroup after set memory limits, because
   // kmem.limit_in_bytes can only be set when the cgroup is empty.
   _, err = d.join("memory")
   if err != nil && !cgroups.IsNotFound(err) {
      return err
   }
   return nil
}

此版本默认关闭KernelMemory功能,所以docker-runc暂时不需要改,接下来看kubelet相关代码,kubelet为1.12.4版本,pkg/kubelet/cm/cgroup_manager_linux.go下

代码语言:javascript
复制
func (s *MemoryGroup) Apply(d *cgroupData) (err error) {
   path, err := d.path("memory")
   if err != nil && !cgroups.IsNotFound(err) {
      return err
   } else if path == "" {
      return nil
   }
   if memoryAssigned(d.config) {
      if _, err := os.Stat(path); os.IsNotExist(err) {
         if err := os.MkdirAll(path, 0755); err != nil {
            return err
         }
         
         // Only enable kernel memory accouting when this cgroup
         // is created by libcontainer, otherwise we might get
         // error when people use `cgroupsPath` to join an existed
         // cgroup whose kernel memory is not initialized.
                // 强制开启
         if err := EnableKernelMemoryAccounting(path); err != nil {
            return err
         }
      }
   }
   defer func() {
      if err != nil {
         os.RemoveAll(path)
      }
   }()
 
   // We need to join memory cgroup after set memory limits, because
   // kmem.limit_in_bytes can only be set when the cgroup is empty.
   _, err = d.join("memory")
   if err != nil && !cgroups.IsNotFound(err) {
      return err
   }
   return nil
}

上面的代码为默认开启KernelMemory,且无法关闭,解决方案是注释掉EnableKernelMemoryAccounting调用,然后重新编译kubelet即可。由于线上docker和cgroup使用的cgroup-driver为cgroupfs而不是systemd**,所以这里并没有修改systemd****对应文件里有关KernelMemory****的代码。**

验证

找了一台新机器,上面没有任何容器,先看下改之前的kubelet所创建的/sys/fs/cgroup/memory/kubepods/memory.kmem.slabinfo文件,如下

/posts/cgroup-leak/cgroup_memory_leak1.png
/posts/cgroup-leak/cgroup_memory_leak1.png

说明已经开启了kmem,然后替换kubelet并重启宿主,观察上面文件,如下

/posts/cgroup-leak/cgroup_memory_leak2.png
/posts/cgroup-leak/cgroup_memory_leak2.png

说明kmem已经关闭了。这里重点强调一下,必须重启宿主才能生效,只重启kubelet无法生效,因为需要修改/sys/fs/cgroup/memory/kubepods,kubelet启动时会检测此目录是否存在,不存在则创建,存在则直接使用,只重启kubelet时此目录依然存在,因为容器业务进程还在使用着相关的cgroup。新创建的Pod会以继承此目录下的cgroup的配置,所以需要重启宿主才能关闭kmem。

总结

本篇是一种快速暴力的解决问题手段,后经过调研测试,有不需要重启宿主的方案,在这一篇中介绍

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-07-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 解决方案
  • 验证
  • 总结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档