景德镇网站建设哪家最好/网络宣传的好处
参考
- docker,containerd,runc,docker-shim 之间的关系
- Containerd shim 进程 PPID 之谜
- 内核大神教你从 Linux 进程的角度看 Docker
- RunC 简介
- OCI和runC
- Containerd 简介
- 从 docker 到 runC
- Dockershim究竟是什么
- 技术干货|Docker和 Containerd 的区别,看这一篇就够了
- Docker,containerd,CRI,CRI-O,OCI,runc 分不清?看这一篇就够了
- k8s、dockershim、containershim、容器运行时的关系
- Docker服务进程关系
- 关于容器中进程的继承关系
- containerd,containerd-shim和runc的依存关系
- dockerd、contaierd、containerd-shim、runC通信机制分析
- docker,containerd,runc,docker-shim 之间的关系 k8s cri 的演变
- 容器中的 Shim 到底是个什么鬼?
排错博客整理
-
【Pod Terminating原因追踪系列之一】containerd中被漏掉的runc错误信息
-
pod terminating 排查之旅
-
pod terminating 排查之旅(二)
-
docker hang 死排查之旅
-
最新的示意图(取消了 docker-shim)
- Kubernetes 的容器运行时对接示意图
名词 | 解释 | 补充 |
---|---|---|
OCI | OCI(open Container Initiative)容器标准化组织的主要目的是推进容器技术的标准化。对容器标准进行准确的定义。其主要目的是为了解决容器标准混乱的问题。没有统一的容器标准,工业界就无法按照统一的标准进行容器开发。因此OCI于2015年由docker牵头和其他公司制定了相应的容器标准。 OCI目前包含两个标准: runtime-spec和image-spec。分别定义了容器运行时标准和容器镜像标准。 - 可以理解为,是个标准,统一创建容器的接口以及镜像的结构 | 接口规范标准 |
RunC | RunC 是一个轻量级的工具,它是用来运行容器的 - 可以理解为实现了 OCI 定义的接口的工具 | 标准的简单实现 |
Containerd | Containerd 是一个工业级标准的容器运行时,它强调简单性、健壮性和可移植性。Containerd 可以在宿主机中管理完整的容器生命周期:容器镜像的传输和存储、容器的执行和管理、存储和网络等。 详细点说,Containerd 负责干下面这些事情: - 管理容器的生命周期(从创建容器到销毁容器) - 拉取/推送容器镜像 - 存储管理(管理镜像及容器数据的存储) - 调用 runC 运行容器(与 runC 等容器运行时交互) - 管理容器网络接口及网络 注意:Containerd 被设计成嵌入到一个更大的系统中,而不是直接由开发人员或终端用户使用。 | 较为丰富的功能,对 RunC 的封装 工业级容器运行时,主要用于大型系统,不直接面向用户 |
Docker | docker本身而言,包括docker client和dockerd,是一个客户端工具,用来把用户的请求发送给docker daemon(dockerd)。 dockerd:dockerd是对容器相关操作的最上层封装,直接面向操作用户。Docker daemon,一般也会被称为docker engine。dockerd启动时会启动containerd 子进程。 | 封装了 Containerd,可以理解为面向用户级别的产品 |
简单总结 | - OCI :是个容器和镜像标准,定义了一些接口和规范 - RunC : 实现了 OCI 标准,可以实现容器的创建,功能比较简单 - Containerd:封装了 RunC,提供更丰富功能,适用于工业级需求(对接大型系统,如k8s) - Docker:引擎部分 dockerd 封装了 Containerd,提供 client 端由客户操作,用户级别的产品 | |
CRI | CRI(容器运行时接口)是 Kubernetes 用来控制创建和管理容器的不同运行时的 API,它使 Kubernetes 更容易使用不同的容器运行时。它一个插件接口,这意味着任何符合该标准实现的容器运行时都可以被 Kubernetes 所使用 | 接口规范标准 |
Docker-shim | 在 Kubernetes 包括一个名为 dockershim 的组件,使它能够支持 Docker。**但 Docker 由于比 Kubernetes 更早,没有实现 CRI,所以这就是 dockershim 存在的原因,它支持将 Docker 被硬编码到 Kubernetes 中。**随着容器化成为行业标准,Kubernetes 项目增加了对额外运行时的支持,比如通过 Container Runtime Interface (CRI) 容器运行时接口来支持运行容器。因此 dockershim 成为了 Kubernetes 项目中的一个异类,对 Docker 和 dockershim 的依赖已经渗透到云原生计算基金会(CNCF)生态系统中的各种工具和项目中,导致代码脆弱。 | 是组件 |
K8s决定在 1.20 开始放弃 Docker,并在1.21完全抛弃 Docker 的支持。。今后 Kubernetes 将取消对 Docker 的直接支持,而倾向于只使用实现其容器运行时接口的容器运行时,这可能意味着使用 containerd 或 CRI-O。这并不意味着 Kubernetes 将不能运行 Docker 格式的容器。containerd 和 CRI-O 都可以运行 Docker 格式(实际上是 OCI 格式)的镜像,它们只是无需使用 docker 命令或 Docker 守护程序。 | ||
适配器,将k8s cri接口与各种容器实现的接口进行适配 - 早期,k8s cri 容器运行时接口直接对接 docker,由于 cri 是个标准(有固定的接口形式),因此为了将 k8s cri 的命令传达给 docker,需要有个翻译,也就是 docker-shim | ||
Containerd-shim | 调用runc启动容器,监控容器进程状态,回收容器中的相关进程等 - 一个 containerd-shim 进程只负责管理一个运行的容器 - 通过 docker 运行容器,containerd-shim 进程可能被命名为 docker-containerd-shim - k8s 1.24 后,cri 直接对接了 containerd,容器对应的 shim 进程名称为 containerd-shim | 是进程 |
CRI-O | CRI-O 是另一个实现了容器运行时接口(CRI)的高级别容器运行时,可以使用 OCI(开放容器倡议)兼容的运行时,它是 containerd 的一个替代品。 CRI-O 诞生于 RedHat、IBM、英特尔、SUSE、Hyper 等公司。它是专门从头开始创建的,作为 Kubernetes 的一个容器运行时,它提供了启动、停止和重启容器的能力,就像 containerd 一样。 | 是组件 注意是容器运行时,和containerd 同等地位 |
k8s 调用链路的变化 | ||
K8s 1.21 前调用链路 | K8S -> kubelet -> grpc call -> Dockerd --> Containerd-> runC - 进程纳管情况:Containerd(纳管所有containerd-shim) --> Containerd-shim(纳管单个容器) --> 容器进程 | |
k8s 1.21 后调用链路 | K8S -> kubelet -> grpc call -> Containerd-> runC - 进程纳管情况:Root-init(宿主机上1号进程)–> Containerd-shim(纳管单个容器) --> 容器进程 - 如何实现被 Root-init 进程纳管呢? - 猜测是(下文有详细介绍): 1. Containerd 启动一个进程(称之为 Start 进程)拉起 Containerd-shim 进程,从而创建出容器 2. 当容器起来后,Start 进程快速结束,此时 Containerd-shim 进程变为了孤儿集成,因此被 Root-init 进程纳管 | |
完全理解 Docker 创建容器的一个过程 | ||
首先理解linux创建子进程 | Docker Daemon 的 fork 和我们程序员普通的 fork 有什么区别,为什么 Docker 的 fork,fork 出的是容器,而我们的却不叫容器呢? | |
Linux 中创建进程的基本模型 | Linux 操作系统中,由父进程创建并执行子进程,创建通过 fork 完成,执行通过 exec 完成 | |
在上图中,我们看到进程 A 创建了一个新的进程 B,最终两个进程各自运行。创建时,进程 A 通过 fork 系统调用来完成。fork 之后,两个进程最大的区别就是:进程 A 依然拥有原来的 PID,新创建的进程 B 会占用一个全新的 PID,两者的 PID 不同。 | ||
并且 Linux 内核会在 fork 系统调用时,会拷贝进程 A 的 task_struct,拷贝的副本是为进程 B 准备的。完成 fork 操作之后,拥有全新 PID 的进程 B 会执行 exec 操作,保证执行新的程序,真正开始进程 B 的运行逻辑。 | ||
进程 B 运行过程中,假若 B 正常或者异常退出,那么内核就会给进程 B 的父进程 A,发送一个 SIGHOLD 信号,父进程 A 则对退出的进程 B 执行 wait 操作,实现对 B 进程资源的回收,如进程描述符 task_struct 等。 | ||
创建逻辑 | 1. Dockerd 通过 GRPC 与 Containerd 通信,传输一些镜像信息等 2. Containerd 通过 exec 系统调用创建 Containerd-shim 进程(创建过程中会传递 namespace 等参数,用于实现之后不同容器进程视图和资源的隔离) 3. Contaienrd-shim 进程通过 exec 系统调用创建容器进程 补充:execve 系统调用创建出来的进程是全新的,不会从原进程复制进程结构 | |
创建容器 | 1. 容器镜像的下载是由 dockerd 完成的,但容器的创建和运行就需要 containerd(docker-containerd) 来完成了。 2. Dockerd 与 docker-containerd 之间是通过 grpc 协议通信的。 3. 当 docker-containerd 收到 dockerd 启动容器的请求之后,会做一些初始化工作,然后启动 docker-containerd-shim 进程,并将相关配置作为参数传给它。 4. docker-containerd 负责管理所有本机正在运行的容器,而一个 docker-containerd-shim 进程只负责管理一个运行的容器,它相当于 docker-runc 的一个封装,充当 docker-containerd 和 docker-runc 之间的桥梁,docker-runc 能干的就交给 docker-runc 来做,docker-runc 做不了的就放到这里来做。 | |
创建完成后没有见到 runc 进程 | 1. 在容器启动的过程中,docker-runc 进程是作为 docker-containerd-shim 的子进程存在的。 2. docker-runc 进程根据配置找到容器的 rootfs 并创建子进程(根据容器的entrypoint和cmd创建进程) 作为容器中的第一个进程。 3. 当这一切都完成后 docker-runc 进程退出,然后容器进程由 docker-runc 的父进程 docker-containerd-shim 接管 | |
为什么需要 docker-containerd-shim | 为什么在容器的启动或运行过程中需要一个 docker-containerd-shim 进程呢?把它移除掉整个架构会更简洁也更优美一些!事实上 docker-containerd-shim 的存在是非常有必要的,其目的有如下几点: 1. 它允许容器运行时(即 runC)在启动容器之后退出,简单说就是不必为每个容器一直运行一个容器运行时(runC) 2. 即使在 containerd 和 dockerd 都挂掉的情况下,容器的标准 IO 和其它的文件描述符也都是可用的 3. 向 containerd 报告容器的退出状态 | 此处 docker-containerd-shim 进程,指的就是 containerd-shim 进程 |
理解OCI标准规定的容器状态转移
在运行 busybox 容器前让我们先来看看 OCI 都定义了哪几种容器状态,以及这些状态是如何转移的。先看容器的状态:
- creating:使用 create 命令创建容器,这个过程称为创建中。
- created:容器已经创建出来,但是还没有运行,表示镜像文件和配置没有错误,容器能够在当前平台上运行。
- running:容器里面的进程处于运行状态,正在执行用户设定的任务。
- stopped:容器运行完成,或者运行出错,或者 stop 命令之后,容器处于暂停状态。这个状态,容器还有很多信息保存在平台中,并没有完全被删除。
- paused:暂停容器中的所有进程,可以使用 resume 命令恢复这些进程的执行。
下图则是对容器不同状态间转移的一个粗略描述:
从进程角度看 Docker 创建容器
dockerd、contaierd、containerd-shim、runC通信机制分析
通信流程:
- docker daemon 模块通过 grpc 和 containerd模块通信:dockerd 由
libcontainerd
负责和containerd
模块进行交换, dockerd 和 containerd 通信socket文件:docker-containerd.sock
- containerd 在dockerd 启动时被启动,启动时,启动grpc请求监听。containerd处理grpc请求,根据请求做相应动作;
- 若是start或是exec 容器,containerd 拉起一个container-shim , 并通过exit 、control 文件(每个容器独有)通信;
- container-shim被拉起后,start/exec/create拉起runC进程,通过exit、control文件和containerd通信,通过父子进程关系和SIGCHLD监控容器中进程状态;
- 若是top等命令,containerd通过runC二级制组件直接和容器交换;
- 在整个容器生命周期中,containerd通过 epoll 监控容器文件,监控容器的OOM等事件;
NOTE: containerd,container-shim 组件本质上runC 和dockerd 间的adapter中间件,容器本身有runC单独完成 — 使用runC可以单独完成一个容器部署。
理解 Docker 和 containerd 的容器进程管控方式
- containerd,containerd-shim和runc的依存关系
首先,我们来看下containerd,containerd-shim和容器进程的关系:
root 2156 1733 0 13:17 pts/0 00:00:00 ./bin/containerd -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --shim /home/fankang/docker/containerd-0.2.4/src/github.com/docker/containerd/bin/containerd-shim --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --runtime docker-runc # containerd 进程,纳管所有容器,就是所有 containerd-shim 进程
root 2198 2156 0 13:45 pts/0 00:00:00 /home/fankang/docker/containerd-0.2.4/src/github.com/docker/containerd/bin/containerd-shim nginx /home/fankang/mycontainer runc # containerd-shim 进程,一个 shim 进程纳管一个容器进程,因此 1 个 shim 进程可以等同于 1 个容器进程
root 2214 2198 0 13:45 ? 00:00:00 /usr/bin/python /usr/bin/supervisord # 容器进程
可以看出,containerd是containerd-shim的父进程,contaienrd-shim是容器进程的父进程。
而杀死containerd进程后,contaienrd-shim和容器进程依然存在,只是containerd进程成孤儿进程后,被1进程接收了:
root 2301 1 0 13:50 pts/0 00:00:00 /home/fankang/docker/containerd-0.2.4/src/github.com/docker/containerd/bin/containerd-shim nginx /home/fankang/mycontainer runc
root 2317 2301 1 13:50 ? 00:00:00 /usr/bin/python /usr/bin/supervisord
所以,为了简化三个进程的关系,我们从下面4种情况来分析:
- containerd进程存在的情况下,杀死containerd-shim进程;
- 结论:容器进程退出。在containerd运行的情况下,杀死containerd-shim,容器进程会退出。
- containerd进程存在的情况下,杀死容器进程;
- containerd存在的情况下,杀死容器进程,conainerd-shim主动退出,containerd触发exit事件以清理该容器。
- containerd进程不存在的情况下,杀死containerd-shim进程,然后启动containerd进程;
- 容器进程还在,成为孤儿进程,被进程1接收
- 启动containerd,容器进程消失
- containerd进程不存在的情况下,杀死容器进程,然后启动containerd进程;
- 所有进程都不存在。
- 所以,在Go中,默认子进程的退出会引起父进程的退出。
理解 k8s 1.21 后 containerd 的管控方式
- Containerd shim 进程 PPID 之谜
Kubernetes 自从 1.21 版废除对 dockershim 的支持,改用 Containerd 作为默认的容器运行时。
我们使用 ps
命令来观察一下 Containerd 相关进程:
$ ps -ef | grep containerd
root 1002 1 3 02:29 ? 00:00:19 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --container-runtime=remote --container-runtime-endpoint=/run/containerd/containerd.sock
root 1011 1 1 02:29 ? 00:00:07 /usr/bin/containerd
root 1622 1 0 02:29 ? 00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id 5ca114f2233d4638fae47b86ed058c0774a248168b3bb66d41f94bdcd1e56626 -address /run/containerd/containerd.sock
root 1624 1 0 02:29 ? 00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id 4727e762c3fa1a7f2d4beebfeb79a4ee22298e48018beee5204cc8fd98e7bd41 -address /run/containerd/containerd.sock
root 1660 1 0 02:29 ? 00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id 35d2d1cafe57afde4a1e3041a75d216e48f75312760b1c77ffaa7acc0ee8802f -address /run/containerd/containerd.sock
root 1661 1 0 02:29 ? 00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id c7769877c77465c86e803b1522ad44ec5ee62b4ff90d1e7f9afd13680215f048 -address /run/containerd/containerd.sock
root 2003 1 0 02:29 ? 00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id f4165704fb540c52586e2edcff1c420fe4177d0494205a019201689c7d65d5d4 -address /run/containerd/containerd.sock
root 2090 1 0 02:29 ? 00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id ebe6394198639bfe1e9a09e5e72bf4fc6f55fb1c1e617cdda5409a7d35941010 -address /run/containerd/containerd.sock
root 2637 1 0 02:29 ? 00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id 68611b98a5fa4e19a18494898d084b1c025ff94bf840ffc035dd00694bb3fd17 -address /run/containerd/containerd.sock
root 2792 1 0 02:29 ? 00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id 5aba84afafa0e41a93034903d079aaa5ba730b7b134fff3a1fd533e4db85f28b -address /run/containerd/containerd.sock
root 2957 1 0 02:29 ? 00:00:00 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id ced3e51f8774077aaaf52bf6e381f0e1d21be585cc1f2f1abd285a1588da638b -address /run/containerd/containerd.sock
我们会发现了一个奇怪的现象,containerd 进程是由 PID 1 号进程 systemd 托管,所以 containerd 进程的父进程 ID(PPID)毫无疑问就是 1;而由 containerd 拉起的 containerd-shim 进程的 PPID 也是 1,但实际上 containerd-shim 并非由 systemd 托管。
这一定是有意为之,containerd-shim 进程与 containerd 进程彻底脱离关系,containerd 进程即使崩溃重启就不会对 containerd-shim 进程造成任何影响,而 Kubernetes 集群中的各个容器进程正是由 containerd-shim 拉起的。
那么 Containerd 是如何做到 fork 出 containerd-shim 进程后保留其 PPID 的呢?
最终落实下来是一个名为 do_fork
的函数 https://github.com/torvalds/linux/blob/v3.10/kernel/fork.c#L1557-L1636:
fork 系统调用会通过 copy_process
函数复制进程结构,第一个参数 clone_flags
标记子进程从父进程中需要继承的资源清单。
再找同一文件下 copy_process
函数的定义 https://github.com/torvalds/linux/blob/v3.10/kernel/fork.c#L1124-L1533:
clone_flags
参数只要传入 CLONE_PARENT
即可在复制进程结构时保留原先的父进程信息。
结合上面 ps
命令的输出,containerd-shim 进程启动时确实带上了 namespace
、id
、address
这几个参数,但可执行二进制文件却是通过 os.Executable()
得到的,并不是通过变量传递来的,我们已经知道了这个执行文件就是 /usr/bin/containerd-shim-runc-v2。那就说明 containerd-shim 进程也是由一个 containerd-shim 父进程拉起来的。
结合源码 https://github.com/containerd/containerd/blob/v1.4.3/runtime/v2/shim/shim.go#L221-L229
还有 StartShim
方法 https://github.com/containerd/containerd/blob/v1.4.3/runtime/v2/runc/v2/service.go#L174-L286
**证实了我的猜想,containerd-shim 进程都是由一个 containerd-shim 父进程通过 start
子命令启动的。**那就回到原来的问题了,containerd-shim 是如何将 PPID 设置为为 1 的,毕竟 execsnoop 显示该进程实际的 PPID 是 1693。
containerd-shim 进程是通过 os/exec 包中的 Start
方法启动的 https://github.com/golang/go/blob/master/src/os/exec/exec.go#L370-L458:
再跳到 os 包的 StartProcess
函数 https://github.com/golang/go/blob/master/src/os/exec_posix.go:
再跳到 syscall 包的 StartProcess
函数 https://github.com/golang/go/blob/master/src/syscall/exec_unix.go
因为 Containerd 运行在 Linux 系统,所以 forkAndExecInChild
函数要看 Linux 的那份 https://github.com/golang/go/blob/master/src/syscall/exec_linux.go
根据 https://github.com/golang/go/blob/master/src/syscall/zsysnum_linux_amd64.go#L68 在 Linux amd64 架构中 SYS_EXECVE
为 59,这与 Linux 系统调用表 sys_call_table 是完全相同的。
再追下去就是汇编了。。。
所以搞了半天最终的系统调用还不是 fork。。。execve 落实下来是一个名为 do_execve
的函数 https://github.com/torvalds/linux/blob/v3.10/fs/exec.c
使用 execve 系统调用创建出来的进程是全新的,不会从原进程复制进程结构。
所以容器进程是通过系统调用 execve 创建出来的
62.028335 1688 1118 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -address /run/containerd/containerd.sock -publish-binary /usr/bin/containerd -id 66cbc3f2e8a67d59177959801cd6b9b3c76cb27833068c426e14dee5667b20d3 start # 此处有个 start
62.061869 1698 1693 /usr/bin/containerd-shim-runc-v2 -namespace k8s.io -id 66cbc3f2e8a67d59177959801cd6b9b3c76cb27833068c426e14dee5667b20d3 -address /run/containerd/containerd.sock
根据源码当 1693 进程也就是 1688 进程很快结束后,1698 也就成为了孤儿进程,孤儿进程会被 init 进程也即是 1 号进程(systemd)收养,这就是 containerd-shim 进程的 PPID 全都是 1 的原因。
kubelet
是怎样创建容器的
Dockershim
作用:把外部收到的请求转化成docker daemon
能听懂的请求,让 Docker Daemon 执行创建、删除等容器操作。CRI容器运行时接口
- 参考链接:https://github.com/kubernetes/community/blob/master/contributors/devel/sig-node/container-runtime-interface.md
- CRI:容器运行时接口 container runtime interface,CRI 中定义了容器和镜像两个接口,实现了这两个接口目前主流的是:CRI-O、Containerd。(目前 PCI 产品使用的即为 Containerd)。
CRI接口的具体用处就在于
- 对容器操作的接口,包括容器的创建、启动和停止.即
create
、stop
等操作。- 对镜像的操作,下载、删除镜像等. 即
pull
、rmi
等操作。- podsandbox
- Kubelet 通过 CRI 接口(gRPC)调用
dockershim
,请求创建一个容器。CRI 即容器运行时接口,这一步中,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 并不是父子进程关系)。 - 我们知道创建容器需要做一些设置 namespaces 和 cgroups,挂载 root filesystem 等等操作,而这些事该怎么做已经有了公开的规范,那就是 OCI。它的一个参考实现叫做 runC。于是,containerd-shim 在这一步需要调用 runC 这个命令行工具,来启动容器。
- runC 启动完容器后本身会直接退出,
containerd-shim
则会成为容器进程的父进程,负责收集容器进程的状态,上报给 containerd,并在容器中 pid 为 1 的进程退出后接管容器中的子进程进行清理,确保不会出现僵尸进程。
k8s 中 shim 的变化
- docker,containerd,runc,docker-shim 之间的关系
在容器标准的大战中,docker公司围绕docker swarm推出了CNM,Google等以屠龙者的姿态围绕 k8s 推出了CNI,目前来看,k8s已经奠定了在 PaaS 事实的地位。
CRI 是一套通过 protocol buffers 定义的 API,如下图:
kubelet 实现了 client 端,CRI shim 实现 server 端。只要实现CRI对应的接口,就能接入 k8s 作为 Container Runtime。
-
k8s 1.5 中自己实现了 docker CRI shim,此时启动容器的流程如下:
-
从 containerd 1.0 开始,为了能够减少一层调用的开销(废掉docker,也就是把上边的docker cri shim和docker踢掉),containerd 开发了一个新的 daemon,叫做 CRI-Containerd,直接与 containerd 通信,从而取代了 dockershim:
-
但是这仍然多了一个独立的 daemon,从 containerd 1.1 开始,社区选择在 containerd 中直接内建 CRI plugin,通过方法调用来进行交互,从而减少一层 gRPC 的开销,最终的容器启动流程如下:
最终的结果是 k8s 的 Pod 启动延迟得到了降低,CPU 和内存占用率都有不同程度的降低。
-
但是这还不是终点,为了能够直接对接 OCI 的 runtime 而不是 containerd,社区孵化了 CRI-O 并加入了 CNCF。CRI-O 的目标是让 kubelet 与运行时直接对接,减少任何不必要的中间层开销。CRI-O 运行时可以替换为任意 OCI 兼容的 Runtime,镜像管理,存储管理和网络均使用标准化的实现。
@xuxinkun 的文章中有个图将他们之间的关系描绘的很清楚:
以下更新于2021年4月9日
相关文章:

