Docker与虚拟机有何不同?


3690

我不断阅读Docker文档,以尝试了解Docker和完整VM之间的区别。它如何提供完整的文件系统,隔离的网络环境等而又不那么繁重?

为什么将软件部署到Docker映像(如果正确的话)比简单地部署到一致的生产环境更容易?


10
Docker vs KVM性能分析: bodenr.blogspot.com/2014/05/…–
HDave

1
如果你正在寻找他们的图像之间的差异- stackoverflow.com/questions/29096967/...
devesh-的Ahuja

20
Docker不是虚拟机-它是一种配置管理工具。
aaa90210

3
简而言之:VM->三个虚拟层必须运行,以允许您的应用程序运行,如果您希望服务器虚拟化还可以,但是如果仅运行Web应用程序则不是最佳解决方案。DOCKER->实际cpu和Web应用程序之间只有一层。如果您只需要运行Web应用程序以虚拟化我建议的功能,则功能更强大,克隆/镜像效果更好
Davide Castronovo '18

6
让我们不要忘记,适用于Mac的Docker和适用于Windows的Docker确实使用了虚拟化层。
Shapeshifter

Answers:


3432

Docker最初使用LinuX容器(LXC),但后来切换到了runC(以前称为libcontainer),后者与主机运行在相同的操作系统中。这使它可以共享许多主机操作系统资源。此外,它使用分层文件系统(AuFS)并管理网络。

AuFS是分层的文件系统,因此您可以具有合并在一起的只读部分和写入部分。可以使操作系统的公共部分为只读(并在所有容器之间共享),然后为每个容器提供自己的安装架以进行写入。

因此,假设您有一个1 GB的容器映像;如果要使用完整的VM,则需要具有1 GB x所需数量的VM。使用Docker和AuFS,您可以在所有容器之间共享1 GB的大部分空间;如果您有1000个容器,则容器OS的空间可能仍然只有1 GB以上(假设它们都运行相同的OS映像) 。

完整的虚拟化系统会为其分配自己的资源集,并且共享最少。您将获得更多的隔离,但是隔离会更重(需要更多资源)。使用Docker可以减少隔离,但是容器重量轻(需要较少的资源)。因此,您可以轻松地在主机上运行数千个容器,并且它甚至不会闪烁。尝试使用Xen来做到这一点,除非您拥有非常庞大的主机,否则我认为不可能。

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

每种类型的虚拟化系统各有利弊。如果要使用有保证的资源进行完全隔离,则必须使用完整的VM。如果您只是想将进程彼此隔离,并希望在合理大小的主机上运行大量进程,那么Doc​​ker / LXC / runC似乎是可行的方法。

有关更多信息,请查看这组博客文章,它们可以很好地解释LXC的工作原理。

为什么将软件部署到docker映像(如果正确的话)比简单地部署到一致的生产环境更容易?

部署一致的生产环境说起来容易做起来难。即使您使用ChefPuppet之类的工具,也始终会在主机和环境之间进行OS更新以及其他更改。

Docker使您能够将操作系统快照到共享映像中,并使其易于部署在其他Docker主机上。在本地,dev,qa,prod等:全都相同。当然,您可以使用其他工具来做到这一点,但并不那么容易或快速。

这非常适合测试;假设您有成千上万个需要连接到数据库的测试,并且每个测试都需要数据库的原始副本,并将对数据进行更改。经典的方法是在每次测试后使用自定义代码或使用Flyway之类的工具重置数据库-这可能非常耗时,并且意味着必须串行运行测试。但是,使用Docker可以创建数据库的映像并为每个测试运行一个实例,然后并行运行所有测试,因为您知道它们都将针对数据库的同一快照运行。由于测试是在Docker容器中并行运行的,因此它们可以同时在同一盒子上运行,并且应该更快地完成。尝试使用完整的VM进行操作。

来自评论...

有趣!我想我仍然对“快照操作系统”的概念感到困惑。如果不制作操作系统映像,该怎么办?

好吧,让我们看看是否可以解释。您从基础映像开始,然后进行更改,然后使用docker提交这些更改,然后创建一个映像。该图像仅包含与基准的差异。当您要运行映像时,您还需要基础,它使用分层的文件系统在基础之上分层映像:如上所述,Docker使用AuFS。AuFS将不同的层合并在一起,您将获得所需的内容。您只需要运行它。您可以继续添加越来越多的图像(图层),它将继续仅保存差异。由于Docker通常基于注册表中的现成映像构建,因此您几乎不必自己“快照”整个操作系统。


238
Ken,在某些地方,您将OS与内核混为一谈。主机上的所有容器都在同一内核下运行,但是其余OS文件在每个容器中可以是唯一的。
安迪

22
有趣!我想我仍然对“快照操作系统”的概念感到困惑。如果不制作操作系统映像,该怎么办?
zslayton

7
@ murtaza52他们正在添加对不同文件系统的支持,因此Aufs离开应该不是问题。不确定何时添加32位支持,不要以为需求很大,因此优先级列表上的支持率很低,但是我可能是错的。
肯·科克伦

21
@Mike:...无疑是受FreeBSD监狱的 启发HISTORY The jail utility appeared in FreeBSD 4.0.
Stefan Paletta

21
对于那些想知道@Mike的评论(因为它似乎已被删除),我们要答复的是:<缺少的一件事是提到Linux容器是灵感的真正来源的复制品这一事实。 :Solaris容器。可以追溯到2004年……这是一个革命性的概念,是一种制造真正高性能的价格合理的托管虚拟机的绝妙方法。Joyent是我所知道的第一个...>
Jeffrey'jf'Lim 2014年

557

好答案。只是要获得容器与VM的图像表示,请看下面的图像。

在此处输入图片说明

资源


