什么是运行时(runtime)?
runtime指的是程序执行时所需要的环境,以确保程序能够在特定的环境中正确运行;
runtime为程序提供运行所需要的各种功能和支持,包括但不限于操作系统、编程语言的运行时库、虚拟机或解释器;
Java程序文件就好比是容器镜像文件,JVM则好比是runtime,运行起来的Java程序就好比是容器。
运行时分类?
- 低级运行时:也称容器执行器,主要有runc、crun、kata-runtime、gVisor(runsc)
- 高级运行时:也称容器生命周期管理工具,主要有containerd、cri-o、docker-engine
低级运行时之runc:
前身为Docker公司的libcontainer模块,于2015年捐献给CNCF,并作为OCI标准的实现。
runc仅支持Linux,由Go语言编写,且必须使用Go1.19或更高版本构建。
runc只负责容器的创建、启动、停止和销毁等基本操作,并且能够与容器生命周期管理工具(如containerd和cri-o)结合使用,由它们实现容器镜像管理等高级功能。
runc是containerd中用于实际运行容器的基础组件,containerd会调用runc来启动一个新的容器。
runc负责将容器的配置信息转换为Linux容器的原生操作,从而在底层启动和管理容器。具体来说:
当runc接收一个标准化的容器配置文件(比如符合OCI标准的config.json文件),其中包含了容器的各种配置参数,如容器的文件系统挂载点、网络设置、环境变量、进程、资源限制等;
runc将这些配置信息转换为底层Linux命令和系统调用,通过调用Linux内核的特性(如命名空间、Cgroups等),来创建并管理容器的执行环境。
runc命令行工具:
[root@k8s-master-01 ~]# runc -v
runc version 1.1.7
commit: v1.1.7-0-g860f061
spec: 1.0.2-dev
go: go1.19.9
libseccomp: 2.5.2
低级运行时之crun:
crun是一个开源的OCI兼容容器运行时,由C语言编写,它专注于提供更轻量级、更快速和安全的容器运行时。
crun的设计目标是在遵循OCI标准的同时,提供更快的容器启动和更小的内存占用。它通常被认为比runc更轻量级。
[root@k8s-master-01 ~]# crun -v
crun version 1.8.4
commit: 5a8fa99a5e41facba2eda4af12fa26313918805b
rundir: /run/user/0/crun
spec: 1.0.0
+SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +CRIU +YAJL
runc和crun的比较:
crun更关注轻量级容器启动、性能和安全性,以及对容器运行时进行自定义和调整的能力;
如果你正在使用Docker或Kubernetes,并且需要广泛的生态系统支持和成熟性,那么runc作为一个经过验证的标准容器运行时是一个更好的选择。
常见的高级容器运行时(容器生命周期管理工具)?
- 由Docker公司开发的容器运行时:
- docker engine:简单称之为docker,是Docker公司的核心产品并提供维护,也是Docker默认使用的容器运行时,并且也是Kubernetes最早支持的容器运行时。它符合OCI标准,但不直接遵循CRI接口规范(所以在K8s 1.24版本之前需要使用k8s社区自研的dockershim适配器对接docker engine作为其容器运行时,因为dockershim满足CRI接口规范)。
- containerd:最早由Docker公司开发并提供维护,但在2016年Docker将containerd开源并捐赠给CNCF,由此成为一个独立的开源项目,并且由众多公司共同维护。K8s从1.20版本开始默认使用containerd作为其容器运行时,当然K8s也可以变更使用那些支持CRI接口规范的容器运行时,如:cri-o等。
- 由RedHat开发的容器运行时:
- CRI-O:Container Runtime Interface-OCI,是一个专为Kubernetes设计且开源的容器运行时并由众多公司共同维护。它符合 Kubernetes Container Runtime Interface (CRI) 规范,并提供与 Kubernetes 紧密集成的轻量级容器执行环境。它使用 Open Container Initiative(OCI)规范定义的容器和镜像格式。它支持容器运行时使用标准的 OCI 镜像(OCI Image)和 OCI 运行时(OCI Runtime)。
- 由CoreOS开发的容器运行时:
- rkt(也称为Rocket)是一个由CoreOS于2014年开发的安全容器运行时,不遵循OCI标准,通过自研的rktlet满足CRI规范。
CNCF展示的容器运行时
CRI:
Container Runtime Interface — 容器运行时接口,是K8s定义的一种接口规范,于2016年发布,此时K8s版本=1.5,该规范使用gRPC协议实现容器运行时与kubelet之间的通信。由K8s社区维护和管理。
CRI为容器运行时提供了一套标准化的接口,使得Kubernetes(kubelet)可以与不同的容器运行时进行通信和交互,而不需要重启编译。
CRI定义了一组gRPC服务和数据类型,用于实现容器生命周期管理、镜像管理、网络和存储等操作。
默认情况下,Kubernetes使用CRI来与你所选择的容器运行时进行交互。(若使用不支持CRI的容器运行时,如DockerEngine,需要使用Dockershim或CRI-dockerd,但Dockershim已在1.24版本移除)
OCI:
OCI (Open Container Initiative) 是一个开放的行业标准组织,于2015年由Docker联合Linux基金会推动成立,之后Google、Red Hat、Microsoft等加入,并共同维护和管理OCI标准。
旨在定义容器格式和运行时的开放标准。OCI 的目标是提供一个统一的容器规范,以确保容器在不同的运行时环境中具有可移植性和互操作性。
同时,OCI还以runc的形式维护了一个runtime-spec的真实实现,这也是containerd和CRI-O依赖的默认运行时。CRI建立在这些底层规范之上,为管理容器提供端到端的标准。
OCI 标准发布了2个spec,分别是runtime spec 和 image format spec:
- 容器运行时 (OCI runtime):定义了容器的生命周期管理,包括创建、启动、停止和销毁容器等操作。容器运行时负责管理容器的隔离、资源管理、文件系统和网络等方面。
- 容器镜像 (OCI image):定义了容器的打包和分发格式。容器镜像是一个只读的文件系统,包含了容器运行所需的文件、库和配置等。OCI 定义了容器镜像的结构、元数据和分发方式。
- Docker engine、Containerd和CRI-O都遵循OCI规范。
CRI主要用于定义Kubernetes与容器运行时之间的接口规范,而OCI主要用于定义容器镜像和容器运行时的规范:
- containerd shim是容器运行时的抽象层,它通过接收来自containerd的请求,并将其转换为容器引擎(runc)所能理解的命令,从而使得containerd可以与多种不同的容器引擎兼容。
- Containerd是通过CRI Plugin来适配CRI的,而CRI-O则是为CRI量生打造。
把一个容器镜像文件运行起来,通常需要以下几个工具共同完成
- 低级运行时:runc、crun等。
- 容器生命周期管理工具:负责创建、启动、停止、销毁容器等操作。对于docker这个部分由docker自身实现;对于cri-o它使用conmon或crun进行容器的生命周期管理。
- 容器镜像工具:负责管理容器的镜像,包括拉取镜像、导出镜像、上传镜像等操作。对于docker这个部分由docker自身实现;对于cri-o它使用skopeo进行镜像的管理。
- CNI插件:是容器网络接口标准,它负责为容器创建和管理网络,允许容器与宿主机或其他容器进行网络通信。
- CRI插件:是K8s使用的容器运行时接口标准,它定义了容器运行时需要实现的接口,使得K8s可以与不同的容器运行时进行通信和交互。