【容器运行时】一文理解 OCI、runc、containerd、docker、shim进程、cri、kubelet 之间的关系
参考 docker,containerd,runc,docker-shim 之间的关系Containerd shim 进程 PPID 之谜内核大神教你从 Linux 进程的角度看 DockerRunC 简介OCI和runCContainerd 简介从 docker 到 runCDockershim究竟是什么技术干货|Docker和 Con…...

spark兼容性验证
前言 Apache Spark是专门为大规模数据处理而设计的快速通用的计算引擎,Spark拥有Hadoop MapReduce所具有的优点,但不同于Mapreduce的是Job中间输出结果可以保存在内存中,从而不再需要读写HDFS,因此Spark能更好的适用于数据挖掘与…...

docker逃逸复现--pid=host模式下的逃逸
漏洞原理当docker以--pidhost模式启动时,你可以通过在容器进程中注入一些shellcode进行逃逸。相当于给了docker Linux中的CAP_SYS_PTRACE权限--pidhost:意味着宿主机与容器公享一套pid,如此做容器就可以访问并跟踪宿主机的进程Linux中的CAP_S…...

【环境配置】Windows系统下搭建Pytorch框架
【环境配置】Windows系统下搭建Pytorch框架 在Windows Serve 2019系统下搭建Pytorch框架 目录 【环境配置】Windows系统下搭建Pytorch框架1.用驱动总裁安装显卡驱动2.在cmd运行nvidia-smi3.安装cuda4.安装cudnn5.安装pytorch的命令1.首次安装2.操作失误需要重新安装6.安装torc…...

