关于docker那点事儿——初识docker

文章目录

  • 前言
  • 一、docker历史
  • 二、docker系统
  • 三、docker容器与镜像


前言

  从过去以物理机和虚拟机为主体的开发运维环境,向以容器为核心的基础设施的转变过程,并不是一次温和的改革,而是涵盖了对网络、存储、调度、操作系统、分布式原理等各个方面的容器化理解和改造。2013 年的后端技术领域,已经太久没有出现过令人兴奋的东西了。曾经被人们寄予厚望的云计算技术,也已经从当初虚无缥缈的概念蜕变成了实实在在的虚拟机和账单。而相比于如日中天 AWS 和盛极一时的 OpenStack,以 Cloud Foundry 为代表的开源 PaaS 项目,却成为了当时云计算技术中的一股清流。 当时,Cloud Foundry 项目已经基本度过了最艰难的概念普及和用户教育阶段,吸引了包括百度、京东、华为、IBM 等一大批国内外技术厂商,开启了以开源 PaaS 为核心构建平台层服务能力的变革。如果你有机会问问当时的云计算从业者们,他们十有八九都会告诉你:PaaS 的时代就要来了!这个说法其实一点儿没错,如果不是后来一个叫 Docker 的开源项目突然冒出来的话。

一、docker历史

  事实上,当时还名叫 dotCloud 的 Docker 公司,也是这股 PaaS 热潮中的一份子。只不过相比于 Heroku、Pivotal、Red Hat 等 PaaS 弄潮儿们,dotCloud 公司实在是太微不足道了,而它的主打产品由于跟主流的 Cloud Foundry 社区脱节,长期以来也无人问津。眼看就要被如火如荼的 PaaS 风潮抛弃,dotCloud 公司却做出了这样一个决定:开源自己的容器项目 Docker。显然,这个决定在当时根本没人在乎。

  PaaS 项目被大家接纳的一个主要原因,就是它提供了一种名叫"应用托管"的能力。 在当时,虚拟机和云计算已经是比较普遍的技术和服务了,那时主流用户的普遍用法,就是租一批 AWS 或者 OpenStack 的虚拟机,然后像以前管理物理服务器那样,用脚本或者手工的方式在这些机器上部署应用。当然,这个部署过程难免会碰到云端虚拟机和本地环境不一致的问题,所以当时的云计算服务,比的就是谁能更好地模拟本地服务器环境,能带来更好的"上云"体验。而 PaaS 开源项目的出现,就是当时解决这个问题的一个最佳方案。

  举个例子,虚拟机创建好之后,运维人员只需要在这些机器上部署一个 Cloud Foundry 项目,然后开发者只要执行一条命令就能把本地的应用部署到云上,这条命令就是:

  $ cf push " 我的应用 "

  是不是很神奇?

  事实上,像 Cloud Foundry 这样的 PaaS 项目,最核心的组件就是一套应用的打包和分发机制。 Cloud Foundry 为每种主流编程语言都定义了一种打包格式,而"cf push"的作用,基本上等同于用户把应用的可执行文件和启动脚本打进一个压缩包内,上传到云上 Cloud Foundry 的存储中。接着,Cloud Foundry 会通过调度器选择一个可以运行这个应用的虚拟机,然后通知这个机器上的 Agent 把应用压缩包下载下来启动。 这时候关键来了,由于需要在一个虚拟机上启动很多个来自不同用户的应用,Cloud Foundry 会调用操作系统的 Cgroups 和 Namespace 机制为每一个应用单独创建一个称作"沙盒"的隔离环境,然后在"沙盒"中启动这些应用进程。这样,就实现了把多个用户的应用互不干涉地在虚拟机里批量地、自动地运行起来的目的。 这正是 PaaS 项目最核心的能力。 而这些 Cloud Foundry 用来运行应用的隔离环境,或者说"沙盒",就是所谓的"容器"。

  而 Docker 项目,实际上跟 Cloud Foundry 的容器并没有太大不同,所以在它发布后不久,Cloud Foundry 的首席产品经理 James Bayer 就在社区里做了一次详细对比,告诉用户 Docker 实际上只是一个同样使用 Cgroups 和 Namespace 实现的"沙盒"而已,没有什么特别的黑科技,也不需要特别关注。 然而,短短几个月,Docker 项目就迅速崛起了。它的崛起速度如此之快,以至于 Cloud Foundry 以及所有的 PaaS 社区还没来得及成为它的竞争对手,就直接被宣告出局了。那时候,一位多年的 PaaS 从业者曾经如此感慨道:这简直就是一场"降维打击"啊。 事实上,Docker 项目确实与 Cloud Foundry 的容器在大部分功能和实现原理上都是一样的,可偏偏就是这剩下的一小部分不一样的功能,成了 Docker 项目接下来"呼风唤雨"的不二法宝。这个功能,就是 Docker 镜像。

  恐怕连 Docker 项目的作者 Solomon Hykes 自己当时都没想到,这个小小的创新,在短短几年内就如此迅速地改变了整个云计算领域的发展历程。最后结局就是,"cf push"确实是能一键部署了,但是为了实现这个一键部署,用户为每个应用打包的工作可谓一波三折,费尽心机。而Docker 镜像解决的,恰恰就是打包这个根本性的问题。 所谓 Docker 镜像,其实就是一个压缩包。但是这个压缩包里的内容,比 PaaS 的应用可执行文件 + 启停脚本的组合就要丰富多了。实际上,大多数 Docker 镜像是直接由一个完整操作系统的所有文件和目录构成的,所以这个压缩包里的内容跟你本地开发和测试环境用的操作系统是完全一样的。

  这就有意思了:假设你的应用在本地运行时,能看见的环境是 CentOS 7.2 操作系统的所有文件和目录,那么只要用 CentOS 7.2 的 ISO 做一个压缩包,再把你的应用可执行文件也压缩进去,那么无论在哪里解压这个压缩包,都可以得到与你本地测试时一样的环境。当然,你的应用也在里面!这就是 Docker 镜像最厉害的地方: 只要有这个压缩包在手,你就可以使用某种技术创建一个"沙盒",在"沙盒"中解压这个压缩包,然后就可以运行你的程序了。更重要的是,这个压缩包包含了完整的操作系统文件和目录,也就是包含了这个应用运行所需要的所有依赖,所以你可以先用这个压缩包在本地进行开发和测试,完成之后,再把这个压缩包上传到云端运行。 在这个过程中,你完全不需要进行任何配置或者修改,因为这个压缩包赋予了你一种极其宝贵的能力:本地环境和云端环境的高度一致!这正是 Docker 镜像的精髓。

  那么,有了 Docker 镜像这个利器,PaaS 里最核心的打包系统一下子就没了用武之地,最让用户抓狂的打包过程也随之消失了。相比之下,在当今的互联网里,Docker 镜像需要的操作系统文件和目录,可谓唾手可得。所以,你只需要提供一个下载好的操作系统文件与目录,然后使用它制作一个压缩包即可,这个命令就是:
  $ docker build " 我的镜像 "
  一旦镜像制作完成,用户就可以让 Docker 创建一个"沙盒"来解压这个镜像,然后在"沙盒"中运行自己的应用,这个命令就是:
  $ docker run " 我的镜像 "
  当然,docker run 创建的"沙盒",也是使用 Cgroups 和 Namespace 机制创建出来的隔离环境。

  不过,Docker 项目固然解决了应用打包的难题,但正如前面所介绍的那样,它并不能代替 PaaS 完成大规模部署应用的职责。遗憾的是,考虑到 Docker 公司是一个与自己有潜在竞争关系的商业实体,再加上对 Docker 项目普及程度的错误判断,Cloud Foundry 项目并没有第一时间使用 Docker 作为自己的核心依赖,去替换自己那套饱受诟病的打包流程。反倒是一些机敏的创业公司,纷纷在第一时间推出了 Docker 容器集群管理的开源项目(比如 Deis 和 Flynn),它们一般称自己为 CaaS,即 Container-as-a-Service,用来跟"过时"的 PaaS 们划清界限。而在 2014 年底的 DockerCon 上,Docker 公司雄心勃勃地对外发布了自家研发的"Docker 原生"容器集群管理项目 Swarm,不仅将这波"CaaS"热推向了一个前所未有的高潮,更是寄托了整个 Docker 公司重新定义 PaaS 的宏伟愿望。
