我一直在重读Docker文档,试图理解Docker和完整VM之间的区别。它是如何设法提供一个完整的文件系统、隔离的网络环境等而不那么沉重的?
为什么将软件部署到Docker映像(如果这是正确的术语)比简单地部署到一致的生产环境更容易?
我一直在重读Docker文档,试图理解Docker和完整VM之间的区别。它是如何设法提供一个完整的文件系统、隔离的网络环境等而不那么沉重的?
为什么将软件部署到Docker映像(如果这是正确的术语)比简单地部署到一致的生产环境更容易?
当前回答
Docker不是一种虚拟化方法。它依赖于实际实现基于容器的虚拟化或操作系统级虚拟化的其他工具。为此,Docker最初使用的是LXC驱动程序,然后转移到libcontainer,现在改名为runc。Docker主要致力于自动化应用程序容器内的应用程序部署。应用程序容器设计用于打包和运行单个服务,而系统容器设计用于运行多个进程,如虚拟机。因此,Docker被认为是容器化系统上的容器管理或应用程序部署工具。
为了了解它与其他虚拟化的区别,我们来了解一下虚拟化及其类型。那么,更容易理解两者之间的区别。
虚拟化
在其构想形式中,它被认为是一种逻辑上划分大型机以允许多个应用程序同时运行的方法。然而,当公司和开源社区能够提供一种以某种方式处理特权指令的方法,并允许多个操作系统在一个基于x86的系统上同时运行时,情况发生了巨大变化。
管理程序
管理程序负责创建来宾虚拟机运行的虚拟环境。它监督宾客系统,并确保在必要时为宾客分配资源。管理程序位于物理机和虚拟机之间,并向虚拟机提供虚拟化服务。为了实现它,它拦截虚拟机上的来宾操作系统操作,并模拟主机操作系统上的操作。
虚拟化技术(主要是云技术)的快速发展进一步推动了虚拟化的使用,允许在虚拟机管理程序(如Xen、VMware Player、KVM等)的帮助下,在单个物理服务器上创建多个虚拟服务器,并将硬件支持纳入商品处理器(如Intel VT和AMD-V)。
虚拟化类型
虚拟化方法可以根据其模拟客户操作系统的硬件和模拟客户操作环境的方式进行分类。主要有三种类型的虚拟化:
仿真准虚拟化基于容器的虚拟化
仿真
仿真(也称为完全虚拟化)完全在软件中运行虚拟机OS内核。此类型中使用的管理程序称为类型2管理程序。它安装在主机操作系统的顶部,负责将来宾操作系统内核代码转换为软件指令。翻译完全由软件完成,不需要硬件参与。仿真使运行任何支持被仿真环境的未修改操作系统成为可能。这种虚拟化的缺点是额外的系统资源开销,与其他类型的虚拟化相比,这会导致性能下降。
此类别中的示例包括VMware Player、VirtualBox、QEMU、Bochs、Parallels等。
准虚拟化
准虚拟化(Paravirtualization)也称为第1类虚拟机管理程序,直接在硬件或“裸机”上运行,并直接向其上运行的虚拟机提供虚拟化服务。它帮助操作系统、虚拟化硬件和真实硬件协作以实现最佳性能。这些虚拟机监控程序通常占地面积很小,本身不需要大量资源。
此类别中的示例包括Xen、KVM等。
基于容器的虚拟化
基于容器的虚拟化,也称为操作系统级虚拟化,支持在单个操作系统内核中执行多个独立的执行。它具有最佳的性能和密度,并具有动态资源管理功能。这种类型的虚拟化提供的隔离虚拟执行环境被称为容器,可以被视为一组可跟踪的进程。
通过添加到Linux内核2.6.24版本中的命名空间特性,容器的概念成为可能。容器将其ID添加到每个进程,并将新的访问控制检查添加到每个系统调用。它由clone()系统调用访问,该系统调用允许创建先前全局命名空间的单独实例。
命名空间可以以多种不同的方式使用,但最常见的方法是创建一个独立的容器,该容器对容器外部的对象没有可见性或访问权限。在容器内运行的进程似乎在正常的Linux系统上运行,尽管它们与位于其他命名空间中的进程共享底层内核,其他类型的对象也是如此。例如,当使用命名空间时,容器内的根用户不会被视为容器外的根用户,从而增加了额外的安全性。
Linux控制组(cgroups)子系统是实现基于容器的虚拟化的下一个主要组件,用于对进程进行分组并管理其总资源消耗。它通常用于限制容器的内存和CPU消耗。由于容器化的Linux系统只有一个内核,并且内核对容器具有完全的可见性,因此只有一个级别的资源分配和调度。
Linux容器有多种管理工具,包括LXC、LXD、systemd nspawn、lmctfy、Warden、Linux VServer、OpenVZ、Docker等。
容器与虚拟机
与虚拟机不同,容器不需要启动操作系统内核,因此可以在不到一秒钟的时间内创建容器。这一特性使基于容器的虚拟化比其他虚拟化方法更为独特和可取。
由于基于容器的虚拟化几乎不会或根本不会增加主机的开销,因此基于容器的虚化具有接近本机的性能
对于基于容器的虚拟化,与其他虚拟化不同,不需要额外的软件。
主机上的所有容器共享主机的调度程序,从而节省了额外的资源。
与虚拟机映像相比,容器状态(Docker或LXC映像)的大小较小,因此容器映像易于分发。
容器中的资源管理是通过cgroups实现的。Cgroups不允许容器消耗比分配给它们的资源更多的资源。然而,到目前为止,主机的所有资源在虚拟机中都是可见的,但无法使用。这可以通过同时在容器和主机上运行top或htop来实现。所有环境的输出看起来都很相似。
更新:
Docker如何在非Linux系统中运行容器?
如果由于Linux内核中的可用特性,容器是可能的,那么显而易见的问题是非Linux系统如何运行容器。Docker for Mac和Windows都使用Linux虚拟机来运行容器。Docker工具箱用于在Virtual Box VM中运行容器。但是,最新的Docker在Windows中使用Hyper-V,在Mac中使用Hypervisor.framework。
现在,让我详细描述Docker for Mac如何运行容器。
Docker for Mac使用https://github.com/moby/hyperkit为了模拟hypervisor功能,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-aLinux linuxkit-025000000001 4.9.93-linuxkit-aufs#1 SMP 6月6日星期三16:86_64 Linux。
所有容器都在此VM内运行。
hypervisor.framework有一些限制。因为Docker没有在Mac中公开docker0网络接口。因此,您无法从主机访问容器。目前,docker0仅在VM中可用。
Hyper-v是Windows中的本机管理程序。他们还试图利用Windows 10的功能以本机方式运行Linux系统。
其他回答
这里的大多数答案都涉及虚拟机。我将给你一个简单的回答,这个问题在过去几年中对我的帮助最大。是这样的:
Docker只是运行进程的一种奇特方式,而不是虚拟机。
现在,让我再解释一下这意味着什么。虚拟机是它们自己的野兽。我觉得解释Docker是什么比解释虚拟机更能帮助你理解这一点。特别是因为这里有很多很好的答案,告诉你某人说“虚拟机”的确切含义。所以
Docker容器只是一个进程(及其子进程),它使用主机系统内核内的cgroups与其他进程进行划分。通过在主机上运行ps aux,您实际上可以看到Docker容器进程。例如,“在容器中”启动apache2只是将apache2作为主机上的一个特殊进程启动。它只是与机器上的其他过程分开了。需要注意的是,容器不存在于容器化流程的生命周期之外。当你的进程失效时,你的容器也会失效。这是因为Docker将容器中的pid 1替换为应用程序(pid 1通常是init系统)。关于pid 1的最后一点非常重要。
就每个容器进程所使用的文件系统而言,Docker使用UnionFS支持的映像,这是您在Docker拉ubuntu时下载的映像。每个“图像”只是一系列层和相关元数据。分层的概念在这里非常重要。每一层都只是其下一层的变化。例如,当你在构建Docker容器时删除Dockerfile中的一个文件时,你实际上只是在最后一层的上面创建一个层,上面写着“该文件已被删除”。顺便说一句,这就是为什么您可以从文件系统中删除一个大文件,但映像仍然占用相同的磁盘空间。文件仍然存在,在当前文件下面的层中。层本身只是文件的tarball。您可以使用docker save--output/tmp/ubuntu.tar-ubuntu和cd/tmp&&tar-xvf-ubuntu.tar来测试这一点。然后您可以四处看看。所有看起来像长散列的目录实际上都是单独的层。每一个都包含文件(layer.tar)和元数据(json)以及有关该特定层的信息。这些层只是描述文件系统的更改,这些更改保存为“在”原始状态之上的层。当读取“当前”数据时,文件系统读取数据时,就像只查看最顶层的更改一样。这就是为什么文件看起来被删除了,尽管它仍然存在于“先前”层中,因为文件系统只查看最顶层。这允许完全不同的容器共享其文件系统层,即使每个容器中最顶层的文件系统可能发生了一些重大变化。当容器共享其基本图像层时,这可以节省大量磁盘空间。但是,当您通过卷将目录和文件从主机系统装载到容器中时,这些卷会“绕过”UnionFS,因此更改不会存储在层中。
Docker中的网络是通过使用以太网桥(主机上称为docker0)和主机上每个容器的虚拟接口实现的。它在docker0中创建一个虚拟子网,用于容器之间的通信。这里有许多联网选项,包括为容器创建自定义子网,以及“共享”主机的网络堆栈以供容器直接访问的功能。
Docker进展很快。它的文档是我见过的最好的文档之一。它通常写得很好,简洁准确。我建议您查看可用的文档以获取更多信息,并将文档置于在线阅读的任何其他内容之上,包括堆栈溢出。如果你有具体的问题,我强烈建议加入Freenode IRC上的#docker并在那里提问(你甚至可以使用Freenode的网络聊天!)。
有三种不同的设置提供了运行应用程序的堆栈(这将帮助我们认识到容器是什么,以及是什么使它比其他解决方案更强大):
1) Traditional Servers(bare metal)
2) Virtual machines (VMs)
3) Containers
1) 传统的服务器堆栈由运行操作系统和应用程序的物理服务器组成。
优势:
原始资源的利用隔离
缺点:
部署时间非常慢昂贵的浪费的资源难以扩展难以迁移复杂的配置
2) VM堆栈由运行操作系统的物理服务器和管理虚拟机、共享资源和网络接口的管理程序组成。每个Vm运行一个客户操作系统、一个应用程序或一组应用程序。
优势:
善用资源易于扩展易于备份和迁移成本效益灵活性
缺点:
资源分配有问题供应商锁定复杂的配置
3) 容器设置与其他堆栈的主要区别是基于容器的虚拟化使用主机操作系统的内核来管理多个孤立的来宾实例。这些来宾实例称为容器。主机可以是物理服务器或VM。
优势:
隔离轻量的资源有效易于迁移安全低开销镜像生产和开发环境
缺点:
相同的体系结构资源密集型应用网络和安全问题。
通过将容器设置与之前的设置进行比较,我们可以得出结论,容器化是迄今为止我们所知的最快、最有效的资源和最安全的设置。容器是运行应用程序的独立实例。Docker以某种方式旋转容器,层使用默认存储驱动程序(Overlay驱动程序)获得运行时内存,这些驱动程序在几秒钟内运行,一旦我们提交到容器中,就会在其上创建写时复制层,从而为容器的执行提供动力。如果是VM,则需要大约一分钟的时间将所有内容加载到虚拟化环境中。这些轻量级实例可以很容易地替换、重建和移动。这使我们能够镜像生产和开发环境,并在CI/CD过程中提供了巨大的帮助。容器所能提供的优势是如此引人注目,它们肯定会继续存在。
这里有很多很好的技术答案,清楚地讨论了VM和容器之间的差异以及Docker的起源。
对我来说,VM和Docker之间的根本区别在于如何管理应用程序的推广。
使用VM,您可以将应用程序及其依赖关系从一个VM提升到下一个DEV,从UAT提升到PRD。
这些VM通常会有不同的补丁和库。多个应用程序共享一个VM并不罕见。这需要管理所有应用程序的配置和依赖关系。回退需要撤消VM中的更改。或者在可能的情况下恢复。
使用Docker的想法是,将应用程序与其所需的库一起打包到自己的容器中,然后将整个容器作为一个单元进行升级。
除了内核之外,补丁和库都是相同的。一般来说,每个容器只有一个应用程序,这简化了配置。回退包括停止和删除容器。
因此,在最基本的层面上,使用VM,您可以将应用程序及其依赖项作为独立的组件进行推广,而使用Docker,您可以一次性推广所有内容。
是的,包括管理容器在内的容器存在问题,尽管Kubernetes或Docker Swarm等工具极大地简化了任务。
Docker封装了一个应用程序及其所有依赖项。
虚拟机封装了一个OS,该OS可以运行它通常可以在裸机上运行的任何应用程序。
在我看来,这取决于你的应用程序的需求,为什么决定部署到Docker,因为Docker根据其功能将应用程序分解为小部分,这变得有效,因为当一个应用程序/功能出现错误时,它对其他应用程序没有影响,与使用完整的vm相比,它的配置会更慢、更复杂,但在某些方面比码头工人更安全