Docker 镜像读写层核心概念:rootfs、Union mount、image以及layser原理详解

这篇具有很好参考价值的文章主要介绍了Docker 镜像读写层核心概念:rootfs、Union mount、image以及layser原理详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Docker 镜像读写层核心概念:rootfs、Union mount、image以及layser原理详解

rootfs

Rootfs: 代表一个 Docker Container 在启动时(而非运行后)其内部进程可见的文件系统视角,或者是 Docker Container 的根目录。当然,该目录下含有 Docker Container 所需要的系统文件、工具、容器文件等。

Docker 镜像读写层核心概念:rootfs、Union mount、image以及layser原理详解,Kubernetes,docker,容器,运维

上面这张图展示了Linux系统中的两个重要的文件系统。

  • bootfs 是指 Linux 系统启动时使用的文件系统,**通常包含操作系统内核、启动加载程序和其他引导文件。**Linux 刚启动时会加载 bootfs 文件系统,在Docker 镜像的最底层是引导文件系统 bootfs。这一层与我们典型的 Linux/Unix 系统是一样的,包含 boot 加载器和内核。当 boot 加载完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs 转交给内核,此时系统也会卸载 bootfs。
  • rootfs 是指 Linux 系统的根文件系统,是系统的主要文件系统,包含所有的文件和目录,比如典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件rootfs 是一个虚拟的文件系统,它由内核挂载并提供给用户空间。在 Linux 系统启动时,内核会将 rootfs 挂载为根文件系统,并将其作为所有其他文件系统的基础。

在Docker镜像中,镜像是由不同的镜像层堆叠而成的,我们常说镜像层都是只读的,容器层是可写的。当容器启动时,一个新的可写层被加载到镜像的顶部。 这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。所有对容器的改动,无论添加、删除、还是修改文件都只会发生在容器层中。

Docker 镜像读写层核心概念:rootfs、Union mount、image以及layser原理详解,Kubernetes,docker,容器,运维

如何理解这句话,背后的原理是什么呢?为什么要这样设计的呢?

传统来说,Linux 操作系统内核启动时,内核首先会挂载一个只读(read-only)的 rootfs,当系统检测其完整性之后,决定是否将其切换为读写(read-write)模式,或者最后在 rootfs 之上另行挂载一种文件系统并忽略 rootfs。 Docker 架构下,依然沿用 Linux 中 rootfs 的思想。当 Docker Daemon 为 Docker Container 挂载 rootfs 的时候,与传统 Linux 内核类似,将其设定为只读(read-only)模式。在 rootfs 挂载完毕之后,和 Linux 内核不一样的是,Docker Daemon 没有将 Docker Container 的文件系统设为读写(read-write)模式,而是利用 Union mount 的技术,在这个只读的 rootfs 之上再挂载一个读写(read-write)的文件系统,挂载时该读写(read-write)文件系统内空无一物。

Docker 镜像读写层核心概念:rootfs、Union mount、image以及layser原理详解,Kubernetes,docker,容器,运维

正如 read-only 和 read-write 的含义那样,该容器中的进程对 rootfs 中的内容只拥有读权限,对于 read-write 读写文件系统中的内容既拥有读权限也拥有写权限。容器虽然只有一个文件系统,但该文件系统由“两层”组成,分别为读写文件系统和只读文件系统。

Union mount

Union mount: 代表一种文件系统挂载的方式,允许同一时刻多种文件系统挂载在一起,并以一种文件系统的形式,呈现多种文件系统内容合并后的目录。

一般情况下,通过某种文件系统挂载内容至挂载点的话,挂载点目录中原先的内容将会被隐藏。而 Union mount 则不会将挂载点目录中的内容隐藏,反而是将挂载点目录中的内容和被挂载的内容合并,并为合并后的内容提供一个统一独立的文件系统视角。 通常来讲,被合并的文件系统中只有一个会以读写(read-write)模式挂载,而其他的文件系统的挂载模式均为只读(read-only)。 实现这种 Union mount 技术的文件系统一般被称为 Union Filesystem,较为常见的有 UnionFS、AUFS、OverlayFS 等。