Dockerfile简单使用入门
什么是 Dockerfile? Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。 docker build命令用于从Dockerfile构建映像。可以在docker build命令中使用-f标志指向文件系统中任何位置的Dockerfile。 例如࿱…...

什么是CCC认证3C强制认证机构
什么是CCC认证3C强制认证机构? 3C认证的全称为“强迫性产物认证轨制”,它是中国政府为掩护消费者人身平安和国度平安、增强产物品质治理、按照法律法规履行的一种产物及格评定轨制。所谓3C认证,便是中国强迫性产物认证轨制,英文名…...

C语言-基础了解-18-C共用体
C共用体 一、共用体 共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式 二、定义共同体 为了定义共用体&…...

Vue基础18之github案例、vue-resource
Vue基础18github案例静态页面第三方样式引入(以bootstrap举例)App.vueSearch.vueList.vue列表展示接口地址使用全局事件总线进行兄弟间组件通信Search.vueList.vue完善案例List.vueSearch.vue补充知识点:{...this.info,...this.dataObj}效果呈…...

UE4 c++ Mediaplayer取消自动播放,运行时首帧为黑屏的问题
0,前言 工作需要使用C制作一个ue4的视频插件,其中一个功能是能够选择 运行时是否自动播放 视频的功能。 在实现时遇见了一个问题,取消自动播放之后,运行时首帧是没有取到的,在场景里面看是黑色的。就这个问题我想到了使…...

