# 容器运行时
---
## 1、定义
> 容器运行时:能够基于在线获取的镜像来创建和运行容器的程序。
## 2、容器是什么
当一个容器被启动时,主要会发生如下活动:
1. 基于镜像(image),一个容器会被创建出来。镜像image就是附加一个JSON配置文件的tar包。镜像常常是嵌套的:例如Libresonic的镜像是基于Tomcat的镜像, 而Tomcat的镜像又最终基于一个Debian的镜像。这样可以防止重复的内容占用空间。一个容器的镜像常常可以通过使用类似docker build的命令来生成。
2. 如果必要, 容器运行时会从某处下载镜像,这个地方称为registry。Registry仓库就是docker pull/push所交互的服务器。
3. 运行时将层次化的镜像解压到支持Copy on Write(CoW)的文件系统里。
4. 最后,运行时来实际地执行容器。 它告诉内核给容器分配合适的资源限制,创建隔离的层(为进程,网络,文件系统等),使用各种机制的混合(包括cgroups,namespaces,capabilities, seccomp, AppArmor, SELinux, 等等)。 比如Docker, 当执行docker run时,它会创建并运行容器,但是底层它实际调用的是runc命令。
### 容器运行时演进过程
![1](https://raw.githubusercontent.com/justingking/img/master/runtime_evolution.png)
容器运行时的演进可以分为三个阶段:
首先,在 Kubernetes v1.5 之前,Kubelet 内置了 Docker 和 rkt 的支持,并且通过 CNI 网络插件给它们配置容器网络。这个阶段的用户如果需要自定义运行时的功能是比较痛苦的,需要修改 Kubelet 的代码,并且很有可能这些修改无法推到上游社区。这样,还需要维护一个自己的 fork 分支,维护和升级都非常麻烦。
第二阶段,不同用户实现的容器运行时各有所长,许多用户都希望Kubernetes支持更多的运行时。于是,从v1.5 开始增加了 CRI 接口,通过容器运行时的抽象层消除了这些障碍,使得无需修改 Kubelet 就可以支持运行多种容器运行时。CRI 接口包括了一组 Protocol Buffer、gRPC API 、用于 streaming 接口的库以及用于调试和验证的一系列工具等。在此阶段,内置的 Docker 实现也逐步迁移到了 CRI 的接口之下。但此时 rkt 还未完全迁移,这是因为 rkt 迁移 CRI 的过程将在独立的 repository 完成,方便其维护和管理。
第三阶段,从 v1.11 开始,Kubelet 内置的 rkt 代码删除,CNI 的实现迁移到 dockershim 之内。这样,除了 docker 之外,其他的容器运行时都通过 CRI 接入。外部的容器运行时一般称为 CRI Shim,它除了实现 CRI 接口外,也要负责为容器配置网络。一般推荐使用 CNI,因为这样可以支持社区内的众多网络插件,不过这不是必需的,网络插件只需要满足 Kubernetes 网络的基本假设即可,即 IP-per-Pod、所有 Pod 和 Node 都可以直接通过 IP 相互访问。
## 容器运行时接口(CRI)
容器运行时接口(CRI)是一个用来扩展容器运行时的接口,它基于 gPRC,用户不需要关心内部通信逻辑,而只需要实现定义的接口就可以,包括 RuntimeService 和 ImageService。
- RuntimeService负责管理Pod和容器的生命周期
- 而ImageService负责镜像的生命周期管理
除了 gRPC API,CRI 还包括用于实现 streaming server 的库(用于 Exec、Attach、PortForward 等接口)和 CRI Tools。
![2](https://raw.githubusercontent.com/justingking/img/master/runtime1.png)
基于 CRI 接口的容器运行时通常称为 CRI shim, 这是一个 gRPC Server,监听在本地的unix socket上;而kubelet作为gRPC的客户端来调用CRI接口。另外,外部容器运行时需要自己负责管理容器的网络,推荐使用CNI,这样跟Kubernetes的网络模型保持一致。
## CRI 接口
CRI 接口包括 RuntimeService 和 ImageService 两个服务,这两个服务可以在一个 gRPC server 里面实现,当然也可以分开成两个独立服务。目前社区的很多运行时都是将其在一个 gRPC server 里面实现。
![3](https://raw.githubusercontent.com/justingking/img/master/CRI_interface.png)
管理镜像的 ImageService 提供了 5 个接口,分别是查询镜像列表、拉取镜像到本地、查询镜像状态、删除本地镜像以及查询镜像占用空间等。这些都很容易映射到 docker API 或者 CLI 上面。
而 RuntimeService 则提供了更多的接口,按照功能可以划分为四组:
- PodSandbox 的管理接口:PodSandbox 是对 Kubernete Pod 的抽象,用来给容器提供一个隔离的环境(比如挂载到相同的 cgroup 下面),并提供网络等共享的命名空间。PodSandbox 通常对应到一个 Pause 容器或者一台虚拟机。
- Container 的管理接口:在指定的 PodSandbox 中创建、启动、停止和删除容器。
- Streaming API 接口:包括 Exec、Attach 和 PortForward 等三个和容器进行数据交互的接口,这三个接口返回的是运行时 Streaming Server 的 URL,而不是直接跟容器交互。
- 状态接口,包括查询 API 版本和查询运行时状态。
## 容器运行时实例
| CRI 容器运行时| 维护者 |主要特性 |容器引擎|
|---------|-------|-------------|-------------------|
|Dockershim | Kubernetes|内置实现、特性最新 | docker|
|cri-o | Kubernetes|OCI标准不需要Docker |OCI(runc、kata、gVisor…) |
|cri-containerd |Containerd|基于 containerd 不需要Docker| OCI(runc、kata、gVisor…)|
|Frakti | Kubernetes|虚拟化容器 | hyperd、docker |
|rktlet | Kubernetes|支持rkt |rkt|
|PouchContainer | Alibaba|富容器 | OCI(runc、kata…)|
|Virtlet | Mirantis|虚拟机和QCOW2镜像 | Libvirt(KVM)|
> 参考网址:https://feisky.xyz/posts/kubernetes-container-runtime/#%E5%AE%B9%E5%99%A8%E8%BF%90%E8%A1%8C%E6%97%B6%E6%8E%A5%E5%8F%A3cri