Docker和虚拟机有什么不同?

26 浏览
0 Comments

Docker和虚拟机有什么不同?

我一直在反复阅读Docker文档,试图理解Docker和完整的虚拟机之间的差别。它如何能够提供完整的文件系统、隔离的网络环境等等,而不像虚拟机那么沉重?

为什么把软件部署到Docker镜像(如果这是正确的术语的话)比部署到一致的生产环境更容易?

admin 更改状态以发布 2023年5月24日
0
0 Comments

了解虚拟化和容器在低级别上的工作原理可能会有所帮助,这将清楚许多事情。

注:以下描述有点简化。有关更多信息,请参见参考文献。

虚拟化是如何在低级别上工作的?

在这种情况下,虚拟机管理器接管CPU环0(或新CPU中的“根模式”),并拦截由客户操作系统(guest OS)发出的所有特权调用,以创造客户操作系统具有自己的硬件的幻象。有趣的事实是:在1998年之前,认为在x86架构上实现这种拦截是不可能的,因为没有办法进行这种拦截类型。 VMware的人们是第一个在内存中重新编写客户操作系统的特权调用的可执行字节以实现这一点。

总的效果是,虚拟化允许您在相同的硬件上运行两个完全不同的操作系统。每个客户操作系统都要经历引导、加载内核等过程。您可以获得非常紧密的安全性。例如,客户操作系统无法完全访问主机操作系统或其他客户,并弄乱事情。

容器是如何在低级别上工作?

大约在2006年,包括一些Google员工在内的人们实施了一个新的内核级别特性,称为名称空间(但是这个想法在< a href="http://rhelblog.redhat.com/2015/08/28/the-history-of-containers/" rel="noreferrer">很久之前已经存在于FreeBSD)。操作系统的一个功能是允许共享全局资源,如网络和磁盘,以在进程之间实现共享。如果这些全局资源被包装在名称空间中,以便它们仅对在同一名称空间中运行的那些进程可见怎么办?比如,您可以获得一个磁盘块,并将其放入名称空间X中,然后在名称空间Y中运行的进程将无法看到或访问它。类似地,名称空间X中的进程无法访问分配给名称空间Y的内存中的任何内容。当然,名称空间X中的进程无法看到或访问名称空间Y中的进程。这提供了一种全局资源的虚拟化和隔离。这就是Docker的工作原理:每个容器运行在自己的名称空间中,但使用完全相同的内核和所有其他容器。隔离发生是因为内核知道分配给进程的名称空间,并且在API调用期间,它确保进程只能访问自己的名称空间中的资源。

容器与虚拟机的限制现在应该很明显了:你不能像在虚拟机中那样在容器中运行完全不同的操作系统。然而,你可以运行不同的Linux发行版,因为它们共享同一内核。隔离级别不像虚拟机那样强。实际上,在早期实现中,"客户"容器可以接管主机。此外,当你加载一个新的容器时,不像在虚拟机中一样启动一个完整的新操作系统的副本。所有容器共享同一内核。这就是为什么容器是轻量级的原因。与虚拟机不同,你不必为容器预先分配大量内存,因为我们没有在运行新的操作系统副本。这使得在一个操作系统上运行数千个容器成为可能,并对它们进行沙盒隔离,如果我们在它们自己的虚拟机中运行单独的操作系统副本,则可能无法实现。

0
0 Comments

Docker最初使用了Linux容器(LXC),但后来转向使用runC(之前称为libcontainer)。runC在与其宿主操作系统相同的操作系统中运行,这允许它共享大量宿主操作系统资源。此外,它使用分层文件系统(AuFS)并管理网络连接。

AuFS是一种分层文件系统,因此您可以拥有只读部分和写入部分,这些部分会被合并在一起。您可以将操作系统的通用部分设置为只读(并在所有容器之间共享),然后为每个容器提供独立的写入挂载。

所以,假设您有一个1GB的容器镜像; 如果您想使用完整的虚拟机,您需要拥有1GB x您想要的虚拟机数量。使用Docker和AuFS,您可以在所有容器之间共享大部分1GB,并且如果您有1000个容器,则仍然可能只有略大于1GB的空间用于容器操作系统(假设它们都运行相同的操作系统镜像)。

完整的虚拟化系统获得其自己的资源集,并进行最小化共享。您获得更大的隔离性,但它更加笨重(需要更多资源)。使用Docker,您获得更少的隔离性,但容器轻量化(需要较少的资源)。所以您可以轻松地在主机上运行数千个容器,它甚至不会超负荷。使用Xen尝试这样做,除非您有一个非常大的主机,否则我认为这是不可能的。

一般来说,完整的虚拟化系统需要几分钟才能启动,而Docker/LXC/runC容器只需要几秒钟,甚至不到一秒钟的时间。

每种虚拟化系统都有其优缺点。如果您需要完全隔离且保证资源,完整的虚拟机是最佳选择。如果您只想彼此隔离进程并希望在大小适中的主机上运行大量进程,则Docker/LXC/runC似乎是最佳选择。

要了解更多信息,请查看这组博客文章,其中详细解释了LXC的工作原理。

部署软件到Docker镜像(如果这是正确的术语)比简单地部署到一致的生产环境更容易吗?

将一致的生产环境部署起来比较困难。即使使用像Chef和Puppet这样的工具,但是在主机和环境之间总会有操作系统更新和其他变化。

Docker使您能够将操作系统快照到共享镜像中,并轻松部署到其他Docker主机。在本地、开发、QA、Prod等方面,所有镜像都相同。当然您可以使用其他工具进行此操作,但远不如使用Docker简单快捷。

这对测试非常好;假设您有数千个需要连接到数据库的测试,并且每个测试都需要数据库的原始副本,并将对数据进行更改。解决此问题的经典方法是使用自定义代码或使用Flyway等工具在每个测试后重置数据库 - 这可能非常耗时,并且必须串行运行测试。但是,使用Docker,您可以创建数据库镜像,并在每个测试中运行一个实例,然后并行运行所有测试,因为您知道它们都将针对数据库的相同快照运行。由于测试在Docker容器中并行运行,它们可以同时在同一台计算机上运行,并且应该更快地完成。尝试使用完整的虚拟机进行此操作。

从评论中得知......

有趣!我猜我还是被"快照操作系统"这个想法所困惑。那么,如果不制作OS的镜像,怎样才能实现这个操作呢?

好的,让我来解释一下。您可以从一个基础镜像开始,然后进行更改并使用Docker提交这些更改,这样会生成一个新的镜像。这个新的镜像中只包含与基础镜像不同的部分。当您想要运行这个新的镜像时,您也需要基础镜像,Docker将使用一种分层文件系统将您的镜像放在基础镜像上,通常使用的是AuFS(即Docker使用的联合文件系统)。AuFS会将不同的层合并在一起,您将获得您需要的内容;您只需要运行它即可。您可以不断地增加更多的镜像(层),它将继续保存差异。由于Docker通常是在仓库里构建基于现成镜像的,您很少需要自己"快照"整个OS。

0