1. 什么是容器运行时

容器本质上就是一个进程,一个特殊的进程,是通过 Namespace 实现资源(网络、文件系统等)隔离,通过 Cgroups 实现资源(CPU、内存)限制;其和虚拟机有本质上的区别,那就是容器和宿主机是共享同一个内核的


2. 容器运行时分类

容器运行时分为低层运行时和高层运行时。
 低层运行时主要负责与宿主机操作系统打交道,根据指定的容器镜像在宿主机上运行容器进程,并对容器的整个生命周期进行管理,也就是负责设置容器 Namespace、Cgroups 等基础操作的组件,常见的低层运行时有:

  • runc:传统的运行时,基于 Linux Namespace 和 Cgroups 技术实现,代表实现 Docker、Containerd。
  • runv:基于虚拟机管理程序的运行时,通过虚拟化 guest kernel,将容器和主机隔离开来,使得其边界更加清晰,代表实现是 Kata Container 和 Firecracker。
  • runscrunc + safety,通过拦截应用程序的所有系统调用,提供安全隔离的轻量级容器运行时沙箱,代表实现是谷歌的 gVisor。

 高层运行时主要负责镜像的管理等工作,为容器的运行做准备,主流的高层运行时包括 Containerd、CRI-O.。高层运行时与低层运行时各司其职,容器运行时一般先由高层运行时将容器镜像下载下来,并解压转换为容器运行需要的操作系统文件,再由低层运行时启动和管理容器。


3. Docker

image-kall.png

 Docker Daemon 请求 Containerd 创建一个容器,Containerd 收到请求,创建一个 Containerd-shim 进程,该进程用于操作容器,指定容器进程是需要一个父进程来做状态收集等工作,假如父进程就是 Containerd,那Containerd 挂掉,整个宿主机所有的容器都得退出,而引入 Containerd-shim 这个垫片就可以来规避这个问题。
 创建容器需要做Namespaces 和 Cgroups 的配置,以及挂载 root 文件系统等操作,这些操作有标准的规范,那就是 OCI(开放容器标准),规定了容器镜像的结构、接收的操作指令,如 create、start、stop、delete 等。runc 是 按照OCI 标准创建符合规范的容器。


4. CRI

CRI(Container Runtime Interface 容器运行时接口): Kubernetes 定义的一组与容器运行时进行交互的接口。
image-ampf.png
 CRI 主要有 gRPC client、gRPC Server 和具体的容器运行时三个组件。其中 Kubelet 作为 gRPC 的客户端来调用 CRI 接口;CRI shim 作为 gRPC 服务端来响应 CRI 请求,负责将 CRI 请求的内容转换为具体的容器运行时 API,在 kubelet 和运行时之间充当翻译的角色。具体的容器创建逻辑是,Kubernetes 在通过调度指定一个具体的节点运行 Pod,该节点的 Kubelet 在接到 Pod 创建请求后,调用一个叫作 GenericRuntime 的通用组件来发起创建 Pod 的 CRI 请求给 CRI shim;CRI shim 监听一个端口来响应 Kubelet,在收到 CRI 请求后,将其转化为具体的容器运行时指令,并调用相应的容器运行时来创建 Pod。