首页 > 其他分享 >Containerd组件 —— containerd-shim-runc-v2作用

Containerd组件 —— containerd-shim-runc-v2作用

时间:2023-07-04 15:01:42浏览次数:52  
标签:容器 00 shim Containerd runc v2 containerd 进程

1、概述

  通过《浅析开源容器标准——OCI》、《浅析容器运行时》和《浅析Kubernetes CRI》这三篇博文我们了解了容器标准OCI、容器运行时以及Kubernetes CRI,在本文以当前最火的容器运行时containerd为例,讲解下它是如何运行和管理容器进程的。

  在讲解containerd是如何运行和管理容器进程前,先通过简单说下Kubelet + CRI + OCI工作流程以回顾下上面三篇博文的内容。

  1. Kubelet在节点上接收到Pod的定义(Pod调度到当前节点上)。

  2. Kubelet通过CRI(Container Runtime Interface)与容器运行时(例如containerd)通信,告知要创建一个新的容器。

  3. 容器运行时(containerd)使用OCI(Open Container Initiative)容器运行时标准来创建容器,包括设置容器的运行时环境、文件系统挂载和网络配置。

  4. 容器运行时(containerd)创建完成后,将容器的状态反馈给Kubelet,表示容器已经启动并正在运行。

  总之,Kubelet作为Kubernetes节点上的代理,负责接收和处理Pod定义,通过CRI与容器运行时(如containerd)通信来创建和管理容器。容器运行时使用OCI标准来创建容器,而Kubelet负责监控容器的状态并协调Pod中多个容器的启动和关联关系。整个流程确保Pod中的容器能够成功启动和运行。

2、简述containerd各组件功能

  通过containerd.io 1.6.6版本rpm包的文件列表来简述下containerd各组件功能:

  • /usr/lib/systemd/system/containerd.service:systemd标准的Unit文件,被systemd管理:systemctl start|stop containerd.service。
  • /usr/bin/containerd:containerd的守护进程文件,在containerd.service Unit文件中通过ExecStart=/usr/bin/containerd调用,以启动containerd守护进程。
  • /etc/containerd/config.toml:在启动过程中加载此配置文件,可以在该配置文件中进行丰富多样的配置,以令containerd更贴合我们的实际需要(比如配置私有镜像源等)。
  • /usr/bin/containerd-shim:containerd套件,其目的主要是隔离containerd和容器。containerd守护进程收到gRPC调用请求(比如来自Kubelet或Docker的创建容器请求),便会启动/usr/bin/containerd-shim套件。
  • /usr/bin/containerd-shim-runc-v2:containerd-shim启动后会去启动/usr/bin/containerd-shim-runc-v2,然后立即退出,此时containerd-shim-runc-v2的父进程就变成了systemd(1),这样containerd-shim-runc-v2就和containerd脱离了关系,即便containerd退出也不会影响到容器(这也是containerd-shim套件的作用)。
  • /usr/bin/runc:OCI标准的具体实现就是runc,真正创建和维护容器最终便是由runc来完成的。/usr/bin/containerd-shim-runc-v2会启动runc去create、start容器,然后runc立即退出,容器的父进程就变成了containerd-shim-runc-v2,这也是容器内部可以看到的PID=1的init进程。
  • /usr/bin/ctr:容器管理的客户端工具,可以对标docker命令。
rpm -ql containerd.io
/etc/containerd
/etc/containerd/config.toml
/usr/bin/containerd
/usr/bin/containerd-shim
/usr/bin/containerd-shim-runc-v1
/usr/bin/containerd-shim-runc-v2
/usr/bin/ctr
/usr/bin/runc
/usr/lib/systemd/system/containerd.service

  本文主题是containerd是如何运行和管理容器进程的,通过containerd各功能组件的介绍,我们可以清晰的知道containerd是通过containerd-shim-runc-v2组件进行进程管理的,所以下文主要讲解containerd的containerd-shim-runc-v2组件。

