Docker分层结构:UnionFS下的Image Layers与Writable Layer
Author:zhoulujun Date:
Docker 镜像的分层结构
Docker 镜像采用联合文件系统(UnionFS)来实现分层存储(Layered Storage),由多个只读层(Image Layers)组成,每一层都代表了一次更改,比如安装软件、复制文件等。
镜像层(Image Layers)
Layer 3: 应用代码 (COPY app /app)
Layer 2: 依赖安装 (RUN pip install -r requirements.txt)
Layer 1: 基础镜像 (FROM python:3.9)
可写层(Writable Layer,容器运行时创建)
因为每一层都是只读的,但上层镜像可以在此基础上添加或修改文件。
节省存储空间:多个镜像可以共享相同的 Base 镜像层。
加速构建:如果 Base 镜像已下载,构建时无需重新下载。
其是,docker每一层都是一个文件系统的快照。这些层是堆叠在一起的,最终形成一个完整的文件系统。每一层只包含与上一层相比发生变化的部分,这种设计使得镜像的构建和共享更加高效。
可写层
当运行容器时,Docker 会在镜像之上添加一个可写层(Writable Layer)。所有对容器的修改(写入、删除等)都会发生在这一层,而不会影响底层的镜像层。
写时复制(Copy-on-Write, CoW):如果容器需要修改一个只读层中的文件,Docker 会先将该文件复制到可写层,然后在可写层中进行修改。原始镜像层保持不变。
临时性:容器的可写层是临时的,容器停止后,可写层的数据通常会被删除(除非使用卷或持久化存储)。
容器的可写层与镜像的只读层隔离,确保镜像的不可变性。
UnionFS 的核心概念
UnionFS 通过**层(Layers)**的概念来管理数据,主要包括以下层级:
底层(Lower Layers):只读层,不能修改,通常是 Docker 镜像的基础层。
上层(Upper Layer):可写层,允许写入数据(可写层)。
联合挂载(Union Mount):所有层被合并为一个文件系统视图。
核心特性
联合挂载:多个层联合后,表现为一个整体的文件系统。
写时复制(Copy-on-Write, CoW):修改文件时,会先复制一份到可写层。
增量存储:修改不会影响底层,只存储变化部分,节省存储空间。
UnionFS(联合文件系统)本身是一个概念,而不是具体的存储驱动。
目前 docker 支持的联合文件系统有很多种,包括:AUFS、overlay、overlay2、DeviceMapper、VSF等。
存储驱动 | 内核要求 | 是否支持多层 | 性能 | 适用场景 |
---|---|---|---|---|
AUFS | 仅部分 Linux | ✅ | 中等 | 早期 Docker,已被淘汰 |
overlay | ≥3.18 | ❌(仅两层) | 较高 | 早期使用,已被 overlay2 替代 |
overlay2 | ≥4.0 | ✅ | 高 | 推荐,适用于现代 Linux 发行版 |
DeviceMapper | 适用于 CentOS/RHEL | ✅ | 低 | 特殊存储需求,如 LVM 配置 |
VFS | 无特殊要求 | ❌ | 低 | 仅用于测试环境 |
Linux 中各发行版实现的 UnionFS 各不相同,所以 docker 在不同 linux 发版中使用的也不同。
通过 docker info 命令可以查看当前系统所使用的是哪种 UnionFS
常见的几种 UnionFS 的 Storage Driver 发行版如下:
CentOS 系统中:overlay2、overlay
debain 系统中:aufs
RedHat 系统中:devicemapper
Union Mount
Union Mount 联合挂载系统,是一种文件系统叠加技术,它允许将多个只读文件系统叠加在一起,形成一个新的只读或可读写的容器文件系统。
UnionFS,即联合文件系统,是一种特殊的文件系统技术;而Union Mount代表一种文件系统挂载方式
UnionFS是实现Union Mount技术的文件系统之一,也可以选择 Aufs(Another Union File System)、mhddfs、Unionfs-FUSE、MergerFS
UnionFS的写时复制、分层和复用等特性,使得Union Mount能够高效地管理多个文件系统的内容。通过Union Mount,用户可以在不改变原始文件系统的前提下,对文件进行创建、修改和删除等操作,这些操作都会被反映到UnionFS的可写层中。
与一般的挂载方式不同,Union Mount不会隐藏挂载点目录中原先的内容,而是将挂载点目录中的内容和被挂载的内容合并,并为合并后的内容提供一个统一独立的文件系统视角。
Union Mount 主要有两个作用:
可以将多个只读文件系统合并成一个只读或可读写的文件系统。 在 Docker 中,这意味着可以将多个只读的镜像层级结构叠加在一起,形成一个可读写的容器文件系统。
可以将一个文件系统作为另一个文件系统的 “补丁”,即只保留被更改的文件,并在需要时覆盖被更改的文件。这样可以减少存储空间的占用,并提高文件系统的性能。
在 Docker 中,Union Mount 技术被用于实现 Docker 镜像的分层存储和容器的文件系统。
每个 Docker 镜像都由多个只读层级结构组成,这些层级结构可以使用 Union Mount 技术叠加在一起,形成一个可读写的容器文件系统。当容器中的文件被更改时,Docker 只需要在容器文件系统的顶层层级结构中进行更改,而不是在底层的只读层级结构中进行更改。这样可以保证 Docker 镜像的不可变性,并且可以更快地更新和部署容器。
以 CentOS 发行版的 overlay2 文件系统为例:
https://docs.docker.com/storage/storagedriver/overlayfs-driver/
镜像层
Base 镜像是最底层,base 镜像有两层含义:
不依赖其他镜像,从 scratch 构建。
其他镜像可以之为基础进行扩展。
scratch 镜像
scratch 镜像是 Docker 的空白镜像:完全为空,不包含任何文件或依赖——它不基于任何其他镜像构建,只包含了Docker容器运行所必需的最小文件系统和执行环境。这意味着它不包含任何额外的组件、库或操作系统,因此镜像体积非常小。
Scratch镜像非常适合用于构建轻量级容器化应用程序,因为它不包含任何不必要的组件或库,从而减小了镜像的大小和传输时间。这对于需要快速部署和启动的应用程序尤为重要。
最小化镜像大小: 由于 scratch 镜像没有任何基础系统,因此基于它构建的镜像会非常小。这对于部署资源有限的环境或需要快速传输镜像的场景非常有益。
最大化控制: 使用 scratch 镜像可以让你完全控制镜像中的内容,避免引入不必要的依赖。这对于安全性要求高的场景非常重要。
优化性能: 由于镜像更小,启动速度也会更快。
busybox镜像
busybox 镜像与scratch 镜像不同,他是一种非常特殊的 base 镜像。它是一个极简的Linux系统,包含了最常用的Linux命令,比如cat、ls、cp等。
对比项 | BusyBox | Scratch |
---|---|---|
大小 | ~1MB | 0MB (完全空) |
基础结构 | 轻量级 Linux 发行版,提供常用 Unix 工具 | 纯空白镜像,无任何内容 |
包管理 | opkg (可选) | 无包管理 |
是否包含 Shell | 是 (sh 可用) | 否 (无 Shell) |
是否包含 libc | 是 (musl libc ) | 否 (无标准库) |
是否可运行动态链接程序 | 是 (支持 musl 动态链接) | 否 (需要静态编译) |
适用场景 | 需要极小 Linux 发行版但仍需要 Shell 和基本命令 | 适用于完全静态编译的 Go、Rust、C/C++ 应用 |
应用方式 | 可以用作轻量级系统环境,如小型服务、工具镜像 | 适用于无依赖的纯二进制文件,通常用于 Go/Rust 应用 |
运行方式 | 可以直接运行 BusyBox 作为 Shell 或执行命令 | 只能运行静态编译的二进制文件,无 Shell 无工具 |
总结就是:
BusyBox 是一个极简 Linux 发行版,包含 sh 和 musl 库,适用于需要极简环境但仍需要基本工具的场景。
Scratch 是完全空白的镜像,没有 Shell、库或任何文件,通常用于静态编译的二进制应用,如 Go 或 Rust。
base镜像
Docker Base 镜像是指只包含操作系统的最小文件系统和必要的工具的镜像。
它是 Docker 镜像分层架构的核心组成部分,作为构建其他镜像的基础:大多数Docker镜像都是基于一个Base镜像构建的,通过在Base镜像上添加额外的软件和配置,可以创建出各种特定用途的镜像。同时,
提供最小化的运行环境:Base镜像提供了一个最小的、可运行的Linux环境,这对于需要严格控制资源使用或确保环境一致性的应用来说非常重要。
精简性:Base镜像只包含运行容器所需的最基本元素,这使得它们非常小巧,便于快速部署和传输。
独立性:Base镜像不依赖其他镜像,可以直接从scratch构建,也可以作为其他镜像的基础进行扩展。
共享性:由于Base镜像的精简性,多个容器可以共享同一个Base镜像,从而节省存储空间和资源。
常见 Base 镜像对比
Base 镜像 | 大小 | 包管理器 | 特点 | 适用场景 |
---|---|---|---|---|
Alpine | ~5MB | apk | 极小体积,安全性高,启动快,默认无 glibc | 适用于微服务、无依赖的小型应用 |
Debian | ~25MB+ | apt | 兼容性好,稳定性高,社区活跃 | 适用于大多数通用应用 |
Ubuntu | ~29MB+ | apt | 生态丰富,软件包多,易用性高 | 适用于开发环境或完整功能的应用 |
CentOS | ~200MB+ | yum | 兼容 RHEL,稳定性高,但体积较大 | 适用于企业级应用或与 RHEL 兼容的项目 |
Fedora | ~150MB+ | dnf | 最新技术,滚动更新 | 适用于测试前沿技术的应用 |
BusyBox | ~1MB | 无或 opkg | 极致轻量级,功能精简 | 适用于超轻量级应用或嵌入式系统 |
Distroless | 10MB+ | 无 | 无包管理器,最小化攻击面 | 适用于高安全性、无 shell 应用 |
Scratch | 0MB | 无 | 纯空镜像,只能基于它构建静态编译应用 | 适用于完全自包含的二进制应用 |
需要注意的是,base镜像只是用户空间和发行版一致。kernel使用的是docker宿主机器的kernel。例如 CentOS 7 使用 3.x.x 的 kernel,如果 Docker Host 是 Ubuntu 16.04(比如我们的实验环境),那么在 CentOS 容器中使用的实际是是 Host 4.x.x 的 kernel。
docker镜像分类:
空白基础镜像(如Scratch):几乎不包含任何内容,适合完全静态链接的应用程序。
轻量级操作系统镜像(如Alpine Linux):提供包管理系统和其他必要组件,同时保持较小的体积。
标准操作系统镜像(如Ubuntu、CentOS):包含完整的操作系统环境,适用于需要完整操作系统的场景。
特定用途的基础镜像(如Python、Node.js官方镜像):预装了特定语言的运行时和开发工具。
转载本站文章《Docker分层结构:UnionFS下的Image Layers与Writable Layer》,
请注明出处:https://www.zhoulujun.cn/html/tools/Virtual/docker/9478.html