添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

线上某环境,遇到pod删除时一直卡在terminating的问题,之前通过 kubectl delete pod --force --grace-period=0 强制删除过2次,但问题反复多次出现,需要调查下详细原因。kubernetes版本为v1.16.6,docker版本18.09.9,containerd版本v1.2.6.

  1. 调查terminating的pod所在节点的message日志,发现kubelet对这个状态的pod提示“prober.go:103] No ref for container "docker:xxx“的报错。 但是docker ps 显示pod对应的容器是存在的。
  1. 同时检索message日志,发现kubelet对一个卡住terminating的pod,有如下报错

    ff3291732 为名为zookeeper0-xxx的pod对应的容器的ID

Aug 20 10:25:54 tke-node kubelet: E0820 10:25:54.561334 12170 remote_runtime.go:243] StopContainer "ff329173246bdc6e0c4db8fa0b3d4902380412664f74331b70197c6999f33d4e" from runtime service failed: rpc error: code = Unknown desc = operation timeout: context deadline exceeded
Aug 20 10:25:54 tke-node kubelet: E0820 10:25:54.562667 12170 kuberuntime_container.go:590] Container "docker://ff329173246bdc6e0c4db8fa0b3d4902380412664f74331b70197c6999f33d4e" termination failed with gracePeriod 30: rpc error: code = Unknown desc = operation timeout: context deadline exceeded

从kubelet日志大致可以看出,kubelet通过调用runtime(环境为docker),进行StopContainer操作时,runtime没有正常返回,导致调用超时退出,进而使pod一直卡在了terminating状态,问题在docker本身的可能性很高,下一步,应该查找docker日志分析为何docker没有响应StopContainer的操作。

  1. 查找节点的docker日志,确发现没有任何信息。只能调查kubelet对runtime的调用链。在 v1.6.0 后, Kubernetes 开始默认启用 CRI(容器运行时接口)。

    CRI 为 kubelet 提供一套抽象的容器调度的接口,主要定义了两个 grpc interface.

    • RuntimeService:容器(container) 和 (Pod)Sandbox 运行时管理
    • ImageService:拉取、查看、和移除镜像

    Kubelet 使用 gRPC 框架利用 Unix socket 同容器运行时(或者是 CRI 代理)进行通信,这一过程中 Kubelet 是客户端,CRI 代理是服务端。

    overview

    CRI 是K8S 定义的一套容器运行时接口,基于gRPC通讯,但是docker不是基于CRI的,因此 kubelet 又把docker 封装了一层,搞了一个所谓的shim,也即是dockershim的东西,dockershim 作为一个实现了CRI 接口的gRPC服务器,供 kubelet 使用。这样的过程其实就是,kubelet作为客户端 通过gRPC调用dockershim服务器,dockershim 内部又通过docker客户端走 http 调用 docker daemon api,多走了一次通讯的开销。下图是目前默认使用docker作为容器引擎的时候,调用过程。

