【containerd】RunPodSandbox for XXX error="failed to reserve sandbox name"

问题背景

工业云部署使用k8s集群

  • k8s: 01746170708faa599113b027772802bcbb594ee8
  • containerd: v1.5.4
  • OS: Tencent tlinux 2.2 (Final)
  • kernel: Linux TENCENT64.site 3.10.0-693_4003268.tl2

问题描述

工业云同学通过控制台升级业务容器镜像版本,升级后导致容器创建失败,失败的error log如下所示:

Jun 06 20:45:29 TENCENT64.site containerd[5327]: time="2022-06-06T20:45:29.816213573+08:00" level=error msg="RunPodSandbox for &PodSandboxMetadata{Name:edge-56c86c995f-tqzz2,Uid:da70d1c2-0978-40c1-a9a6-c5a25a7f41a3,Namespace:edge-adapter,Attempt:0,} failed, error" error="failed to reserve sandbox name \"edge-56c86c995f-tqzz2_edge-adapter_da70d1c2-0978-40c1-a9a6-c5a25a7f41a3_0\": name \"edge-56c86c995f-tqzz2_edge-adapter_da70d1c2-0978-40c1-a9a6-c5a25a7f41a3_0\" is reserved for \"762b66093089b50109f74fa5a4cc6e7165d916b18dfd1b5c877fc4effff1e558\""

问题排查

  • 创建一个测试nginx的容器也创建失败,报错相同也是卡在create pod sandbox:


    image.png
  • 通过nerdctl run创建容器发现也创建失败,卡在creating 状态:

  • 查看containerd的error log:


    image.png
  • 查看kubelet日志:

Jun 06 20:45:29 TENCENT64.site containerd[5327]: time="2022-06-06T20:45:29.816213573+08:00" level=error msg="RunPodSandbox for &PodSandboxMetadata{Name:edge-56c86c995f-tqzz2,Uid:da70d1c2-0978-40c1-a9a6-c5a25a7f41a3,Namespace:edge-adapter,Attempt:0,} failed, error" error="failed to reserve sandbox name \"edge-56c86c995f-tqzz2_edge-adapter_da70d1c2-0978-40c1-a9a6-c5a25a7f41a3_0\": name \"edge-56c86c995f-tqzz2_edge-adapter_da70d1c2-0978-40c1-a9a6-c5a25a7f41a3_0\" is reserved for \"762b66093089b50109f74fa5a4cc6e7165d916b18dfd1b5c877fc4effff1e558\""
  • 环境中发现kworker占用CPU的使用率很高:


    image.png
  • 集群上的Pod IP分配情况:


    image.png
  • 内存使用情况


    image.png
  • 有个containerd的僵尸进程是5月25号启动的,被systemd 1号进程托管,kill -9也杀不掉该进程

  • 环境中存在chaosmesh 进程使用containerd,

ps -ef | grep chao
root        752 101375  0 16:05 pts/1    00:00:00 grep --color=auto chao
root      60780  59079  0 06:30 ?        00:00:03 /usr/local/bin/chaos-daemon --runtime containerd --http-port 31766 --grpc-port 31767 --pprof --ca /etc/chaos-daemon/cert/ca.crt --cert /etc/chaos-daemon/cert/tls.crt --key /etc/chaos-daemon/cert/tls.key --runtime-socket-path /host-run/containerd.sock

问题处理

  • GitHub上搜索相关的issue,发现有类似error的issue:https://github.com/containerd/containerd/issues/4604
  • 根据issue描述,初步怀疑是磁盘的IO过高导致容器创建失败,此问题社区已经有对应的bug fix PR:https://github.com/containerd/containerd/pull/6478/files
  • 由于1.5.4版本中没有这个fix,所以在环境上升级了containerd版本,v1.5.10,这个版本包含对应的code fix,并且重启了机器,机器重启后pod都正常running,kworker使用CPU也恢复正常,由于当时没有查看IO的使用情况,所以不能排除IO不是真正的root cause,此问题需要继续跟进。

后续问题跟进

  • 环境上已经替换为新版本的containerd,后面继续观察集群节点上的IO使用情况iotop,kworker的资源使用情况top;
  • 在自测环境中做压力测试复现问题:
stress-ng --io 30 -d 5
image.png

创建nginx deployment:

kubectl apply -f nginx.yaml
 kubectl get pods
NAME                               READY   STATUS              RESTARTS   AGE
nginx-deployment-857cbc9c6-7plrb   0/1     ContainerCreating   0          7m41s
nginx-deployment-857cbc9c6-f5gjq   0/1     ContainerCreating   0          7m40s
image.png

kubelet error log:


image.png

containerd error log:

Jun 07 21:03:05 VM-71-117-ubuntu containerd[14269]: time="2022-06-07T21:03:05.036947355+08:00" level=error msg="RunPodSandbox for &PodSandboxMetadata{Name:nginx-deployment-857cbc9c6-f5gjq,Uid:29d9b646-2ed6-411d-b89a-5e1526de3393,Namespace:default,Attempt:0,} failed, error" error="failed to reserve sandbox name \"nginx-deployment-857cbc9c6-f5gjq_default_29d9b646-2ed6-411d-b89a-5e1526de3393_0\": name \"nginx-deployment-857cbc9c6-f5gjq_default_29d9b646-2ed6-411d-b89a-5e1526de3393_0\" is reserved for \"aa39cc65311ca413accf095a659c372b02e987d5b97687d3241c830f3b1091d5\""

