问题现象

在传统的项目开发流程中,我们写的代码会接触到好几个环境,如开发环境、测试环境以及生产环境。

  • 问题:“水土不服”。即不同环境可能由于依赖版本或配置的不同,导致应用在不同环境的表现不同。如下图所示(JDK 版本不同):
    Docker&容器 介绍

  • 解决方案:在开发环境将应用所依赖的环境和配置一起打包(容器技术),统一流转给测试环境和生产环境。
    Docker&容器 介绍


什么是 Docker ?

Docker&容器 介绍

  • Docker 是一个开源的应用容器引擎。
  • 诞生于 2013 年初,基于 Go 语言实现, dotCloud 公司出品(后改名为 Docker Inc)。
  • Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上。
  • 容器是完全使用沙箱机制,相互隔离。
  • 容器性能开销极低。
  • Docker 从 17.03 版本之后分为 CE(Community Edition: 社区版) 和 EE(Enterprise Edition: 企业版)

Docker 优点

  1. 快速交付应⽤:加快打包时间,加快测试,加快发布,缩短开发及运⾏代码之间的周期。
  2. 复杂环境管理,应⽤隔离:不同软件运⾏环境兼容依赖问题,开发环境/测试环境/线上环境保持⼀致。
  3. 轻量级:对于系统内核来说,⼀个 Docker 容器只是⼀个进程,⼀个系统可以运⾏上千个容器。

Docker 架构与核心概念

Docker&容器 介绍

  • 镜像(Image):Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。

  • 容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和对象一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

  • 仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。


Docker 容器 VS 虚拟机

Docker&容器 介绍

相同点

  • 容器和虚拟机具有相似的资源隔离和分配优势。

不同点

  • 容器与容器之间只是进程的隔离;⽽虚拟机是完全的资源隔离。
  • 虚拟机的启动可能需要分钟级别;容器启动是秒级或者更短。
  • 容器使⽤宿主操作系统的内核,因此只能运行同一类型操作系统;⽽虚拟机使⽤完全独⽴的内核,因此可以运行不同的操作系统。
特性 容器 虚拟机
启动 秒级 分钟级
硬盘使用 一般为 MB 一般为 GB
性能 接近原生 弱于
系统支持量 单机支持上千个容器 一般几十个

Linux 容器详解

什么是 Linux 容器?

Linux 容器是与系统其他部分隔离开的一系列进程,从一个镜像运行起来,并由该镜像提供支持进程所需的全部文件。

  • 容器:将软件打包成标准化单元,以用于开发、交付和部署。
  • 镜像:是轻量的、可执行的独立软件包,包含了应用运行所需的所有内容:代码、运行时环境、系统工具、系统库和设置。

我们通常用集装箱来比喻和表示容器,本来容器的名字也来源于集装箱(Container)。将任何需要的操作系统以及操作系统之上的应用、中间件、数据库等“货物”打包在一起,形成标准的类似集装箱的交付物,可随地运行、随时转移、不依赖底层环境,就像集装箱可以在汽车、火车、轮船上运输一个道理,集装箱中的内容并不会发生改变。

所谓的镜像,就是将你焊好集装箱(Container)的那一刻,将集装箱的状态保存下来,就像孙悟空说:“定”,集装箱里面就定在了那一刻,然后将这一刻的状态保存成一系列文件。这些文件的格式是标准的,谁看到这些文件都能还原当时定住的那个时刻。将镜像还原成运行时的过程(就是读取镜像文件,还原那个时刻的过程)就是容器运行的过程。

镜像包含了应用的所有依赖项,因而在从开发到测试再到生产的整个过程中,它都具有很高的可移植性一致性

所以说,容器赋予了软件独立性,使其免受外在环境差异(例如,开发和预演环境的差异)的影响,从而有助于减少团队间在相同基础设施上运行不同软件时的冲突。

Docker&容器 介绍

