技术开发 频道

一文让你秒懂低级容器运行时的前世今生

  【IT168 评论】在Red Hat中有一种说法“容器就是Linux,Linux也是容器”。这是什么意思呢?事实上,传统的容器是一个系统的过程,通常有以下三个特点:


  1.资源限制

  当你在一个系统上运行大量的容器时,且不希望任何容器垄断操作系统,我们就会使用资源约束来控制CPU、内存、网络带宽等等。Linux内核提供了cgroups功能,可以配置为控制容器的进程资源。

  2.安全约束

  通常,大家都不希望容器能够相互攻击或攻击主机系统。我们利用Linux内核的几个特性来建立安全分离,如SELinux,seccomp,capabilities等。

  3.虚拟分离

  容器进程不应该有容器外任何进程的视图,他们应该在自己的网络上。容器进程需要能够绑定到不同容器的80端口。每个容器需要不同的图像视图,需要自己的根文件系统(rootfs)。在Linux中,我们使用内核命名空间来提供虚拟分离。

  因此,在cgroup中运行的进程具有安全设置、并在namespaces中运行,我们就将之称为容器。在Red Hat Enterprise Linux 7系统上查看system 1的PID 1,可以看到systemd在cgroup中运行。

  #tail -1 / proc / 1 / cgroup

  1:name = systemd:/

  该ps命令显示系统进程有一个SELinux标签...

  #ps -eZ | grep systemd

  system_u:system_r:init_t:s0 1?00:00:48 systemd

  Capabilities

  #grep Cap / proc / 1 / status

  ...

  CapEff:0000001fffffffff

  CapBnd:0000001fffffffff

  CapBnd:0000003fffffffff

  最后,如果查看/proc/1/ns子目录,你将看到systemd运行的命名空间。

  ls -l / proc / 1 / ns

  lrwxrwxrwx。1 root root 0 1月11日11:46 mnt - > mnt:[4026531840]

  lrwxrwxrwx。1 root root 0 Jan 11 11:46 net - > net:[4026532009] lrwxrwxrwx

  。1 root root 0 1月11日11:46 pid - > pid:[4026531836]

  ...

  如果PID 1(以及系统上的其他所有进程)具有资源约束,安全设置和名称空间,我就认为系统上的每个进程都在一个容器中。

  容器运行时工具只是修改这些资源约束,安全设置和命名空间,然后Linux内核执行这些进程。容器被推出后,将容器运行时可以监视PID 1所述容器或所述容器的内部stdin/ stdout-the容器运行时管理这些过程的生命周期。

  Container runtimes

  你可能会说,systemd听起来和容器运行时非常相似。那么,在讨论了为什么容器运行时不用systemd-nspawn作启动容器的工具之后,我决定讨论容器的运行时和其发展历史。

  Docker通常被称为容器运行时,但是“容器运行时”是一个重载的术语。当人们谈论“容器运行时”时,他们实际上是在讨论诸如Docker、crio - o和RKT之类的高级工具,这些工具与开发人员的功能有关。他们是API驱动的,包括一些概念,比如从容器注册表中提取容器映像,设置存储,最后启动容器。启动容器通常需要运行一个专门的工具来配置内核来运行容器,这些工具也被称为“容器运行时”。我把它们称为“低级容器运行时”。像Docker和crio - o这样的守护进程,以及像Podman和Buildah这样的命令行工具,应该被称为“容器管理器”。

  Docker最初编写时,它使用lxc工具集启动容器,该工具集先于systemd-nspawn。Red Hat与Docker的最初合作是尝试将libvirt (libvirt-lxc)集成到Docker中,作为lxc工具的替代品,而lxc工具在RHEL中不受支持。libvirt-lxc也没有使用systemd-nspawn。在那个时候,systemd团队说systemd-nspawn只是一个用于测试的工具,而不是用于生产的工具。

  与此同时,上游的Docker开发人员,包括Red Hat团队的一些成员希望使用一种golangnative的方式来启动容器,而不是启动一个单独的应用程序。这个工作开始于libcontainer,它是一个用于启动容器的本地golang库。红帽公司认为这是非常好的路径,并放弃了libvirt-lxc。

  后来,Open Container Initiative (OCI)成立了,因为人们希望能够以其他方式启动容器。传统的名称空间分隔的容器很受欢迎,但是人们也有对虚拟机级隔离的渴望。英特尔和Hyper.sh正在使用kvm分离的容器,而微软则在使用基于windows的容器。OCI需要一个标准规范来定义容器是什么,因此OCI Runtime Specification诞生了。

  OCI Runtime Specification定义了一个JSON文件格式,该格式描述了应该运行什么二进制文件,如何包含它,以及容器rootfs的位置。相关工具生成JSON文件,其他工具可以读取这个JSON文件并在rootfs上执行一个容器。Docker的libcontainer部分被分解并捐赠给OCI。上游Docker工程师和红帽工程师帮助创建了一个新的前端工具来读取OCI Runtime Specification JSON文件,并与libcontainer交互以运行容器。这个叫做runc的工具也被捐赠给了OCI。虽然runc可以读取OCI JSON文件,但用户只能自己生成它。runc已经成为最流行的底层容器运行时,几乎所有的容器管理工具都支持runc,包括crio、Docker、Buildah、Podman和Cloud Foundry Garden。从那时起,其他工具也实现了OCI运行时规范来执行遵从OCI的容器。

  Clear Containers和Hyper.sh的runV工具被创建来使用OCI运行时规范来执行基于kvm的容器,并且这些内容都集中在一个名为Kata的新项目中。去年,Oracle创建了一个名为RailCar的OCI运行时工具的演示版本,该工具使用Rust编写,目前GitHub上这个项目已经更新了两个多月。

2
相关文章