3、Containerd通过containerd-shim-runc-v2组件管理进程

  通过《浅析容器运行时》这篇博文和本文第二章节对containerd各组件功能介绍我们可知。

  1. 当客户端(Kubelet或者DockerDaemon等)调用 containerd 来创建一个容器时,containerd 收到请求后,并不会直接去操作容器,而是创建一个叫做 containerd-shim 的进程,让这个进程去操作容器;  
  2. containerd-shim 启动后会去启动一个叫做 /usr/bin/containerd-shim-runc-v2 的进程,然后立即退出,此时 containerd-shim-runc-v2 的父进程就变成了systemd(1),这样 containerd-shim-runc-v2 就和containerd脱离了关系,即便containerd退出也不会影响到容器(这也是containerd-shim套件的作用);
  3. 之后 /usr/bin/containerd-shim-runc-v2 会运行runc这个二进制文件去create、start容器,runc 启动完容器后本身会直接退出, containerd-shim-runc-v2 则会成为容器进程的父进程, 负责收集容器进程的状态, 上报给 containerd, 并在容器中 pid 为 1 的进程退出后接管容器中的进程(containerd-shim-runc-v2进程所有子孙进程)进行清理, 确保不会出现僵尸进程。   

注意 1: 为什么需要引入 containerd-shim-runc-v2 ?  

  我们指定容器进程是需要一个父进程来做状态收集、维持 stdin 等 fd 打开等工作的,假如这个父进程就是 containerd,那如果 containerd 挂掉的话,整个宿主机上所有的容器都得退出了,而引入 containerd-shim 这个垫片就可以来规避这个问题了。

  • containerd-shim可以翻译成垫片或者中间件;
  • containerd-shim可以认为是托管我们容器父进程的一个工具;
  • 每一个容器起起来之后,都会有一个conatinerd-shim存在;
  • containerd-shim主要是来控制你的容器的。

 4、通过实战观察containerd-shim-runc-v2组件和容器进程关系

以docker作为客户端,观察docker调用 containerd 来创建一个容器时,containerd-shim-runc-v2组件和容器进程关系。

4.1 环境检查

[root@pdh1 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@pdh1 ~]# ps -ef|grep containerd|grep -v grep
root      1057     1  0 Apr19 ?        00:12:26 /usr/bin/containerd
root      1371     1  0 Apr19 ?        00:19:27 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

可以看到,当前没有容器在这台机器上跑,只有一个containerd进程,没有containerd-shim-runc-v2进程。

4.2 启动一个busybox容器

启动一个busybox容器,启动命令为:sleep 10000秒。

[root@pdh1 ~]# docker run -d busybox:1.28 sleep 10000
fa19597696960f0ce6414eccc7402c25fb66be021707c31ab03034cd01f80d81
[root@pdh1 ~]# docker ps
CONTAINER ID   IMAGE          COMMAND         CREATED          STATUS          PORTS     NAMES
fa1959769696   busybox:1.28   "sleep 10000"   14 seconds ago   Up 13 seconds             serene_germain
[root@pdh1 ~]# ps -ef|grep containerd|grep -v grep
root      1057     1  0 Apr19 ?        00:12:26 /usr/bin/containerd
root      1371     1  0 Apr19 ?        00:19:28 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root     29765     1  0 10:09 ?        00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id fa19597696960f0ce6414eccc7402c25fb66be021707c31ab03034cd01f80d81 -address /run/containerd/containerd.sock

可以看到,宿主机上,多了一个/usr/bin/containerd-shim-runc-v2进程,PID为29765,它的父进程(ppid)是1,而不是containerd进程。由此可以证明,当客户端调用 containerd 来创建一个容器时,containerd 收到请求后,并不会直接去操作容器,而是创建一个叫做 containerd-shim 的进程,让这个进程去操作容器;containerd-shim 启动后会去启动一个叫做 /usr/bin/containerd-shim-runc-v2 的进程,然后立即退出,此时 containerd-shim-runc-v2 的父进程就变成了systemd(1),这样 containerd-shim-runc-v2 就和containerd脱离了关系,即便containerd退出也不会影响到容器。