更加详细地来说,请您假定您在开发一个应用。您使用的是一台笔记本电脑,而且您的开发环境具有特定的配置。其他开发人员身处的环境配置可能稍有不同。您正在开发的应用依赖于您当前的配置,还要依赖于某些特定文件。与此同时,您的企业还拥有标准化的测试和生产环境,且具有自身的配置和一系列支持文件。

您希望尽可能多地在本地模拟这些环境,而不产生重新创建服务器环境的开销。因此,您要如何确保应用能够在这些环境中运行和通过质量检测,并且在部署过程中不出现令人头疼的问题,也无需重新编写代码和进行故障修复?答案就是使用容器。

容器可以确保您的应用拥有必需的配置和文件,使得这些应用能够在从开发到测试、再到生产的整个流程中顺利运行,而不出现任何不良问题。这样可以避免危机,做到皆大欢喜。

虽然这只是简化的示例,但在需要很高的可移植性、可配置性、隔离性的情况下,我们可以利用 Linux 容器通过很多方式解决难题。无论基础架构是在企业内部还是在云端,或者混合使用两者,容器都能满足大部分需求。


容器不就是虚拟化吗?

是,但也不尽然。容器的本质是对进程的管理,为进程隔离专用资源

虚拟化使得许多操作系统可同时在单个操作系统上运行;容器则可共享同一个操作系统内核,将应用进程与系统其他部分隔离开。

这意味着什么?首先,让多个操作系统在单个虚拟机监控程序上运行以实现虚拟化,并不能达成和使用容器同等的轻量级效果。事实上,在仅拥有有限的资源时,您需要能够可以进行密集部署的轻量级应用。

Linux 容器可从单个操作系统运行,在所有容器中共享该操作系统,因此应用和服务能够保持轻量级,并行快速运行。

Docker&容器 介绍

容器和虚拟机的具体区别:(这里抛开容器装在虚拟机中的特例,只考虑容器直接部署在物理机上)

  1. 两者都需要有物理机(图中 Server)和物理机操作系统(图中 Host OS)的承载。
  2. 虚拟机体系里面的 Hypervisor 是一组程序,这组程序通过 Host OS 操作物理机。Hypervisor 向物理机申请一定量的 CPU、内存、磁盘、网络,然后将这一组资源封装并模拟成一台物理机,通常我们把这个称之为虚拟机(vm)。
    • 用户这时感知不到下层的物理机和 Hypervisor,看上去就是拿到了一台独立的物理机。在这虚拟机上装好操作系统(Guest OS)后,就像使用物理机一样使用虚拟机,在 Guest OS 上安装 App,利用 Guset OS 的 Bins 库和 Libs 库运行 App。
    • 注意关键点,上层的 App 仅能感知到 Guest OS,完全感知不到下面的 Hypervisor 和 Host OS。
  3. 容器体系中的容器引擎也是一组程序,这组程序同样通过 Host OS 操作物理机。容器引擎(图中为 Docker Engine)向物理机申请一定量的 CPU、内存、磁盘、网络,然后将这一组资源封装,至此和虚拟机的动作是相同的。
    • 接下来,容器引擎利用 Host OS 的内核、Libs 库、Bins 库伪装出来一个操作系统,并在这个操作系统里启动至少一个进程(图中是 App)。注意:这里说的是广义上的容器,而不是 docker 或者任何目前流行的具体的容器。现在的这些容器技术,还会加入部分 Guest OS 的 Libs 库和 Bins 库内容,但是不用 guest OS 的内核。所以现在的容器看上去多了一层 Guest OS,更像虚拟机。
    • 注意关键点,上层的 App 实际上使用的是 Host OS 的能力,只是被容器限制了使用 Host OS 的程度,换句话说,被容器限制了通过 Host OS 使用底层物理机的资源程度。
  4. 从本质上讲,虚拟机管理的是物理机资源,划分了物理机资源后提供给 App 使用;容器管理的是进程,启动进程后并限制进程对资源的消耗。前者彻底隔离底层资源,后者仅仅是限制底层资源。
  5. 虚拟机和容器看上去都是对资源的隔离,但是本质上完全不一样。容器发展到 docker 出现后迅速火起来也不是因为容器的资源隔离方式更有优势,节省的一点点资源其实不值一提。