Docker 镜像读写层核心概念:rootfs、Union mount、image以及layser原理详解,Kubernetes,docker,容器,运维

假设,在我们使用镜像 ubuntu 创建的容器中,可以暂且将该容器整个 rootfs 当成是一个文件系统。上文也提到,挂载时读写(read-write)文件系统中空无一物。既然如此,从用户视角来看,容器内文件系统和 rootfs 完全一样,用户完全可以按照往常习惯,无差别的使用自身视角下文件系统中的所有内容;然而,从内核的角度来看,两者在有着非常大的区别。追溯区别存在的根本原因,那就不得不提及 AUFS 等文件系统的 COW(copy-on-write)特性。

COW 文件系统和其他文件系统最大的区别就是:从不覆写已有文件系统中已有的内容。 由于通过 COW 文件系统将两个文件系统(rootfs 和 read-write filesystem)合并,最终用户视角为合并后的含有所有内容的文件系统,然而在 Linux 内核逻辑上依然可以区别两者,那就是用户对原先 rootfs 中的内容拥有只读权限,而对 read-write filesystem 中的内容拥有读写权限。

既然对用户而言,全然不知哪些内容只读,哪些内容可读写,这些信息只有内核在接管,那么假设用户需要更新其视角下的文件 /etc/hosts,而该文件又恰巧是 rootfs 只读文件系统中的内容,内核是否会抛出异常或者驳回用户请求呢?答案是否定的。当此情形发生时,COW 文件系统首先不会覆写 read-only 文件系统中的文件,即不会覆写 rootfs 中 /etc/hosts,其次反而会将该文件拷贝至读写文件系统中,即拷贝至读写文件系统中的 /etc/hosts,最后再对后者进行更新操作。 如此一来,纵使 rootfs 与 read-write filesystem 中均由 /etc/hosts,诸如 AUFS 类型的 COW 文件系统也能保证用户视角中只能看到 read-write filesystem 中的 /etc/hosts,即更新后的内容。

当然,这样的特性同样支持 rootfs 中文件的删除等其他操作。例如:用户通过 apt-get 软件包管理工具安装 Golang,所有与 Golang 相关的内容都会被安装在读写文件系统中,而不会安装在 rootfs。此时用户又希望通过 apt-get 软件包管理工具删除所有关于 MySQL 的内容,恰巧这部分内容又都存在于 rootfs 中时,删除操作执行时同样不会删除 rootfs 实际存在的 MySQL,而是在 read-write filesystem 中删除该部分内容,导致最终 rootfs 中的 MySQL 对容器用户不可见,也不可访。

了解了上面容器启动时的rootfs和文件挂载方式,我们不禁要发出疑问,即为什么docker要将容器这样设计?在只读层上添加一个读写层的意义在哪儿?去掉读写层的话会有什么问题?

为什么镜像层都是只读的

  1. 在Docker镜像的设计中,一个镜像是由多个镜像层堆叠而成的。这样设计的好处是之一是有利于镜像层的复用,从而节省存储空间。而可复用就要保证某个镜像的容器在运行中,对该镜像层是不能修改的,也就是只有当镜像层是只读的条件时,才能保证多个容器可以同享某些镜像层。
  2. 提高应用程序的可移植性。由于容器层是可写的,容器中的应用程序可以在容器内部进行读写操作,而不会影响到宿主机的文件系统。这样就可以使应用程序更加容易地移植到不同的环境中。

去掉读写层的话会有什么问题

如果在没有可写层的情况下,那么容器对内部文件的任何更改操作都会直接影响到底层镜像层的内容。举个例子来说,假设我们有一个基于Ubuntu操作系统的Docker镜像,并且该镜像中已经包含了一个名为/etc/nginx/nginx.conf的Nginx配置文件。现在,我们使用该镜像启动了一个容器,并在容器中修改了/etc/nginx/nginx.conf文件,将默认的Nginx欢迎页面修改为自定义的欢迎页面。如果这个容器使用的是没有可写层的配置,那么对/etc/nginx/nginx.conf文件的修改会直接影响到镜像层中的该文件,从而影响到所有基于该镜像构建的容器。也就是说,所有从这个镜像启动的容器都将使用这个自定义的欢迎页面。

