固定链接 【docker-ce】k8s集群docker容器异常重启问题分析

【docker-ce】k8s集群docker容器异常重启问题分析

【docker-ce】k8s集群docker容器异常重启问题分析

背景

  • 目前机器学习平台后端采用k8s架构进行GPU和CPU资源的调度和容器编排。k8s的核心能力是容器编排,容器服务的稳定运行直接关系到整体平台的稳定性。
  • 春节值班期间,机器学习平台实验环境-隔离环境 vgpu资源出现比较多的用户容器异常退出问题。此问题导致Pod中的用户容器发生重建,一些用户在容器运行时环境的数据会丢失,由于平台具有暂存用户异常容器现场的能力,值班同学可以通过恢复用户异常容器现场来恢复用户的数据。
  • 用户容器异常退出,虽然可以通过运维工具来恢复用户的数据进行问题降级处理,但是频繁无故的用户容器异常退出,环境重启问题,极大的影响了用户使用 机器学习平台实验环境-隔离环境 vgpu资源的体验和值班同学处理类似问题的时效性。

问题记录-之看现象

  • 【看现场】
    • 版本信息

    • 表格中记录了2020-01-14到2020-02-04期间一部分用户容器的kvm环境、docker、containerd、容器错误码的信息。
      avatar

    • 开始部分同学是怀疑cuda版本兼容性问题,导致用户容器异常退出,想通过升级cuda版本查看此问题是否收敛,但是cuda-10.0上也有类似现场,此怀疑不攻自破。

    • 是否是由于用户容器OOM,导致异常退出,通过dmesg也没有查到任何异常日志。OOM论也被否定了。

    • 相同版本的kernel、docker版本,物理GPU节点为出现用户容器重启,只有在kvm vgpu上出现,也让人摸不着头脑。

    • 查看docker的日志,当用户容器异常退出时,就只有正常容器退出 clean up的信息,无其他异常日志。PS:其实此处才是澄清137问题的关键。

  • 【找同盟】

问题排查-之得细品

  • 【升级否】
    • 组内讨论了一波是否直接升级到docker 18.09.2之后的版本来解决137容器重启的问题。但是社区用户的环境毕竟和机器学习平台还是有差异,存在一些不确定性,在没有详细版本测试情况下,全量升级docker的版本,势必对用户环境稳定性有影响。而且物理GPU节点上部署同样的docker版本,并未出现此问题。保守起见,灰度了一部分节点,升级docker版本,确认是否会出现137问题。
    • 事实升级了docker版本还是会出现137问题。同时并行着再灰度一些containerd的版本。PS:升级了contianerd版本的节点未出现容器137问题。
      avatar
  • 【抓现场】
    • 从 Random task failures with “non-zero exit (137)” since 18.09.1 issue中发现了auditctl这个信号抓取的工具,可以澄清到底是哪个进程给容器发送了kill -9 信号。

    • 发现抓取到的现场确实是/usr/bin/nvidia-container-runtime把用户容器systemd进程kill了。因为GPU节点docker runtime都是使用nvidia-container-runtime。但是还是无法确认为什么被kill -9了。

    • 一方面为了抓取更多的docker日志,灰度一部分节点,打开docker debug日志开关。

    • 一方面为了确认是否有进程coredump的问题,把一些节点的coredump配置也打开,抓取问题现场。

    • 同时review docker的代码,发现容器创建运行的一个简单基本流程是dockerd -> containerd -> containerd-shim -> nvidia-container-runtime -> entrypoint。containerd-shim托管了容器的运行时状态,当contianerd-shim 异常退出时,会调用exitHandler 中进行cleanupAfterDeadShim操作触发kill -9。

    • 为了确认containerd-shim进程是异常退出,增加kill -15信号捕获。

    • 抓取到trace信号 -9 和-15,证明containerd-shim进程确实异常退出,具体还是需要确认是什么原因导致。

  • 【起死回生】

    • containerd-shim 异常退出现场,看到在执行docker exec命令时,发生了panic: runtime error: invalid memory address or nil pointer dereference,显示代码访问空指针,contaienrd-shim进程异常退出,触发cleanupAfterDeadShim,导致用户容器异常退出。

问题分析-之论本质

  • 【从代码中来到代码中去】
    • 为什么在打开docker debug日志节点能抓到现场,线上其他vgpu上为什么没有出现SIGSEGV这个panic的问题。

    • containerd-shim出现panic时,因为containerd启动containerd-shim进程时,stdout/stderr都没有重定向到os的stdout/stderr上,所以在messages中没有找到任何panic信息。只有debug日志打开时,

      containerd-shim设置了重定向

      ,才会有panic的日志输出。

    • 为什么containerd-shim出现panic时,dmesg和/var/log/message中都没有相关segment fault的日志。

    • c/c++程序遇到segment fault都会在messages有类似的日志。
      segfault at 0 ip 00000000004005c7 sp 00007ffce36494f0 error 6 in main。因为containerd-shim是go程序,go的runtime catch到了SIGSEGV。当containerd-shim SIGSEGV 触发panic时,go runtime会调用runtime.crash,dieFromSignal(_SIGABRT) 实际 raise的是SIGABRT信号,所以dmesg和/var/log/message同时由于docker启动的时候,没有配置GOTRACEBACK=crash环境变量,默认是 GOTRACEBACK=single,ulimited -c 是0,也不会生成coredump文件。

    • 为什么容器中会有频繁的exec操作

    • 平台kubelet使用内网sdn接口获取ip,没有使用cni插件的方式,当每秒执行PLEG,检查Pod状态,通过docker exec -i ip a 获取Pod IP。

    • 频繁的exec操作,增加了containerd-shim触发exec bug概率。

    • 问题本质是exec.go代码 访问了空指针。

  • 【从社区来到社区去】

解决方案

  • 【降运维】
    • 在137问题根本原因未澄清前,为了减少用户容器异常退出带来的运维工作量。修改了kubelet 容器异常重启的策略,通过用户容器的标签信息,将平台实验环境vgpu的容器发生异常退出时,不在是容器重建,修改成容器重启。
    • 修改平台Daemonset hostNetwork=true的方式,不在使用sdn网络,减少exec操作。
  • 【开处方】
    • 问题本质原因是containerd execde bug,后续增量环境containerd升级至1.2.4版本。
    • 去除kubelet sdn网络exec获取容器IP的方式。
    • 使用平台自研的sdn cni网络插件,目前正在研发中。

参考文档

您的留言将激励我们越做越好