总结:容器不是虚拟化,但是它具备虚拟化的功能

  • 虚拟化是在硬件隔离
  • 容器是共享系统内核,在软件上隔离。容器的启动比虚拟机要快得多。

容器发展简史

“容器”一词 2013 年后才开始火起来,但是容器技术可以追溯的历史很早。以下是从知乎截出来的一张容器关键技术发展时间轴。

Docker&容器 介绍

  1. 早在计算机诞生初期的 unix 系统时代,就有了 chroot 的功能,该功能直到现在也可以在主流 linux 发行版上使用。为单个进程或者一组进程划分独立的目录体系。这种隔离仅仅针对文件系统,计算资源和 I/O 都无法控制。这是容器的鼻祖。
  2. 2007 年谷歌的 Control Groups,即“cgroup”(这是一个命令)可以为进程提供所有资源的隔离,包括 CPU、内存、网络 I/O、磁盘。
  3. 与此同时,LXC 的问世也是具有里程碑意义的。其实 LXC 和 cgroup 某种程度上是一起问世的,LXC 是 cgroup 的 linux 化,也可以理解成为 linux 专门定制的有更多接口和协议支撑的 cgroup。
  4. 最后就是 2013 年 Docker 的横空出世和对传统资源管理方式的降维打击。Docker 是在 LXC 基础上做的全面的封装和创新。

从上述四个里程碑不难看出,容器的本质是对进程的管理,是为进程隔离专用资源。


容器的优缺点

优点

  • “一次构建、处处运行”的可移植性。
  • 启动速度快。
  • 资源占用小。

缺点

  • 资源隔离性不够完全:CPU、内存能被隔离,但文件句柄等资源则无法被隔离,如果一个容器中被放了 fork 炸弹,那么会连带其他容器甚至物理机也会挂掉。
  • 镜像安全无法得到保证:对于非官方镜像无法得知其中的具体修改内容;即使是官方镜像也难以保证无漏洞。
  • 容器本身的优势并不足以把我们说的容器技术推上技术的风口浪尖,容器技术还包括编排,编排本身包含了部署管理、流量层控制、服务发现、资源管理等功能(Docker 在容器之战中取得了绝对优势,但在编排之战中丢失了所有的优势)。

Docker 详解

“Docker” 一词指代多种事物,包括开源社区项目、开源项目使用的工具、主导支持此类项目的公司 Docker Inc. 以及该公司官方支持的工具。技术产品和公司使用同一名称,的确让人有点困惑。

我们来简单说明一下:

IT 软件中所说的 “Docker” :是指容器化技术,用于支持创建和使用 Linux 容器,是一个能够把开发的应用程序自动部署到容器的开源引擎。
开源 Docker 社区:致力于改进这类技术,并免费提供给所有用户,使之获益。
Docker Inc. 公司:凭借 Docker 社区产品起家,它主要负责提升社区版本的安全性,并将改进后的版本与更广泛的技术社区分享。此外,它还专门对这些技术产品进行完善和安全固化,以服务于企业客户。
Docker 是公司名称、是 2013 — 2017 年间最火的容器技术、是容器界的实际行业标准、是 2018 年至今技术人割舍不掉的情怀。

容器起于 Docker,因为 Docker 提出了镜像概念,这是降维打击。当年 Devops 风风火火,如何实践也是众说纷纭。Docker 的横空出世(一次打包多次使用的镜像模式)直击 Devops 实现的痛点。

Docker 以提供镜像打包的创新技术实现了“一次构建、处处运行”的软件交付方式,开启了一个全新的容器时代。借助 Docker ,我们可将容器当做轻量级、模块化的虚拟机使用,同时还获得高度的灵活性,从而实现对容器的高效创建、部署、复制和迁移。