这种情况下,如果仍然将镜像层共享复用的话,就会导致以该本地nginx镜像层为基础创建的其他容器下的/etc/nginx/nginx.conf也被修改为自定义的欢迎页,从而对其他镜像造成了影响。

为此,为了避免容器对镜像层内容的影响,通常都会使用可写层。可写层提供了一个可写的文件系统,容器中的任何更改都会被记录在可写层中,而不会直接影响到镜像层的内容。这种设计可以实现容器与镜像的分离,容器层中的任何更改都不会影响到原始镜像的内容。

掌握 Docker 中 rootfs 以及 Union mount 的概念之后,再来理解 Docker 镜像,就会变得水到渠成。

Docker镜像image

Docker 中 rootfs 的概念,起到容器文件系统中基石的作用。对于容器而言,其只读的特性,也是不难理解。神奇的是,实际情况下 Docker 的 rootfs 设计与实现比上文的描述还要精妙不少。

继续以 ubuntu 为例,虽然通过 AUFS 可以实现 rootfs 与 read-write filesystem 的合并,但是考虑到 rootfs 自身接近 200MB 的磁盘大小,如果以这个 rootfs 的粒度来实现容器的创建与迁移等,是否会稍显笨重,同时也会大大降低镜像的灵活性。而且,若用户希望拥有一个 ubuntu 的 rootfs,那么是否有必要创建一个全新的 rootfs,毕竟 ubuntu 和 ubuntu 的 rootfs 中有很多一致的内容。

Docker 中 image 的概念,非常巧妙的解决了以上的问题。最为简单的解释 image,就是 Docker 容器中只读文件系统 rootfs 的一部分。换言之,实际上 Docker 容器的 rootfs 可以由多个 image 来构成。多个 image 构成 rootfs 的方式依然沿用 Union mount 技术。

Docker 镜像读写层核心概念:rootfs、Union mount、image以及layser原理详解,Kubernetes,docker,容器,运维

多个 Image 构成 rootfs 的示意图。图中,rootfs 中每一层 image 中的内容划分只为了阐述清楚 rootfs 由多个 image 构成,并不代表实际情况中 rootfs 中的内容划分。

从上图可以看出,举例的容器 rootfs 包含 4 个 image,其中每个 image 中都有一些用户视角文件系统中的一部分内容。4 个 image 处于层叠的关系,除了最底层的 image,每一层的 image 都叠加在另一个 image 之上。另外,每一个 image 均含有一个 image ID,用以唯一的标记该 image。

基于以上的概念,Docker Image 中又抽象出两种概念:Parent Image 以及 Base Image。除了容器 rootfs 最底层的 image,其余 image 都依赖于其底下的一个或多个 image,而 Docker 中将下一层的 image 称为上一层 image 的 Parent Image。imageID_0 是 imageID_1 的 Parent Image,imageID_2 是 imageID_3 的 Parent Image,而 imageID_0 没有 Parent Image。对于最下层的 image,即没有 Parent Image 的镜像,在 Docker 中习惯称之为 Base Image。

通过 image 的形式,原先较为臃肿的 rootfs 被逐渐打散成轻便的多层。Image 除了轻便的特性,同时还有上文提到的只读特性,如此一来,在不同的容器、不同的 rootfs 中 image 完全可以用来复用。

多 image 组织关系与复用关系如图下图(图中镜像名称的举例只为将 image 之间的关系阐述清楚,并不代表实际情况中相应名称 image 之间的关系):

Docker 镜像读写层核心概念:rootfs、Union mount、image以及layser原理详解,Kubernetes,docker,容器,运维

Docker镜像层layer

Docker 术语中,layer 是一个与 image 含义较为相近的词。容器镜像的 rootfs 是容器只读的文件系统,rootfs 又是由多个只读的 image 构成。于是,rootfs 中每个只读的 image 都可以称为一层 layer。

除了只读的 image 之外,Docker Daemon 在创建容器时会在容器的 rootfs 之上,再 mount 一层 read-write filesystem,而这一层文件系统,也称为容器的一层 layer,常被称为 top layer。