4.3 查看containerd-shim-runc-v2进程的子进程

继续看一下这个containerd-shim-runc-v2进程,生出了哪些“宝宝”(子进程)。

[root@pdh1 ~]# ps -ef|grep 29765|grep -v grep
root     29765     1  0 10:09 ?        00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id fa19597696960f0ce6414eccc7402c25fb66be021707c31ab03034cd01f80d81 -address /run/containerd/containerd.sock
root     29785 29765  0 10:09 ?        00:00:00 sleep 10000

可以看到,containerd-shim-runc-v2进程fork出sleep 10000进程(PID=29785), 这正是busybox容器的主进程, 是通过docker run 时设置进去的。

当然也可以使用docker top [容器ID]来查看当前容器的父进程。

[root@pdh1 ~]# docker ps
CONTAINER ID   IMAGE          COMMAND         CREATED         STATUS         PORTS     NAMES
fa1959769696   busybox:1.28   "sleep 10000"   6 minutes ago   Up 6 minutes             serene_germain
[root@pdh1 ~]# docker top fa1959769696
UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
root                29785               29765               0                   10:09               ?                   00:00:00            sleep 10000

由此可以证明, /usr/bin/containerd-shim-runc-v2 调用runc二进制文件创建、启动容器后,runc 启动完容器后本身会直接退出, containerd-shim-runc-v2 则会成为容器主进程(容器内部PID=1 的进程)的父进程。  

4.4 进入到容器中查看容器内进程

[root@pdh1 ~]# docker ps
CONTAINER ID   IMAGE          COMMAND         CREATED         STATUS         PORTS     NAMES
fa1959769696   busybox:1.28   "sleep 10000"   9 minutes ago   Up 9 minutes             serene_germain
[root@pdh1 ~]# docker exec -it fa1959769696 ps -ef
PID   USER     TIME  COMMAND
    1 root      0:00 sleep 10000
   23 root      0:00 ps -ef

除了ps 进程外,容器里,只有一个sleep 10000的进程,它在容器里为PID=1,是容器的主进程,起着操作系统的systemd作用。

4.5 在容器里面运行一个长期运行的命令

ps命令跑完结束了,我们在容器里跑一个长期运行的命令:sleep 20000

4.6 换一个终端,继续观察containerd-shim-runc-v2进程的子进程

[root@pdh1 ~]# docker ps
CONTAINER ID   IMAGE          COMMAND         CREATED          STATUS          PORTS     NAMES
fa1959769696   busybox:1.28   "sleep 10000"   13 minutes ago   Up 13 minutes             serene_germain
[root@pdh1 ~]# ps -ef|grep containerd|grep -v grep
root      1057     1  0 Apr19 ?        00:12:26 /usr/bin/containerd
root      1371     1  0 Apr19 ?        00:19:28 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
root     29765     1  0 10:09 ?        00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id fa19597696960f0ce6414eccc7402c25fb66be021707c31ab03034cd01f80d81 -address /run/containerd/containerd.sock
[root@pdh1 ~]#  ps -ef|grep 29765|grep -v grep
root     29765     1  0 10:09 ?        00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id fa19597696960f0ce6414eccc7402c25fb66be021707c31ab03034cd01f80d81 -address /run/containerd/containerd.sock
root     29785 29765  0 10:09 ?        00:00:00 sleep 10000
root     32315 29765  0 10:22 pts/0    00:00:00 sleep 20000

可以看到,在宿主机上,那个containerd-shim-runc-v2又多了一个子进程:sleep 20000(PID=32315)。

4.7 再次进入到容器中查看容器内进程

[root@pdh1 ~]# docker ps
CONTAINER ID   IMAGE          COMMAND         CREATED          STATUS          PORTS     NAMES
fa1959769696   busybox:1.28   "sleep 10000"   23 minutes ago   Up 23 minutes             serene_germain
[root@pdh1 ~]# docker exec -it fa19 /bin/sh
/ # 

在容器内部执行top命令。

