转载kubernetes 1.9 与 CentOS 7.3 内核兼容问题

2023-05-16

20201022转载kubernetes 1.9 与 CentOS 7.3 内核兼容问题

原文:http://www.linuxfly.org/kubernetes-19-conflict-with-centos7/

​ 生产环境发现不定时 Java 应用出现 coredump 故障,测试环境不定时出现写入 /cgroup/memory 报 no space left on device 的故障,导致整个 kubernetes node 节点无法使用。设置会随着堆积的 cgroup 越来越多,docker ps 执行异常,直到把内存吃光,机器挂死。

典型报错:

kubelet.ns-k8s-node001.root.log.ERROR.20180214-113740.15702:1593018:E0320 04:59:09.572336 15702 remote_runtime.go:92] RunPodSandbox from runtime service failed: rpc error: code = Unknown desc = failed to start sandbox container for pod “osp-xxx-com-ljqm19-54bf7678b8-bvz9s”: Error response from daemon: oci runtime error: container_linux.go:247: starting container process caused “process_linux.go:258: applying cgroup configuration for process caused “mkdir /sys/fs/cgroup/memory/kubepods/burstable/podf1bd9e87-1ef2-11e8-afd3-fa163ecf2dce/8710c146b3c8b52f5da62e222273703b1e3d54a6a6270a0ea7ce1b194f1b5053: no space left on device””

或者

Mar 26 18:36:59 ns-k8s-node-s0054 kernel: SLUB: Unable to allocate memory on node -1 (gfp=0x8020)
Mar 26 18:36:59 ns-k8s-noah-node001 kernel: cache: ip6_dst_cache(1995:6b6bc0c9f30123084a409d89a300b017d26ee5e2c3ac8a02c295c378f3dbfa5f), object size: 448, buffer size: 448, default order: 2, min order: 0

该问题发生前后,进行过 kubernetes 1.6 到 1.9 的升级工作。怀疑问题与 kubernetes 、内核有关。

一、对比测试结果

使用同样的测试方法,结果为:
1)使用初次部署 k8s 1.6 版本测试,没有出现 cgroup memory 遗漏问题;
2)从 k8s 1.6 升级到 1.9 后,测试没有出现 cgroup memory 遗漏问题;
3)重启 kubelet 1.9 node 节点重启,再次测试,出现 cgroup memory 遗漏问题。
对比 k8s 1.6 和 1.9 创建的 POD 基础容器和业务容器,runc、libcontainerd、docker inspect 的容器 json 参数都一致,没有差异。
为什么同样是 k8s 1.9(其他 docker、kernel 版本一致)的情况下,结果不一样呢?重启的影响是?

二、问题重现

对于 cgroup memory 报 no space left on device ,是由于 cgroup memory 存在 64k(65535 个)大小的限制。
采用下面的测试方式,可以发现在删除 pod 后,会出现 cgroup memory 遗漏的问题。该测试方法通过留空 99 个 系统 cgroup memory 位置,来判断引起问题的原因是由于 pod container 导致的。

2.1、填满系统 cgroup memory

# uname -r  
3.10.0-514.10.2.el7.x86_64  
# kubelet --version  
Kubernetes 1.9.0  
# mkdir /sys/fs/cgroup/memory/test  
# for i in `seq 1 65535`;do mkdir /sys/fs/cgroup/memory/test/test-${i}; done  
# cat /proc/cgroups |grep memory  
memory  11      65535   1  

把系统 cgroup memory 填到 65535 个。

2.2、腾空 99 个 cgroup memory

# for i in `seq 1 100`;do rmdir /sys/fs/cgroup/memory/test/test-${i} 2>/dev/null 1>&2; done   
# mkdir /sys/fs/cgroup/memory/stress/  
# for i in `seq 1 100`;do mkdir /sys/fs/cgroup/memory/test/test-${i}; done   
mkdir: cannot create directory ‘/sys/fs/cgroup/memory/test/test-100’: No space left on device  
# for i in `seq 1 100`;do rmdir /sys/fs/cgroup/memory/test/test-${i}; done  
# cat /proc/cgroups |grep memory  
memory  11      65436   1  

在写入第 100 个的时候提示无法写入,证明写入了 99 个。

2.3、创建一个 pod 到这个 node 上,查看占用的 cgroup memory 情况

