我一直在反复阅读Docker文档,试图理解Docker和完整虚拟机之间的区别。它如何在不过重的情况下提供完整的文件系统、隔离的网络环境等等。
为什么将软件部署到Docker镜像(如果这是正确的术语)比仅仅部署到一致的生产环境更容易呢?
我一直在反复阅读Docker文档,试图理解Docker和完整虚拟机之间的区别。它如何在不过重的情况下提供完整的文件系统、隔离的网络环境等等。
为什么将软件部署到Docker镜像(如果这是正确的术语)比仅仅部署到一致的生产环境更容易呢?
容器可以将库和软件包与系统隔离,使您可以安装同一软件的不同版本和库而不会发生冲突。它在空闲时使用最少的存储和内存,几乎没有开销,使用相同的基本操作系统内核和可用的库,如果可能,有一个很小的增量差异。您可以直接或间接地将硬件暴露给容器,以便您可以使用加速,比如GPU进行计算。
在实践中,您可以使用Docker预制容器。您只需安装并在一行命令中运行它们。安装tensorflow-gpu就像使用docker run -it tensorflow-gpu
一样简单。虽然我找不到太多关于LXD(LXC容器)预制容器,但我发现它们更易于定制,且更加稳定且性能更佳。
容器和虚拟机都可以用于分布式负载。但由于容器几乎没有开销,容器管理软件专注于创建容器群集,以便您轻松地将它们(及负载)分配给物理机器。
真实生活的例子:
假设你需要50多种计算环境和50多种服务,例如mysql、webhosting和基于云的服务(如jenkins和对象存储),并且你拥有50多个不同的裸金属服务器。通常这是一个拥有许多系别的学术环境。您需要高效地使用资源,并且需要高可用性。当一台服务器崩溃时,用户不应该遇到任何问题。因此,提供这种灵活性优势的容器最重要的区别特征是:
可以使用不同版本的相同软件和库而不会发生冲突,准备好部署的预制容器,几乎没有开销并且具有快速生成能力,可通过实时可调配额来进行管理。
使用 .cpu_allowencess、.ram_allowances 或直接 cgroup。Kubernetes 为您完成所有这些工作。在尝试过 Docker 和 LXD 后,您可能想要查看它。
我假设您已经熟悉虚拟机依赖于硬件级别仿真的方式。
然而,Docker容器作为主机操作系统上的常规进程运行,并依赖于提供隔离的Linux内核功能:命名空间。如果您想要,您实际上可以单独使用命名空间进行操作,这可能有助于您理解它们如何配合使用。以下是一个列表:
当您定义一个容器时,通常是定义一个单一的根进程,Docker会将其引导到一组专用的命名空间中,我们称之为容器。 Docker将监视此父进程作为容器,并在其停止时将其视为已停止的容器。这就是为什么通常不应尝试在容器内运行后台服务的原因 - 将Docker视为服务管理器,而您的应用程序是单个服务。子进程保留在与其父进程相同的命名空间中,因此隔离得到保留。 "Docker exec"实际上只是对由内核提供的实际"nsenter"命令的一种花式编排,允许您在命名空间内执行程序。
除了共享相同的内核外,Docker还使用了一些技巧来实现轻量化。
镜像层
首先,正如其他人指出的那样,Docker使用联合文件系统(UnionFS),这是一种分层文件系统。之前的层是只读的,当前层是可编辑的,但是采用写时复制(copy-on-write)方式。因此,如果在以前的层中有一个文件A,并且您修改了该文件,则整个文件及其修改将保存到当前的读/写层中。UnionFS负责仅显示文件的最新副本。这听起来可能很浪费——即使您不再使用旧文档,您仍然保留着旧文档的副本?但是,这允许镜像层像树一样结构化,您可以从常见的基础镜像中分支出大量不同的配置,而无需复制这些基础层中的文件。
假设您为Web服务器构建了一个Docker镜像。您从中开始的第一层通常是操作系统。操作系统开发人员通常会发布只有一层或两层的映像,因为他们预先构建了操作系统,然后将其解压缩到单个映像层中。在Dockerfile中,每个命令通常创建一个新的层,这就是为什么您经常会看到带有许多行连续和删除临时文件的RUN命令:您在图像层中留下的任何内容都会永远停留在那里,即使您在新的层中删除它。构建完Web服务器映像后,所有层都变成只读的。这个问题超出了本回答的范围,但是如果您的容器将创建比单个容器的生命周期更长时间需要保留的重要文件(如数据库),则可以在运行时将“卷”挂载到容器中,这些卷将提供安全的数据持久性,与镜像/容器生命周期分开。
控制组
另一个可用于容器的内核功能称为“cgroups”或“控制组”:这些允许您限制一组进程(如容器)可用的硬件资源。
默认情况下,Docker 容器拥有所有 RAM 和 CPU 资源可用,这非常高效。与 VM 不同,资源相对专用,容器可以根据负载一起垂直地扩展和缩小,共享资源。
然而,这有时可能不安全 - 应用程序可能会有负载峰值,消耗过多资源,并使其他容器饥饿。假设这不是恶意或糟糕编写的应用程序,处理此合法的负载峰值的好方法是使用集群中的多个主机,并使用某种编排系统动态启动容器的新实例。
情况更加复杂的是,Windows 主机上的 Docker 使用 HyperV 中嵌入的 Linux,并在其中运行其容器。因此,Windows 上的 Docker 使用了一种组合硬件和半虚拟化解决方案。
简而言之,Docker 容器是低质量的(半)虚拟机,具有巨大的优势和许多缺点。