C语言-基础了解-17-C结构体
C结构体一、c结构体C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。结构体中的数据成员可以是基本数据类型(如 int、float、char 等),也可…...

Python爬虫实践:优志愿 院校列表
https://www.youzy.cn/tzy/search/colleges/collegeList获取目标网址等信息打开开发人员工具(F12),拿到调用接口的地址,以及接口请求参数等信息,如下curl https://uwf7de983aad7a717eb.youzy.cn/youzy.dms.basiclib.ap…...

Java框架学习 | MySQL和Maven笔记
1.MySQL提问式思考 为什么要有数据库?MySQL的优劣势?Java的优劣势? JavaMySQL开源具有大量的社区成员和丰富的资源免费/具有大量的社区成员和丰富的资源可扩展性多态、继承和接口等分区、复制和集群等方式扩展数据库的容量和性能安全性有许…...

C++入门教程||C++ 变量作用域||C++ 常量
C 变量作用域 作用域是程序的一个区域,一般来说有三个地方可以声明变量: 在函数或一个代码块内部声明的变量,称为局部变量。在函数参数的定义中声明的变量,称为形式参数。在所有函数外部声明的变量,称为全局变量。 我…...

想找工作,这一篇15w字数+的文章帮你解决
文章目录前言一 专业技能1. 熟悉GoLang语言1.1 Slice1.2 Map1.3 Channel1.4 Goroutine1.5 GMP调度1.6 垃圾回收机制1.7 其他知识点2. 掌握Web框架Gin和微服务框架Micro2.1 Gin框架2.2 Micro框架2.3 Viper2.4 Swagger2.5 Zap2.6 JWT3. 熟悉使用 MySQL 数据库3.1 索引3.2 事务3.3…...