20
<strike>据我了解,在“ docker engine”上方应该有一个共享的Linux内核。然后通常甚至有共享的bin / lib。首先是特定于每个容器的bin / lib和应用程序。如果我错了,请纠正我。</ strike>我错了。Docker映像与主机共享内核,请参见superuser.com/questions/889472/…。但是,为了说明容器的联合文件系统,可能在docker引擎正上方有一个共享的libs / bins层。
Betamos

13
我对上面的图片有问题,因为可以将Hypervisor安装在裸机/基础架构上,但是Docket不能(至今)
reza

@reza,我同意可以在Bare metal上安装Hypervisor,但要点是建议将Docker用于应用程序的容器化以及如何限制或避免在某些情况下不需要/不适用的虚拟化。肯·科克伦(Ken Cochrane)更详细地解释了这一点stackoverflow.com/a/16048358/2478933
manu97'6

4
这并不能阐明什么是Docker Engine。非常抽象的图片。
kyb

9
有容器和内核之间没有“泊坞引擎”层,容器仅仅是一个在内核特殊设置处理(命名空间,cgroup中,等)
帕维尔Prażak

503

了解虚拟化和容器如何在低级别工作可能会有所帮助。这将清除很多事情。

注意:我在下面的描述中做了一些简化。有关更多信息,请参见参考。

虚拟化如何在低层工作?

在这种情况下,VM管理器将接管CPU环0(或较新的CPU中的“根模式”),并拦截来宾OS进行的所有特权调用,从而造成幻觉,即来宾OS具有自己的硬件。有趣的事实:在1998年之前,由于没有办法进行这种拦截,人们认为在x86架构中不可能实现这一点。VMWare的人们是第一个想到重写内存中的可执行字节以实现来宾OS特权调用的想法的人。

最终结果是虚拟化允许您在同一硬件上运行两个完全不同的OS。每个来宾OS都要进行引导,加载内核等所有过程。您可以具有非常严格的安全性,例如,来宾OS无法获得对主机OS或其他来宾的完全访问权限并弄乱了事情。

容器如何在低层工作?

大约2006年,人们包括一些谷歌员工实施了新的内核级别的功能,称为命名空间(不过这个想法之前在FreeBSD中存在)。操作系统的一项功能是允许将网络和磁盘等全局资源共享给进程。如果将这些全局资源包装在名称空间中,以便它们仅对在相同名称空间中运行的那些进程可见,该怎么办?说,您可以获得一块磁盘并将其放入命名空间X中,然后在命名空间Y中运行的进程无法看到或访问它。同样,名称空间X中的进程无法访问分配给名称空间Y的内存中的任何内容。当然,X中的进程无法查看或与名称空间Y中的进程对话。这为全局资源提供了一种虚拟化和隔离。这是码头工人的工作原理:在它自己的命名空间,但将每个容器运行完全一样内核与其他所有容器一样。发生隔离是因为内核知道分配给进程的名称空间,并且在API调用期间它确保进程只能访问其自己的名称空间中的资源。

容器与VM的局限性现在应该很明显:您不能像VM中那样在容器中运行完全不同的OS。但是,您可以运行不同的Linux发行版,因为它们确实共享相同的内核。隔离级别不如VM中强。实际上,在早期的实现中,有一种“来宾”容器接管主机的方法。您还可以看到,加载新容器时,操作系统的整个新副本不会像在VM中那样启动。所有容器共享同一内核。这就是为什么容器重量轻的原因。同样与VM不同,您不必为容器预先分配大量内存,因为我们没有运行新的OS副本。这样一来,就可以在一个操作系统上运行数千个容器,同时对它们进行沙盒处理,如果我们在自己的VM中运行单独的OS副本,则可能无法做到。


26
哇,谢谢您的低级解释(和历史事实)。我一直在寻找,但找不到上面。您的意思是“您可以运行不同的Linux发行版,因为它们确实共享相同的内核。” ?您是说来宾容器必须具有完全相同的Linux内核版本,还是没关系?如果我在客户机上调用OS命令但仅在客户机内核中受支持,该怎么办。或者,例如,来宾内核中已修复但主机内核中未修复的错误。所有来宾都会显示错误,对吗?即使客人被打补丁。
Jeach

7
@Jeach:容器没有自己的内核,它们正在共享/使用主机之一。因此,您不能在同一台机器/ VM上运行需要不同内核的容器。
user276648 '16

2
问题:您写道Google的某些员工在1996年左右就参与了名称空间内核功能-但是Google直到1998年才成立。您的意思是“后来会成为Google员工的人”吗?
Martin Gjaldbaek '16

3
@martin-感谢您注意到这一年是2006年。我还要指出的是,自2002年以来,Linux中已经存在不同类型的名称空间,但是正是2006年的工作为容器化奠定了基础。我已经参考更新了答案。
Shital Shah

20
+1这应该是标记的答案,而其他答案则提供了一些澄清,只有自下而上的低级解释才能弄清楚该技术的工作原理,即“分组在其自己的命名空间=容器中的进程”。非常感谢,我明白了。
蒂诺·麦克拉伦

328

我喜欢肯·科克伦的回答。

但是我想补充一些观点,这里不再详细介绍。我认为Docker在整个过程中也有所不同。与VM相比,Docker并非(仅)与硬件的最佳资源共享有关,而且它为打包应用程序提供了一个“系统”(最好但不是必须的,作为一组微服务)。

对我来说,它适合一方面面向rpm,Debian软件包,Maven,npm + Git等面向开发人员的工具与诸如Puppet,VMware,Xen之类的ops工具之间的鸿沟,您可以将其命名为...

为什么将软件部署到docker映像(如果正确的话)比简单地部署到一致的生产环境更容易?

您的问题假设一个一致的生产环境。但是如何保持一致呢? 考虑流水线中某些数量的服务器和应用程序(> 10)。

