父镜像、子镜像、AUFS、UFS之间的关系、基础镜像

Docker 到底为什么这么快!?
两句话回答这个问题:

轻量级虚拟化,性能损耗小
AUFS文件系统分层设计,将资源利用率玩到极致
原理冗长,但很有意思,感兴趣请继续。

1、轻量级虚拟化技术
一句话,一张图说明问题。

Docker虚拟化技术是基于容器化,容器化技术的本质其实是基于内核资源调度的再分配! 并不是什么新技术,只是近年Linux内核更加成熟,在资源调度隔离更成熟,所以容器化技术再被提上议程。

比起传统 KVM,VMware 在磁盘上划分区域,虚拟操作系统的方式,性能不知道提升了多少倍。

虚拟化技术

2、Docker Imagae 镜像到底是什么?
两句话回答问题:

所有父层Image中的数据信息、ID、网络、LXC管理的资源调度、具体的Container配置等,称为 Docker 概念上的 Container 。即 Image 镜像其实也是容器!
要从一个Image启动一个容器,其实是Docker从顺序加载父Image到Base Image的过程. 用户的进程也是运行在Writeable文件系统层。
仓库 -> 镜像 -> 容器 被认为是容器的完整生命周期。从仓库下载镜像,基于镜像创建容器,在容器上运行我们的应用,这是我们绝大多数人对容器和镜像的认知。那么容器和镜像有什么关系,下面这个试验可能会刷新你对容器的认知深度!

2.1、小试验:docker images为什么删除失败?
一句话回答问题:Docker Image 其实也是容器,是基于其运行容器的父容器。删除时会判断是否有子容器依赖

试验内容如下:
我们安装一个nginx容器,stop 容器后,尝试直接删除Image 镜像,看看会有什么结果。

