一. 容器技术的起源

想象一下,你们公司正在秘密研发一款超级厉害的 APP,就叫 “超酷头条” 吧。程序员小哥哥吭哧吭哧地自己搭建了一套环境,开始写代码。好不容易写完了,交给测试小姐姐测试。这时候问题来了,测试小姐姐又得从头到尾搭建一遍这套环境。要是测试过程中出了问题,程序员小哥哥还能一脸无辜地说:“明明在我的环境上可以运行的呀。”

测试小姐姐好不容易测完,终于可以上线了。运维大哥却又要重新搭建这套环境,费了好大劲搭建好,一上线,系统居然崩溃了。这时候,心理素质超强的程序员小哥哥又可以施展演技了:“真的,在我的环境上运行得好好的。”

从这个过程可以看出,我们重复搭建了三套环境,不仅浪费时间和效率,还埋没了程序员小哥哥的表演才华。聪明的程序员可不会满足于这种现状,于是,容器技术就应运而生啦。

可能有人会说:“等等,我们不是有虚拟机吗?VMware 用起来也挺顺手的,先搭好一套虚拟机环境,然后给测试和运维克隆出来不就行了?” 在没有容器技术之前,这确实是个办法,不过,它还不够完美。

现在云计算的底层基石就是虚拟机技术。云计算厂商买回来一堆硬件,搭建好数据中心,然后用虚拟机技术把硬件资源切分。比如说,可以切分出 100 台虚拟机,这样就能卖给好多用户了。那为什么说这个办法不够好呢?下面我们来看看容器技术和虚拟机的区别。

二. 容器技术 vs 虚拟机

大家都知道,和一个单纯的应用程序相比,操作系统那可是又重又笨。它到底有多笨重呢?操作系统运行起来要占用好多资源,大家肯定都有体会。刚装好的系统,啥都还没部署呢,单纯的操作系统磁盘占用至少几十 GB 起步,内存也要几个 GB 起步。

假设我有一台机器,内存是 16GB,需要部署三个应用。要是用虚拟机技术,可能会这么划分:在这台机器上开启三个虚拟机,每个虚拟机上部署一个应用。其中,VM1 占用 2GB 内存,VM2 占用 1GB 内存,VM3 占用 4GB 内存。可以看到,虚拟机本身就占据了总共 7GB 内存,这样一来,我们就没办法划分出更多虚拟机来部署更多应用程序了。可我们要部署的是应用程序,要用的也是应用程序,又不是操作系统。要是有一种技术,能让我们避免把内存浪费在 “无用” 的操作系统上,那该多好啊,这是问题一,主要就是因为操作系统太重了。

还有个问题,就是启动时间。大家都知道,操作系统重启超级慢,因为它要从头到尾把该检测的都检测了,该加载的都加载上,这个过程动不动就得好几分钟,所以说操作系统还是太笨了。

那有没有一种技术,既能让我们获得虚拟机的好处,又能克服这些缺点,实现鱼和熊掌兼得呢?答案是肯定的,这就是容器技术。下面,我们先来看看什么是容器。

三. 什么是容器

容器,英文是 container,它还有 “集装箱” 的意思。你可别小看集装箱,它可是商业史上超了不起的一项发明,大大降低了海洋贸易运输成本。我们来看看集装箱都有啥好处:

  1. 集装箱之间相互隔离,每个箱子里装的东西都互不干扰。
  2. 可以长期反复使用,非常耐用。
  3. 能快速装载和卸载,装卸效率超高。
  4. 规格标准统一,在港口和船上都能整整齐齐地摆放。

回到软件中的容器,其实容器和集装箱在概念上非常相似。现代软件开发特别注重隔离,就是要让应用程序在运行时相互独立,互不干扰。实现这种隔离可不容易,其中一种解决办法就是前面提到的虚拟机技术,把应用程序部署在不同的虚拟机中,从而实现隔离。但是虚拟机技术有各种缺点,那容器技术又怎么样呢?

与虚拟机通过操作系统实现隔离不同,容器技术只隔离应用程序的运行时环境,而且容器之间可以共享同一个操作系统。这里的运行时环境,指的是程序运行依赖的各种库以及配置。容器更加轻量级,占用的资源也更少。和操作系统动辄几个 GB 的内存占用相比,容器技术只需几 MB 空间。所以,我们可以在同样规格的硬件上大量部署容器,这是虚拟机做不到的。而且,和操作系统几分钟的启动时间比起来,容器几乎能瞬时启动。容器技术为打包服务栈提供了一种更高效的方式,简直太酷了!

那我们该怎么使用容器呢?这就要讲到 Docker 了。注意哦,容器是一种通用技术,Docker 只是其中的一种实现。接下来,我们就来看看什么是 Docker。

四. 什么是 Docker

Docker 是一个用 Go 语言实现的开源项目,它能让我们很方便地创建和使用容器。Docker 把程序以及程序所有的依赖都打包到 Docker container 里,这样,你的程序在任何环境下都会有一致的表现。这里程序运行的依赖,也就是容器,就好比集装箱;容器所处的操作系统环境,就好比货船或港口。程序的表现只和集装箱(容器)有关系,和集装箱放在哪个货船或者哪个港口(操作系统)没啥关系。