为了保持同步,您将开始使用Puppet,Chef或您自己的配置脚本,未发布的规则和/或大量文档等内容。理论上,服务器可以无限期地运行,并且可以保持完全一致和最新。实践无法完全管理服务器的配置,因此存在很大的配置漂移范围以及对运行中的服务器进行的意外更改。

因此,有一种避免这种情况的已知模式,即所谓的不可变服务器。但是不喜欢不变的服务器模式。主要是由于Docker之前使用的VM的局限性。处理几个千兆字节的大图像,移动这些大图像,只是为了更改应用程序中的某些字段,非常费力。可以理解的...

有了Docker生态系统,您将不需要在“小变化”(感谢aufs和Registry)的情况下移动数GB,也不必担心在运行时将应用程序打包到Docker容器中而导致性能下降。您无需担心该图像的版本。

最后,您甚至甚至可以在Linux笔记本电脑上重现复杂的生产环境(如果在您的情况下不起作用,请不要打电话给我;)

当然,您可以在VM中启动Docker容器(这是一个好主意)。在VM级别上减少服务器配置。以上所有内容都可以由Docker管理。

PS同时,Docker使用其自己的实现“ libcontainer”而不是LXC。但是LXC仍然可用。


1
将git包含在rpm和dpkg之类的工具中似乎有些奇怪。我之所以这样说,是因为我发现尝试将git之类的版本控制系统用作分发/打包工具的尝试引起了很多混乱。
blitzen9872 '17

2
他没错,不过git可以用于软件包管理,例如bower在内部基本上是下载git标签的cli。
roo2

2
将应用程序包装在容器中是一种有趣且有效的方法。但是,如果将其打包在docker中,这将是多余的,因为不会直接支持依赖项或任何共享库。这正是Ubuntu Snap和Flatpak for Redhat等新包装技术正在试图实现的目标。我认为,其中一种包装技术将获胜,并成为Linux中包装的未来。
yosefrow

@ blitzen9872对此表示同意。但是之所以被提及,正是因为它在实践中经常用于分发,我再次也不喜欢它。
aholbreich

@yosefrow详细说明了“过度杀伤”。检查“不可变服务器”模式的思想和优点,当然也有一些缺点...如果您看到过大的杀伤力,请不要使用它
。.– aholbreich

245

Docker不是一种虚拟化方法。它依赖于实际上实现基于容器的虚拟化或操作系统级虚拟化的其他工具。为此,Docker最初使用LXC驱动程序,然后移至libcontainer,现在将其重命名为runc。Docker主要致力于自动化应用程序容器内应用程序的部署。应用程序容器旨在打包和运行单个服务,而系统容器旨在运行多个进程,例如虚拟机。因此,Docker被视为容器化系统上的容器管理或应用程序部署工具。

为了了解它与其他虚拟化有何不同,让我们看一下虚拟化及其类型。然后,将更容易理解那里的区别。

虚拟化

在其设想的形式中,它被认为是一种逻辑上划分大型机以允许多个应用程序同时运行的方法。但是,当公司和开放源代码社区能够提供一种以一种或另一种方式处理特权指令的方法,并允许在单个基于x86的系统上同时运行多个操作系统时,情况发生了巨大变化。

管理程序

系统管理程序处理创建来宾虚拟机在其上运行的虚拟环境。它监督来宾系统,并确保根据需要将资源分配给来宾。虚拟机管理程序位于物理机和虚拟机之间,并为虚拟机提供虚拟化服务。为了实现它,它拦截了虚拟机上的来宾操作系统操作,并模拟了主机操作系统上的操作。

虚拟化技术的快速发展(主要是在云中)通过允许在虚拟机管理程序(例如Xen,VMware Player,KVM等)的帮助下在单个物理服务器上创建多个虚拟服务器,进一步推动了虚拟化的使用。在商用处理器(例如Intel VT和AMD-V)中整合了硬件支持。

虚拟化类型

可以基于虚拟化方法如何将硬件模拟为来宾操作系统并模拟来宾操作系统来对其进行分类。主要有三种虚拟化类型:

  • 仿真
  • 半虚拟化
  • 基于容器的虚拟化

仿真

仿真(也称为完全虚拟化)完全在软件中运行虚拟机OS内核。这种类型的管理程序称为类型2管理程序。它安装在主机操作系统的顶部,该主机操作系统负责将来宾OS内核代码转换为软件指令。翻译完全由软件完成,不需要硬件。通过仿真,可以运行支持仿真环境的任何未修改的操作系统。这种虚拟化的缺点是额外的系统资源开销,与其他类型的虚拟化相比,这会导致性能下降。

仿真

此类别中的示例包括VMware Player,VirtualBox,QEMU,Bochs,Parallels等。

半虚拟化

半虚拟化也称为Type 1虚拟机管理程序,直接在硬件或“裸机”上运行,并直接向其上运行的虚拟机提供虚拟化服务。它可以帮助操作系统,虚拟化硬件和实际硬件进行协作以实现最佳性能。这些虚拟机管理程序通常占用空间很小,并且本身不需要大量资源。

此类别中的示例包括Xen,KVM等。

半虚拟化

基于容器的虚拟化

基于容器的虚拟化,也称为操作系统级虚拟化,可在单个操作系统内核中实现多个隔离的执行。它具有最佳的性能和密度,并具有动态资源管理功能。这种虚拟化提供的隔离的虚拟执行环境称为容器,可以看作是一组跟踪的进程。

基于容器的虚拟化

通过添加到Linux内核版本2.6.24的名称空间功能,可以使容器的概念成为可能。容器将其ID添加到每个进程,并将新的访问控制检查添加到每个系统调用。它由clone()系统调用访问,该系统调用允许创建先前全局名称空间的单独实例。

命名空间可以以多种不同的方式使用,但是最常见的方法是创建一个隔离的容器,该容器不具有可见性或对容器外部对象的访问。尽管容器内运行的进程与位于其他名称空间中的进程(与其他类型的对象相同)共享底层内核,但它们似乎在普通的Linux系统上运行。例如,当使用命名空间时,容器内的root用户不会被视为容器外的root用户,从而增加了安全性。