Mac brew搭建php整套开发环境
Homebrew完整版,安装时间较长/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"精简版/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" speednginxBrew sear…...

111 e
全部 答对 答错 单选题 4.一个项目已经执行了两个多月,出乎意料的是,项目经理收到一封来自高级管理层的电子邮件,指出项目发起人正在请求变更项目开工会议的日期,项目经理未能执行哪项活动? A为项目管理计划制定基准…...

Cookie和Session
1. Cookie饼干 1.1 什么是Cookie? Cookie翻译过来就是饼干的意思Cookie是服务器通知客户端保存键值对的一种技术客户端有了Cookie后,每次请求都发送给服务器每个Cookie的大小不能超过4kb 1.2 如何创建Cookie BaseServlet 程序 package com.gdhd;impo…...

git上传下载
拉取: 先在电脑中创建一个文件夹用来存放要从码云上拉下来的项目并且用Git打开输入 git remote add origin + (想要下拉的项目的地址http/ssh)第一次拉取代码,输入码云的用户名(自己设置的个人地址名)和码云的账号密码 git pull origin master 拉取完成OK 上传: 进行 G…...

如何使用码匠连接 Oracle
目录 在码匠中集成 Oracle 在码匠中使用 Oracle 关于码匠 Oracle 是一种关系型数据库,可用于存储和管理大量结构化数据。Oracle 数据源支持多种操作系统,包括 Windows、Linux 和 Unix 等,同时也提供了各种工具和服务,例如 Orac…...

