我不断地重读Docker文档,试图理解Docker和一个完整的VM之间的区别。它是如何提供完整的文件系统、独立的网络环境等而又不那么沉重的呢?
为什么将软件部署到Docker映像(如果这是正确的术语)比简单地部署到一致的生产环境更容易?
理解虚拟化和容器如何在低层工作可能会有帮助。那会澄清很多事情。
注意:我在下面的描述中简化了一点。有关更多信息,请参阅参考资料。
虚拟化在低层是如何工作的?
在这种情况下,VM管理器接管CPU环0(或较新CPU中的“根模式”),并截取来宾OS发出的所有特权调用,以创建来宾OS拥有自己硬件的假象。有趣的事实:在1998年之前,人们认为在x86架构上实现这一点是不可能的,因为没有办法进行这种拦截。VMware的工作人员是第一个想到重写内存中的可执行字节以便对客户操作系统进行特权调用的人。
净效果是虚拟化允许您在同一硬件上运行两个完全不同的操作系统。每个guest OS都经历引导、加载内核等所有过程,您可以拥有非常严密的安全性。例如,来宾操作系统不能完全访问主机操作系统或其他来宾,并把事情搞得一团糟。
容器如何在低层工作?
大约在2006年,包括Google的一些员工在内的人们实现了一个新的内核级特性,称为名称空间(然而这个想法很久以前就存在于FreeBSD中)。操作系统的一个功能是允许在进程之间共享全局资源,如网络和磁盘。如果这些全局资源被包装在命名空间中,以便它们只对运行在同一命名空间中的进程可见,那么该怎么办?例如,您可以获得一个磁盘块并将其放入名称空间X中,然后在名称空间Y中运行的进程就无法看到或访问它。类似地,命名空间X中的进程不能访问内存中分配给命名空间Y的任何东西,当然,X中的进程不能看到或与命名空间Y中的进程对话,这为全局资源提供了一种虚拟化和隔离。这就是Docker的工作方式:每个容器在自己的名称空间中运行,但使用与所有其他容器完全相同的内核。之所以会发生隔离,是因为内核知道分配给进程的名称空间,并且在API调用期间,它确保进程只能访问自己名称空间中的资源。
容器vs VM的局限性现在应该很明显了:您不能像在VM中那样在容器中运行完全不同的OS。但是,您可以运行不同的Linux发行版,因为它们共享相同的内核。隔离级别不如VM中的那么强。事实上,在早期的实现中,有一种让“来宾”容器接管主机的方法。您还可以看到,当您加载一个新容器时,整个OS的新副本并不像在VM中那样启动。所有容器共享相同的内核。这就是集装箱重量轻的原因。另外,与VM不同的是,您不必为容器预分配相当大的内存块,因为我们运行的不是OS的新副本。这允许在一个OS上运行数千个容器,同时对它们进行沙箱装箱,如果我们在它们自己的VM中运行OS的单独副本,这可能是不可能的。
好答案。为了获得容器vs VM的图像表示,请看下面的一个。
来源
Docker最初使用LinuX容器(LXC),但后来切换到runC(以前称为libcontainer),它运行在与其主机相同的操作系统中。这允许它共享大量的主机操作系统资源。此外,它使用分层文件系统(AuFS)并管理网络。
AuFS是一个分层的文件系统,所以您可以有一个合并在一起的只读部分和写部分。可以将操作系统的公共部分作为只读(并在所有容器中共享),然后为每个容器提供自己的写入挂载。
假设您有一个1 GB的容器图像;如果你想要使用一个完整的VM,你需要有1 GB x数量的VM你想要。使用Docker和AuFS,您可以在所有容器之间共享1 GB的大部分空间,如果您有1000个容器,您仍然可能只有略高于1 GB的空间用于容器OS(假设它们都运行相同的OS映像)。
一个完全虚拟化的系统得到自己分配给它的一组资源,并进行最小的共享。你得到了更多的隔离,但它要重得多(需要更多的资源)。使用Docker,您可以获得更少的隔离,但是容器是轻量级的(需要更少的资源)。因此您可以轻松地在一个主机上运行数千个容器,而它甚至不会眨眼。试着用Xen做这件事,除非你有一个真正大的主机,否则我认为这是不可能的。
一个完全虚拟化的系统通常需要几分钟才能启动,而Docker/lxc/runc容器需要几秒钟,甚至不到一秒钟。
每种类型的虚拟化系统都有利弊。如果您想要在保证资源的情况下实现完全隔离,那么一个完整的VM就是一个好办法。如果您只是想将进程彼此隔离,并希望在一个大小合理的主机上运行大量进程,那么Docker/lxc/runc似乎是一种可行的方法。
要了解更多信息,请查看这组博客文章,它们很好地解释了LXC的工作原理。
为什么将软件部署到docker映像(如果这是正确的术语)比简单地部署到一致的生产环境更容易?
部署一致的生产环境说起来容易做起来难。即使您使用像Chef和Puppet这样的工具,也总是有OS更新和其他东西在主机和环境之间发生变化。
Docker使您能够将操作系统快照到共享映像中,并使其易于部署在其他Docker主机上。在本地,dev,qa,prod等:都是相同的图像。当然,您可以使用其他工具完成此操作,但不是那么容易或快速。
这对于测试是很好的;假设您有数千个测试需要连接到一个数据库,每个测试都需要数据库的原始副本,并将对数据进行更改。这方面的经典方法是在每次测试后使用自定义代码或Flyway之类的工具重置数据库--这可能非常耗时,并且意味着测试必须串行运行。但是,使用Docker,您可以创建数据库的映像,并在每个测试中运行一个实例,然后并行运行所有测试,因为您知道它们都将针对数据库的同一快照运行。由于测试是并行运行的,并且是在Docker容器中运行的,所以它们可以同时在同一个盒子上运行,并且应该可以更快地完成。试着用一个完整的VM来做这件事。
来自备注...
有意思!我想我仍然对“快照操作系统”的概念感到困惑。如果不制作操作系统的图像,该如何做到这一点呢?
看看我能不能解释清楚。您从一个基本映像开始,然后进行更改,并使用docker提交这些更改,它就会创建一个映像。此图像仅包含与基础的差异。当您想要运行您的映像时,您还需要基,并且它使用分层文件系统将您的映像分层到基之上:如上所述,Docker使用AUFS。AuFS将不同的层合并在一起,你就能得到你想要的;你只需要运行它。您可以继续添加更多的图像(层),它将继续只保存差异。由于Docker通常构建在注册表中的现成映像之上,因此您很少需要自己“快照”整个OS。
问题内容: 我不断阅读Docker文档,以尝试了解Docker和完整VM之间的区别。它如何提供完整的文件系统,隔离的网络环境等而又不那么繁重? 为什么将软件部署到Docker映像(如果是正确的说法)比简单地部署到一致的生产环境更容易? 问题答案: Docker最初使用LinuX容器(LXC),但后来切换到runC(以前称为 libcontainer ),后者与主机运行在相同的操作系统中。这使它可以
查看虚拟机相关的监控告警信息。 监控菜单下的虚拟机页面主要用于查看虚拟机相关的监控告警信息。 入口:在云管平台单击左上角导航菜单,在弹出的左侧菜单栏中单击 “监控/资源/虚拟机” 菜单项,进入虚拟机页面。 查看虚拟机列表 该功能用于查看虚拟机的监控告信息。 在虚拟机页面,支持查看以下信息: 名称:虚拟机的名称。 IP:虚拟机的IP地址。 监控状态:虚拟机是否设置告警以及发生告警。 状态:虚拟机的当
主机回收站用于存放用户删除的虚拟机和裸金属文件。 主机回收站用于存放用户删除的虚拟机和裸金属文件。回收站中主机文件默认保存3天,如有误删除的主机需要在3天内进行恢复操作,可以将其恢复到原来位置,超过3天后,文件将被彻底删除。 入口:在云管平台单击左上角导航菜单,在弹出的左侧菜单栏中单击 “主机/回收站/主机” 菜单项,进入主机回收站列表。 清除 当确定回收站中的主机无用后,可使用清除功能立即彻底删
虚拟机是采用虚拟化技术构建的运行在宿主机上的虚拟机实例。 虚拟机是采用虚拟化技术构建的运行在宿主机上的虚拟机实例,包括CPU、内存、操作系统、硬盘、网卡等完整的虚拟硬件基础环境。 虚拟机来源: 当云管平台对接其他平台云账号后,将会自动同步其他平台上的虚拟机到云管平台上进行管理。 新建虚拟机。 入口:在云管平台单击左上角导航菜单,在弹出的左侧菜单栏中单击 “主机/主机/虚拟机” 菜单项,进入虚拟机页
TJS2 は、スクリプトをいったん仮想マシン (TJS2 VM) 用のバイナリコードにコンパイルしてから実行します。 例外が発生したときやダンプを行ったときにこの TJS2 VM のコードの逆アセンブル結果が表示されるので、この仮想マシンについて簡単に説明します。 命令コード TJS2 VM は関数やプロパティなどの実行単位ごとに独立していて、ある一つの関数が他の関数と命令コード空間、レジス
稳定性: 2 - 稳定的 vm 模块提供了一系列 API 用于在 V8 虚拟机环境中编译和运行代码。 它可以通过以下方式使用: const vm = require('vm'); JavaScript 代码可以被编译并立即运行,或编译、保存然后再运行。 Note: The vm module is not a security mechanism. Do not use it to run un