换个视角, dockershim -> containerd 的流程 (称为 docker cri)如下

  • Kubelet 通过 CRI 接口(gRPC)调用 dockershim,请求创建一个容器。CRI 即容器运行时接口(Container Runtime Interface),这一步中,Kubelet 可以视作一个简单的 CRI Client,而 dockershim 就是接收请求的 Server。目前 dockershim 的代码其实是内嵌在 Kubelet 中的,所以接收调用的凑巧就是 Kubelet 进程

  • dockershim 收到请求后,转化成 Docker Daemon 能听懂的请求,发到 Docker Daemon 上请求创建一个容器。

  • Docker Daemon 早在 1.12 版本中就已经将针对容器的操作移到另一个守护进程——containerd 中了,因此 Docker Daemon 仍然不能帮我们创建容器,而是要请求 containerd 创建一个容器;

  • containerd 收到请求后,并不会自己直接去操作容器,而是创建一个叫做 containerd-shim 的进程,让 containerd-shim 去操作容器。这是因为容器进程需要一个父进程来做诸如收集状态,维持 stdin 等 fd 打开等工作。而假如这个父进程就是 containerd,那每次 containerd 挂掉或升级,整个宿主机上所有的容器都得退出了。而引入了 containerd-shim 就规避了这个问题(containerd 和 shim 并不是父子进程关系),这样最大的好处就是可以方便的实现live-restore能力,也就是即使containerd重启也不会影响到容器进程;

  • 我们知道创建容器需要做一些设置 namespaces 和 cgroups,挂载 root filesystem 等等操作,而这些事该怎么做已经有了公开的规范了,那就是 OCI(Open Container Initiative,开放容器标准)。它的一个参考实现叫做 runC。于是,containerd-shim 在这一步需要调用 runC 这个命令行工具,来启动容器;

  • runC 启动完容器后本身会直接退出,containerd-shim 则会成为容器进程的父进程,负责收集容器进程的状态,上报给 containerd,并在容器中 pid 为 1 的进程退出后接管容器中的子进程进行清理,确保不会出现僵尸进程。

  1. 可以看出上面的kubelet到docker runtime的调用链很长。在腾讯云原生的一篇文章-《Pod Terminating原因追踪系列之一containerd中被漏掉的runc错误信息》(https://blog.csdn.net/yunxiao6/article/details/108120909),提到了kubelet的pod删除流程,虽然文章里面使用的环境直接使用的containerd,没有使用docker,结合上面CRI的分析,大体类似。

    img

CRI插件中存在一个eventloop专门处理从containerd中获取的event。比如当容器删除后,会收到TaskExit事件,这是cri会做清理工作;比如当容器oom时,会收到OOMKill事件,cri除了清理还会更新Reason。文章也提到,过长调用链容易经常出现的docker和containerd数据不一致问题。

  1. 于是检查容器在docker和containerd状态,确实发现不一致。

    # xxx为容器的ID,可通过kubectl describe pod获得
    ctr --namespace moby --address /var/run/docker/containerd/containerd.sock  task list|grep xxx
    docker ps |grep xxx
    

    如上图,名为zookeeper0-xxx的pod,容器IDff3291732,通过containerd的ctr task list,显示在containerd中容器状态是 stopped。dockper ps确显示容器在docker中为UP状态。

    1. google为何出现状态不一致,发现github有这方面issue-【process exited, containerd task is stopped, but docker container is running】(https://github.com/docker/for-linux/issues/779),在此链接中,提到如下信息

      image-20200914224806507

    总体而言,events might not be reliable.系统发生oom时事件信息可能无法有效传递,而出现异常的环境节点,确实在dmesg日志中有大量oom的信息。

    1. 因着急业务恢复,通过docker prune和重启故障节点docker,清理了卡住的terminating的pod。
    2. 按照github的对应issue描述,此问题应该容易复现,在使用docker的情况下,貌似无法避免,待调研是否可直接使用 containerd,绕过 dockerd ?在直接使用containerd时,事件信息是否也是可靠传递?
    背景线上某环境,遇到pod删除时一直卡在terminating的问题,之前通过kubectl delete pod --force --grace-period=0强制删除过2次,但问题反复多次出现,需要调查下详细原因。kubernetes版本为v1.16.6,docker版本18.09.9,containerd版本v1.2.6.排查调查terminating的pod所在节点的message日志,发现kubelet对这个状态的pod提示“prober.go:103] No ref for cont
    nginx通过FastCGI运行PHP比Apache包含PHP环境有明显的优势,最近有消息称,PHP5.4将很有可能把PHP-FPM补丁包含在内核里,nginx服务器平台上运行PHP将更加轻松,下面我们就来看一篇php-fpm平滑启动并配置服务例子。 我的php是源码安装的。php-fpm在PHP 5.3.2以后的版本不支持以前的php-fpm (start|restart|stop|reload) ,那么如果将php-fpm配置成服务,并添加平滑启动/重启。 配置php-fpm.conf(vi /usr/local/php54/etc/php-fpm.conf),将pid(;pid = ru
    研诺逻辑科技有限公司(AnalogicTech, 纳斯达克股票市场代码:AATI) ,今日宣布推出一款高频率、高效率、恒电流升压转换器AAT1239-1,它可驱动多达10个串联的白光型发光二极管(WLED)。该款新型驱动器芯片是针对个人导航设备(PND)、电子词典、电子相框和蜂窝手机的背光应用专门设计,采用研诺专有的简化串行控制S2C单线接口,有效地减少常用的低频率脉宽调制(PWM)控制设计中产生的屏闪。   “由于便携式系统设计人员在其产品中不断扩充功能,因此他们需要使用日趋先进的照明功能来支持那些新的性能,”研诺产品线经理Phil Dewsbury说道。“通过驱动多达10个串联的WLED
    在docker/k8s时代,经常听到CRI, OCI,contained和各种shim等名词,看完本篇博文,您会有个彻底的理解。 典型的K8S Runtime架构 从最常见的Docker说起,kubelet和Docker的集成方案图如下: 当kubelet要创建一个容器时,需要以下几步: Kubelet 通过 CRI 接口(gRPC)调用 dockershim,请求创建一个容器。CRI 即容器...
    pod状态为Terminating 我们需要从pod的生命周期与Node的NotReady来分析。在节点处于“NotReady”状态时,deployment控制器会迁移节点上的容器实例,并将节点上运行的pod置为“Terminating”状态。待节点恢复后,处于“Terminating”状态的pod会自动删除。偶现部分pod(实例)一直处于“Terminating ”状态,发现这部分的pod没有得到重新调度,不能提供服务。 pod的生命周期 Pod对象自从其创建开.
    前一阵有客户docker18.06.3集群中出现Pod卡在terminating状态的问题,经过排查发现是containerd和dockerd之间事件流阻塞,导致后续事件得不到处理造成的。 定位问题的过程极其艰难,其中不乏大量工具的使用和大量的源码阅读。本文将梳理排查此问题的过程,并总结完整的dockerd和contaienrd之间事件传递流程,一步一步找到问题产生的原因,特写本文记录分享,希望大家在有类似问题发生时,能够迅速定位、解决。 对于本文中提到的问题,在docker19中已经得到解决,但docke
    docker与 contained的状态不同步 Daemonset Controller 的 BUG 最常见的多为存在finalizers资源导致pod内的容器虽被驱逐kill但是任然有容器在运行 以上问题处理请参考文档连接 https://www.bookstack.cn/read/kubernetes-pract
    本套课程涵盖Kubernetes生态圈涉及到的所有知识点,包括K8S、Docker、harbor、Gitlab、Sonarqube、Nexus、Gogs、Prometheus、EFK、Istio、SpringCloud等,含有大量企业实战项目,项目均来自老师多年工作经验总结出的真实项目,让你学完之后,实现薪资增加。 课程知识点如下1、docker容器虚拟化平台的安装和配置-dockerfile构建企业级镜像2、docker资源配额和数据持久化3、docker实战-创建私有镜像仓库和加密认证4、containerd和podman容器的安装和使用5、kubernetes深度解读-架构-组件-资源对象6、使用kubeadm搭建生产环境的多master节点k8s高可用集群7、使用kubeadm搭建生产环境的单master节点k8s集群8、Pod入门到高级-Pod资源清单编写技巧9、Pod高级实战-pod亲和性和反亲和性10、Pod高级实战-pod生命周期和健康检测11、使用kubectl管理Kubernetes容器平台12、k8s控制器-Replicaset-Deployment13、k8s控制器-Daemonset-Job14、kubernetes四层代理Service-使用技巧和使用场景15、k8s持久化存储-常见的存储卷介绍16、kubernetes控制器-Statefulset详解-管理有状态的应用17、Apiserver安全机制之RBAC授权18、基于Ingress实现k8s七层调度和负载均衡19、k8s结合Prometheus构建企业级监控告警系统 本课程可以帮助从事运维工作的同学,和需要相关知识的人,推荐从事相关工作人员,提升提升自己的同学。