【Git】git常用命令集合
目录最常用的git命令git拉取代码git本地如何合并分支上传文件识别大小写开发分支(dev)上的代码达到上线的标准后,要合并到master分支当master代码改动了,需要更新开发分支(dev)上的代码git本地版本回退与远…...

基于 WebSocket、Spring Boot 教你实现“QQ聊天功能”的底层简易demo
目录 前言 一、分析 1.1、qq聊天功能分析 1.2、WebSocket介绍 1.2.1、什么是消息推送呢? 1.2.2、原理解析 1.2.3、报文格式 二、简易demo 2.1、后端实现 2.1.1、引入依赖 2.1.2、继承TextWebSocketHandler 2.1.3、实现 WebSocketConfigurer 接口 2.2、…...

13. 郭老师爱合并果子
1 题目描述 郭老师爱合并果子成绩20开启时间2021年10月8日 星期五 18:00折扣0.8折扣时间2021年10月26日 星期二 00:00允许迟交否关闭时间2021年12月1日 星期三 00:00 郭老师家有个果园,每年到了秋收的时候都会收获很多不同种类的果子。他决定把所有的果子合成一堆&…...

Method breakpoints may dramatically slow down debugging 解决方案
项目无法启动了 简单介绍一下事情的过程:昨天在进行代码调试的时候,代码部分处理完成之后,启动debug模式的热部署准备测试一下逻辑,结果左下角提示我热部署失败,需要重新启动Tomcat才能再次调试,所以只得重…...