虽然 17 年底 Docker 公司丢掉了编排的市场,拱手让给谷歌 K8S,虽然 K8S 不再支持 Docker,虽然红帽一系列动作整出一堆的容器化标准或者产品,但 Docker 依然还在,大家最习惯的提起容器还是Docker。


Docker 如何工作?

Docker 技术使用 Linux 内核和内核功能(例如 Cgroups 和 Namespaces)来分隔进程,以便各进程相互独立运行。

这种独立性正是采用容器的目的所在:它可以独立运行多种进程、多个应用程序,更加充分地发挥基础设施的作用,同时保持各个独立系统的安全性。

Namespaces:属于 Linux 内核功能,用于隔离文件系统、进程和网络

  • 文件系统隔离:每个容器都有自己的 rootfs 文件系统。
  • 进程隔离:每个容器都运行在自己的进程环境中。
  • 网络隔离:容器间的虚拟网络接口和 IP 地址都是分开的。
  • 资源隔离和分组:使用 cgroups(control group,Linux 的内核特性之一)将 CPU 和内存之类的资源独立分配给每个 Docker 容器。
  • 写时复制:文件系统都是通过写时复制创建的,这就意味着文件系统是分层的、快速的,而且占用的磁盘空间更小。
  • 日志:容器产生的 IO 流都会被收集并记入日志,用来进行日志分析和故障排错。
  • 交互式 shell:用户可以创建一个伪 tty 终端,将其连接到 STDIN,为容器提供一个交互式的 shell。

Docker 技术是否与传统的 Linux 容器相同?

否。Docker 技术最初是基于 LXC 技术构建(大多数人都会将这一技术与传统的 Linux 容器联系在一起),但后来它逐渐摆脱了对这种技术的依赖。

就轻量级和虚拟化的功能来看,LXC 非常有用,但它无法提供出色的开发人员或用户体验。除了运行容器之外,Docker 技术还具备其他多项功能,包括简化用于构建容器、传输镜像以及控制镜像版本的流程。

Docker&容器 介绍

传统的 Linux 容器使用 init 系统来管理多种进程。这意味着,所有应用程序都作为一个整体运行。

与此相反,Docker 技术鼓励应用程序各自独立运行其进程,并提供相应工具以实现这一功能。这种精细化运作模式自有其优势。


Docker 的目标

Docker 的主要目标是“Build, Ship and Run any App, Anywhere”(一次构建,处处运行)。

  • Build(构建镜像):镜像就像是集装箱,包含文件以及运行环境等等资源。
  • Ship(运输镜像):在宿主机和仓库间进行运输,这里的仓库就像是超级码头。
  • Run(运行镜像):运行的镜像就是一个容器,容器就是运行程序的地方。

可以认为镜像是 Docker 生命周期中的构建或打包阶段,容器即启动或执行阶段。

Docker&容器 介绍

综上所述,Docker 的运行过程,也就是去仓库把镜像拉到本地,然后用执行命令把镜像运行起来变成容器,这也就是为什么人们常常将 Docker 称为码头工人或码头装卸工

在没有 Docker 之前,我们需要手动创建容器,这个过程也是容易出错的,而 Docker 可以帮助我们把容器启动自动化,进一步简化了环境部署和配置的过程。当然这种自动化依赖于镜像,Docker 还提供了镜像的注册服务,方便了镜像的共享和分发。

下面这个图可以帮助理解:

Docker&容器 介绍


Docker 核心概念详解

Image(镜像)

Docker 掀起来的技术浪潮,不仅仅因为 Docker 是容器技术,而是因为 Docker 使用了镜像。镜像才是 Docker 降维打击的武器。

Image(镜像)这个词早就在 IT 界为工程师们提供便利。

操作系统的安装利用的就是厂商为大家封装的镜像,自己也可以封装自己定制的镜像做操作系统,此时的镜像针对的是操作系统,定制的也是操作系统。