Mem: 8715620K used, 7552384K free, 794432K shrd, 3268K buff, 6090752K cached
CPU:  2.4% usr  2.4% sys  0.0% nic 95.1% idle  0.0% io  0.0% irq  0.0% sirq
Load average: 0.03 0.03 0.09 2/499 48
  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
   42     0 root     S     1232  0.0   1  0.0 /bin/sh
   48    42 root     R     1228  0.0   3  0.0 top
    1     0 root     S     1216  0.0   0  0.0 sleep 10000
   29     0 root     S     1216  0.0   3  0.0 sleep 20000 

在容器内部可以看到sleep 10000、sleep 20000这两个命令以及进入容器内部命令/bin/sh进程的父进程都是0,在宿主机上这三个进程都是/usr/bin/containerd-shim-runc-v2进程(PID为29765)进程的子进程。

[root@pdh1 ~]# ps -ef|grep 29765|grep -v grep
root      2151 29765  0 10:32 ?        00:00:00 /bin/sh
root     29765     1  0 10:09 ?        00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id fa19597696960f0ce6414eccc7402c25fb66be021707c31ab03034cd01f80d81 -address /run/containerd/containerd.sock
root     29785 29765  0 10:09 ?        00:00:00 sleep 10000
root     32315 29765  0 10:22 pts/0    00:00:00 sleep 20000  

使用pstree命令显示/usr/bin/containerd-shim-runc-v2进程(PID为29765)进程号树状信息。

[root@pdh1 ~]# pstree -p 29765
containerd-shim(29765)─┬─sh(2151)───top(2327)
                       ├─sleep(29785)
                       ├─sleep(32315)
                       ├─{containerd-shim}(29766)
                       ├─{containerd-shim}(29767)
                       ├─{containerd-shim}(29768)
                       ├─{containerd-shim}(29769)
                       ├─{containerd-shim}(29770)
                       ├─{containerd-shim}(29771)
                       ├─{containerd-shim}(29772)
                       ├─{containerd-shim}(29773)
                       ├─{containerd-shim}(29774)
                       ├─{containerd-shim}(29775)
                       ├─{containerd-shim}(29811)
                       ├─{containerd-shim}(29818)
                       ├─{containerd-shim}(32321)
                       ├─{containerd-shim}(2159)
                       └─{containerd-shim}(2160)
[root@pdh1 ~]# 

和上面top命令结果吻合,sh、sleep、sleep这三个进程都是containerd-shim-runc-v2的子进程(PID为29765),top这个进程又是sh这个进程衍生出来子进程。

[root@pdh1 ~]# ps -ef|grep 2151|grep -v grep
root      2151 29765  0 10:32 ?        00:00:00 /bin/sh
root      2327  2151  0 10:33 ?        00:00:00 top

由此可以证明,容器本质上就是宿主机上的一个特殊的进程,通过 Namespace 实现资源(网络、文件系统等)隔离,通过 Cgroups 实现资源(CPU、内存)限制,让我们使用起来就感觉像在操作虚拟机一样(但其和虚拟机有本质上的区别,那就是容器和宿主机是共享同一个内核的)。为了将我们的应用进程运行在容器中,容器运行时通过更加简单的接口和命令去帮我们调用 Linux 的系统功能来运行和管理容器进程和容器镜像。

注意 1:安装pstree命令,psmisc时一个进程管理软件包套装,里面拥有很多小工具来管理linux系统进程,pstree只是它的其中的一个。

yum install -y psmisc

注意 2:通过pstree列出来的containerd-shim进程的子进程containerd-shim(29766)通过ps -ef是查询不到的。

4.8  杀死容器主进程

