容器、虚拟机、Docker入门指南

11/13/2022 Docker

# 引言

  作为一名开发者,我想应该没有人没听说过Docker(一个在“容器”中打包、运输和运行应用程序的工具。)

  不论你是否在实际的开发过程中使用过Docker,我认为了解一些基础概念,关于什么是容器以及它与虚拟机之间的差异,这仍然是很重要的。虽然网络上目前充斥着很多Docker的优秀使用指南,但目前没找到比较适合初学者的一些概念及入门指南,尤其是关于容器的组成部分。希望这篇博客能帮助初学者解决这个困扰。

# 什么是容器和虚拟机?

  容器和虚拟机要做的事情都很相似: 将应用程序及其依赖项隔离为一个可以在任何地方运行的独立单元。此外,容器和虚拟机消除了对物理硬件的需求,允许在能耗和成本效益方面更有效地使用计算资源。容器和VM之间的主要区别在于它们的架构体系。接下来,让我们仔细看看。

# 虚拟机

  虚拟机——通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。在实体计算机中能够完成的工作在虚拟机中都能够实现。虚拟机使用管理程序在物理机器上运行。管理程序反过来在主机或裸机上运行。

  虚拟机监控程序(VMM)是虚拟机在其上运行的软件、固件或硬件。管理程序本身运行在物理计算机上,称为主机。主机为VM提供资源,包括RAMCPU。这些资源在虚拟机之间根据需要进行分配。因此,如果一个虚拟机正在运行一个资源量更大的应用程序,那么将会为该虚拟机分配比在同一主机上运行的其他虚拟机更多的资源。

  在主机上运行的VM通常也被称为客户机。该客户机包含应用程序以及运行该应用程序所需的内容(例如系统二进制文件和库)。不仅如此客户机还拥有自己的整个虚拟化硬件堆栈,包括虚拟化网络适配器、存储和CPU,这意味着客户机也有着自己配套的操作系统。从内部来看,客户机作为自己的单元,拥有自己的专属资源。从外部来看,我们知道它是一个VM,共享着主机提供的资源。如上所述,客户机可以在托管管理程序或裸机管理程序上运行。但是在两者之间,也有一些重要的区别。

  首先,托管虚拟化管理程序在主机的操作系统上运行。比如运行OSX的计算机可以在该操作系统上安装VM(例如VirtualBox或VMware Workstation 8)。VM无法直接访问硬件,因此必须通过主机操作系统进行访问(Mac的OSX)。托管管理程序的好处是底层硬件不那么重要,主机的操作系统负责硬件驱动程序,而不是管理程序本身,因此被认为具有更多的“硬件兼容性”。另一方面,硬件和管理程序之间的这一额外层会产生更多的资源开销,从而降低虚拟机的性能。

  裸机管理程序环境通过在主机硬件上安装和运行来解决性能问题。因为它直接与底层硬件对接,所以它不需要主机操作系统来运行。在这种情况下,作为操作系统安装在主机服务器上的第一件事就是管理程序。与托管管理程序不同,裸机管理程序有自己的设备驱动程序,并直接与每个组件交互以执行任何I/O、处理或操作系统特定的任务。这将带来更好的性能、可扩展性和稳定性。这里的折衷是硬件兼容性有限,管理程序只能内置这么多设备驱动程序。说了那么多关于管理程序的内容之后,你可能会想知道为什么我们需要在VM和主机之间添加额外的管理程序层。

  原因是由于虚拟机有自己的虚拟操作系统,管理程序在为虚拟机提供管理和执行该客体操作系统的平台方面发挥了重要作用。它允许主机在其上作为客体运行的虚拟机之间共享其资源。

VM示意图

正如图中所示,为每个新的虚拟机打包了虚拟硬件、内核(即操作系统)和用户空间。

# 容器

  与提供硬件虚拟化的VM不同,容器通过抽象“用户空间”来提供操作系统级虚拟化。无论出于何种目的,容器看起来就像VM。例如,他们有执行所需的专有空间,可以以root的身份执行命令,有专有的网络接口和IP地址,并允许自定义路由和防火墙规则,可以装载文件系统等等。

容器和VM之间的最大区别在于,容器可以与其他容器共享主机系统的内核

Container示意图

  从上面的示意图中我们不难看出,容器仅将用户空间进行打包,而不是像虚拟机一样打包了内核或者虚拟硬件。每个容器都有自己的隔离用户空间,并允许多个容器在一台主机上运行。我们可以看到,所有的操作系统级别的架构都是跨容器共享的。唯一从头开始创建的部分是bins和libs。这就是为什么容器如此轻量级的原因。

# Docker

Docker是一个基于Linux容器,并用Go实现的开源项目,使用Linux内核特性(如命名空间和控制组)在操作系统上创建容器

  容器化并不是一个新技术,Google多年前就在使用自己的容器技术。而其他的Linux容器技术包括Solaris Zones、BSD监狱和LXC,这些也已经存在多年。那为什么我们还需要Docker呢?

# 易用性

  Docker让任何人—开发人员都可以更容易地利用容器来快速构建和测试可移植的应用。它允许用户在自己的电脑上打包应用,并且应用在任何的公共云、私有云甚至裸机上不用修改也能运行。就像Docker的口号:“构建一次,在任何地方运行。”

