OverlayFS

OverlayFS

OverlayFS(Overlay File System)是一种联合文件系统,它允许将多个目录挂载到同一个虚拟文件系统下。这种机制在容器技术中非常重要,因为它支持以层的形式来构建和管理容器的文件系统。

关键特性

  1. 层叠式结构:OverlayFS 允许通过叠加多个目录(称为“层”)来创建一个单一的、统一的视图。这些层是只读的,除了最顶层外,可以进行写操作。

  2. 高效的存储和速度:通过共享底层的只读层,OverlayFS 可以高效地管理存储空间,同时还提供了良好的读取性能。

  3. 写时复制(Copy-on-Write, CoW):在进行写操作时,OverlayFS 会复制被修改的文件到最上层的可写层中,以此保持底层的不变性。

工作原理

  1. Lower Layer:这是只读层,通常用于存储容器图像的基本文件和目录。在 containerd 中,这包括基础镜像和其它层。

  2. Upper Layer:这是可写层,所有对文件系统的更改(如文件修改、新增、删除)都在这一层上进行。在 containerd 中,这对应于容器的可写层。

  3. Merge Layer:
    这是一个虚拟的文件系统层,它将上层和下层整合到一起,提供一个统一的文件系统视图。当从容器内部访问文件时,实际上是通过这个合并层访问的。

  4. 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# 

  • 挂载 Overlay
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 124 14:36 lower
drwxr-xr-x 1 root root 4096 124 14:36 merged
drwxr-xr-x 2 root root 4096 124 14:36 upper
drwxr-xr-x 3 root root 4096 124 14:37 work

./lower:
总用量 8
-rw-r--r-- 1 root root 12 124 14:36 in_both.txt
-rw-r--r-- 1 root root 11 124 14:36 in_lower.txt

./merged:
总用量 12
-rw-r--r-- 1 root root 11 124 14:36 in_both.txt
-rw-r--r-- 1 root root 11 124 14:36 in_lower.txt
-rw-r--r-- 1 root root 11 124 14:36 in_upper.txt

./upper:
总用量 8
-rw-r--r-- 1 root root 11 124 14:36 in_both.txt
-rw-r--r-- 1 root root 11 124 14:36 in_upper.txt

./work:
总用量 4
d--------- 2 root root 4096 124 14:37 work

./work/work:
总用量 0

  • 创建新文件
    在 merged 目录中创建一个文件,会发现新建的文件出现在读写层的 upper 目录。
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

  • 删除文件
    删除 merged 目录中的 in_both.txt 文件,lower 目录里的 in_both.txt 文件不变,upper 目录中的文件in_both.txt 变成了一个特殊文件,标记其被删除
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 124 14:44 upper/in_both.txt
-rw-r--r-- 1 root root   11 124 14:36 upper/in_upper.txt
-rw-r--r-- 1 root root    9 124 14:42 upper/new_file
root@go:/tmp/tmp.wVpBziRnQE# ls -l work/work/*
c--------- 2 root root 0, 0 124 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: 没有那个设备或地址

  • 修改文件
    修改 merged 目录中的 in_lower.txt,会在upper目录中新建一个 in_lower.txt 文件包含新的内容。
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

  • containerd
    可以看到容器镜像的各层挂载为 overlayfs 的 lowerdir,可读写层挂载为 overlayfs 的 upperdir,最终联合挂载合并呈现的目录为 /run/containerd/io.containerd.runtime.v2.task/default/8ff29698fb69b0723146cc7d122d159bf74c26f5c53fc694d5c76e9488a6fc54/rootfs 为容器的 rootfs。
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)

CoW

写时复制(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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值