在 2014 年的这段巅峰岁月里,Docker 公司离自己的理想真的只有一步之遥。2013~2014 年,以 Cloud Foundry 为代表的 PaaS 项目,逐渐完成了教育用户和开拓市场的艰巨任务,也正是在这个将概念逐渐落地的过程中,应用"打包"困难这个问题,成了整个后端技术圈子的一块心病。Docker 项目的出现,则为这个根本性的问题提供了一个近乎完美的解决方案。这正是 Docker 项目刚刚开源不久,就能够带领一家原本默默无闻的 PaaS 创业公司脱颖而出,然后迅速占领了所有云计算领域头条的技术原因。 而在成为了基础设施领域近十年难得一见的技术明星之后,dotCloud 公司则在 2013 年底大胆改名为 Docker 公司。不过,这个在当时就颇具争议的改名举动,也成为了日后容器技术圈风云变幻的一个关键伏笔。

  在过去的很长一段时间里,相较于前端和互联网技术社区,服务器端技术社区一直是一个相对沉闷而小众的圈子。在这里,从事 Linux 内核开发的极客们自带"不合群"的"光环",后端开发者们啃着多年不变的 TCP/IP 发着牢骚,运维更是天生注定的幕后英雄。而 Docker 项目,却给后端开发者提供了走向聚光灯的机会。就比如 Cgroups 和 Namespace 这种已经存在多年却很少被人们关心的特性,在 2014 年和 2015 年竟然频繁入选各大技术会议的分享议题,就因为听众们想要知道 Docker 这个东西到底是怎么一回事儿。而 Docker 项目之所以能取得如此高的关注,一方面正如前面所说的那样,它解决了应用打包和发布这一困扰运维人员多年的技术难题;而另一方面,就是因为它第一次把一个纯后端的技术概念,通过非常友好的设计和封装,交到了最广大的开发者群体手里。在这种独特的氛围烘托下,你不需要精通 TCP/IP,也无需深谙 Linux 内核原理,哪怕只是一个前端或者网站的 PHP 工程师,都会对如何把自己的代码打包成一个随处可以运行的 Docker 镜像充满好奇和兴趣。

  这种受众群体的变革,正是 Docker 这样一个后端开源项目取得巨大成功的关键。这也是经典 PaaS 项目想做却没有做好的一件事情:PaaS 的最终用户和受益者,一定是为这个 PaaS 编写应用的开发者们,而在 Docker 项目开源之前,PaaS 与开发者之间的关系却从未如此紧密过。解决了应用打包这个根本性的问题,同开发者与生俱来的的亲密关系,再加上 PaaS 概念已经深入人心的完美契机,成为 Docker 这个技术上看似平淡无奇的项目一举走红的重要原因。