# 速度

  Docker非常轻便和快速。因为容器只是在内核上运行的沙盒环境,所以占用的资源很少。用户可以在几秒钟内创建和运行自己的Docker容器,而VM可能需要更长的时间,因为VM每次都必须启动一个完整的虚拟操作系统。

# 生态

  Docker用户也得益于Docker Hub日益丰富的社区生态,你可以认为它就像一个类似App store一样得Docker镜像商店。在这个商店里搜索满足你需求的镜像非常的容易,用户可以随时下载并使用,几乎不需要任何的修改。

# 模块化和拓展性

  Docker可以轻松地将应用里面的多个模块的功能分解为单个的独立容器。比如,你可能在一个容器中运行你的Postgres数据库,在另一个容器中运行你的Redis服务器,而你的Node.js应用在另一个容器中,并使用Docker将这些容器链接在一起。这就使得Docker用户将来可以轻松地独立的扩展或更新自己的组件。

# Docker的一些基本概念

  下图是Docker的一个全览示意图

# Docker引擎

  Docker引擎是Docker的运行层,它是一个轻量级的运行工具在Linux系统上运行,可以管理容器、图像、构建等。由以下部分组成:

  1. 在主机上运行的Docker守护进程
  2. Docker客户端,与Docker守护进程通信以执行命令
  3. REST API:与Docker守护进程交互

# Docker客户端

  Docker客户端(Docker Client)是用户与Docker进行交互的最主要方式。可以把它看作是Docker的用户界面。例如,当执行下面的命令时

docker build appkey/someImage .
1

那就代表正在与Docker客户端通信,然后Docker客户端将用户的指令传递给Docker守护进程

# Docker守护进程

  Docker守护进程用于监控指定的进程,当发现目标进程工作异常时,可以对该目标进程进行控制。一个守护进程可以对多个目标进程进行守护,在守护进程中,守护者对目标进程的管理是利用心跳机制实现的。

# Dockerfile

Dockerfile是编写构建Docker镜像指令的地方。比如:

  • RUN apt-get y install some-package 安装一个软件包
  • EXPOSE 8000:暴露一个端口
  • ENV ANT_HOME /usr/local/apache-ant 传递一个环境变量

一旦设置好Dockerfile,我们就可以使用docker build命令从中构建镜像。下面是Dockerfile的示例:

FROM mysql:5.7
LABEL OG=felord.cn
COPY utf8mb4.cnf /etc/mysql/conf.d/utf8mb4.cnf
COPY ./sql  /tmp/sql
RUN mv /tmp/sql/*.sql /docker-entrypoint-initdb.d
RUN rm -rf /tmp/sql
1
2
3
4
5
6

# Docker镜像

  镜像是只读模板,用户可以根据Dockerfile中编写的一组指令构建。镜像里面定义了我们希望打包的应用程序及其依赖项的一些操作,以及启动时要运行什么进程。

  Docker镜像使用Dockerfile进行构建。Dockerfile中的每一条指令都会向镜像中添加一个新的layer,这些layer代表图像文件系统的一部分,可以添加或替换其下面的层。这些layer是Docker轻量级且功能强大的关键。Docker通过使用联合文件系统来实现这一点:

# 联合文件系统

  Docker使用Union File Systems来构建镜像。我们可以把联合文件系统视为可堆叠的文件系统,这意味着可以透明地覆盖单独文件系统(称为分支)的文件和目录,以形成单个文件系统。 在重叠的分支中具有相同路径的目录的内容被视为单个合并目录,这样就避免了创建每个层的单独副本的需要。同样地,这些分支都可以被赋予指向同一资源的指针,当需要修改某些layer时,将会创建一个新的副本并修改一个本地副本,并保持原来的副本不变。这样就使得文件系统在不允许写入的情况下看起来好像是可写入的。

分层系统的设计有两个巨大的优点:

  • 免复制:`layer``避免了每次使用镜像创建和运行新容器时复制一组完整的文件,从而使Docker容器的实例化非常快。
  • 分层隔离:当用户变更镜像时,Docker只将更新传递到已更改的层。

# Volumes(数据卷)

  Volumes是一个可供一个或多个容器使用的位于宿主机上特殊目录,它拥有以下特性:

  可以在容器间共享和重用 对数据卷的写入操作,不会对镜像有任何影响 数据卷默认会一直存在,即使容器被删除,使用数据卷的目的是持久化容器中的数据,以在容器间共享或者防止数据丢失(写入容器存储层的数据会丢失)。

# Docker容器

  正如上面所说到的,Docker容器将应用的软件包装到一个不可见的盒子中,其中包含应用所需要运行的所有内容:操作系统、应用代码、运行依赖、系统工具、系统库等。Docker容器是基于Docker镜像构建的。由于镜像是只读的,Docker在镜像的只读文件系统上添加了一个读写文件系统来创建容器。

  另外,在创建容器之后,Docker会新建一个网络接口,以便于让容器可以与本地主机进行通信,接着会将可用的IP地址附加到容器中,然后执行用户在定义镜像时指定的进程。

  一旦容器被成功创建,那么就可以在任何环境中运行它,而且不需要进行任何变更。

# 一点感受

  Docker的内容真的太多了,上面只是挑选了一些我认为可能对于初学者比较重要的基础概念的进行讲解。最后,希望大家对于Docker的了解不仅仅只是停留在只会使用。

Last Updated: 11/21/2022, 6:50:20 AM