Linux Control Groups(cgroups)子系统是实现基于容器的虚拟化的下一个主要组件,用于对进程进行分组并管理其总资源消耗。它通常用于限制容器的内存和CPU消耗。由于容器化的Linux系统只有一个内核,并且内核对容器具有完全的可见性,因此只有一层资源分配和调度。

几种管理工具可用于Linux容器,包括LXC,LXD,systemd-nspawn,lmctfy,Warden,Linux-VServer,OpenVZ,Docker等。

容器与虚拟机

与虚拟机不同,容器不需要启动操作系统内核,因此可以在不到一秒钟的时间内创建容器。与其他虚拟化方法相比,此功能使基于容器的虚拟化具有独特性和可取性。

由于基于容器的虚拟化几乎不给主机增加任何开销,因此基于容器的虚拟化具有近乎原生的性能

对于基于容器的虚拟化,与其他虚拟化不同,不需要其他软件。

主机上的所有容器共享主机的调度程序,从而节省了额外的资源。

与虚拟机映像相比,容器状态(Docker或LXC映像)的大小较小,因此容器映像易于分发。

容器中的资源管理是通过cgroups实现的。Cgroup不允许容器消耗比分配给它们更多的资源。但是,到目前为止,主机的所有资源在虚拟机中都是可见的,但无法使用。这可以通过在容器和主机上同时运行top或同时运行来实现htop。在所有环境中的输出将看起来相似。

更新:

Docker如何在非Linux系统中运行容器?

如果由于Linux内核中可用的功能而使容器成为可能,那么显而易见的问题是非Linux系统如何运行容器。适用于Mac和Windows的Docker均使用Linux VM运行容器。Docker Toolbox用于在Virtual Box VM中运行容器。但是,最新的Docker在Windows中使用Hyper-V,在Mac中使用Hypervisor.framework。

现在,让我详细介绍Docker for Mac如何运行容器。

适用于Mac的Docker使用https://github.com/moby/hyperkit来模拟虚拟机监控程序功能,而Hyperkit在其核心中使用hypervisor.framework。Hypervisor.framework是Mac的本机虚拟机管理程序解决方案。Hyperkit还使用VPNKit和DataKit分别命名网络和文件系统的名称空间。

Docker在Mac中运行的Linux VM是只读的。但是,您可以通过运行以下命令对其进行重击:

screen ~/Library/Containers/com.docker.docker/Data/vms/0/tty

现在,我们甚至可以检查此VM的内核版本:

# uname -a Linux linuxkit-025000000001 4.9.93-linuxkit-aufs #1 SMP Wed Jun 6 16:86_64 Linux

所有容器都在此VM中运行。

hypervisor.framework有一些限制。因此,Docker不会docker0在Mac中公开网络接口。因此,您无法从主机访问容器。截至目前,docker0仅在VM内部可用。

Hyper-v是Windows中的本机管理程序。他们还试图利用Windows 10的功能在本地运行Linux系统。


1
非常好的帖子。非常感谢!我的另一个问题是,我可以在Mac x86_64机器上构建docker arm7v 32位映像。但是,我无法在x86_64机器上安装的Ubuntu上生成相同的映像。这与您提到的Mac hypervisor解决方案有关吗?
jiashenC

1
您的答案是唯一解决“ Docker如何在非Linux系统中运行容器?”的问题。这些信息很难在任何地方找到。一切都强调“容器与VM完全不同!”,速度更快,重量更轻等,但是在非Linux系统上运行容器的唯一方法是启动VM。
Bogatyr

@Bogatyr IINM,它是所有容器的一个VM。
dstromberg

147

通过这篇文章,我们将画出VM和LXC之间的一些差异。首先定义它们。

虚拟机

虚拟机模拟物理计算环境,但是对CPU,内存,硬盘,网络和其他硬件资源的请求由虚拟化层管理,该层将这些请求转换为底层物理硬件。

在这种情况下,VM称为来宾,而其运行的环境称为主机。

LXC s:

Linux容器(LXC)是操作系统级别的功能,可以在一个控制主机(LXC主机)上运行多个隔离的Linux容器。Linux容器不需要VM虚拟机监控程序,因此可以作为VM的轻型替代方案。Virtualbox,KVM,Xen等

现在,除非您被Alan(来自Hangover系列的Zach Galifianakis)迷住了,并且去年曾在拉斯维加斯,否则您将非常清楚Linux容器技术的巨大兴趣,如果我要专门介绍一个容器过去几个月在全球引起轰动的项目是– Docker引起了一些共鸣,即云计算环境应放弃虚拟机(VM),而用容器代替它们,因为它们的开销较低且可能具有更好的性能。

但是最大的问题是,是否可行?是否明智?

一个。LXC限于Linux实例。可能是不同风格的Linux(例如,CentOS主机上的Ubuntu容器,但仍是Linux。)类似地,如果我们查看基于VM的VM,它们的范围更广,并且使用虚拟机管理程序,您不仅限于Linux或Windows操作系统。

b。与VM相比,LXC具有较低的开销并具有更好的性能。工具即。基于LXC技术的Docker为开发人员提供了运行其应用程序的平台,同时为操作人员提供了一种工具,使他们可以在生产服务器或数据中心上部署相同的容器。它试图使开发人员在运行应用程序,启动和测试应用程序与部署该应用程序的操作人员之间获得无缝的体验,因为这是所有麻烦的源头,DevOps的目的是消除这些孤岛。

因此,最好的方法是云基础架构提供商应提倡适当使用VM和LXC,因为它们各自适合处理特定的工作负载和方案。

到目前为止,放弃虚拟机是不切实际的。因此,VM和LXC都有其各自的存在和重要性。


