Docker(四)进阶:Docker镜像概述和分层原理

目录

  • 前言
  • 一、Docker镜像概述
    • 1、镜像是什么?
    • 2、如何获取镜像?
  • 二、Docker镜像加载原理
    • 1、UnionFs 联合文件系统
    • 2、Docker镜像加载原理
      • 1)base镜像
      • 2)bootfs
      • 3)rootfs
  • 三、分层原理
    • 1、思考:为什么Docker镜像采用分层的结构呢?
    • 2、Copy-on-Write(COW)
    • 3、理解
    • 4、特点
  • 四、Commit镜像
    • 1、作用
    • 2、格式:
    • 3、可选项:
    • 4、说明:
    • 5、测试
      • 1)提交一个容器
      • 2)提交一个新配置的容器
      • 3)实战测试

前言

学习本文需要一些了解Docker的概念以及一些名词。
个人网站:https://linzyblog.netlify.app/

一、Docker镜像概述

1、镜像是什么?

镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时的库、环境变量和配置文件。

镜像是一个只读模板,带有创建Docker容器的说明。通常,一个镜像基于另一个镜像,并带有一些额外的定制。例如,您可以构建一个基于ubuntu镜像的镜像,但是要安装Apache web服务器和您的应用程序,以及运行应用程序所需的配置细节。

Docker 镜像(Image),就相当于是一个 模板,其中包含创建 Docker 容器的说明,可以通过模板来创建容器服务,通过这个镜像我们可以创建多个容器,最终服务运行或项目运行都是在容器中的。

2、如何获取镜像?

你可以创建自己的镜像,也可以只使用其他人创建并在Docker Hub中发布的镜像。要构建自己的镜像,需要创建一个Dockerfile,使用简单的语法定义创建和运行镜像所需的步骤。Dockerfile中的每一条指令都会在图像中创建一个层。当你更改Dockerfile并重新构建镜像时,只有那些已经更改的层才会重新构建。与其他虚拟化技术相比,这是镜像如此轻量级、小巧和快速的原因之一。

  • 从Docker Hub上拉取镜像(常用)
  • 自己制作镜像 Dockerfile 创建
  • 从别人那边拷贝一份

二、Docker镜像加载原理

1、UnionFs 联合文件系统

Docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统被称为UnionFS。

  • Union文件系统(UnionFs)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下,而且目录的物理位置是分开的。

  • Union文件系统可以把只读和可读写文件系统合并在一起,具有Copy-on-Write功能,允许只读文件系统的修改可以保存到可写文件系统当中。

  • Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统回包含所有底层的文件和目录。

2、Docker镜像加载原理

1)base镜像

base 镜像简单来说就是不依赖其他任何镜像,完全从0开始建起,其他镜像都是建立在他的之上,可以比喻为大楼的地基,docker镜像的鼻祖。

base 镜像的特性:
(1)不依赖其他镜像,从 scratch 构建。
(2)其他镜像可以之为基础进行扩展。

所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等。

我们以 CentOS 为例查看 base 镜像包含哪些内容。
Docker(四)进阶:Docker镜像概述和分层原理_第1张图片

提问:docker cnetos的镜像大小200多M,和平时的所用的发行版的大小(几G)相差很大,为什么?

Linux 操作系统由内核空间和用户空间组成。

  1. 内核空间是 kernel,Linux 刚启动时会加载 bootfs 文件系统,之后 bootfs 会被卸载掉。
  2. 用户空间的文件系统是 rootfs,包含我们熟悉的 /dev, /proc, /bin 等目录。

Docker(四)进阶:Docker镜像概述和分层原理_第2张图片

对于 base 镜像来说,底层直接用 Host 的 kernel,自己只需要提供 rootfs 就行了
而对于一个精简的 OS,rootfs 可以很小,只需要包括最基本的命令、工具和程序库就可以了。相比其他 Linux 发行版,CentOS 的 rootfs 已经算臃肿的了,alpine 还不到 10MB。

由此可见对于不同的Linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs。

我们平时安装的 CentOS 除了 rootfs 还会选装很多软件、服务、图形桌面等,需要好几个 GB 就不足为奇了。

base 镜像提供的是最小安装的 Linux 发行版。

2)bootfs

bootfs(boot file system):主要包含 bootloader 和 kernel。

  • bootloader 主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs,这一层与我们典型的Linux/Unix系统是一样的,包含bootfs加载器和内核。当bootfs加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。

3)rootfs

rootfs(root file system):在bootfs之上,包含类似于典型Linux系统中的/dev,/proc,/bin,/etc等标准目录文件。

  • rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等。

三、分层原理

参考文章:https://blog.51cto.com/wzlinux/2044797

Docker Hub 中 99% 的镜像都是通过在 base 镜像中安装和配置需要的软件构建出来的。比如我们现在构建一个新的镜像,Dockerfile 如下:

# Version: 0.0.1
FROM debian               1.新镜像不再是从 scratch 开始,而是直接在 Debian base 镜像上构建。
MAINTAINER wzlinux
RUN apt-get update && apt-get install -y emacs        2.安装 emacs 编辑器。
RUN apt-get install -y apache2             3.安装 apache2。
CMD ["/bin/bash"]              4.容器启动时运行 bash。

构建过程:

Docker(四)进阶:Docker镜像概述和分层原理_第3张图片

可以看到,Docker镜像都起始于一个基础镜像层,新镜像是从 Base 镜像一层一层叠加生成的。
当进行修改或增加新的内容时,就会在当前镜像层上,创建新的镜像层。

