OverlayFS(Overlay File System)是一种联合文件系统,它允许将多个目录挂载到同一个虚拟文件系统下。这种机制在容器技术中非常重要,因为它支持以层的形式来构建和管理容器的文件系统。
层叠式结构:OverlayFS 允许通过叠加多个目录(称为“层”)来创建一个单一的、统一的视图。这些层是只读的,除了最顶层外,可以进行写操作。
高效的存储和速度:通过共享底层的只读层,OverlayFS 可以高效地管理存储空间,同时还提供了良好的读取性能。
写时复制(Copy-on-Write, CoW):在进行写操作时,OverlayFS 会复制被修改的文件到最上层的可写层中,以此保持底层的不变性。
Lower Layer:这是只读层,通常用于存储容器图像的基本文件和目录。在 containerd 中,这包括基础镜像和其它层。
Upper Layer:这是可写层,所有对文件系统的更改(如文件修改、新增、删除)都在这一层上进行。在 containerd 中,这对应于容器的可写层。
Merge Layer:
这是一个虚拟的文件系统层,它将上层和下层整合到一起,提供一个统一的文件系统视图。当从容器内部访问文件时,实际上是通过这个合并层访问的。
Work Layer:这是 OverlayFS 所需的一个技术性目录,用于存放临时文件。这个层是 OverlayFS 实现 CoW 机制的关键部分。
每个容器都使用 OverlayFS。当启动一个新容器时,会为其创建一个新的 Upper Layer。所有对容器的更改都会保存在这个层中,而不会影响到原始镜像的 Lower Layer。这样,多个容器可以共享同一个基础镜像,同时保持它们各自的改动,从而实现了高效的存储和快速的部署。
OverlayFS 的这种设计非常适合容器化的环境,它提供了一种轻量级、高效和灵活的方式来管理容器的文件系统。
root@go:/tmp# ROOTDIR=$(mktemp -d)
root@go:/tmp# cd $ROOTDIR
root@go:/tmp/tmp.wVpBziRnQE# mkdir upper lower merged work
root@go:/tmp/tmp.wVpBziRnQE# echo "from lower" > lower/in_lower.txt
root@go:/tmp/tmp.wVpBziRnQE# echo "from upper" > upper/in_upper.txt
root@go:/tmp/tmp.wVpBziRnQE# echo "Ifrom lower" > lower/in_both.txt
root@go:/tmp/tmp.wVpBziRnQE# echo "from upper" > upper/in_both.txt
root@go:/tmp/tmp.wVpBziRnQE#
root@go:/tmp/tmp.wVpBziRnQE# mount -t overlay overlay -o lowerdir=lower,upperdir=upper,workdir=work merged
root@go:/tmp/tmp.wVpBziRnQE# mount | grep overlay
overlay on /tmp/tmp.wVpBziRnQE/merged type overlay (rw,relatime,lowerdir=lower,upperdir=upper,workdir=work)
root@go:/tmp/tmp.wVpBziRnQE# tree
.
├── lower
│ ├── in_both.txt
│ └── in_lower.txt
├── merged
│ ├── in_both.txt
│ ├── in_lower.txt
│ └── in_upper.txt
├── upper
│ ├── in_both.txt
│ └── in_upper.txt
└── work
└── work
5 directories, 7 files
### 所有的文件已经被合并到 merged 目录了,in_lower.txt文件来自lower目录,in_upper.txt文件来自upper目录,in_both.txt文件来自upper目录(覆盖了lower目录中的同名文件)
root@go:/tmp/tmp.wVpBziRnQE# cat merged/in_both.txt
from upper
root@go:/tmp/tmp.wVpBziRnQE# cat merged/in_lower.txt
from lower
root@go:/tmp/tmp.wVpBziRnQE# cat merged/in_upper.txt
from upper
root@go:/tmp/tmp.wVpBziRnQE#
root@go:/tmp/tmp.wVpBziRnQE# ls -Rl
.:
总用量 16
drwxr-xr-x 2 root root 4096 12月 4 14:36 lower
drwxr-xr-x 1 root root 4096 12月 4 14:36 merged
drwxr-xr-x 2 root root 4096 12月 4 14:36 upper
drwxr-xr-x 3 root root 4096 12月 4 14:37 work
./lower:
总用量 8
-rw-r--r-- 1 root root 12 12月 4 14:36 in_both.txt
-rw-r--r-- 1 root root 11 12月 4 14:36 in_lower.txt
./merged:
总用量 12
-rw-r--r-- 1 root root 11 12月 4 14:36 in_both.txt
-rw-r--r-- 1 root root 11 12月 4 14:36 in_lower.txt
-rw-r--r-- 1 root root 11 12月 4 14:36 in_upper.txt
./upper:
总用量 8
-rw-r--r-- 1 root root 11 12月 4 14:36 in_both.txt
-rw-r--r-- 1 root root 11 12月 4 14:36 in_upper.txt
./work:
总用量 4
d--------- 2 root root 4096 12月 4 14:37 work
./work/work:
总用量 0
root@go:/tmp/tmp.wVpBziRnQE# echo 'new file' > merged/new_file
root@go:/tmp/tmp.wVpBziRnQE# tree
.
├── lower
│ ├── in_both.txt
│ └── in_lower.txt
├── merged
│ ├── in_both.txt
│ ├── in_lower.txt
│ ├── in_upper.txt
│ └── new_file
├── upper
│ ├── in_both.txt
│ ├── in_upper.txt
│ └── new_file
└── work
└── work
5 directories, 9 files
root@go:/tmp/tmp.wVpBziRnQE# rm -f merged/in_both.txt
root@go:/tmp/tmp.wVpBziRnQE# tree
.
├── lower
│ ├── in_both.txt
│ └── in_lower.txt
├── merged
│ ├── in_lower.txt
│ ├── in_upper.txt
│ └── new_file
├── upper
│ ├── in_both.txt
│ ├── in_upper.txt
│ └── new_file
└── work
└── work
└── #14
5 directories, 9 files
root@go:/tmp/tmp.wVpBziRnQE# ls -l upper/*
c--------- 2 root root 0, 0 12月 4 14:44 upper/in_both.txt
-rw-r--r-- 1 root root 11 12月 4 14:36 upper/in_upper.txt
-rw-r--r-- 1 root root 9 12月 4 14:42 upper/new_file
root@go:/tmp/tmp.wVpBziRnQE# ls -l work/work/*
c--------- 2 root root 0, 0 12月 4 14:44 work/work/#14
root@go:/tmp/tmp.wVpBziRnQE# cat upper/in_both.txt
cat: upper/in_both.txt: 没有那个设备或地址
root@go:/tmp/tmp.wVpBziRnQE# cat work/work/#14
cat: work/work/#14: 没有那个设备或地址
root@go:/tmp/tmp.wVpBziRnQE# echo "modify lower" >> merged/in_lower.txt
root@go:/tmp/tmp.wVpBziRnQE# tree
.
├── lower
│ ├── in_both.txt
│ └── in_lower.txt
├── merged
│ ├── in_lower.txt
│ ├── in_upper.txt
│ └── new_file
├── upper
│ ├── in_both.txt
│ ├── in_lower.txt
│ ├── in_upper.txt
│ └── new_file
└── work
└── work
└── #14
5 directories, 10 files
root@go:/tmp/tmp.wVpBziRnQE# cat lower/in_lower.txt
from lower
root@go:/tmp/tmp.wVpBziRnQE# cat merged/in_lower.txt
from lower
modify lower
root@go:/tmp/tmp.wVpBziRnQE# cat upper/in_lower.txt
from lower
modify lower
root@go:/tmp# nerdctl run -d nginx:alpine
8ff29698fb69b0723146cc7d122d159bf74c26f5c53fc694d5c76e9488a6fc54
root@go:/tmp# nerdctl ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8ff29698fb69 docker.io/library/nginx:alpine "/docker-entrypoint.…" 30 seconds ago Up nginx-8ff29
root@go:/tmp# mount | grep 8ff29
overlay on /run/containerd/io.containerd.runtime.v2.task/default/8ff29698fb69b0723146cc7d122d159bf74c26f5c53fc694d5c76e9488a6fc54/rootfs type overlay (rw,relatime,lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/20/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/19/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/18/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/17/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/16/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/15/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/14/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/9/fs,upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/22/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/22/work)
写时复制(Copy-on-Write,简称 CoW) 是一种计算机编程中的优化策略,广泛应用于文件系统、程序内存管理等领域。在容器技术和特别是 OverlayFS 文件系统中,CoW 扮演着关键角色。以下是 CoW 机制的主要特点和工作原理:
节省资源:通过仅在必要时复制数据,CoW 能有效减少不必要的数据复制,从而节约存储空间和提高性能。
延迟复制:CoW 机制不会在数据被共享时立即进行复制。相反,它会等到数据被修改时才进行复制,这样可以减少对存储的需求和提高效率。
保持一致性:CoW 保证在复制过程中,任何读取操作都能获得一致且未修改的数据视图。
在 OverlayFS 和容器技术中,CoW 机制通常如下工作:
共享数据:在最初,容器共享基础镜像中的文件和数据,这些都是只读的。
修改请求:当容器内的进程尝试修改某个文件时,这个文件原本存在于只读层(Lower Layer)。
触发 CoW:OverlayFS 会在这一时刻触发 CoW 机制。它不是在只读层修改文件,而是将文件复制到可写层(Upper Layer)。
写入更改:容器内的进程实际上是对这个新复制的文件版本进行修改,而不影响原始文件。
保留改动:这些更改保存在容器的 Upper Layer 中,使得基础镜像(Lower Layer)保持不变。
文件系统:在文件系统中,CoW 能减少对磁盘空间的需求,特别是在文件系统快照和备份的场景下。
内存管理:在程序的内存管理中,CoW 用于优化内存的分配和使用,特别是在虚拟内存和分页机制中。
容器技术:在 Docker 等容器技术中,CoW 允许多个容器共享相同的基础镜像,同时维护各自的改动,从而提高了存储效率和容器启动的速度。
CoW 是一种高效的数据管理策略,它通过仅在实际需要时复制数据,来优化资源使用和提高系统性能。
Containerd是如何存放容器镜像和数据的–overlayfs
理解容器文件系统OverlayFS
How containers work: overlayfs