[root@pdh1 ~]# ps -ef|grep 29765|grep -v grep
root      2151 29765  0 10:32 ?        00:00:00 /bin/sh
root     29765     1  0 10:09 ?        00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id fa19597696960f0ce6414eccc7402c25fb66be021707c31ab03034cd01f80d81 -address /run/containerd/containerd.sock
root     29785 29765  0 10:09 ?        00:00:00 sleep 10000
root     32315 29765  0 10:22 pts/0    00:00:00 sleep 20000  
[root@pdh1 ~]# kill -9 29785
[root@pdh1 ~]# ps -ef|grep 29765|grep -v grep
[root@pdh1 ~]# 
[root@pdh1 ~]# docker ps -a
CONTAINER ID   IMAGE                         COMMAND                  CREATED             STATUS                       PORTS     NAMES
fa1959769696   busybox:1.28                  "sleep 10000"            About an hour ago   Exited (137) 2 minutes ago             serene_germain
[root@pdh1 ~]# ps -ef|grep containerd|grep -v grep
root      1050     1  0 11:00 ?        00:00:00 /usr/bin/containerd
root      1316     1  0 11:00 ?        00:00:00 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

在宿主机执行kill -9命令杀死容器主进程(容器内部 PID=1 的init进程),可以看到容器中的其他子进程和containerd-shim-runc-v2进程(PID为29765)都会被清理,由此说明,containerd-shim-runc-v2负责收集容器进程的状态, 上报给 containerd, 并在容器中 pid 为 1 的进程退出后接管容器中的子进程进行清理, 确保不会出现僵尸进程。

4.9  containerd-shim-runc-v2进程和容器个数的关系

[root@node1 ~]# ps -ef|grep containerd|grep -v grep|wc -l    #由4.1可知,统计containerd进程个数需要-2
439
[root@node1 ~]# docker ps -q | wc -l
437

在一台运行多个容器的物理机上分别统计运行容器和containerd-shim-runc-v2进程个数的关系,可以得出containerd-shim-runc-v2进程个数等于当前机器上运行容器个数。

5、总结 

  通过本博文阐述的内容,可以得出以下结论:  

  1. 当客户端(Kubelet或者DockerDaemon等)调用 containerd 来创建一个容器时,containerd 收到请求后,并不会直接去操作容器,而是创建一个叫做 containerd-shim 的进程,让这个进程去操作容器;  
  2. containerd-shim 启动后会去启动一个叫做 /usr/bin/containerd-shim-runc-v2 的进程,然后立即退出,此时 containerd-shim-runc-v2 的父进程就变成了systemd(1),这样 containerd-shim-runc-v2 就和containerd脱离了关系,即便containerd退出也不会影响到容器(这也是containerd-shim套件的作用);
  3. 之后 /usr/bin/containerd-shim-runc-v2 会运行runc这个二进制文件去create、start容器,runc 启动完容器后本身会直接退出, containerd-shim-runc-v2 则会成为容器进程的父进程, 负责收集容器进程的状态, 上报给 containerd, 并在容器中 pid 为 1 的进程退出后接管容器中的进程(containerd-shim-runc-v2进程所有子孙进程)进行清理, 确保不会出现僵尸进程。  
  4. 容器本质上就是宿主机上的一个特殊的进程,通过 Namespace 实现资源(网络、文件系统等)隔离,通过 Cgroups 实现资源(CPU、内存)限制,让我们使用起来就感觉像在操作虚拟机一样(但其和虚拟机有本质上的区别,那就是容器和宿主机是共享同一个内核的)。为了将我们的应用进程运行在容器中,容器运行时通过更加简单的接口和命令去帮我们调用 Linux 的系统功能来运行和管理容器进程和容器镜像。(在容器里看到的所有进程,其实都是在宿主机上的,容器技术只不过中用了“障眼法”,把它们的pid改了,让我们误以为容器是跑一个独立的环境中,这个技术叫PID Namespace。)
  5. 当前机器containerd-shim-runc-v2进程个数等于当前机器上运行容器个数。

    

参考:观察containerd-shim-runc-v2进程与容器里的1号进程

参考:Containerd shim 進程 PPID 之謎

标签:容器,00,shim,Containerd,runc,v2,containerd,进程
From: https://www.cnblogs.com/zhangmingcheng/p/17524721.html