到了虚拟机时代,镜像的生成、转移和获取则更加的灵活,各种各样的镜像被制作出来。由于制作、分发镜像的成本降低,镜像开始针对中间件,不同功能的镜像被制作出来用于初始化虚拟机。

Docker 的镜像问世后,颠覆了人们对镜像和镜像管理的认知。原来镜像可以针对一行代码、一个进程;镜像可以分层;镜像还可以这样快速地传递分发;镜像可以启动得如此迅速,堪比进程直接启动。于是“一次构建(制作镜像),处处运行(使用镜像启动容器)”的方式终于颠覆了传统的操作系统安装、中间件实施、应用业务部署。

Docker 镜像得成功,主要因为其具有两个特性:

  1. 分层和联合挂载
  2. 写时复制

时势造英雄,还是英雄推动了时代进步?容器技术、联合挂载、写时复制都不是 2013 年被 Docker 创造的技术,这些技术早已存在,但是当这些技术被 Docker 合理利用,恰逢 Devops、敏捷开发这个浪潮,Docker 在技术史上留了浓重一笔。


镜像的分层

镜像是基于联合(Union)文件系统的一种层式的结构,即由文件系统叠加而成的。

无论哪个时期的镜像,都是有逻辑层级的。或许界限没有那么明晰。最底层是内核,向上是库文件和系统命令,再向上是中间件,再向上就是应用(以前物理机时代和虚拟机时代通常是不会把应用,甚至中间件封装进镜像)。

Docker 把这件逻辑上的事情固化了,真的把镜像一层一层的分别存储起来。当需要启动容器的时候,再利用联合挂载的技术把每一层组装起来。

Docker&容器 介绍

Docker 支持通过扩展现有镜像,创建新的镜像。实际上,Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。

Docker&容器 介绍

从上图可以看到,新镜像是从 base 镜像一层一层叠加生成的。每安装一个软件,就在现有镜像的基础上增加一层。

  1. 底层的 bootfs 依赖的是操作系统,不在镜像范围内。
  2. Base Image 中封装的就是想要的操作系统的壳子,其实完全就是依照使用习惯封装的。官方给出的操作系统镜像通常都是最小功能合集,站在 2021 年看容器,最小功能完成工作的理念已经深入人心,很少有人会需要登录进容器进行复杂操作,最小功能是最好的。当然也会有功能比较齐全的 Base Image。
  3. 中间 Image 层通常会实现某个功能,比如 nginx、tomcat、mysql 等,也会有 vi、filebeat 等偏底层的功能。可以加载多个或者一个。也可以把中间件层和 base 层放在一起做成 base 层,这个都看使用习惯,官方建议尽量精细化、单一功能分层。
  4. 当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”(Container Layer),“容器层”之下则称为“镜像层”(Image Layer)。日志、配置文件、代码都在容器层这一层运行,也可以在这一层执行安装中间件的命令,相对都是很灵活的。当然从这一层直接导出镜像也可以得到一个新的 base 镜像,这样的镜像在使用时,又会增加一层新的可写层。

综上可以看到,Docker 的分层只是提供了技术和方法以及最佳实践的建议,具体如何分还是看用户的使用习惯。在日常实际操作中

  • 如果要遵守精细的分层管理,就使用 dockerfile,其中的 RUN 和 ADD 命令产生的中间层会被缓存下来。
  • 如果要打包出来一个个性化的镜像,可以直接在所有工作都完成后,export 出来一个镜像,当然这个镜像会变成私有的基础镜像。

Docker 镜像为什么分层?

  • 镜像分层最大的一个好处就是共享资源。
  • 比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。并且镜像的每一层都可以被共享。
  • 如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是不会被修改的,修改只会被限制在单个容器内。这就是容器 Copy-on-Write (写时复制)特性。

联合挂载

联合挂载技术(Unionfs)从 2004 年就开始活跃,基本理念就是:可以联合多个目录的内容挂载到一个目录中,并且这些目录有独立的内存,可以把只读和可写的文件系统合并起来,并且实现了允许修改只读文件系统的内容,并把这些修改保存在可写文件系统。这个技术早期被用来制作 liveCD,实际上就是 Docker Image 的前身。