1、思考:为什么Docker镜像采用分层的结构呢?

  1. 分层最大的优点是共享资源
  2. 多个镜像都可以基于相同的 Base 镜像构建而来,那么宿主机只需在磁盘上保存一份base 镜像即可。
  3. 同时内存中也只需要加载一份 Base 镜像,就可以为所有容器服务,而且镜像的每一层都可以被共享。

如果多个容器共享一份基础镜像,当某个容器修改了基础镜像的内容,比如 /etc 下的文件,这时其他容器的 /etc 是否也会被修改?
答案是不会!
修改会被限制在单个容器内。
这就是我们接下来要说的容器 Copy-on-Write(COW) 特性。

  1. 新数据会直接存放在最上面的容器层。
  2. 修改现有数据会先从镜像层将数据复制到容器层,修改后的数据直接保存在容器层中,镜像层保持不变。
  3. 如果多个层中有命名相同的文件,用户只能看到最上面那层中的文件。

2、Copy-on-Write(COW)

Copy-on-write 是一种共享和复制文件以实现最大效率的策略。当我们试图读取一个文件时,Docker 会从上到下一层层去找这个文件,找到的第一个就是我们的文件,所以下面层相同的文件就被“覆盖”了。
而修改就是当我们找到这个文件时,将它“复制”到读写层并修改,这样读写层的文件就是我们修改后的文件,并且“覆盖”了镜像中的文件了。这最大限度地减少了 I/O 和每个后续层的大小。而删除就是创建了一个特殊的 whiteout 文件,这个 whiteout 文件覆盖的文件即表示删除了。

3、理解

这是一个三层的镜像分层结构图,在外部看整个镜像只有6个文件,app2.0 是 app1.0的更新版。

Docker(四)进阶:Docker镜像概述和分层原理_第4张图片

在这种情况下,上层镜像层中的文件会覆盖底层镜像层的文件。这样就使得文件的更新版本作为新镜像层添加到镜像中。

Docker 通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。

  • 存储引擎的选择文档:https://docs.docker.com/storage/storagedriver/select-storage-driver/

Linux 上可用存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及 ZFS。顾名思义,每种存储引擎都基于 Linux 中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。

Docker 在 Windows 上仅支持 Windowsfilter 一种存储引擎,该引擎基于 NTFS 文件系统之上实现了分层和COW。

Docker(四)进阶:Docker镜像概述和分层原理_第5张图片

4、特点

Docker 镜像都是只读的,当你创建一个新的容器时,你会在基础层之上添加一个新的可写层,该层通常都称为 容器层

对正在运行的容器所做的所有更改,例如写入新文件、修改现有文件和删除文件,都被写入这个可写的容器层。

下图显示了基于ubuntu:15.04图像的容器。
Docker(四)进阶:Docker镜像概述和分层原理_第6张图片
存储引擎处理有关这些层相互交互方式的详细信息。有不同的存储引擎可用,它们在不同的情况下各有优缺点。

四、Commit镜像

1、作用

将容器提交后,创建为一个新的镜像,命令与git原理类似。

2、格式:

 docker commit [OPTIONS] 容器id [目标镜像名[:TAG]]

3、可选项:

名称,简写 默认 描述
–author,-a 作者
–change,-c 将 Dockerfile 指令应用于创建的镜像
–message,-m 提交的描述消息
–pause,-p true 提交期间暂停容器

4、说明:

将容器的文件更改或设置后创建为新镜像。这允许您通过运行交互式shell调试容器,或者将工作数据集导出到另一个服务器。一般来说,最好使用Dockerfiles以文档化和可维护的方式来管理映像。

提交操作将不包括容器内挂载的卷中包含的任何数据。

默认情况下,正在提交的容器及其进程将在映像提交时暂停。这减少了在创建提交过程中遇到数据损坏的可能性。如果不希望出现这种行为,请将 --pause 选项设置为false。

–change选项将对所创建的映像应用Dockerfile指令。
支持的Dockerfile指令:CMD | ENTRYPOINT | ENV | EXPOSE | LABEL | ONBUILD | USER | VOLUME | WORKDIR

5、测试

1)提交一个容器

docker ps 找到一个新的容器,用commit命令提交一个容器,新增了一个命名为commit/test的镜像 tag为test1.0,用docker images查看本地镜像是否成功提交了。
Docker(四)进阶:Docker镜像概述和分层原理_第7张图片

2)提交一个新配置的容器

用docker inspect命令查看容器的环境变量
在这里插入图片描述

提交一个新配置的容器,新增了一个命名为commit/test的镜像 tag为test2.0,跟上一个例子区分

Docker(四)进阶:Docker镜像概述和分层原理_第8张图片

3)实战测试

  1. 拉取并启动一个tomcat:9.0的镜像。

Docker(四)进阶:Docker镜像概述和分层原理_第9张图片

  1. 我们用docker exec命令进入tomcat 容器中,官方默认的tomcat镜像时没有 webapps 应用,需要将webapps.dist目录下的基本文件拷贝到webapps目录下。

Docker(四)进阶:Docker镜像概述和分层原理_第10张图片

  1. 验证tomcat,访问http://localhost:8088/

Docker(四)进阶:Docker镜像概述和分层原理_第11张图片

  1. 将操作过后的tomcat容器提交为一个镜像,下次用的时候直接运行这个修改后的tomcat镜像即可。

Docker(四)进阶:Docker镜像概述和分层原理_第12张图片

你可能感兴趣的:(Docker入门到精通,docker,学习,容器,运维,云原生)