# ll /sys/fs/cgroup/memory/kubepods/pod0f6c3c27-3186-11e8-afd3-fa163ecf2dce/  
total 0  
drwxr-xr-x 2 root root 0 Mar 27 14:14 6d1af9898c7f8d58066d0edb52e4d548d5a27e3c0d138775e9a3ddfa2b16ac2b  
drwxr-xr-x 2 root root 0 Mar 27 14:14 8a65cb234767a02e130c162e8d5f4a0a92e345bfef6b4b664b39e7d035c63d1 

这时再次创建 100 个 cgroup memory ,因为 pod 占用了 3 个,会出现 4 个无法成功:

# for i in `seq 1 100`;do mkdir /sys/fs/cgroup/memory/test/test-${i}; done      
mkdir: cannot create directory ‘/sys/fs/cgroup/memory/test/test-97’: No space left on device <-- 3 directory used by pod  
mkdir: cannot create directory ‘/sys/fs/cgroup/memory/test/test-98’: No space left on device  
mkdir: cannot create directory ‘/sys/fs/cgroup/memory/test/test-99’: No space left on device  
mkdir: cannot create directory ‘/sys/fs/cgroup/memory/test/test-100’: No space left on device  
# cat /proc/cgroups   
memory  11      65439   1

写入到的 cgroup memory 增加到 65439 个。

2.4、删掉测试 pod ,看看 3 个占用的 cgroup memory 是否有释放

看到的结果:

# cat /proc/cgroups   
memory  11      65436   1  
# for i in `seq 1 100`;do mkdir /sys/fs/cgroup/memory/test/test-${i}; done      
mkdir: cannot create directory ‘/sys/fs/cgroup/memory/test/test-97’: No space left on device  
mkdir: cannot create directory ‘/sys/fs/cgroup/memory/test/test-98’: No space left on device  
mkdir: cannot create directory ‘/sys/fs/cgroup/memory/test/test-99’: No space left on device  
mkdir: cannot create directory ‘/sys/fs/cgroup/memory/test/test-100’: No space left on device  

可以看到,虽然 cgroup memory 减少到 65536 ,似乎 3 个位置释放了。但实际上测试结果发现,并不能写入,结果还是 pod 占用时的无法写入 97-100 。
这就说明,cgroup memory 数量减少,但被 pod container 占用的空间没有释放。

反复验证后,发现随着 pod 发布和变更的增加,该问题会越来越严重,直到把整台机器的 cgroup memory 用完。

$ cat /proc/cgroups   
#subsys_name    hierarchy       num_cgroups     enabled  
cpuset  10      229418  1                 -- 但 cpuset 数量很恐怖  
cpu     6       118     1  
cpuacct 6       118     1  
memory  7       109     1                  -- 看上去不多,实际没有释放空间的  
devices 3       229504  1  
freezer 5       32      1  
net_cls 4       32      1  
blkio   9       118     1  
perf_event      11      32      1  
hugetlb 2       32      1  
pids    8       32      1  
net_prio        4       32      1  

三、问题根源

经过大量的测试和对比分析,在两个 k8s 1.9 环境中 kubelet 创建的 /sys/fs/cgroup/memory/kubepods 差异,发现:

没问题的:  
[root@k8s-node01 kubepods]# cat memory.kmem.slabinfo   
cat: memory.kmem.slabinfo: Input/output error  
有问题的:  
[root@k8s-node01 kubepods]# cat memory.kmem.slabinfo   
slabinfo - version: 2.1  
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>  

也就是说,在有问题的环境下,cgroup kernel memory 特性被激活了。

关于 cgroup kernel memory,在 kernel-doc 中有如下描述:

# vim /usr/share/doc/kernel-doc-3.10.0/Documentation/cgroups/memory.txt
2.7 Kernel Memory Extension (CONFIG_MEMCG_KMEM)
With the Kernel memory extension, the Memory Controller is able to limit
the amount of kernel memory used by the system. Kernel memory is fundamentally
different than user memory, since it can't be swapped out, which makes it
possible to DoS the system by consuming too much of this precious resource.
Kernel memory won't be accounted at all until limit on a group is set. This
allows for existing setups to continue working without disruption. The limit
cannot be set if the cgroup have children, or if there are already tasks in the
cgroup. Attempting to set the limit under those conditions will return -EBUSY.
When use_hierarchy == 1 and a group is accounted, its children will
automatically be accounted regardless of their limit value.
After a group is first limited, it will be kept being accounted until it
is removed. The memory limitation itself, can of course be removed by writing
-1 to memory.kmem.limit_in_bytes. In this case, kmem will be accounted, but not
limited.