二、docker系统

Docker系统有两个程序:docker服务端和docker客户端

 docker服务端:

  是一个服务进程,管理着所有的容器。

 docker客户端:

  扮演着docker服务端的远程控制器,可以用来控制docker的服务端进程。

关于docker那点事儿——初识docker_第1张图片

Docker三大核心组件:

Docker 镜像 - Docker images

Docker 仓库 - Docker registeries

Docker 容器 - Docker containers

  docker仓库用于存储镜像,包含公有仓库(docker-hub daocloud ali)和私有仓库(公司自建)

  docker镜像由镜像名与tag号组成。是 Docker 容器运行时的只读模板,每一个镜像由一系列的层 (layers) 组成。Docker 使用 UnionFS 来将这些层联合到单独的镜像中。UnionFS 允许独立文件系统中的文件和文件夹(称之为分支)被透明覆盖,形成一个单独连贯的文件系统。正因为有了这些层的存在,Docker 是如此的轻量。当你改变了一个 Docker 镜像,比如升级到某个程序到新的版本,一个新的层会被创建。因此,不用替换整个原先的镜像或者重新建立(在使用虚拟机的时候你可能会这么做),只是一个新的层被添加或升级了。现在你不用重新发布整个镜像,只需要升级,层使得分发 Docker 镜像变得简单和快速。

  由于 Docker 使用一个统一文件系统,Docker 进程认为整个文件系统是以读写方式挂载的。 但是所有的变更都发生顶层的可写层,而下层的原始的只读镜像文件并未变化。由于镜像不可写,所以镜像是无状态的。

  每一个镜像都可能依赖于由一个或多个下层的组成的另一个镜像。下层那个镜像是上层镜像的父镜像。一个没有任何父镜像的镜像,谓之基础镜像。

关于docker那点事儿——初识docker_第2张图片

  Docker 容器和文件夹很类似,一个Docker容器包含了所有的某个应用运行所需要的环境。每一个 Docker 容器都是从 Docker 镜像创建的。Docker 容器可以运行、开始、停止、移动和删除。每一个 Docker 容器都是独立和安全的应用平台,Docker 容器是 Docker 的运行部分。

三、docker容器与镜像

Docker镜像

  假设Linux内核是第0层,那么无论怎么运行Docker,它都是运行于内核层之上的。这个Docker镜像,是一个只读的镜像,位于第1层,它不能被修改或不能保存状态。

  一个Docker镜像可以构建于另一个Docker镜像之上,这种层叠关系可以是多层的。第1层的镜像层我们称之为基础镜像(Base Image),其他层的镜像(除了最顶层)我们称之为父层镜像(Parent Image)。这些镜像继承了他们的父层镜像的所有属性和设置,并在Dockerfile中添加了自己的配置。

   Docker镜像通过镜像ID进行识别。镜像ID是一个64字符的十六进制的字符串。但是当我们运行镜像时,通常我们不会使用镜像ID来引用镜像,而是使用镜像名来引用。

Docker容器

  Docker容器,它会在所有的镜像层之上增加一个可写层。这个可写层是运行在CPU上的进程,而且有两个不同的状态:运行态(Running)和退出态 (Exited)

  当我们使用docker run启动容器,Docker容器就进入运行态,当我们停止Docker容器时,它就进入退出态。当我们有一个正在运行的Docker容器时,从运行态到停止态,我们对它所做的一切变更都会永久地写到容器的文件系统中。对容器的变更是写入到容器的文件系统的,而不是写入到Docker镜像中的。我们可以用同一个镜像启动多个Docker容器,这些容器启动后都是活动的,彼此还是相互隔离的。我们对其中一个容器所做的变更只会局限于那个容器本身。

  如果对容器的底层镜像进行修改,那么当前正在运行的容器是不受影响的,不会发生自动更新现象。因为docker会从镜像层复制一份数据到读写层,然后对读写层的数据修改。所以所有对容器的改动,无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。

你可能感兴趣的:(docker,容器,docker)