因此,总结而言,Docker 容器中的每一层只读的 image,以及最上层可读写的文件系统,均被称为 layer。如此一来,layer 的范畴比 image 多了一层,即多包含了最上层的 read-write filesystem。

有了 layer 的概念,大家可以思考这样一个问题:容器文件系统分为只读的 rootfs,以及可读写的 top layer,那么容器运行时若在 top layer 中写入了内容,那这些内容是否可以持久化,并且也被其它容器复用?

上文对于 image 的分析中,提到了 image 有复用的特性,既然如此,再提一个更为大胆的假设:容器的 top layer 是否可以转变为 image?

答案是肯定的。Docker 的设计理念中,top layer 转变为 image 的行为(Docker 中称为 commit 操作),大大释放了容器 rootfs 的灵活性。Docker 的开发者完全可以基于某个镜像创建容器做开发工作并且无论在开发周期的哪个时间点,都可以对容器进行 commit,将所有 top layer 中的内容打包为一个 image,构成一个新的镜像。 Commit 完毕之后,用户完全可以基于新的镜像,进行开发、分发、测试、部署等。不仅 docker commit 的原理如此,基于 Dockerfile 的 docker build,其核心的思想,也是不断将容器的 top layer 转化为 image。

Docker 镜像下载

Docker Image 作为 Docker 生态中的精髓,下载过程中需要 Docker 架构中多个组件的协作。Docker 镜像的下载流程如图:

Docker 镜像读写层核心概念:rootfs、Union mount、image以及layser原理详解,Kubernetes,docker,容器,运维

1、docker client发送镜像的tag到registry。
2、registry根据镜像tag,得到镜像的manifest文件,返回给docker client。
3、docker client拿到manifest文件后,根据其中的config的digest,也就是image ID,检查下镜像在本地是否存在。
4、如果镜像不存在,则下载config文件,并根据config文件中的diff_ids得到镜像每一层解压后的digest。
5、然后根据每层解压后的digest文件,检查本地是否存在,如果不存在,则通过manifest文件中的6、layer的digest下载该层并解压,然后校验解压后digest是否匹配。
7、下载完所有层后,镜像就下载完毕。

Docker 镜像存储

Docker Daemon 执行镜像下载任务时,从 Docker Registry 处下载指定镜像之后,仍需要将镜像合理地存储于宿主机的文件系统中。更为具体而言,存储工作分为两个部分:

(1) 存储镜像内容;

(2) 在 graph 中注册镜像信息。

说到镜像内容,需要强调的是,每一层 layer 的 Docker Image 内容都可以认为有两个部分组成镜像中每一层 layer 中存储的文件系统内容,这部分内容一般可以认为是未来 Docker 容器的静态文件内容;另一部分内容指的是容器的 json 文件,json 文件代表的信息除了容器的基本属性信息之外,还包括未来容器运行时的动态信息,包括 ENV 等信息。

存储镜像内容,意味着 Docker Daemon 所在宿主机上已经存在镜像的所有内容,除此之外,Docker Daemon 仍需要对所存储的镜像进行统计备案,以便用户在后续的镜像管理与使用过程中,可以有据可循。为此,Docker Daemon 设计了 graph,使用 graph 来接管这部分的工作。graph 负责记录有哪些镜像已经被正确存储,供 Docker Daemon 调用。文章来源地址https://www.toymoban.com/news/detail-736020.html