这是一个 cgroup memory 的扩展,用于限制对 kernel memory 的使用。但该特性在老于 4.0 版本中是个实验特性,若使用 docker run 运行,就会提示:

# docker run -d --name test001 --kernel-memory 100M registry.vclound.com:5000/hyphenwang/sshdserver:v1
WARNING: You specified a kernel memory limit on a kernel older than 4.0. Kernel memory limits are experimental on older kernels, it won’t work as expected and can cause your system to be unstable.
# cat /sys/fs/cgroup/memory/docker/eceb6dfba2c64a783f33bd5e54cecb32d5e64647439b4932468650257ea06206/memory.kmem.limit_in_bytes
104857600

# cat /sys/fs/cgroup/memory/docker/eceb6dfba2c64a783f33bd5e54cecb32d5e64647439b4932468650257ea06206/memory.kmem.slabinfo   
slabinfo - version: 2.1  
# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>  
ip6_dst_cache          0      0    448   18    2 : tunables    0    0    0 : slabdata      0      0      0  
UDPv6                  0      0   1216   26    8 : tunables    0    0    0 : slabdata      0      0      0  
kmalloc-8192           0      0   8192    4    8 : tunables    0    0    0 : slabdata      0      0      0  
signal_cache          28     28   1152   28    8 : tunables    0    0    0 : slabdata      1      1      0  
sighand_cache         15     15   2112   15    8 : tunables    0    0    0 : slabdata      1      1      0  
sysfs_dir_cache       36     36    112   36    1 : tunables    0    0    0 : slabdata      1      1      0  
task_struct            8      8   4016    8    8 : tunables    0    0    0 : slabdata      1      1      0  
......  

经过反复验证,当使用 docker run --kernel-memory 参数启动的容器,在删除后也不会释放 cgroup memory 占用的位置 ,存在同样的问题。