Docker 的联合挂载做了一些定制,Image Layer 层全部都是只读层,Container Layer 是读写层。如果联合挂载后有冲突,以上层镜像为准。这种联合挂载的文件系统和普通文件系统在写操作上有本质的不同。

可以想象以下场景:在中间层上安装了 Nginx 和 Apache,启动容器后发现 apache 没有用,如果直接执行删除操作并导出镜像,会减小镜像大小吗?实际上并不会。在 Container 层的删除,实际上只是标记这个目录不能使用,然后联合文件系统看不到该 Apache 目录,但是底层的 Apache 目录并没有被删除(这个特性决定了,尽量不要在容器上做配置的修改)。

联合挂载是分层的技术基础,同时保证了底层镜像不被改动,所有的改动都仅体现在容器启动后的容器层上。当容器销毁后,镜像依然是原始的样子(除非在容器中做了容器的导出或者提交动作)。


写时复制

写时复制(Copy-on-Write)简单来说,文件可以被只读加载而不需要被复制,只有需要更改的时候才复制一份数据。

对于容器来说:

  • Image 可以被多个容器只读加载共享,而不需要复制。
  • 容器层下面的所有镜像层都是只读的,只有容器层是可写的,所有对容器的改动无论添加、删除、还是修改文件都只会发生在容器层中。
  • 容器层保存的是镜像变化的部分,不会对镜像本身进行任何修改。因此每一个 Container Layer 的变化不会影响到其他容器。

容器层的细节说明

  • 镜像层数量可能会很多,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件 比如 /a,那么上层的 /a 会覆盖下层的 /a,也就是说用户只能访问到上层中的文件 /a。在容器层中,用户看到的是一个叠加之后的文件系统。

Docker&容器 介绍


镜像总结

Docker 镜像优点

  • 写时复制加上镜像分层,极大降低了容器整体的磁盘使用率。

  • 写时复制加上联合挂载,理论上可以将整个 Image 缓存进机器内存,保证容器迅速启动。

思考

  • Docker 镜像本质是什么?
    • 是一个分层文件系统
  • Docker 中一个 centos 镜像为什么只有 200MB,而一个 centos 操作系统的 iso 文件要几个 G ?
    • Centos 的 iso 镜像文件包含 bootfs 和 rootfs,而 docker 的 centos 镜像复用操作系统的 bootfs,只有 rootfs 和其他镜像层
  • Docker 中一个 tomcat 镜像为什么有 500MB,而一个 tomcat 安装包只有 70 多 MB ?
    • 由于 docker 中镜像是分层的,tomcat 虽然只有 70 多 MB,但他需要依赖于父镜像和基础镜像,所有整个对外暴露的 tomcat 镜像大小 500 多 MB 。

Registry(仓库)

仓库(Repository)是集中存放镜像文件的场所。

注意,仓库(Repository)和仓库注册服务器(Registry)是有区别的。仓库注册服务器(Registry)上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。

仓库又分为公开仓库(Public)和私有仓库(Private)两种形式。

最大的公开仓库是 Docker Hub,是 Dokcer 公司运营的公共 Registry 服务,里面存放了数量庞大的镜像供用户下载。

  • 用户仓库:由 Dokcer 用户创建和发布的。
  • 顶层仓库:由 Dokcer 公司及认可的供应商共同维护的。

国内的公开仓库则包括阿里云、网易云等。

相关文章:

  • 2021-06-16
  • 2021-05-01
  • 2021-11-05
  • 2021-04-30
  • 2021-10-23
  • 2021-11-23
  • 2022-01-02
猜你喜欢
  • 2021-05-05
  • 2021-11-07
  • 2021-09-03
  • 2021-08-07
  • 2021-12-02
  • 2021-10-18
相关资源
相似解决方案