问题

开发环境集群中的业务pod每天频繁更新重建,最近发现部分节点出现以下问题:

  1. pod经常在创建时提示runc/pod sandbox相关的错误
  2. 想登陆节点时发现ssh也连不上节点
  3. 某个节点上的系统pod以及业务pod中的微服务均会出现不稳定的状态
  4. node的状态会在ready/not ready之间漂移
  5. 通过lens查看node的状态,发现有系统进程oom的event出现,且每次oom的进程不固定
  6. 登陆openstack查看虚机控制台和日志,发现大量和oom相关的日志

排查

  1. 首先让负责openstack的同事确定openstack底层状态正常,排除底层故障原因。巧的是我司openstack也确实偶尔出故障,导致节点状态不佳。

  2. 确定openstack稳定后,发现问题依旧。

  3. 一开始看到runc/sandbox相关的问题,搜索社区issue怀疑是docker版本问题。该集群里的docker版本确实搞出了k8s支持的docker版本,于是对部分节点docker进行了降级,发现问题依旧。

  4. 看到大量oom日志后,开始学习OOM相关原理,从这里作为入口点排查问题。

  5. 确认节点物理内存是否足够,通过top和free命令观察发现物理内存足够。

  6. egrep -i 'killed process' /var/log/messages或直接dump出/var/log/messages,使用killed process关键字搜索(注意大小写),可以看到系统oom的历史和具体情况。

  7. 使用invoke作为关键字搜索,可以看到是哪些进程触发了oom,触发了哪个cgroup组的限制,以及触发oom后进程打分的详情,以及最终内核选择了哪个进程牺牲掉的过程。比如某次oom的过程:

    # containerd是kubelet和docker运行时对接的垫片,就是k8s要移除docker支持中涉及到的模块
    # containerd触发了oom-killer
    containerd invoked oom-killer: gfp_mask=0x50, order=0, oom_score_adj=-999
    
    # sshd服务由于/system.slice cgroup的内存限制被杀掉
    Task in /system.slice/sshd.service killed as a result of limit of /system.slice
    
    # 接下来是一系列该cgroup下进程的oom打分表,[-1000,1000],优先干掉分数高的。可以看到一众系统进程以0分领先
    [ pid ]   uid  tgid total_vm      rss nr_ptes swapents oom_score_adj name
    Jan  5 05:40:48 gxx-ptkf3 kernel: [  569]     0   569    12197     1250      25        0         -1000 systemd-udevd
    Jan  5 05:40:48 gxx-ptkf3 kernel: [  709]     0   709    13883      179      29        0         -1000 auditd
    Jan  5 05:40:48 gxx-ptkf3 kernel: [  739]    32   739    17314      217      37        0             0 rpcbind
    Jan  5 05:40:48 gxx-ptkf3 kernel: [  742]    81   742    16571      418      33        0          -900 dbus-daemon
    Jan  5 05:40:48 gxx-ptkf3 kernel: [  743]     0   743    48802      234      35        0             0 gssproxy
    Jan  5 05:40:48 gxx-ptkf3 kernel: [  750]     0   750     6596      290      19        0             0 systemd-logind
    Jan  5 05:40:48 gxx-ptkf3 kernel: [  751]     0   751     5424      278      15        0             0 irqbalance
    Jan  5 05:40:48 gxx-ptkf3 kernel: [  762]   998   762     5634      269      16        0             0 chronyd
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 1019]     0  1019   597532    12297     129        0          -999 containerd
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 1191]     0  1191    22447      449      45        0             0 master
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 1202]    89  1202    22517      510      45        0             0 qmgr
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 1213]     0  1213    27552      197      11        0             0 agetty
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 1238]     0  1238    31598      383      19        0             0 crond
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 1247]     0  1247    12923      289      28        0         -1000 sshd
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 1498]     0  1498    27552      202      10        0             0 agetty
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 3200]     0  3200    27554      730      11        0          -998 containerd-shim
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 3254]     0  3254    27554     1602      11        0          -998 containerd-shim
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 3278]     0  3278    27202     1123      10        0          -998 containerd-shim
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 3336]     0  3336    27202     1111      10        0          -998 containerd-shim
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 3468]     0  3468    27202     1119      10        0          -998 containerd-shim
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 3547]     0  3547    27554      735      11        0          -998 containerd-shim
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 3597]     0  3597    27202     1630      12        0          -998 containerd-shim
    Jan  5 05:40:48 gxx-ptkf3 kernel: [ 3700]     0  3700    27202     1105      10        0          -998 containerd-shim
  8. 可以看到应该是/system.slice这个cgroup内存设置的值太低了,导致系统内存用量很容易达到上限,触发oom。

  9. 使用cgroupfs的接口,直接通过文件系统查看/system.slice cgroup的配置:cat /sys/fs/cgroup/memory/system.slice/memory.limit_in_bytes,同时查看当前使用量:cat /sys/fs/cgroup/memory/system.slice/memory.usage_in_bytes

  10. 可以看到集群的system.slice group的memory.limit_in_bytes被设置成了512Mb,而usage经常在400Mb上下浮动,如此一来当系统控制组下的进程消耗内存稍微一多,就可能触发OOM。

解决

取消kubelet对system.slice的硬限

那么是谁设置了system.slice的内存限制值为512Mb了呢?答案是kubelet。

如果不是特殊情况,需要严格限制system进程的资源用量,那么取消掉kubelet启动配置中enforce-node-allocatable参数中的system-reserved即可。

如果在这里配置了system-reserved,那么kubelet会使用systemReserved配置中的cpu和memory值,去设置cgroup中system.slice(这个cgroup也是参数,可以配置)对应的资源限制。

具体的修改方法,跟集群部署有关系,比如本文涉及集群的修改方式是编辑/etc/kubernetes/kubelet-config.yml,注释掉enforce-node-allocatable里的system-reserved即可。

重新配置system.slice的硬限

使用systemd的cgroup接口重新设置system.slice cgroup的内存上限,避免触发oom

systemctl set-property system.slice MemoryLimit=9223372036854771712

总结

根据k8s官方文档以及本次问题,kubelet的system-reserved应当谨慎配置,因为:

  1. 如果节点不单独作为k8s节点,有外部进程直接跑在system cgroup下,可能导致system cgroup内存超限,触发oom。
  2. system cgroup下的系统进程本身随着运行时间的增大,或者类似于containerd进程的频繁大量创建,内存占用量可能会增高,所以如果确定需要设置system-reserved,需要结合监控数据谨慎设定。

解决该问题的过程中,产生了一个疑问,cgroupfs是内核中cgroup暴露出的控制接口,那么systemd也有一套维护cgroup相关的接口,二者是什么关系?在k8s中这两套接口的使用是什么关系?经过查阅k8s官方文档:

  1. 容器运行时和kubelet可以通过配置选择两个cgroup驱动之一,推荐systemd。这样统一使用一套cgroup接口,单一视图不容易混乱。另外kubelet和容器运行时的cgroup驱动必须保持一致。
  2. 节点不可随意切换cgroup驱动,需要一些额外的工作才能完成节点cgroup驱动的切换。

参考

为系统守护进程预留计算资源 | Kubernetes

正确配置Kubelet可一定程度防止K8S集群雪崩-阿里云开发者社区 (aliyun.com)

Kubernetes因限制内存配置引发的错误 - 云+社区 - 腾讯云 (tencent.com)

容器运行时 | Kubernetes

文章目录