基于该现象,对比 kubernetes 1.6 和 kubernetes 1.9 对 cgroup kernel memory 设置的差异。
在k8s 1.9 vendor库中,少了if d.config.KernelMemory != 0 { 这行代码的判断, 而在k8s的Github,1.6.4版本在官方的runc/libcontainerd增加了这行代码,但在1.9.0删掉了,导致默认就使用kmem 。

$ git diff remotes/origin/vip_v1.6.4.3 remotes/origin/vip_v1.9.0 -- vendor/github.com/opencontainers/runc/libcontainer/cgroups/fs/memory.go  
@@ -29,14 +35,18 @@ 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 path != "" {  
+               if _, err := os.Stat(path); os.IsNotExist(err) {  
                        if err := os.MkdirAll(path, 0755); err != nil {  
                                return err  
                        }  
-               }  
-               if d.config.KernelMemory != 0 { // 删除了这行的判断,使得 1.9 默认就 enable cgroup kernel memory 特性  
+                       // 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  
                        }  

这就引发了 cgroup memory 也不能释放的问题(与通过 docker run --kernel-memory 打开的情况一样。)
其实根据 libcontainerd 推荐的 kernel 4.3 以上版本,打开 cgroup kernel memory 应该也是没问题的。可惜我们使用的kernel版本是3.10.0-514.16.1.el7.x86_64,kernel memory在这个版本是不稳定的。因此让我们踩了这个坑。

四、解决问题

经过以上分析,造成该故障的原因,是由于 kubelet 1.9 激活了 cgroup kernel-memory 特性,而在 CentOS 7.3 kernel 3.10.0-514.10.1.el7.x86_64 中对该特性支持不好。
导致删除容器后,仍有对 cgroup memory 的占用,没有执行 free_css_id() 函数的操作。
解决方式,就是修改 k8s 1.9 代码,再次禁止设置 cgroup kernel-memory 配置,保持关闭状态。

五、疑问

5.1、为什么同样是 k8s 1.9 的版本,在不同的测试中没有问题

原因是第一次的 k8s 1.9 是在原来 k8s 1.6 的环境中,通过升级 kubelet 版本来测试的。
而 /sys/fs/cgroup/kubepods 是由 k8s 1.6 创建的,升级到 k8s 1.9 后,启动服务时,判断到该路径已经存在,就没有再创建新的。
所以,也就没有激活 cgroup kernel-memory 特性。
接下来创建的 POD 会继承该路径的 cgroup memory 属性,也没有激活 cgroup kernel-memoy ,所以没有引发问题。
相反,在重启 k8s 1.9 node 后,kubelet 新建了 /sys/fs/cgroup/kubepods ,激活了 cgroup kernel-memoy ,导致后续的 POD 在删除时也有问题。

5.2、cgroup kernel memory 激活后可以关闭吗?

按 kernel 的说明,以及 kernel 代码,激活的方式,就是传递非 -1 的值(0 也是激活)来激活。而且最小单位是 4096 PageSize 的大小。
在激活 cgroup kernel memory 后,是不能关闭的,只能通过设置 -1 关闭限制,但还是会继续计数。

After a group is first limited, it will be kept being accounted until it is removed. The memory limitation itself, can of course be removed by writing -1 to memory.kmem.limit_in_bytes. In this case, kmem will be accounted, but not limited.

另外,在 CentOS 7.3 kernel 中,激活 cgroup kernel memory 后,即使通过 -1 设置不限制使用,但还是会频繁出现 SLUB 的报警,以及 Java crash 的问题。

Mar 26 18:36:59 ns-k8s-noah-s0054 kernel: SLUB: Unable to allocate memory on node -1 (gfp=0x8020)
Mar 26 18:36:59 ns-k8s-noah-s0054 kernel: cache: ip6_dst_cache(1995:6b6bc0c9f30123084a409d89a300b017d26ee5e2c3ac8a02c295c378f3dbfa5f), object size: 448, buffer size: 448, default order: 2, min order: 0

5.3、判断 cgroup kernel memory 是否激活的方式

查看对应 POD container 下的 memory.kmem.slabinfo。

关闭

# cat memory.kmem.slabinfo   
cat: memory.kmem.slabinfo: Input/output error 

开启

# cat memory.kmem.slabinfo   
slabinfo - version: 2.1  
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>  

需要注意的是,如果给 cgroup memory.kmem.limit_in_bytes 设置 -1 ,其结果为:

# cat memory.kmem.limit_in_bytes
9223372036854771712

这个值在关闭时和不限制 kernel memory 时是一样的,不能作为 kernel memory 是否激活的判断条件。

六、参考资料

/usr/share/doc/kernel-doc-3.10.0/Documentation/cgroups/memory.txt

在下面两个 issue 中讨论这个问题:
application crash due to k8s 1.9.x open the kernel memory accounting by default #61937

Docker leaking cgroups causing no space left on device? #29638

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

转载kubernetes 1.9 与 CentOS 7.3 内核兼容问题 的相关文章

随机推荐

  • SpringMVC配置文件(spring-mvc.xml)

    springMVC主要有以下四个配置 xff1a 1 配置组件扫描 xff0c 必配 xff0c 组件扫描会扫描包下的所有的Controller类 lt 配置组件扫描 gt lt context component scan base pa
  • C++环境配置(MinGW的下载及安装)

    首先说明 xff1a MinGW就是gcc的安装工具 1 下载 MinGW的下载地址 xff1a www mingw org xff0c 点击右上角的Download Installer即可下载 2 安装mingw get setup ex
  • 如何使用imp导入dmp文件

    一 创建临时表空间 xff1a create temporary tablespace yd temp tempfile 39 D oracledata file temp dbf 39 路径根据实际情况填写 size 50m autoex
  • I2C设备主机与从机地址设置

    1 I2C主机与从机定义 I2C设备一般使用MCU作为主机 xff0c 主机与从机通过总线连接起来 xff0c 分别是SCL时钟总线和SDA数据总线 xff0c 主机发送给从机SCL时钟信号 xff0c SDA发送数据 xff0c 如下图所
  • EFM32jg之FreeRTOS(5)-任务调度、创建、切换

    64 EFM32JG移植FreeRTOS 1 任务调度器 1 xff09 创建空闲任务 xff0c 优先级为0 xff0c 表示最低优先级 xff0c 在无其他高优先级任务的情况下 xff0c 执行空闲任务 xff0c 若打开configU
  • 令人厌恶的错误MSB3721,以及win10,VS2019,YOLO V4 环境搭建

    总结一下yolo环境的搭建 xff0c 以及MSB3721的一种解决方案 xff0c 如果有相似的背景 xff0c 不妨一试 另外在搭建环境的过程中 xff0c 感觉最浪费时间的就是下载所需的安装包 xff0c 因为是外网 xff0c 速度
  • python&多路归并

    问题 xff1a 在项目中 xff0c 需从待分析的数据中选出最大的前几名 xff0c 但由于数据量太大 xff0c 直接排序会内存报错 xff0c 因此尝试用多路归并的思路来解决问题 接口 xff1a 一个目录下有x个已排序好的csv 最
  • PX4飞控学习(四)

    系统启动 启动文件 xff1a nuttx arch arm stm32 stm32 start c stm32 clockconfig span class hljs regexp span 时钟 stm32 fpuconfig span
  • VSCode 搭建 C++ 开发环境

    文章目录 前言一 获取参考资料二 下载安装 VSCode三 安装编译器四 添加环境变量五 使用VSCode 开发 C 43 43 程序总结 前言 鲁迅曾说过 xff0c 不以敲代码为目的的学编程都是耍流氓 xff01 我最近在撸 C 43
  • Ubuntu安装VMware

    Ubuntu安装VMware xff08 1 xff09 需求 由于windows 的日渐卡顿还有变态的更新 xff0c 我的需求就是稳定单调优化好所以我通过Ubuntu 安装VMware xff0c 然后开启虚拟机继续学习 xff08 2
  • python实现TCP通信

    本例是在Ubuntu虚拟机中本机互传实现的TCP通信 一 TCP服务器端 xff08 server端 xff09 1 创建套接字 xff0c 绑定套接字到本地IP与端口 s 61 socket socket socket AF INET s
  • agrc argv解释

    以前经常看见过 xff1a int main int argc char argv 这样形式的main但是一直没有这样用直到研究点云时发现有个例子是 xff1a gt exe pcd 这样的doc下的命令才想起有这样的两个参数 xff0c
  • 个人面试细节、技巧总结(没有面试题哦!)

    面试除了自身技能过硬外 xff0c 良好的沟通 xff0c 平和的心态 xff0c 细节的拿捏也都是额外的加分项 最后 xff0c 以些许运气加以点缀 xff0c offer 便八九不离十了 参加工作两年有余 xff0c 只大专文凭 xff
  • 【记录】ORB-SLAM3编译以及在realsense D435i运行

    环境 xff1a 最开始用的是源码是ORB SLAM3 的1 0版本 xff0c 但是编译的时候出错太多了 xff0c 超出了能力范围 xff0c 更换了0 4 beta版本 xff0c 但是这个版本在运行的时候会直接segmentatio
  • ArtiPub

    ArtiPub ArtiPub Article Publisher的简称 xff0c 意为 34 文章发布者 34 是一款开源的一文多发平台 xff0c 可以帮助文章作者将编写好的文章自动发布到掘金 SegmentFault CSDN 知乎
  • mac安装配置zsh

    mac安装配置zsh 比mac自带的shell好用太多 一 安装homebrew 参考 xff1a https brew sh index zh cn bin bash c span class token string 34 span c
  • 手把手教你给win10 2004版本的ubuntu1804子系统安装docker

    ubuntu1804子系统安装docker ce 分两种情况 xff1a 1 win10版本小于2004版本2 win10版本大于2004版本 一 说明 win10版本小于2004的话 xff0c 可以使用WSL1 0 xff0c WSL1
  • windows安装scoop

    参考 xff1a https scoop sh 参考 xff1a https github com lukesampson scoop wiki Quick Start 懂不懂 xff0c 先装上 xff0c 这样你就完成了该工具学习的第一
  • PX4飞控学习(五)

    PX4的应用 程序入口为 程序名 main int argc char argv 这里实现应用参数 主循环函数在 task main int argc char argv thread main int argc char argv 等函数
  • 转载kubernetes 1.9 与 CentOS 7.3 内核兼容问题

    20201022转载kubernetes 1 9 与 CentOS 7 3 内核兼容问题 原文 xff1a http www linuxfly org kubernetes 19 conflict with centos7 生产环境发现不定