4
上面的“ b”部分正是Docker员工一直在谈论的技术。旨在简化开发部署任务。根据我作为开发人员和系统管理员的经验,我必须同意。
WineSoaked,2014年

3
这是非常抽象的答案。我们在何时使用/不使用Docker时需要用例。这就是问题所在。每个人都可以找到Docker的模样,但只有少数人可以在实际场景中进行解释。
伊万·沃罗林

1
docker现在正被带入Windows世界,因为它不再依赖于LXC: blogs.msdn.com/b/nzdev/archive/2015/06/02/…如果我误解了这里的答案,请纠正我
bubakazouba

6
我很难理解容器“(例如Centos主机上的Ubuntu容器,但仍是Linux)”部分。据我了解,容器共享主机内核。例如,如果我有一个运行Linux内核4.6的主机VM,那么有几个运行Linux内核2.4、2.6、3.2、4.1和4.4的来宾VM。如果执行特定于该内核的命令,则将获得来宾内核的行为(而不是主机)。但是,如果我的来宾VM现在是容器,执行的命令是否由主机内核确定?
Jeach

@bubakazouba是的。你是对的。现在他们使用runC
Rumesh Eranga Hapuarachchi

140

这里的大多数答案都谈论虚拟机。对于这个问题,我将给您一个单线答复,这在使用Docker的过去几年中对我的帮助最大。是这样的:

Docker只是一种运行过程的理想方式,而不是虚拟机。

现在,让我解释一下这意味着什么。虚拟机是他们自己的野兽。我觉得解释Docker是什么比解释虚拟机更能帮助您理解这一点。特别是因为这里有许多很好的答案,可以准确地告诉您某人说“虚拟机”时的意思。所以...

Docker容器只是一个进程(及其子进程),使用主机系统内核中的cgroup与其余进程进行分隔。您实际上可以通过ps aux在主机上运行来查看Docker容器进程。例如,apache2“在容器中”启动只是apache2作为主机上的特殊过程启动。它只是与机器上的其他进程分隔开的。重要的是要注意,在容器化过程的生命周期之外,容器不存在。进程死亡时,容器死亡。那是因为Docker pid 1用您的应用程序替换了容器内部(pid 1通常是init系统)。最后一点pid 1很重要。

至于每个容器进程使用的文件系统,Docker使用UnionFS支持的映像,这是您在执行时要下载的映像docker pull ubuntu。每个“图像”只是一系列图层和相关的元数据。分层的概念在这里非常重要。每层只是其下一层的变化。例如,当您在构建Docker容器时删除Dockerfile中的文件时,您实际上只是在最后一层之上创建了一层,该层显示“此文件已被删除”。顺便说一句,这就是为什么您可以从文件系统中删除大文件,但是映像仍占用相同数量的磁盘空间的原因。该文件仍然位于当前文件所在的图层中。图层本身只是文件的压缩文件。你可以用docker save --output /tmp/ubuntu.tar ubuntu然后cd /tmp && tar xvf ubuntu.tar。然后,您可以环顾四周。那些看起来像长哈希的目录实际上是各个层。每个文件都包含文件(layer.tar)和元数据(json)以及有关该特定图层的信息。这些层仅描述对文件系统的更改,这些更改保存为原始状态“之上”的一层。当读取“当前”数据时,文件系统将读取数据,就好像它只是在查看更改的最顶层。这就是即使文件仍然存在于“上一个”层中也似乎将其删除的原因,因为文件系统仅在最顶层。这允许完全不同的容器共享其文件系统层,即使每个容器中最顶层的文件系统可能发生了重大更改。当您的容器共享其基本映像层时,这可以为您节省大量磁盘空间。然而,

Docker中的网络是通过使用以太网桥(docker0在主机上称为)和主机上每个容器的虚拟接口来实现的。它在其中创建了一个虚拟子网,docker0供您的容器相互之间“通信”。这里有许多用于联网的选项,包括为您的容器创建自定义子网,以及“共享”主机的网络堆栈以供您的容器直接访问的能力。

Docker的发展非常快。它的文档是我见过的最好的文档。它通常是精心编写,简洁且准确的。我建议您查看可用的文档以获取更多信息,并信任您在线上阅读的所有文档(包括Stack Overflow)。如果您有特定问题,我强烈建议您加入#dockerFreenode IRC并在那里提问(您甚至可以使用Freenode的网络聊天!)。


12
“ Docker只是一种运行过程的理想方式,而不是虚拟机。” 这是一个很好的总结,谢谢!
mkorman

谢谢!功劳从#dockerFreenode IRC上的频道传给programq。
L0j1k

这比其他答案要清楚得多。我想这是为我做的过程比喻。它只是降低了抽象级别。
MateMrše18年

我要补充一点:“ Docker只是一种以隔离,受保护,封装的方式而不是虚拟机来运行进程的理想方式。” 主机系统具有子系统的可见性(通过过程和资源),但是隔离的系统在主机系统中没有可见性(通过过程和资源)。
Sohail Si

87

Docker封装了具有所有依赖关系的应用程序。

虚拟器封装了可以运行通常可以在裸机上运行的任何应用程序的OS。


1
我正在学习LXC,如果我输入错了,请纠正我,但这可能是某种virtualenv?但范围更广,不仅限于Python的说法
NeoVe 2015年

2
我最喜欢这个答案。它很简单,直截了当。既然已经对LXC和Virtualizers可以做什么有一个基本的了解,那么其他阅读的细节将很有意义。
Phil

2
@Phil在我首先阅读上面的详细答案之后就做到了。
约翰尼,2015年

我假设他们想知道如何封装。这是很大的一部分,可以显示它们之间的差异,但是您没有回答。
Light.G

60

他们俩都非常不同。Docker是轻量级的,并且使用LXC / libcontainer(依赖于内核命名空间和cgroup),并且没有诸如虚拟机管理程序,KVM之类的机器/硬件仿真。Xen很重。

