Docker容器与虚拟化技术:容器运行时说明与比较

目录

一、理论

1.容器运行时

2.容器运行时接口

 3.容器运行时层级

4.容器运行时比较

5.强隔离容器

二、问题

1.K8S为何难以实现真正的多租户

三、总结


一、理论

1.容器运行时

(1)概念

Container Runtime 是运行于 k8s 集群每个节点中,负责容器的整个生命周期。Docker 就目前来说是应用最为广泛的。随着容器云的发展,涌现了很多容器运行时。Google 为了将 kubelet 和特定的容器运行时解耦(主要还是为了干掉 Docker),于是推出了 CRI(容器运行时接口)。

2.容器运行时接口

CRI 是 k8s 定义的一组 gRPC 服务。kubelet 作为客户端,基于 gRPC 框架,通过 Socket 和容器运行时通信。CRI 包括两类服务:镜像服务(Image Service)和运行时服务(Runtime Service)。镜像服务提供下载、检查和删除镜像的远程程序调用。运行时服务用于管理容器的生命周期,以及和容器交互的调用(exec / attach / port-forward)。

 3.容器运行时层级

Container Runtime 分为高低两个层级。

(1)  高层级运行时
Dockershim、containerd 和 CRI-O 都是遵循 CRI 的容器运行时,属于高层级运行时,主要是面向外部提供 gRPC 调用。

注意这里是 Dockershim,并不是 Docker,Docker 至今也没有遵循 CRI。

OCI
OCI(OPen Container Initiative)定义了创建容器的格式和运行时的开源行业标准,包括镜像规范和运行时规范。

高层级运行时会下载一个 OCI 镜像,并把它解压成 OCI 运行时文件系统包(filesystem bundle)。

(2)低层级运行时
低层级运行时定义如何为新容器设置 Linux namespaces 和 cgroups,以及 rootfs 等操作, runC 就是具体的参考实现。除了 runC 外,还有很多其他的运行时遵循 OCI 标准,例如 kata 以及 gVisor。

4.容器运行时比较


Docker 的多层封装和调用,导致其在可维护性上略逊一筹。containerd 和 CRI-O 的方案比 Docker 简洁很多。

dockershim 遵循 CRI,并把请求转为 dockerd 可处理的请求,其代码集成在 kubelet 中,这也是 k8s 急于摆脱 Docker 的原因之一。

真正的启动容器是通过 containerd-shim 去调用 runC 来启动容器的,runC 启动完成后会直接退出,containerd-shim 会成为容器进程的父进程,负责收集容器进程的状态,上报给 containerd,并在容器中 pid 为 1 的进程退出后接管容器中的子进程,确保不会出现僵尸进程。同时也避免了宿主机上 containerd 进程挂掉的话,所有容器进程都退出。

(1) containerd 和 Docker 细节差异


 Docker 作为容器运行时,k8s 其实根本没有使用 docker 本身的存储、网络等功能,只是用了 Docker 的 Image 功能,来满足 CRI 中的镜像服务。

(2)containerd 和 CRI-O

CRI-O是由红帽发起并开源的一款容器运行时,本身比较新,没有太多的生产实践。而且在社区的测试结果中,在操作容器方面的性能以及延时都没有 containerd 优秀。

5.强隔离容器

(1)常用强隔离容器

Kata, gVisor, firecracker

(2)安全容器与 Serverless

Serverless 要做到所有的用户容器或函数按需使用计算资源, 那必须满足两点:

多租户强隔离: 用户的容器或函数都是按需启动按秒计费, 我们可不能给每个用户预先分配一坨隔离的资源,因此我们要保证整个 Platform 是多租户强隔离的;
极度轻量: Serverless 的第一个特点是运行时沙箱会更频繁地创建和销毁, 第二个特点是切分的粒度会非常非常细, 细中细就是 FaaS, 一个函数就要一个沙箱。 因此就要求两点: 1. 沙箱启动删除必须飞快; 2. 沙箱占用的资源越少越好。

(3)Kata Containers

① 概念

Kata Containers作为OpenStack基金会的一个开放源代码项目,作为其最近扩展的包含OpenStack核心项目的章程的一部分。这个项目肯定会促进标准化和创新,从而推动容器技术的快速发展。已经有将近20家公司同意在Kata Containers上共同合作。

Kata容器也将在多个基础架构和容器编排和规范社区中集成和兼容:Kubernetes,Docker,Open Container Initiative(OCI),Container Runtime Interface(CRI),容器网络接口(CNI),QEMU,KVM,HyperV和OpenStack。

② 特点 

容器的速度,虚拟机的安全。

Kata 的一张图很好地解释了基于虚拟机的容器与基于 namespaces 和 cgroups 的容器间的区别:

Kata Containers是一种轻量级虚拟机的新颖实现无缝集成在容器生态系统中。Kata Containers同容器一样轻而快,并与容器结合管理层,同时也提供了虚拟机的安全优势。

Kata Containers是两个现有的开源项目合并:英特尔Clear Containers和Hyper runV。新项目汇集了最好的这两种技术都具有重构虚拟化,容器原生应用程序的共同愿景,为了提供容器的速度,和虚拟机的安全。

Kata Containers从每个项目的优势中受益。Intel Clear Containers专注于性能(<100ms启动时间)和增强安全性,而hyper runV优先于技术无关支持许多不同的CPU架构和管理程序。通过合并这些项目,Clear Containers提供了卓越的最终用户体验性能和兼容性,统一开发者社区,并加速功能开发以解决未来的使用案例。

行业转向容器在安全方面提出了独特的挑战,用户工作负载在多租户不受信任的环境中。Kata Containers使用开源虚拟机管理程序作为每个容器的隔离边界(或一个容器中的容器的集合);这种方法解决了与现有的裸机容器解决方案共同的内核困境。

Kata Containers是非常适合按需,基于事件的部署,如无服务器功能,连续整合/持续交付,以及更长时间运行的Web服务器应用。开发者不再需要知道任何事情下面的基础或执行任何类型的容量规划之前启动他们的容器工作量。Kata Containers交付增强安全性,可扩展性和更高的资源利用率,同时导致整体简化的堆栈。

二、问题

1.K8S为何难以实现真正的多租户

(1)问题

k8s 做不到多租户状态, 其中最大的两个原因是:

1.kube-apiserver 是整个集群中的单例, 并且没有多租户概念;

2.默认的 oci-runtime 是 runC, 而 runC 启动的容器是共享内核的。

 (2) 原因

理想的多租户状态:

理想来说, 平台的各个租户(tenant)之间应该无法感受到彼此的存在, 表现得就像每个租户独占这整个平台一样. 具体来说, 我不能看到其它租户的资源, 我的资源跑满了不能影响其它租户的资源使用, 我也无法从网络或内核上攻击其它租户。

(3)解决方法

对于第二个问题, 一个典型的解决方案就是提供一个新的 OCI 实现, 用 VM 来跑容器, 实现内核上的硬隔离。 runV 和 Clear Containers 都是这个思路. 因为这两个项目做得事情是很类似, 后来就合并成了一个项目 Kata Container

三、总结

runtime容器运行时:
 高层级运行时(Dockershim、containerd 和 CRI-O ),主要是面向外部提供 gRPC 调用。
 低层级运行时(runC、kata和gVisor ),定义如何为新容器设置 Linux namespaces 和 cgroups,以及 rootfs 等操作。