ABAP ALV和OOALV设置单元格颜色,编辑
首先给大家分享一篇博客: REUSE_ALV_GRID_DISPLAY_LVC-可编辑单元格 文章目录单元格编辑单元格/行-颜色效果展示**需求:**我是想实现某个单元格可根据数据来判断是否是可以进行编辑的或要添加一个什么样的颜色. 我们需要用到下面的三个结构 ALV 控制: 单元格的类型表:LVC_T_ST…...

Java知识复习(十三)数据库和SQL
1、主键和外键 主键也叫主码。主键用于唯一标识一个元组,不能有重复,不允许为空。一个表只能有一个主键。外键也叫外码。外键用来和其他表建立联系用,外键是另一表的主键,外键是可以有重复的,可以是空值。一个表可以有…...

JVM虚拟机种类
1,Sun Classic VM: 1.现在此款虚拟机已经淘汰了,是历史上第一款商用的虚拟机。2.只能使用纯解释器的方式来执行Java代码。3.服役于 JDK 1.0、1.1、1.2;在 1.3、1.4 作为 HotSpot VM 的备选 VM;之后退出历史舞台;2,Sun Exact VM 1.…...

Linux操作系统学习(线程基础)
文章目录线程的基础概念线程控制内核LWP和线程ID的关系线程的基础概念 一般教材对线程描述是:是在进程内部运行的一个分支(执行流),属于进程的一部分,粒度要比进程更加细和轻量化 一个进程中是可能存在多个线程…...

YOLOv5源码逐行超详细注释与解读(1)——项目目录结构解析
前言 前面简单介绍了YOLOv5的网络结构和创新点(直通车:【YOLO系列】YOLOv5超详细解读(网络详解)) 在接下来我们会进入到YOLOv5更深一步的学习,首先从源码解读开始。 因为我是纯小白,刚开始下…...

前端开发总结的一些技巧和实用方法(2)
本文主要介绍一些JS中用到的小技巧和实用方法,可以在日常Coding中提升幸福度,也可以通过一些小细节来增加代码可读性,让代码看起来更加优雅,后续将不断更新1.数组 map 的方法 (不使用Array.Map) Array.from 还可以接受第二个参数…...

Docker搭建jenkins(Vue自动化部署)
前言 需要提前准备的条件 Docker环境 一、jenkins镜像 # 查询镜像 docker search jenkins# 下载镜像 # lts稳定版 docker pull jenkins/jenkins:lts#查看镜像 docker images二、启动Jenkins容器 创建挂载文件夹,并且进行文件授予权限 #创建文件夹 mkdir -p /home/j…...