Docker&容器 介绍


初识 Docker

问题现象

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

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

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


什么是 Docker ?

image

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

Docker 优点

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

Docker 架构与核心概念

image

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

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

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


Docker 容器 VS 虚拟机

image

相同点

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

不同点

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

Linux 容器详解

什么是 Linux 容器?

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

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

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

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

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

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

image

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

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

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

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


容器不就是虚拟化吗?

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

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

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

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

image

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

  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 年后才开始火起来,但是容器技术可以追溯的历史很早。以下是从知乎截出来的一张容器关键技术发展时间轴。

image

  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 技术还具备其他多项功能,包括简化用于构建容器、传输镜像以及控制镜像版本的流程。

image

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

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


Docker 的目标

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

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

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

image

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

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

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

image


Docker 核心概念详解

Image(镜像)

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

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

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

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

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

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

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

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


镜像的分层

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

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

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

image

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

image

从上图可以看到,新镜像是从 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。在容器层中,用户看到的是一个叠加之后的文件系统。

image


镜像总结

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 公司及认可的供应商共同维护的。

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

posted @ 2022-01-18 12:43  Juno3550  阅读(203)  评论(0编辑  收藏  举报