把压力测试进程停掉,pod就创建成功了:

kubectl get pods
NAME                               READY   STATUS    RESTARTS   AGE
nginx-deployment-857cbc9c6-7plrb   1/1     Running   0          14m
nginx-deployment-857cbc9c6-f5gjq   1/1     Running   0          14m
  • 使用containerd v1.5.10做压力测试
    创建Pod还是会卡在creating状态大概五分钟,最后状态变成RunContainerError状态,最后还是会报错failed to reserve sandbox name \"nginx-deployment-857cbc9c6-sp5rp_default_c2c8a3d4-0e02-4688-8b6e-711a0f6525c5_0\": name \"nginx-deployment-857cbc9c6-sp5rp_default_c2c8a3d4-0e02-4688-8b6e-711a0f6525c5_0\" is reserved for \"39ab9d7b6250608fd911ff079f3d0781044674e2d6a1e58893ed422d6a2adb60\""
 Normal   Scheduled               7m41s  default-scheduler  Successfully assigned default/nginx-deployment-857cbc9c6-sp5rp to 10.0.71.117
  Warning  FailedCreatePodSandBox  3m37s  kubelet            Failed to create pod sandbox: rpc error: code = DeadlineExceeded desc = context deadline exceeded
root@VM-71-117-ubuntu:~# kubectl get pods
NAME                               READY   STATUS              RESTARTS   AGE
nginx-deployment-857cbc9c6-sp5rp   0/1     ContainerCreating   0          7m23s
nginx-deployment-857cbc9c6-wm88t   0/1     RunContainerError   0          7m24s

kubelet log:

Jun 08 10:00:13 VM-71-117-ubuntu kubelet[11643]: E0608 10:00:13.322478   11643 pod_workers.go:190] "Error syncing pod, skipping" err="failed to \"CreatePodSandbox\" for \"nginx-deployment-857cbc9c6-sp5rp_default(c2c8a3d4-0e02-4688-8b6e-711a0f6525c5)\" with CreatePodSandboxError: \"Failed to create sandbox for pod \\\"nginx-deployment-857cbc9c6-sp5rp_default(c2c8a3d4-0e02-4688-8b6e-711a0f6525c5)\\\": rpc error: code = DeadlineExceeded desc = context deadline exceeded\"" pod="default/nginx-deployment-857cbc9c6-sp5rp" podUID=c2c8a3d4-0e02-4688-8b6e-711a0f6525c5

containerd log:


image.png
  • 分析错误产生的原因
    1、kubelet 发送请求给 containerd 创建容器,当 containerd 第一次尝试创建这个容器的时候,它会创建名为Attempt的元数据,该变量保持默认值为0代码)
    2、在kubelet和containerd之间发生context timeout
    3、在下一次kubelet运行 SyncPod 时,kubelet 会尝试再次创建相同的容器。但是,它不会在 CreateContainer 超时时增加Attempt次数,只会在容器重新启动时增加,在超时之后,Attempt number 不会增加,但是 CRI 已经保留了容器名称,因此所有后续创建相同容器的请求都会失败代码
    这是kubelet和containerd的正常的行为,如果容器设置策略为restartPolicy:Always or restartPolicy:OnFailure当磁盘IO下降,containerd最终会创建容器成功。(根据前面的压测结果,如果kill掉IO比较高的压测进程,容器会很快创建成功。)
  • PR fix解析
    目前社区内针对这个问题,merge了一个PR ,此PR主要是解决在createContainer的时候调用umount触发内核调用sync-fs,这样会增加磁盘的IO开销,使用readonly mount就不会掉用sync-fs方法,此PR改用readonly mount,这样可以减少 PodCreateContainer 中的 syncfs,减小containerd带来的IO开销,从而加快容器的创建,但它不能减少 runc 进程中的 mount 时的产生的磁盘IO。
    所以继续跟踪发现:runc init确实也卡住了
root      3516  3508  0 15:54 pts/1    00:00:00 runc init
image.png
image.png

通过ps aux | grep runc会发现有些runc stack是卡在do_mount上,并且runc的进程状态是D,什么是D状态呢?D状态的进程通常是在等待IO,比如磁盘IO,网络IO,其他外设IO,很明显这块是在等待磁盘IO。

  • 目前的解决方法
    从上面的排查和社区的分析来看,此问题主要是磁盘IO过高导致的,所以要解决问题,就是从如何降低磁盘IO出发,上面的PR fix也是从containerd方面降低磁盘IO:
    1、更换高性能的磁盘,提高磁盘IO,增大磁盘容量;
    2、增加集群节点,对于高IO的业务,迁移到其它节点,减小节点的IO(公有云的解决方法是加cbs或者挪到eks);
    3、在更新业务的时候,不要同时更新多个,可以每次保持最小化更新,防止pull image加大磁盘IO导致更新失败。

你可能感兴趣的:(【containerd】RunPodSandbox for XXX error="failed to reserve sandbox name")