容器 or 虚拟机?
![容器or虚拟机?](https://static001.geekbang.org/infoq/d1/d1cfe329cd26c990d79b66cc86b89366.jpeg)
介 绍
容器,以及 Docker 和 Kubernetes 之类的容器技术已经日益成为许多开发人员工具包中常见的工具。容器化的核心目标是提供一种更好的方式,以可预测和便于管理的方式在不同的环境中创建、打包以及部署软件。
在本文中,我们将一窥什么是容器,它与其他虚拟化技术有何不同以及它在部署和运维的过程中有哪些优势。如果您只是想迅速了解有关容器的核心概念,您可以直接滑到倒数第二部分【容器专用术语】查看。
什么是容器?
容器是一种操作系统虚拟化技术,用于打包应用程序及其依赖项,并在隔离环境中运行它们。在不同类型的基础架构中,容器以一种标准的方式,提供了轻量级打包和部署应用程序的方法。
容器的这些特性使其对开发和运维人员极具吸引力。因为容器可以在任意支持容器的主机上运行一致,所以开发人员可以直接在本地测试相同的软件,稍后就可以方便地部署到完整的生产环境中。同时,Container Format 可以确保应用程序的依赖项被放到镜像中,简化了手动操作的部分和发布流程。因为运行容器的主机和平台是通用的,所以可以标准化管理基于容器系统的基础架构。
容器从容器镜像中创建,其中包含了系统、应用程序和容器环境。容器镜像和创建特定容器模板一样,同一镜像可用于生成任意数量的运行中的容器。这与类和实例在面向对象编程中的工作方式类似:一个单独的类可以用于创建任何数量的实例,一个单独的容器镜像也可以用于创建任何数量的容器。这类比喻也适用于继承方面,因为容器镜像可以作为其他自定义容器镜像的父级。用户可以从外部资源下载预先构建的容器,也可以根据需要构建自定义镜像。
什么是 Docker?
虽然 Linux 容器是一种能够以不同方式实现和管理的通用技术,但 Docker 是目前为止运行构建和容器最常见的方式。它包含了一系列的工具,可以允许用户创建容器镜像,从外部镜像仓库推送或者拉取镜像,还能在不同的环境中运行和管理容器。可以这么说,容器在 Linux 上迅速流行主要归功于 Docker 在 2013 年发布之后所做的努力。
docker 命令行工具扮演了多种角色。它可以充当容器工作负载的流程管理器来运行和管理容器。此外,它还可以通过阅读和执行 Dockerfile 或者拍摄运行中的容器快照来创建新的容器镜像。这一命令还可以和 Docker Hub(一种容器镜像仓库)交互,来拉取新的容器镜像或者推送本地镜像以保存或者发布它们。
虽然在 Linux 上 Docker 只提供了众多实现方式中的一种,但它让容器世界更容易进入,并且具备最常用的解决方案。尽管已经为容器开发了开放标准以确保互通性,但大多数与容器相关的平台和工具都将 Docker 作为测试和发布软件时的主要参照。对于既定环境,Docker 可能并不总是最高性能的解决方案,但它可能是最受欢迎的测试选项之一。实际上,对于容器而言,虽然在 Linux 上有许多其他的替代方案,但大家通常都会首先学习 Docker,这并非毫无理由,因为 Docker 无处不在并且在容器生态系统中对术语、标准以及工具都拥有影响力。
容器如何工作?
了解容器的工作原理对于讨论其与虚拟机的区别大有裨益。
虚拟机 vs 容器
虚拟机,或称 VMs,是一种硬件虚拟技术,它可以让您完全虚拟化硬件或计算机资源。一个单独的访客操作系统管理虚拟机与运行在主机系统的 OS 完全分开。在主机系统上,一个名为 hypervisor 的软件负责启动、停止和管理虚拟机。由于虚拟机作为完全不同的计算机运行,在正常运行条件下不会影响主机系统或其他虚拟机,因此虚拟机具备极大的隔离性和安全性。然而,它们也存在不足。例如,虚拟化整个计算机需要 VM 使用大量的资源。此外,由于虚拟机在单独的访客操作系统上运行,因此虚拟机的配置和启动时间可能相当慢。同时,因为虚拟机作为一个独立的机器运行,所以管理员通常需要采用类似基础架构的管理工具和流程来更新和运行各个环境。
总而言之,虚拟机允许您将计算机的资源细分为较小的单个计算机,但最终结果与管理一组物理计算机没有显著差异。计算机规模扩大,每个主机的责任可能变得更加集中,但您使用的工具,策略和流程以及系统的功能可能不会有明显的变化。
与虚拟化整个计算机相比,容器则采用不同的方式——直接虚拟化操作系统。它作为由主机操作系统内核管理的专用进程运行,但具有受限且严格操作的系统进程、资源和环境视图。容器存在于共享系统上,并且像它们在完全控制的计算机上运行一样。
![](https://static001.geekbang.org/infoq/51/51c8e37d82d59d07c02db553edb6ec17.jpeg?x-oss-process=image/resize,p_80/auto-orient,1)
与其将容器视为像虚拟机一样的完整计算机,倒不如说更常见的管理容器与应用程序更为相似。例如,虽然您可以将 SSH 服务器绑定到容器中,但这不是推荐的模式。相反,调试通常通过日志记录界面执行,通过滚动新镜像来应用更新,并且不再强调服务管理以支持管理整个容器。
这些特性意味着容器占据着位于虚拟机的强隔离性和传统流程的本地管理之间的空间。容器提供区域化和以流程为中心的虚拟化,可在限制,灵活性和速度之间实现良好平衡。
Linux cgroups 和命名空间
Linux 控制组或 cgroups 是一种内核功能,允许将进程及其资源作为一个单元进行分组、隔离和管理。cgroups 和流程一起绑定,并且决定资源的访问权限以及提供管理和监控它们行为的机制。它们遵循分层系统,允许子进程继承其父进程的条件并可能采用进一步的限制。cgroups 将进程作为一个组,并将所需的功能与其绑定在一起,并限制它们可以访问的资源。
另一个容器所依赖的内核功能是 Linux 命名空间。命名空间限制了什么进程可以看到余下的系统。运行在命名空间内部的进程无法获取任何命名空间外运行的进程。由于命名空间定义了与系统其余部分分离的独特上下文,因此命名空间的进程树需要反映该上下文。在命名空间内部,主进程变为 PID1(process ID1),传统上为 OS 的 init 系统保留 PID。在命名空间内构建严格操作的虚拟进程树让在容器内运行的进程表现得像在正常的、不受限制的环境中操作一样。
容器化的优势
上文中我们已经讨论了一些能够使得容器成为可能的技术,那么现在我们来看一看它们最重要的特性有什么。
轻量级虚拟化
与使用虚拟机的硬件虚拟化相比,容器显得更为轻便。首先,容器使用主机系统的内核并在该操作系统中作为分区进程运行,而不是虚拟化所有硬件资源并在该环境中运行完全独立的操作系统。
其次,从主机的角度出发,容器像其他进程一样运行,这意味着它们可以迅速启动和停止并且可以使用受限制的资源。此外,容器不仅可以查看和访问主机的进程空间和资源子集,而且还能够在大多数情况下,可以表现得像一个完全独立的操作系统。
容器镜像本身也可以非常小。最小的镜像能够使依赖于拉取最新镜像的工作流不会出现显著延迟。这是许多容错,自我修复的分布式系统的要求。
环境隔离
通过使用 cgroups 以及命名空间等 Linux 内核功能,容器可以与主机环境彼此隔离。这提供了一定程度的功能限制,以防止容器环境互相干扰。
虽然不够强大,不足以被视为完全安全沙箱,但这种隔离确实具有优势。由于主机和每个容器将软件保存在单独的文件系统中,因此更容易避免依赖性和库冲突。网络环境可以分离,因此容器内的应用程序可以绑定到其本机端口,而无需担心主机系统中或其他容器中的软件会产生冲突。然后,管理员可以根据需要选择如何将容器的网络映射到主机网络中。
标准化打包格式和运行时目标
容器最引人注目的其中一个优势是它可以统一和简化打包和部署软件的流程。容器镜像可以让您绑定应用程序和所有的运行时需求到可跨多个基础架构部署的单个单元中。
在容器内部,开发人员可以安装和使用其应用程序所需的任一库,而无需担心干扰主机系统库。当镜像创建时,依赖项是版本锁定的。容器运行时可以充当一个标准、稳定的部署平台,因此开发人员无需了解容器在哪个特定的机器上运行。只要容器运行时可操作且有足够的系统资源可用,容器就会像在开发环境中那样运行。
同样的,从运维的角度来看,容器化使部署环境的需求标准化了。管理员可以专注于维护充当容器平台的通用主机,并分配这些计算机可以访问的资源池,而不是基于应用程序的语言、运行时和依赖项来配置和维护特定的环境。绑定容器中的所有特定应用程序特性会在应用程序的关注点与平台的关注点之间创建自然边界。
可扩展性
容器的既定范式可以让您以一种相对简单的机制来扩展您的应用程序。轻量级镜像、快速的启动时间、创建测试以及部署“黄金镜像”以及标准化的运行时环境这些特性使得构建高度扩展的系统成为可能。
一个可扩展性的系统是高度依赖于应用程序架构和容器镜像本身是如何构建的。与容器范例配合良好的设计将会充分发挥容器格式的优势,以实现速度、可用性和可管理性的良好平衡。面向服务的架构,特别是微服务,在容器化环境中非常流行,因为将应用程序分解为具有集中目的的离散组件使得开发,扩展和更新更加简单。
![](https://static001.geekbang.org/infoq/bd/bdc7e85676a9507a23bdf54e79b41583.webp?x-oss-process=image/resize,p_80/format,jpg)
容器专用术语
在我们结束之前,让我们回顾一下我们在本文中介绍的一些关键术语,以及您在继续学习时可能遇到的一些新术语。
容器:在 Linux 系统中,容器是一个操作系统虚拟化技术,来打包应用程序及它们的依赖项并在独立的环境中运行它们。
容器镜像:容器镜像是静态文件,其定义文件系统以及特定容器配置的行为。它还可以作为创建容器的模板。
容器编排:容器编排用于描述跨多个主机管理容器队列所需的进程和工具。它通常使用容器平台控制扩展、容错、资源分配和调度。
容器运行时:容器运行时是在一台主机上运行和管理容器的组件。其最基本的要求通常是能够从给定的镜像中配置容器,但许多运行时还绑定了其他功能,如进程管理、监控和镜像管理。Docker 内在 docker 命令中包含了一个容器运行时,但还有许多其他可用于不同用例的替代方案。
Docker:Docker 是第一个成功推广 Linux 容器概念的技术。其中,Docker 的工具生态系统包括 docker,一个带有大量容器的容器运行时以及镜像管理特性,docker-compose,一个定义和运行多容器应用程序的系统,以及 Docker Hub,容器镜像仓库。
Dockerfile:Dockerfile 是一个用于描述如何构建一个容器镜像的文本文件。它定义了基本的镜像,在系统内运行的命令以及在容器内运行时启动和管理进程的方式。虽然 Dockerfile 并非唯一的选项,但它是最常用的定义容器镜像的格式,即使不使用 Docker 镜像的构建功能。
Kata Containers:Kata Container 是一种使用模型,工作流和工具来管理轻量级虚拟机的方法,它复制了容器的使用体验。Kata Container 寻求获得容器的好处,同时提供更强大的隔离和安全性。
Kubernetes:Kubernetes 是一个功能强大的容器编排平台,它可以管理容器主机的集群以及运行在上面的工作负载。Kubernetes 提供工具和抽象化,以在高可用生产环境中部署、扩展、监控和管理容器。
Linux cgroups:Linux cgroups,或称控制组,是绑定了进程的内核功能,并且可以决定它们对资源的访问权限。Linux 中的容器是使用 cgroups 实现的,可以方便管理资源和单独的进程。
Linux 命名空间:Linux 命名空间用于将进程或 cgroup 的可见性限制为余下系统的一种内核功能。在 Linux 的容器使用命名空间来帮助隔离工作负载和来自运行在系统上的其他进程的资源。
LXC:LXC 是 Linux 容器化的一种形式,它早于 Docker 和其他许多技术,同时也依赖于许多相同的内核技术。相比于 Docker,LXC 通常虚拟化整个操作系统而非仅仅运行应用程序的进程,这与虚拟机更为相似。
虚拟机:虚拟机,或 VMs,是一种硬件虚拟技术,它模拟为一整台计算机。在虚拟机内安装一个完整的操作系统可用于管理内部组件和访问虚拟机的计算资源。
虚拟化:虚拟化是一个创建、运行以及管理虚拟环境或者计算机资源的过程。虚拟化是一种抽象物理资源的方式,并且常用于以不同目的分割资源池。
总 结
容器并非魔弹,但它们的确具备一些优于在裸机上运行软件或使用其他虚拟化技术的优势。通过提供轻量级、功能性隔离和开发丰富的工具生态系统来帮助管理复杂性,为容器在开发期间和整个运维生命周期中提供了极大的灵活性和可控性。
评论