Linux容器如何工作
我有机会在工作中使用几种不同的容器技术,所以我想我会写一些博客文章来解释容器是什么,并深入探讨LXC的工作方式。
什么是容器?
将计算资源分配到单个裸机(bare metal)主机上有时很有用。也许你想要隔离进程的安全性,或者只是想要最有效地使用计算机上可用的计算资源。Unix系统早在1979年就拥有了chroot的隔离功能,而2005年标志着对虚拟化兴趣的复苏。Chroot环境允许系统管理员限制进程只能访问文件系统上的特定子目录树,但不支持限制对其他资源(CPU,内存,网络等)的访问。虚拟化在主操作系统之上引入了虚拟机管理程序(hypervisor)层,允许在现有系统之上创建新的虚拟机。
虽然这提供了隔离,但它会因为在客户虚拟机上安装另一个操作系统副本而引入开销。与这两种方法相比,你可以将容器想象为chroot概念的扩展。它限制对主机文件系统特定部分的访问,但也提供了限制访问主机上其他计算资源的机制。与虚拟机相比,容器使用主机操作系统和内核来提供隔离和限制,因此可以完全避免虚拟机管理程序和客户操作系统层的开销。Docker的人创建了一个非常好的图形,比较了虚拟机和容器之间的差异 。结果是,更多的计算资源可用于你真正关心的进程,并且容器环境的设置比创建类似的虚拟机环境简单得多。
容器如何工作?
容器通过四个主要组件工作: 名称空间(namespaces) , 控制组(cgroups) , 映像(images)和用户空间工具,如LXC或docker 。
在传统的Linux系统中, init进程在机器启动时启动,并且每个后续进程都从其父进程派生(fork-execed)出来(init在进程树的根上)。每个正在运行的进程都存在于一个相同的环境中,并且能够访问该计算机上的所有资源。命名空间允许你将资源组合到一个共同的集合中。然后可以将进程与该名称空间相关联,从而为他们提供该机器上可用资源的更有限视图。Linux内核中目前有六个命名空间。这些大致可以分为:安装,进程,网络,进程间通信,主机名和用户(mount, process, network, interprocess communication, hostname, 和 user)。命名空间的价值应该是明确的:例如,如果一个进程需要对网络进行更改,则可以自由进行,而不会影响其他命名空间中的进程。这与容器有何关系?回想一下,Linux系统上的所有进程都从init进程派生。Linux容器的一个主要组件是在新的命名空间下创建一个新的init进程。没有名称空间功能,就不可能在主机上运行多个init进程。因此,仅凭名称空间(namespaces),我们就有能力生成一个进程树并操纵一些底层系统资源,而不会影响主机系统。如果容器的主要优点之一是隔离,那么是什么来阻止新产生的容器过度使用主机的资源呢?例如消耗太多的磁盘,内存或处理能力?这是cgroups发挥作用的地方。
C组(或“控制组(control groups)”)负责限制和记录系统资源的使用情况。该功能在2008年Linux内核中开始可用。使用cgroups,我们可以限制CPU使用率,内存,磁盘等等。描述如何配置cgroup超出了本概述的范围,但如果你想了解更多信息,可以查看内核文档 。通过命名空间和cgroups的组合,我们能够生成一个单独的进程层次结构(process hierarchy),并对系统资源进行有限的访问,并且我们可以限制这个进程层次结构对它可以看到的资源的访问量。尽管如此,我们仍然缺少容器生态系统的一个主要组件,那就是它可以访问的文件系统的内容。
容器最常见的误解之一是它们“就像一个迷你虚拟机”。混乱是可以理解的。当你在Linux容器中时,它看起来就像任何其他Linux发行版一样。你会看到你熟悉的文件系统布局,设备和系统软件。但是容器文件系统的内容不是完整的操作系统,而是目标操作系统的精简版本。底层资源和内核由主机提供,系统软件和设备由映像提供。因此,主机Linux发行版能够运行看起来完全不同的Linux发行版的容器。映像本身是通过采用超薄版本的目标发布版创建的,并以减小其大小并使其可在容器中运行的方式进行操作。描述这些映像的构建方式也超出了本文的范围,但你可以通过查看LXC github存储库来了解如何创建LXC映像。因此命名空间,cgroup和映像提供了三个主要的构建块,使容器可以工作。最后剩下的技术是一组用户工具,它们可以让你无缝地操纵这些概念并在容器内部创建自己的环境。在下一篇文章中,我将详细介绍如何使用LXC来实现这一点。