到了这里,关于Docker 镜像读写层核心概念:rootfs、Union mount、image以及layser原理详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Docker Image(镜像)

    Docker image 本质上是一个 read-only 只读文件,这个文件包含了文件系统、源码、库文件、依赖、工具等一些运行 application 所必须的文件。我们可以把 Docker image 理解成一个模板, 可以通过这个模板实例化出来很多容器。 image 里面是一层层文件系统 Union FS。联合文件系统,可以

    2024年01月25日
    浏览(23)
  • Docker导入导出Image镜像

    要导出 Docker 镜像,可以按照下面的步骤进行操作: 在终端中输入以下命令来列出所有本地镜像: 可以找到你想要导出的镜像,复制它的 REPOSITORY 和 TAG 。 输入以下命令来导出镜像: 其中 your-image-name.tar 是你要导出的镜像的名称。 your-repository 和 your-tag 分别是上一步中复制

    2024年02月07日
    浏览(31)
  • 【云原生 | Docker篇】Docker镜像(image)与服务

    镜像是Docker的三大组件之一。 Docker运行容器前需要本地存在对应的镜像,如果本地不存在,Docker会从镜像仓库下载。 下面主要从以下几个方面来了解docker镜像: 从仓库获取镜像 管理本地仓库的镜像 Docker命令使用 获取命令行帮助信息直接在命令行内输入docker命令后敲回车

    2024年02月02日
    浏览(29)
  • 【加速排坑】docker设置国内image镜像源

    第零步,查看阿里最新的镜像源:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors 第一步:在 /etc/docker/daemon.json 中添加镜像源 第二步:重启docker 到此就ok了,我们可以查一下docker的镜像源是否加载成功: 倒数第几行显示为: 常见错误:添加的镜像源不可用,比如中科大USTC的

    2024年01月17日
    浏览(48)
  • K8S Containerd导入Docker image镜像

    Kubernetes在v1.20 版本宣布弃用 Dockershim (在v1.24正式移除),改用CRI接口去操作更为基础的containerd或CRI-O。 K8S在创建容器时,或多或少有些镜像无法正常拉取(网络等原因)。 还在使用 Docker Engine 时我们能方便的pull第三方同步的镜像,然后tag成需要的标签版本,让K8S从本地获

    2024年02月11日
    浏览(30)
  • 【Docker】虚悬镜像(Dangling Image)介绍和处理方法

    虚悬镜像 (Dangling Image) 指的是仓库名 (镜像名) 和标签 TAG 都是 none 的镜像。如下图所示。 在实际开发中,在构建或者删除镜像时出错会有一定概率出现虚悬镜像。虚悬镜像在实际开发中产生概率不高,然而,一旦虚悬镜像生成,就可能对你的系统造成一些潜在的风险。因此,

    2024年02月06日
    浏览(27)
  • Docker基本操作之删除容器Container和删除镜像IMAGE

    1.1 删除容器Container语法 1.2 删除容器Container 操作 删除容器Container使用docker rm 命令,例如删除mysql容器: 1.3 docker ps docker ps 语法: docker ps 各个参数的说明: 2.1 删除镜像IMAGE语法 删除镜像IMAGE使用 docker rmi 命令,例如删除 mysql 镜像: 2.2 docker images 各个参数的说明: 2.3 强制删

    2024年02月14日
    浏览(31)
  • 【玩转Docker小鲸鱼叭】理解Docker的核心概念

    在 什么是虚拟化技术? 一文中,我们对虚拟机和 Docker 都有了简单的了解,需要的小伙伴可以自行跳转回顾~ Docker与传统虚拟化技术有什么区别? Docker 相比传统的虚拟机技术更轻量级,它可以将应用程序打包成容器镜像,每个容器都具有自己的应用程序和系统依赖,并共享

    2024年02月10日
    浏览(36)
  • 【云原生 | Docker】Docker核心概念 & 应用上手最佳流程

    🤵‍♂️ 个人主页: @AI_magician 📡主页地址: 作者简介:CSDN内容合伙人,全栈领域优质创作者。 👨‍💻景愿:旨在于能和更多的热爱计算机的伙伴一起成长!!🐱‍🏍 🙋‍♂️声明:本人目前大学就读于大二,研究兴趣方向人工智能硬件(虽然硬件还没开始玩,但一直

    2024年02月03日
    浏览(30)
  • 【Docker系列】Docker-核心概念/常用命令与项目部署实践

      Docker是一种开源的容器化技术,它允许开发者将应用程序及其依赖项打包到一个轻量级、可移植的容器中,从而实现快速部署和高效运行。Docker的核心概念包括镜像、容器、仓库等。本文将详细介绍Docker的基本概念、安装方法以及常用命令。 介绍3个基础概念: 镜像(Ima

    2024年02月11日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包