下载安装nginx容器并启动
[root@O2O-T-K8S-TEST4 ~]# docker run -dt nginx /bin/sh
Unable to find image ‘nginx:latest’ locally
Trying to pull repository docker.io/library/nginx …
latest: Pulling from docker.io/library/nginx
123275d6e508: Pull complete
6cd6a943ce27: Pull complete
a50b5ac4a7fb: Pull complete
Digest: sha256:d81f010955749350ef31a119fb94b180fde8b2f157da351ff5667ae037968b28
Status: Downloaded newer image for docker.io/nginx:latest
be89d49cace9294db10b1255ce9f3226f1a7505bdb84596f595dd4c06ffb0232
[root@O2O-T-K8S-TEST4 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
be89d49cace9 nginx “/bin/sh” 26 seconds ago Up 25 seconds 80/tcp objective_williams
stop 容器
[root@O2O-T-K8S-TEST4 ~]# docker stop be89d49cace9
be89d49cace9
【删除失败】 直接删除 Nginx Image
[root@O2O-T-K8S-TEST4 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker.io/nginx latest e791337790a6 3 days ago 127 MB
You have new mail in /var/spool/mail/root
[root@O2O-T-K8S-TEST4 ~]# docker rmi e791337790a6
Error response from daemon: conflict: unable to delete e791337790a6 (must be forced) - image is being used by stopped container be89d49cace9
报错了!Nginx的容器存在,无法删除镜像! 这是什么呢?还记得我们的容器是STOP状态吗?

【删除成功】 先删除容器,再删除Nginx Image
[root@O2O-T-K8S-TEST4 ~]# docker rm be89d49cace9
be89d49cace9
[root@O2O-T-K8S-TEST4 ~]# docker rmi e791337790a6
Untagged: docker.io/nginx:latest
Untagged: docker.io/nginx@sha256:d81f010955749350ef31a119fb94b180fde8b2f157da351ff5667ae037968b28
Deleted: sha256:e791337790a6181d5ce870b3bb16de1a4d5aa3a916e8fba6907f57eb409934cf
Deleted: sha256:615a169a3412634ebf75d5f0f5162290fb6042ba36285bd0ddc9ee123165b95e
Deleted: sha256:bd32d67adcec3dba661c5afebc8a2a5413e68a3283b5ad7df134ed86f00b380a
Deleted: sha256:b60e5c3bcef2f42ec42648b3acf7baf6de1fa780ca16d9180f3b4a3f266fe7bc
这个试验说明Image和Container是有依赖关系的。究其源头,要从Docker的AUFS文件系统说起,而AUFS是UnionFS联合文件系统的一种衍生版本。

哈,很多新名词,莫着急,我们下面会逐步了解

2.2、什么是UnionFS
Union File System,简称UnionFS ,是一种为 Linux, FressBSD和NetBSD操作系统设计的,把多个文件系统联合挂载到一个挂载点的文件系统技术。

敲黑板,下面讲的每句话,每个字都特别重要!特别重要!特别重要!

其核心技术是:它使用branch把不同文件系统的文件和目录“透明”覆盖,形成一个单一的文件系统。外部对该文件系统执行写操作时,系统并未真正改变readonly权限的的系统,而是写入到有read-write权限的系统,即原来的文件没有改变。

联合文件系统,是Docker镜像技术的基础,一种轻量级的高性能分层文件系统,支持将文件系统中的修改进行提交和层层叠加。该特性有利于镜像通过分层实现继承,同时支持将不同目录挂载到同一虚拟文件系统下。

即Docker镜像分为基础镜像和父镜像,没有父镜像的统称为基础镜像。

用户基于基础镜像制作不同的应用镜像。这些应用镜像共享同一个基础镜像,提高存储效率。

用户针对镜像的操作,通常会在新建镜像层进行,其基础镜像并不会改变。使用PhotoShop的同学会更容易理解,很像新建图层。

AUFS是UnionFS的一种。

Docker目前支持的联合文件系统包括AUFS、Btrfs、VSF、DeviceMapper、overlay、overlay2。

2.3、各发行版 UnionFS 的实现
Linux各发行版实现的UnionFS各不相同,所以Docker在不同linux发行版中使用的也不同。通过docker info可以查看docker使用的是哪种UnionFS:

CentOS, Storage Driver: overlay2
debain, Storage Driver: aufs
2.4、AUFS简介
如下内容摘自 COOLSHELL
AUFS又叫Another UnionFS,后来叫Alternative UnionFS,后来可能觉得不够霸气,叫成Advance UnionFS。是个叫Junjiro Okajima(岡島順治郎)在2006年开发的,AUFS完全重写了早期的UnionFS 1.x,其主要目的是为了可靠性和性能,并且引入了一些新的功能,比如可写分支的负载均衡。AUFS在使用上全兼容UnionFS,而且比之前的UnionFS在稳定性和性能上都要好很多,后来的UnionFS 2.x开始抄AUFS中的功能。但是他居然没有进到Linux主干里,就是因为Linus不让,基本上是因为代码量比较多,而且写得烂(相对于只有3000行的union mount和10000行的UnionFS,以及其它平均下来只有6000行代码左右的VFS,AUFS居然有30000行代码),所以,岡島不断地改进代码质量,不断地提交,不断地被Linus拒掉,所以,到今天AUFS都还进不了Linux主干(今天你可以看到AUFS的代码其实还好了,比起OpenSSL好N倍,要么就是Linus对代码的质量要求非常高,要么就是Linus就是不喜欢AUFS)。

Docker使用AUFS就是一种联合文件系统。简单讲**“支持将不同目录挂载到同一虚拟文件系统下的文件系统”**。其思想也是借鉴 Linux 启动。

Linux的启动到运行需要两个文件系统: BootFS 和 RootFS.

BootFS
BootFS主要包括BootLoader和Kernel。BootLoader主要引导加载Kernel,当Boot成功后,Kernel被加载到内存中BootFS就被Umount了。

RootFS
RootFS包含了典型Linux中的/dev、/proc、/bin等标准目录和文件。

不同的Linux发行版,BootFS基本一致,但RootFS可能会有差异。

Linux启动后,先将RootFS置为Readonly,检查结束后切换为Readwrite供用户使用。

Docker也是利用该技术,Union Mount在Readonly的RootFS系统上挂载Readwrite文件系统。并且向上叠加,使一组Readonly和Readwrite的结构构成一个Container的运行目录。每层被称为一个文件系统Layer。

镜像
敲黑板了哦!镜像究竟是什么,埋伏了这么多,这里终于经神龙现身了!!

AUFS的特性,使得每个针对Readonly层文件/目录的修改都只会存在于上层的Writeable层中,这样不存在竞争,且多个Container可以共享Readonly文件系统层 。在 Docker 中,将Readonly层称为镜像层.

对于Container整体而言,整个RootFS是read-write,但事实上所有修改都写入的是上层的writeable 层, image 并不保存用户状态。

通常,上层的image依赖下层的image, 因此, Docker 通常把下层的image称为父镜像, 没有父镜像的image称为Base Image.

容器的启动
因此,要从一个Image启动一个容器,其实是Docker从顺序加载 父Image到Base Image的过程. 用户的进程也是运行在Writeable文件系统层。

所有父层Image中的数据信息、ID、网络、LXC管理的资源调度、具体的Container配置等,称为 Docker 概念上的 Container .

讲到这里,终于结束了。那么你已经懂了吧?^^

3、参考
https://docs.docker.com/storage/storagedriver/overlayfs-driver/ https://coolshell.cn/articles/17061.html

我们通常会以一个镜像为基础,在其上进行定制,这就是基础镜像。

就像运行了一个 nginx 镜像的容器,再进行修改一样。在DockerFile中基础镜像是必须指定的 (FROM 就是指定 基础镜像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令)

比如构建一个Java应用的镜像,选择一个Oracle JDK的镜像作为基础镜像比选择一个alpine镜像作为基础镜像更方便。

都有哪些
在 Docker Hub 上有非常多的高质量的官方镜像,可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。

有应用镜像,如 nginx、redis、mongo、mysql、httpd、php、tomcat 等;

有方便开发、构建、运行各种语言应用的编程语言镜像,如 node、oraclejdk,openjdk、python、ruby、golang 等。

还有更为基础的操作系统镜像,如 ubuntu、debian、centos、fedora、alpine 等,这些操作系统的软件库为我们提供了更广阔的扩展空间。

除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。

如果你在DockerFIle中以 scratch 为基础镜像的话(FROM scratch),意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,比如 swarm、coreos/etcd。对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 FROM scratch 会让镜像体积更加小巧。使用 Go 语言 开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 Go 是特别适合容器微服务架构的语言的原因之一。
————————————————
版权声明:本文为CSDN博主「无数_mirage」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43413788/article/details/108162920

おすすめ

転載: blog.csdn.net/qq_36657175/article/details/121395142