Docker和LXC的目的更多是用于沙箱,容器化和资源隔离。它使用主机操作系统(目前仅Linux内核)的克隆API,该API为IPC,NS(安装),网络,PID,UTS等提供命名空间。

内存,I / O,CPU等如何?这可以使用cgroups进行控制,您可以在其中创建具有特定资源(CPU,内存等)规范/限制的组,并将进程放入其中。在LXC之上,Docker提供了一个存储后端(http://www.projectatomic.io/docs/filesystems/),例如,联合安装文件系统,您可以在其中添加层并在不同的安装名称空间之间共享层。

这是一项强大的功能,基本映像通常是只读的,只有容器在层中修改某些内容时,它才会将某些内容写入可读写分区(也称为写时复制)。它还提供了许多其他包装器,例如注册表和映像版本控制。

对于普通的LXC,您需要附带一些rootfs或共享rootfs,并且在共享时,更改会反映在其他容器上。由于这些附加功能很多,Docker比LXC更受欢迎。LXC在嵌入式环境中很流行,用于围绕暴露于外部实体(例如网络和UI)的流程实现安全性。Docker在期望一致的生产环境的云多租户环境中很流行。

普通VM(例如VirtualBox和VMware)使用虚拟机监控程序,并且相关技术具有专用固件(该固件成为第一个OS(主机OS或来宾OS 0)的第一层)或在主机OS上运行的软件,向来宾OS提供硬件仿真,例如CPU,USB /附件,内存,网络等。VM(截至2015年)仍在高安全性多租户环境中流行。

Docker / LXC几乎可以在任何便宜的硬件上运行(只要您有较新的内核,少于1 GB的内存也是可以的),而普通VM至少需要2 GB的内存等,以便对其进行有意义的处理。但是在Windows之类的操作系统(截至2014年11月)中,主机操作系统上的Docker支持不可用,其中可能在Windows,Linux和Mac上运行多种类型的VM。

这是来自docker / rightscale的图片: 这是右比例的照片


34

1.轻巧

这可能是许多Docker学习者的第一印象。

首先,Docker映像通常比VM映像小,从而易于构建,复制和共享。

其次,Docker容器可以在几毫秒内启动,而VM可以在数秒内启动。

2.分层文件系统

这是Docker的另一个主要功能。图像具有图层,并且不同的图像可以共享图层,从而更加节省空间并加快构建速度。

如果所有容器都使用Ubuntu作为其基本映像,则不是每个映像都有其自己的文件系统,而是共享相同的下划线ubuntu文件,并且它们各自的应用程序数据不同。

3.共享的操作系统内核

将容器视为流程!

主机上运行的所有容器的确是一堆具有不同文件系统的进程。它们共享相同的OS内核,仅封装系统库和依赖项。

这在大多数情况下是很好的(不需要额外的OS内核),但是如果在容器之间需要严格的隔离,则可能会成为问题。

为什么重要呢?

所有这些似乎都是改进,而不是革命。好吧,定量积累会导致质变

考虑一下应用程序部署。如果要部署新软件(服务)或升级软件(服务),最好更改配置文件和流程,而不要创建新的VM。因为创建具有更新服务的虚拟机,然后对其进行测试(在Dev和QA之间共享),部署到生产需要数小时甚至数天的时间。如果有任何问题,您必须重新开始,浪费更多时间。因此,请使用配置管理工具(木偶,盐堆,厨师等)来安装新软件,最好下载新文件。

对于docker,不可能使用新创建的docker容器替换旧的docker容器。维护容易得多!构建新映像,与质量检查共享,进行测试,部署,只需几分钟(如果一切都是自动化的),在最坏的情况下只需几个小时。这被称为不可变基础架构:不要维护(升级)软件,而是创建一个新的。

它改变了服务的交付方式。我们需要应用程序,但必须维护VM(这很痛苦,与我们的应用程序无关)。Docker使您专注于应用程序并使所有事情变得顺利。


27

Docker基本上是容器,它支持OS虚拟化,即您的应用程序感觉它具有OS的完整实例,而VM支持硬件虚拟化。您会觉得这是一台可以在其中引导任何OS的物理机。

在Docker中,运行的容器共享主机OS内核,而在VM中,它们具有自己的OS文件。将应用程序部署到各种服务环境(例如“测试”或“生产”)时,用于开发应用程序的环境(操作系统)将相同。

例如,如果您开发了一个在端口4000上运行的Web服务器,则将其部署到“测试”环境时,该端口已被其他程序使用,因此它将停止工作。容器中有几层。您对操作系统所做的所有更改都将保存在一个或多个层中,这些层将成为映像的一部分,因此无论映像到哪里,都将存在依赖项。

在下面显示的示例中,主机具有三个VM。为了使VM中的应用程序完全隔离,它们各自具有自己的OS文件,库和应用程序代码副本以及OS的完整内存实例。没有容器 下图显示了使用容器的相同情况。在这里,容器仅共享主机操作系统,包括内核和库,因此它们不需要启动操作系统,加载库或为这些文件支付专用内存成本。它们占用的唯一增量空间是应用程序在容器中运行所需的任何内存和磁盘空间。尽管应用程序的环境感觉像是专用的OS,但应用程序的部署就像在专用主机上一样。容器化的应用程序在几秒钟内启动,与VM相比,该应用程序实例可以在计算机上安装的更多。 在此处输入图片说明

来源:https : //azure.microsoft.com/en-us/blog/containers-docker-windows-and-trends/


我非常喜欢第一段。
Light.G

23

提供了三种不同的设置来提供堆栈以在其上运行应用程序(这将帮助我们识别什么是容器以及什么使其比其他解决方案强大得多):

1) Traditional Servers(bare metal)
2) Virtual machines (VMs)
3) Containers

1)传统的服务器堆栈由运行操作系统和您的应用程序的物理服务器组成。

优点:

  • 原始资源利用

  • 隔离

