一、说明
如果你是一个程序员或技术人员,你可能至少听说过Docker:一个有用的工具,用于在“容器”中打包,运输和运行应用程序。很难不这样做,这些天它得到了所有的关注 - 来自开发人员和系统管理员。即使是像谷歌、VMware和亚马逊这样的大型企业也在构建支持它的服务。
无论您是否对 Docker 有直接的用例,我仍然认为了解“容器”是什么以及它与虚拟机 (VM) 的比较的一些基本概念非常重要。虽然互联网上到处都是 Docker 的优秀使用指南,但我找不到很多适合初学者的概念指南,尤其是关于容器的组成。所以,希望这篇文章能解决这个问题:)
让我们从了解什么是虚拟机和容器开始。
二、什么是“容器”和“虚拟机”?
容器和虚拟机的目标相似:将应用程序及其依赖项隔离到可在任何位置运行的独立单元中。
此外,容器和虚拟机消除了对物理硬件的需求,从而在能耗和成本效益方面更有效地利用计算资源。
容器和虚拟机之间的主要区别在于它们的体系结构方法。让我们仔细看看。
2.1 虚拟机
VM 本质上是对真实计算机的仿真,它像真实计算机一样执行程序。VM 使用“虚拟机监控程序”在物理机上运行。反过来,虚拟机监控程序在主机或“裸机”上运行。
让我们解开行话:
虚拟机监控程序是 VM 在其上运行的软件、固件或硬件。虚拟机管理程序本身在物理计算机上运行,称为“主机”。主机为 VM 提供资源,包括 RAM 和 CPU。这些资源在 VM 之间分配,可以根据需要进行分配。因此,如果一个 VM 正在运行资源量更大的应用程序,则与在同一主机上运行的其他 VM 相比,您可以为该 VM 分配更多的资源。
在主机上运行的 VM(同样,使用虚拟机监控程序)通常也称为“来宾计算机”。此来宾计算机包含应用程序以及运行该应用程序所需的任何内容(例如系统二进制文件和库)。它还拥有自己的整个虚拟化硬件堆栈,包括虚拟化网络适配器、存储和 CPU,这意味着它还拥有自己成熟的来宾操作系统。从内部看,来宾计算机充当自己的单元,具有自己的专用资源。从外部,我们知道它是一个虚拟机 - 共享主机提供的资源。
如上所述,来宾计算机可以在托管虚拟机管理程序或裸机虚拟机管理程序上运行。它们之间存在一些重要差异。
首先,托管虚拟化虚拟机管理程序在主机的操作系统上运行。例如,运行OSX的计算机可以在该操作系统上安装VM(例如VirtualBox或VMware Workstation 8)。虚拟机无法直接访问硬件,因此它必须通过主机操作系统(在本例中为 Mac 的 OSX)。
托管虚拟机管理程序的好处是底层硬件不太重要。主机的操作系统负责硬件驱动程序而不是虚拟机管理程序本身,因此被认为具有更多的“硬件兼容性”。另一方面,硬件和虚拟机管理程序之间的这一额外层会产生更多的资源开销,从而降低 VM 的性能。
裸机虚拟机管理程序环境通过在主机硬件上安装并从中运行来解决性能问题。由于它直接与底层硬件接口,因此不需要主机操作系统即可运行。在这种情况下,作为操作系统安装在主机服务器上的第一件事将是虚拟机监控程序。与托管虚拟机监控程序不同,裸机虚拟机监控程序具有自己的设备驱动程序,并直接与每个组件交互以执行任何 I/O、处理或特定于操作系统的任务。这样可以提高性能、可伸缩性和稳定性。这里的权衡是硬件兼容性有限,因为虚拟机管理程序只能内置这么多设备驱动程序。
在讨论了虚拟机管理程序之后,您可能想知道为什么我们需要在虚拟机和主机之间增加这个“虚拟机管理程序”层。
由于虚拟机有自己的虚拟操作系统,因此虚拟机管理程序在为 VM 提供管理和执行此来宾操作系统的平台方面起着至关重要的作用。它允许主机计算机在作为来宾运行的虚拟机之间共享其资源。
虚拟机关系图
如图所示,虚拟机为每个新虚拟机打包了虚拟硬件、内核(即操作系统)和用户空间。
2.2 容器
与提供硬件虚拟化的 VM 不同,容器通过抽象“用户空间”来提供操作系统级虚拟化。当我们解开容器一词时,您将明白我的意思。
出于所有意图和目的,容器看起来像一个 VM。例如,它们具有用于处理的私有空间,可以以root身份执行命令,具有专用网络接口和IP地址,允许自定义路由和iptable规则,可以挂载文件系统等。
容器和虚拟机之间的一个很大区别是容器与其他容器*共享*主机系统的内核。
此图显示容器仅打包用户空间,而不是像 VM 那样打包内核或虚拟硬件。每个容器都有自己的独立用户空间,以允许多个容器在单个主机上运行。我们可以看到,所有操作系统级别的架构都在容器之间共享。从头开始创建的唯一部分是垃圾箱和库。这就是使容器如此轻巧的原因。
2.3 Docker从何而来?
Docker是一个基于Linux容器的开源项目。它使用 Linux 内核功能(如命名空间和控制组)在操作系统之上创建容器。
容器远非新鲜事物;谷歌多年来一直在使用自己的容器技术。其他Linux容器技术包括Solaris Zones,BSD监狱和LXC,它们已经存在了很多年。
那么,为什么Docker突然变得火了呢?
1. 易用性:Docker 使任何人(开发人员、系统管理员、架构师和其他人)都更容易利用容器来快速构建和测试可移植应用程序。它允许任何人在他们的笔记本电脑上打包应用程序,而这些应用程序又可以在任何公共云、私有云甚至裸机上未经修改地运行。口头禅是:“一次构建,随处运行。
2.速度:Docker容器非常轻巧和快速。由于容器只是在内核上运行的沙盒环境,因此它们占用的资源更少。您可以在几秒钟内创建和运行 Docker 容器,相比之下,VM 可能需要更长的时间,因为它们每次都必须启动完整的虚拟操作系统。
3. Docker Hub:Docker 用户还受益于 Docker Hub 日益丰富的生态系统,您可以将其视为“Docker 镜像的应用商店”。Docker Hub 拥有数以万计由社区创建的公共镜像,随时可供使用。搜索满足您需求的图像非常容易,几乎无需修改即可下拉和使用。
4. 模块化和可扩展性:Docker 可以轻松地将应用程序的功能分解为单独的容器。例如,您可能将 Postgres 数据库运行在一个容器中,将 Redis 服务器运行在另一个容器中,而 Node.js 应用程序在另一个容器中运行。借助 Docker,可以更轻松地将这些容器链接在一起以创建应用程序,从而在将来轻松独立扩展或更新组件。
最后但并非最不重要的一点是,谁不喜欢码头工人鲸?;)
来源: Docker: Accelerated Container Application Development
三、基本码头工人概念
现在我们已经了解了大局,让我们逐一介绍 Docker 的基本部分:
3.1 码头工人引擎
Docker 引擎是 Docker 运行的层。它是一个轻量级运行时和工具,用于管理容器、映像、生成等。它在 Linux 系统上本机运行,由以下部分组成:
1. 在主机中运行的 Docker 守护程序。
2. 一个 Docker 客户端,然后与 Docker 守护程序通信以执行命令。
3. 用于与 Docker 守护进程远程交互的 REST API。
3.2 码头工人客户端
作为 Docker 的最终用户,Docker 客户端是与之通信的对象。可以将其视为 Docker 的 UI。例如,当您执行...
您正在与 Docker 客户端通信,然后 Docker 客户端将您的指令传达给 Docker 守护程序。
3.3 码头工人守护进程
Docker 守护程序是实际执行发送到 Docker 客户端的命令,例如构建、运行和分发容器。Docker 守护程序在主机上运行,但作为用户,您从不直接与守护程序通信。Docker 客户端也可以在主机上运行,但不是必需的。它可以在不同的计算机上运行,并与主机上运行的 Docker 守护程序进行通信。
3.4 Dockerfile
Dockerfile 是您编写构建 Docker 映像的说明的地方。这些说明可以是:
- 运行 apt-get y install some-package: 安装软件包
- 公开 8000:公开端口
- ENV ANT_HOME /usr/local/apache-ant 来传递环境变量
等等。设置 Dockerfile 后,可以使用 docker build 命令从中构建映像。下面是一个 Dockerfile 的示例:
示例 Dockerfile
3.5 码头工人镜像
映像是根据 Dockerfile 中编写的一组指令构建的只读模板。映像定义您希望打包的应用程序及其依赖项的外观,以及启动时要运行的进程。
Docker 镜像是使用 Dockerfile 构建的。Dockerfile 中的每个指令都会向映像添加一个新“层”,其中层表示映像文件系统的一部分,该部分添加或替换其下方的层。层是 Docker 轻巧而强大的结构的关键。Docker 使用联合文件系统来实现这一点:
3.6 联合文件系统
Docker 使用联合文件系统来构建映像。您可以将联合文件系统视为可堆叠的文件系统,这意味着可以透明地覆盖单独文件系统(称为分支)的文件和目录以形成单个文件系统。
在覆盖分支中具有相同路径的目录的内容被视为单个合并目录,从而避免了为每个层创建单独副本的需要。相反,它们可以都被赋予指向同一资源的指针;当某些图层需要修改时,它将创建一个副本并修改一个本地副本,保持原始副本不变。这就是文件系统在实际上不允许写入的情况下*看起来*可写的方式。(换句话说,“写入时复制”系统。
分层系统有两个主要优点:
1. 无重复:层有助于避免每次使用映像创建和运行新容器时复制一组完整的文件,从而使 docker 容器的实例化非常快速和便宜。
2. 层隔离:进行更改要快得多 — 当您更改映像时,Docker 只会将更新传播到已更改的层。
3.7 卷
卷是容器的“数据”部分,在创建容器时初始化。卷允许您保留和共享容器的数据。数据卷独立于默认的联合文件系统,并作为普通目录和文件存在于主机文件系统上。因此,即使销毁、更新或重建容器,数据卷也不会受到影响。当您想要更新卷时,您可以直接对其进行更改。(作为额外的好处,数据量可以在多个容器之间共享和重用,这非常整洁。
3.8 码头工人容器
如上所述,Docker 容器将应用程序的软件包装到一个不可见的盒子中,其中包含应用程序运行所需的一切。这包括操作系统、应用程序代码、运行时、系统工具、系统库等。Docker 容器基于 Docker 镜像构建。由于镜像是只读的,Docker 会在镜像的只读文件系统上添加读写文件系统来创建容器。
此外,在创建容器时,Docker 会创建一个网络接口,以便容器可以与本地主机通信,将可用的 IP 地址附加到容器,并执行您在定义映像时指定用于运行应用程序的进程。
成功创建容器后,可以在任何环境中运行它,而无需进行更改。
四、双击“容器”
唷!这是很多活动部件。总是让我好奇的一件事是容器是如何实际实现的,特别是因为容器周围没有任何抽象的基础设施边界。经过大量阅读,这一切都是有道理的,所以这是我尝试向您解释的尝试!:)
术语“容器”实际上只是一个抽象的概念,用于描述几个不同的功能如何协同工作以可视化“容器”。让我们快速浏览一下它们:
4.1 命名空间
命名空间为容器提供了自己的底层 Linux 系统视图,从而限制了容器可以看到和访问的内容。运行容器时,Docker 会创建特定容器将使用的命名空间。
Docker 在内核中使用了几种不同类型的命名空间,例如:
a. NET:为容器提供自己的系统网络堆栈视图(例如,它自己的网络设备、IP 地址、IP 路由表、/proc/net 目录、端口号等)。
b. PID:PID 代表进程 ID。如果您曾经在命令行中运行过ps aux来检查系统上正在运行的进程,那么您会看到一个名为“PID”的列。PID 命名空间为容器提供了自己的进程范围视图,这些进程可以查看并与之交互,包括独立的 init (PID 1),它是“所有进程的祖先”。
c. MNT:为容器提供自己的系统“挂载”视图。因此,不同挂载命名空间中的进程具有不同的文件系统层次结构视图。
d. UTS:UTS 代表 UNIX 分时系统。它允许一个过程来识别系统标识符(即主机名、域名等)。UTS 允许容器拥有独立于其他容器和主机系统的主机名和 NIS 域名。
e. IPC:IPC 代表进程间通信。IPC 命名空间负责在每个容器内运行的进程之间隔离 IPC 资源。
f. USER:此命名空间用于隔离每个容器中的用户。它的工作原理是允许容器具有与主机系统不同的 uid(用户 ID)和 gid(组 ID)范围视图。因此,进程的 uid 和 gid 在用户命名空间内部和外部可能不同,这也允许进程在容器外部拥有非特权用户,而不会牺牲容器内的根特权。
Docker 将这些命名空间一起使用,以便隔离并开始创建容器。下一个功能称为控制组。
4.2 控制组
控制组(也称为 cgroups)是一种 Linux 内核功能,用于隔离一组进程的资源使用情况(CPU、内存、磁盘 I/O、网络等),并确定其优先级并考虑其使用情况。从这个意义上说,cgroup 确保 Docker 容器只使用它们需要的资源——如果需要,可以对容器*可以使用的资源设置限制。Cgroups还确保单个容器不会耗尽其中一个资源并导致整个系统瘫痪。
最后,联合文件系统是Docker使用的另一个功能:
4.3 隔离联合文件系统:
如上文 Docker 映像部分所述:)
这就是 Docker 容器的全部内容(当然,魔鬼在于实现细节——比如如何管理各个组件之间的交互)。
五、Docker的未来:Docker和VM将共存
虽然Docker肯定会获得很大的动力,但我不相信它会成为对虚拟机的真正威胁。 容器将继续取得进展,但有许多用例仍然更适合虚拟机。
例如,如果需要在多个服务器上运行多个应用程序,则使用 VM 可能是有意义的。另一方面,如果您需要运行单个应用程序的多个*副本*,Docker提供了一些引人注目的优势。
此外,虽然容器允许您将应用程序分解为功能更强大的离散部分以创建关注点分离,但这也意味着需要管理越来越多的部分,这可能会变得笨拙。
安全性也是Docker容器关注的一个领域 - 由于容器共享相同的内核,因此容器之间的屏障更薄。虽然完整 VM 只能向主机虚拟机监控程序发出超级调用,但 Docker 容器可以对主机内核进行系统调用,这会为攻击创建更大的外围应用。当安全性特别重要时,开发人员可能会选择虚拟机,这些虚拟机被抽象的硬件隔离,这使得相互干扰变得更加困难。
当然,随着容器在生产中获得更多曝光和用户的进一步审查,安全性和管理等问题肯定会发生变化。就目前而言,关于容器与虚拟机的争论最好是每天生活和呼吸它们的开发人员运营人员!
六、结论
我希望你现在具备了学习更多关于Docker的知识,甚至有一天可以在项目中使用它。与往常一样,如果我犯了任何错误或无论如何都可以提供帮助,请在评论中给我留言!
普雷蒂·卡西雷迪