所以,我们可以看到 Docker 能屏蔽环境差异。也就是说,只要你的程序打包到了 Docker 中,那么不管运行在什么环境下,程序的行为都是一致的。这下,程序员小哥哥再也没法施展他的 “演技” 了,不会再有 “在我的环境上可以运行” 这种情况,真正实现了 “build once, run everywhere”(一次构建,到处运行)。

Docker 还有个好处,就是快速部署,这在当前互联网公司可是最常见的应用场景之一。一方面,容器启动速度非常快;另一方面,只要确保一个容器中的程序能正确运行,那么你就能确信,无论在生产环境部署多少个这样的容器,程序都能正确运行。

五. 如何使用 Docker

Docker 中有这么几个概念:Dockerfile、image、container。实际上,你可以简单地把 image 理解为可执行程序,container 就是运行起来的进程。那写程序需要源代码,“写” image 就需要 Dockerfile,所以 Dockerfile 就是 image 的源代码,而 Docker 就是 “编译器”。

我们只需要在 Dockerfile 中指定需要哪些程序、依赖什么样的配置,然后把 Dockerfile 交给 “编译器” Docker 进行 “编译”,这个 “编译” 操作就是 docker build 命令,生成的可执行程序就是 image。之后就可以运行这个 image 了,运行操作就是 docker run 命令,image 运行起来后就是 Docker container。

具体的使用方法这里就不详细说了,大家可以参考 Docker 的官方文档,那里有非常详细的讲解。接下来,我们看看 Docker 是怎么工作的。

六. Docker 是如何工作的

实际上,Docker 采用了常见的 CS 架构,也就是 client - server 模式。Docker client 负责处理用户输入的各种命令,比如 docker build、docker run。而真正干活的是 server,也就是 Docker demon。值得注意的是,Docker client 和 Docker demon 可以运行在同一台机器上。

下面我们用几个命令来详细讲讲 Docker 的工作流程:

  1. docker build:当我们写完 Dockerfile 交给 Docker “编译” 时,就用这个命令。client 接收到请求后,会把它转发给 Docker daemon,然后 Docker daemon 根据 Dockerfile 创建出 “可执行程序” image。
  2. docker run:有了 “可执行程序” image 后,就可以运行程序了,这时候使用 docker run 命令。Docker daemon 接收到该命令后,找到具体的 image,然后加载到内存开始执行,image 执行起来就变成了所谓的 container。
  3. docker pull:其实 docker build 和 docker run 是两个最核心的命令,学会这两个,Docker 基本上就能用起来了,剩下的就是一些补充命令。那 docker pull 是什么意思呢?我们之前说过,Docker 中 image 的概念就类似于 “可执行程序”。我们平时下载应用程序,会去 APP Store,也就是应用商店。类似地,既然 image 也是一种 “可执行程序”,那有没有 “Docker Image Store” 呢?当然有啦,这就是 Docker Hub,它是 Docker 官方的 “应用商店”,你可以在这里下载到别人编写好的 image,这样就不用自己编写 Dockerfile 了。

Docker registry 可以用来存放各种 image,像 Docker Hub 这种公共的、任何人都能下载 image 的仓库,就属于 Docker registry。那怎么从 Docker Hub 中下载 image 呢?这就得用到 docker pull 命令了。这个命令的实现很简单,就是用户通过 Docker client 发送命令,Docker daemon 接收到命令后,向 Docker registry 发送 image 下载请求,下载后存放在本地,这样我们就可以使用 image 了。

最后,我们来简单了解一下 Docker 的底层实现。

七. Docker 的底层实现

Docker 是基于 Linux 内核提供的这几项功能来实现的:

  1. NameSpace:我们知道,在 Linux 中,PID、IPC、网络等资源是全局的。而 NameSpace 机制是一种资源隔离方案,在这种机制下,这些资源就不再是全局的了,而是属于某个特定的 NameSpace,各个 NameSpace 下的资源互不干扰。这就使得每个 NameSpace 看上去就像一个独立的操作系统一样。不过,只有 NameSpace 还不够。
  2. Control groups:虽然有了 NameSpace 技术可以实现资源隔离,但进程还是可能不受控制地访问系统资源,比如 CPU、内存、磁盘、网络等。为了控制容器中进程对资源的访问,Docker 采用了 control groups 技术(也就是 cgroup)。有了 cgroup,就可以控制容器中进程对系统资源的消耗了。比如说,你可以限制某个容器使用内存的上限,还能规定它可以在哪些 CPU 上运行等等。

有了这两项技术,容器看起来就真的像独立的操作系统了。

Docker 是目前非常流行的技术,很多公司都在生产环境中使用它。不过,Docker 依赖的底层技术其实很早就出现了,现在以 Docker 的形式重新焕发出活力,而且能很好地解决我们面临的问题。希望这篇文章能帮助大家理解 Docker。如果对 Docker 感兴趣,不妨自己动手实践一下,说不定你会发现更多有趣的地方!

Logo

为武汉地区的开发者提供学习、交流和合作的平台。社区聚集了众多技术爱好者和专业人士,涵盖了多个领域,包括人工智能、大数据、云计算、区块链等。社区定期举办技术分享、培训和活动,为开发者提供更多的学习和交流机会。

更多推荐