缺点:

  • 部署时间很慢
  • 昂贵
  • 资源浪费
  • 难以扩展
  • 迁移困难
  • 复杂的配置

2)VM堆栈由运行操作系统的物理服务器和管理虚拟机,共享资源和网络接口的管理程序组成。每个Vm运行一个来宾操作系统,一个应用程序或一组应用程序。

优点:

  • 善用资源
  • 易于扩展
  • 易于备份和迁移
  • 成本效益
  • 灵活性

缺点:

  • 资源分配有问题
  • 供应商锁定
  • 复杂的配置

3)Container Setup,与其他堆栈的主要区别在于基于容器的虚拟化使用主机OS的内核来朗读多个隔离的来宾实例。这些来宾实例称为容器。主机可以是物理服务器或VM。

优点:

  • 隔离
  • 轻巧的
  • 资源有效
  • 易于迁移
  • 安全
  • 低开销
  • 镜面生产开发环境

缺点:

  • 相同的架构
  • 资源密集型应用
  • 网络和安全问题。

通过将容器设置与其之前的版本进行比较,我们可以得出结论:迄今为止,容器化是最快,最节省资源和最安全的设置。容器是运行您的应用程序的隔离实例。Docker以某种方式启动容器,各层通过默认存储驱动程序(覆盖驱动程序)在几秒钟内运行获得运行时内存,并在我们提交到容器后在其之上创建写时复制层,从而为执行提供动力。容器。如果是VM,则需要大约一分钟才能将所有内容加载到虚拟化环境中。这些轻量级实例可以轻松替换,重建和移动。这使我们能够镜像生产和开发环境,并且在CI / CD流程中提供了巨大帮助。容器可以提供的优势是如此引人注目,以至于它们肯定会留下来。


请说明为什么这是与虚拟机相比“最安全的设置”。
MKesper '18年

@MKesper:从旧版环境迁移到容器环境时,您可以通过多种方式来构建安全范式,一种基于主动而非被动的方法来防止入侵。它使您可以在更细化和细微的层次上保护应用程序和运行时的安全。它们还可以在破坏您的工作流之前识别并解决潜在的安全威胁。而且,可以将静态分析与ML结合起来,以自动化运行时防御并在整个环境中实施策略。因此,这行是“最安全的设置”。
mohan08p '18

18

和---关联:-

“为什么将软件部署到Docker映像比简单地部署到一致的生产环境更容易?”

大多数软件已部署到许多环境中,通常至少有以下三种:

  1. 个别开发人员PC
  2. 共享的开发人员环境
  3. 个人测试仪电脑
  4. 共享测试环境
  5. 质量检查环境
  6. UAT环境
  7. 负载/性能测试
  8. 现场演出
  9. 生产
  10. 封存

还需要考虑以下因素:

  • 根据工作的性质,开发人员,甚至是测试人员,都将拥有微妙或完全不同的PC配置
  • 开发人员通常可以在PC上进行开发,而不受公司或业务标准化规则的控制(例如,在自己的计算机上(通常是远程开发)的自由职业者,或者为没有“雇用”或“委托”来配置PC的开源项目的贡献者)道路)
  • 某些环境将由固定数量的多台计算机组成,并采用负载平衡配置
  • 许多生产环境将根据流量水平动态(或“弹性”)创建和销毁基于云的服务器

如您所见,组织的外推服务器总数很少是单个数字,通常是三个数字,并且很容易更高。

这一切都意味着,仅仅因为数量庞大(即使在绿地场景中),首先要创建一致的环境就足够困难了,但是鉴于服务器数量众多,添加新的服务器(动态地或动态地),保持它们的一致性几乎是不可能的。手动),来自操作系统供应商,防病毒软件供应商,浏览器供应商等的自动更新,由开发人员或服务器技术人员执行的手动软件安装或配置更改等。让我重复一遍-这几乎是(没有双关语)保持环境一致(可以,对于纯粹主义者而言,可以做到,但这需要大量的时间,精力和纪律,这正是为什么首先设计VM和容器(例如Docker)的原因)。

因此,更像这样思考您的问题:“考虑到保持所有环境一致的极端困难,即使考虑了学习曲线,将软件部署到Docker映像是否更容易?” 。我认为您会发现答案总是肯定的-是,但是只有一种方法可以找到答案,将这个新问题发布到Stack Overflow上。


那么,如果我将Docker映像与15个具有不同操作系统/版本组合的不同盒子一起部署,那么我所有的Docker映像将运行相同吗?
Teoman shipahi

@Teomanshipahi如果所有这些容器都可以使用主机提供的相同内核,是的,它们都将成功运行。
Light.G

如果我在本地Windows上将docker用于Windows,是否可以在linux / mac中以相同的方式部署和运行?
Teoman shipahi 18/09/28

似乎总是被蒙蔽的是仍然存在版本依赖性:1)开发人员必须在图像所包含的相同环境下进行开发;2)开发环境和测试环境需要同时运行Linux内核和docker本身的相同(或兼容)版本...是吗?
Bogatyr

18

有很多答案可以更详细地解释它们之间的差异,但这是我的简短解释。

一个重要的区别是VM使用单独的内核来运行OS。这就是它很重且启动需要花费时间,消耗更多系统资源的原因。

在Docker中,容器与主机共享内核。因此,它很轻巧,可以快速启动和停止。

在虚拟化中,资源是在设置开始时分配的,因此,当虚拟机在许多时间处于空闲状态时,资源不会得到充分利用。在Docker中,不会为容器分配固定数量的硬件资源,而是可以根据要求自由使用这些资源,因此具有高度可伸缩性。

Docker使用UNION File system。Docker使用写时复制技术来减少容器占用的内存空间。在这里阅读更多


1
“在虚拟化中,资源是在设置开始时分配的,因此,当虚拟机在许多时间处于空闲状态时,资源不会得到充分利用。” Hyper-V具有动态内存的概念,您可以在其中指定最小,最大和启动RAM。
Mariusz