相关文章

  • containerd 安装和配置
    使用containerd不仅性能提高了(调用链变短了),而且资源占用也会变小(Docker不是一个纯粹的容器运行时,具有大量其他功能)。调用链Docker作为k8s容器运行时,调用关系如下:kubelet-->dockershim(在kubelet进程中)-->dockerd-->containerdContainerd作为k8s容器运行时,......
  • 焰火十二卷调色板软件 v2.8.27 更新进度说明
    ​ 调色板是数字创意时代的重要工具,它能够影响设计作品的视觉效果和美感。焰火十二卷是一款免费开源的色彩编辑器,它可以让你从色轮或者其他来源生成一组协调的色彩,并且可以自由调整色彩的属性(比如亮度、饱和度、对比度等)。也可以把生成的色彩保存为色彩组或者色库,并且可以方便地......
  • nacos-sdk-go/v2版本 提示客户端连接不上
    nacos-sdk-gov2报错提示客户端连接不上标签(空格分隔):nacos前言nacos版本:v2nacos-sdk-go版本:v2背景:使用nacos-sdk-go来获取配置,发现一直在找缓存目录的文件,但使用openapi可以获取到配置报错信息clientnotconnected,currentstatus:STARTING提示客户端连接失败???1999-0......
  • rsync 遇到中文乱码文件名无法同步,并报错:rsync: rename "/test1/abc/abc/opt/abc/abc/
    rsync遇到中文文件名乱码报错报错如下:rsync:rename"/test1/abc/def/efg/abc-V2/img_abc/.δ\#261\#352\#314\#342-3.jpg.wdPu5C"->"event/abc-V2/img_abc/δ\#261\#352\#314\#342-3.jpg":Input/outputerror(5)rsync:rename"/test1/abc/def/e......
  • Codeforces Round 881 Div2 A-F1题解
    codeforcesround881div2题解马上要秋招了,自己本事全丢了,感觉如果这样的话今年就估计要饿死了。先打div3,7月份得开始收心了A.SashaandArrayColoring题意,可以分任意组,每组的贡献是max-min,问最大贡献显然是贪心,从大到小配对一下就行,不想放代码了’B.LongLong给出一......
  • 赛灵思FPGA匹配CMV2000,图纸资料齐全,提供代码及说明,pcb等,可科研,可生产
     "赛灵思公司的可编程逻辑器件(FPGA)与CMV2000相匹配,我们提供了完整的图纸资料,包括代码和说明,还有PCB设计等。这些资源既可以用于科研,也可以用于生产。"涉及到的知识点和领域范围包括:1.赛灵思(Xilinx):赛灵思是一家知名的半导体公司,专注于可编程逻辑器件(FPGA)和相关技术的研发和制造......
  • 界面组件DevExpress WPF v23.1新版亮点 - 启动和内存优化
    DevExpressWPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpressWPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸的解决方案。无论是Office办公软件的衍伸产品,还是以数据为中心......
  • 西门子V20变频器和200Smart通讯程序
    西门子V20变频器和200Smart通讯程序。    硬件配置有:西门子ST2O一台,威伦触摸屏TK607OiQ一台,V2O变频器一台,三相220∨小电机一个。                            程序功能介绍:使用MODBUS通讯控制变频器正转,反转,......
  • 11-gorm-v2-03-基本查询
    @目录1.简单示例2.基本查询2.1获取第一条记录,按主键排序2.2获取一条记录,不指定排序2.3获取最后一条记录,按主键排序2.4获取所有的记录2.5通过主键进行查询(仅适用于主键是数字类型)2.6查询指定字段3.where3.1原生sql3.1.1简单使用3.1.2<>(不为)3.1.3IN3.1.4LIKE3.1.5......
  • 11-gorm-V2-04-高级查询
    @目录1.用Struct或Map接收数据1.1Find到Struct1.2Find到Map2.子查询3.Group/Having3.1Group完整示例3.2Having4.变量4.1使用sql.Named定义4.2使用map定义变量5.用Rows()迭代6.查钩子7.Pluck(单列查询)8.Scopes(调用查询函数)8.1使用8.2示例9.Count1.用Struct或Map......