15

使用虚拟机,我们有一个服务器,在该服务器上有一个主机操作系统,然后有一个虚拟机监控程序。然后,在该虚拟机监控程序之上运行,我们可以使用任意数量的来宾操作系统,以及一个应用程序及其相关二进制文件以及该服务器上的库。它带来了整个来宾操作系统。它是重量级的。此外,每个物理机上实际可以放置的数量也有限制。

在此处输入图片说明

另一方面,Docker容器略有不同。我们有服务器。我们有主机操作系统。但是在这种情况下,我们使用Docker引擎代替了hypervisor。在这种情况下,我们不会带来整个客户操作系统。我们带来了非常薄的操作系统层,容器可以与主机OS进行对话,以获取那里的内核功能。这样我们就可以拥有一个非常轻巧的容器。

它包含的全部是应用程序代码以及所需的任何二进制文件和库。如果您也希望这些二进制文件和库也可以在不同容器之间共享。这使我们能够做很多事情。它们具有更快的启动时间。像这样的几秒钟内,您无法站立一个虚拟机。同样,将它们快速删除..这样我们就可以快速放大和缩小,我们稍后再讨论。

在此处输入图片说明

每个容器都认为它在自己的操作系统副本上运行。它有自己的文件系统,自己的注册表等,这是一种谎言。它实际上是虚拟化的。



11

我已经在生产环境中使用了Docker,并且进行了很多次调试。当您习惯了它之后,您会发现它对于构建多容器和隔离环境非常强大。

Docker是基于LXC(Linux容器)开发的,可以在许多Linux发行版中完美运行,尤其是Ubuntu。

Docker容器是隔离的环境。top在从Docker映像创建的Docker容器中发出命令时,可以看到它。

除此之外,由于dockerFile配置,它们非常轻巧且灵活。

例如,您可以创建一个Docker映像并配置一个DockerFile,并告诉它例如在运行时然后wget'this',apt-get'that',运行'some shell script',设置环境变量等。

在微服务项目和架构中,Docker是一个非常可行的资产。您可以使用Docker,Docker swarm,Kubernetes和Docker Compose实现可伸缩性,弹性和弹性。

关于Docker的另一个重要问题是Docker Hub及其社区。例如,我实现了一个使用Prometheus,Grafana,Prometheus-JMX-Exporter和Docker监视kafka的生态系统。

为此,我为Zookeeper,kafka,Prometheus,Grafana和jmx-collector下载了已配置的Docker容器,然后使用YAML文件为其中的某些文件安装了我自己的配置,对于其他文件,我在Docker容器中更改了一些文件和配置,在一台机器上使用多容器Docker构建一个用于监视kafka的整个系统,该系统具有隔离性,可伸缩性和弹性,可以轻松地将该体系结构移动到多台服务器中。

除了Docker Hub站点外,还有一个名为quay.io的站点,您可以使用该站点在其中拥有自己的Docker图像仪表板,然后从中拉入/推入。您甚至可以从Docker Hub导入Docker映像到码头,然后在自己的计算机上从码头运行它们。

注意:首先学习Docker似乎很复杂而且很困难,但是一旦习惯了Docker,就不能没有它。

我记得在使用Docker的最初几天,我发布了错误的命令或错误地删除了我的容器以及所有数据和配置。


6

这就是码头工人自我介绍:

Docker是推动容器发展的公司,并且是唯一可解决混合云中每个应用程序需求的容器平台提供商。当今的企业面临着进行数字化转型的压力,但受到现有应用程序和基础架构的限制,同时使越来越多样化的云,数据中心和应用程序体系结构合理化。Docker使应用程序和基础架构之间真正的独立性得以实现,开发人员和IT运营者可以释放其潜力,并创建更好的协作和创新模型。

因此,Docker是基于容器的,这意味着您拥有可以在当前计算机上运行的映像和容器。它不包括像VM这样的操作系统,而是像一堆不同的工作包,例如Java,Tomcat等。

如果您了解容器,那么您将了解Docker是什么以及它与VM的区别...

那么,什么是容器?

容器映像是一个软件的轻量级独立可执行软件包,包括运行该映像所需的一切:代码,运行时,系统工具,系统库,设置。不论环境如何,容器化软件都可用于基于Linux和Windows的应用程序,并且始终可以运行相同的软件。容器将软件与其周围环境隔离开来,例如,开发环境和登台环境之间的差异,并有助于减少在同一基础架构上运行不同软件的团队之间的冲突。

码头工人

因此,如您在下图中所看到的,每个容器都有一个单独的包装,并且在与该机器的操作系统共享的一台机器上运行...它们安全且易于运输...


4

这里有很多不错的技术答案,可以清楚地讨论VM和容器之间的差异以及Docker的起源。

对我而言,VM和Docker之间的根本区别在于管理应用程序升级的方式。

使用VM,您可以将应用程序及其依赖关系从一个VM升级到下一个DEV,再从UAT升级到PRD。

  1. 通常,这些VM具有不同的补丁程序和库。
  2. 多个应用程序共享一个VM并不少见。这需要管理所有应用程序的配置和依赖性。
  3. 撤消要求撤消VM中的更改。或尽可能恢复它。

使用Docker的想法是,将应用程序连同所需的库一起捆绑在其自己的容器中,然后将整个容器作为一个单元提升。

  1. 除了内核外,补丁和库是相同的。
  2. 通常,每个容器只有一个应用程序可以简化配置。
  3. 退出包括停止和删除容器。

因此,在最基本的层次上,使用VM可以将应用程序及其依赖项作为离散的组件进行推广,而使用Docker则可以一口气推广所有内容。

是的,尽管诸如Kubernetes或Docker Swarm之类的工具大大简化了任务,但是容器存在一些问题,包括管理它们。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.