一、先搞懂两个核心概念:snapshotter和两种存储格式

很多刚接触容器的朋友,一听到“snapshotter”就懵,其实它本质就是容器的“临时文件管家”——容器跑起来时,需要把镜像拆成一层一层的文件,再给容器加一层自己的临时修改层,snapshotter就是专门管这些层怎么存、怎么拼、怎么删的工具。 而我们常说的overlay2和btrfs,是两种不同的“文件存储格式”,就像你电脑里的NTFS和FAT32,各有各的特点,适合不同的场景。 先给大家说个基础背景:容器的文件系统是“联合挂载”的,简单说就是把镜像的只读层(比如系统文件、软件包)和容器的可写层(比如你临时改的配置、生成的日志)拼在一起,给容器用。snapshotter的作用,就是帮我们高效管理这些层,避免浪费空间。

二、先搞懂overlay2:最通用的“临时文件管家”

2.1 overlay2的核心逻辑

overlay2是目前容器最常用的snapshotter,它的逻辑特别简单:给每个容器建两个文件夹,一个是“只读层目录”(存镜像的所有层),一个是“可写层目录”(存容器自己改的内容),最后把这两个目录拼起来,给容器用。 举个例子:你用CentOS镜像启动一个容器,镜像里有/bin/bash(只读),容器里你改了/etc/resolv.conf(加了DNS),overlay2会把镜像的所有层(比如CentOS的系统文件)放在只读目录,把你改的resolv.conf放在可写目录,容器用的时候,会先找可写目录的文件,没有再找只读目录的。

2.2 overlay2的优缺点

优点:

  • 兼容性极强:几乎所有的Linux发行版(CentOS、Ubuntu、Debian)都支持,不用额外装软件;
  • 速度快:因为逻辑简单,读写性能和本地文件差不多;
  • 空间省:多个容器用同一个镜像时,只读层是共享的,不会重复存,比如10个CentOS容器,只读层只存一次; 缺点:
  • 不支持“写时复制(COW)”的高级特性:比如你要给一个大文件(比如10G的数据库备份)做快照,overlay2会直接复制整个文件,浪费空间;
  • 不能当持久化存储用:容器删了,可写层的内容就没了,适合临时用的场景。

2.3 overlay2的适用场景

所有“临时运行、不需要持久化数据”的容器,比如:

  • 测试用的临时容器:比如你要测试一个新的Python脚本,启动一个Python容器,跑完就删;
  • 无状态服务容器:比如Nginx(只要配置文件是持久化的,容器本身的临时内容没用)、API服务(数据存在数据库里,容器只是处理请求);
  • 批量任务容器:比如批量处理日志的容器,跑完就删,不需要存结果。

三、再搞懂btrfs:带“高级功能”的存储管家

3.1 btrfs的核心逻辑

btrfs是一种“高级文件系统”,自带COW(写时复制)、快照、压缩、子卷等功能,所以用btrfs当snapshotter时,容器的镜像层和可写层都是btrfs的“子卷”。 简单说:btrfs的子卷就像“独立的文件夹”,但比普通文件夹更灵活——你可以给子卷做快照(瞬间复制,不占空间),可以压缩子卷的内容(省空间),可以把多个子卷拼在一起(联合挂载)。 举个例子:你用CentOS镜像启动一个容器,btrfs会把镜像的只读层做成一个子卷,把容器的可写层做成另一个子卷,然后把这两个子卷联合挂载,给容器用。如果你要给这个容器做快照,btrfs会瞬间生成一个新的子卷,只存和原容器不一样的内容,其他内容共享。

3.2 btrfs的优缺点

优点:

  • 自带COW:做快照时不占空间,适合需要频繁做快照的场景;
  • 支持压缩:可以自动压缩子卷的内容,省空间;
  • 支持子卷配额:可以限制每个容器的存储大小,防止某个容器占满磁盘;
  • 适合持久化存储:如果容器的可写层用btrfs子卷,容器删了,子卷还能保留; 缺点:
  • 兼容性差:很多Linux发行版默认不装btrfs,比如CentOS 7默认是ext4,要手动装;
  • 性能稍差:因为有压缩、快照等功能,读写性能比overlay2慢一点;
  • 配置复杂:要手动创建子卷、设置挂载点,新手容易出错。

3.3 btrfs的适用场景

所有“需要持久化数据、频繁做快照”的容器,比如:

  • 有状态服务容器:比如MySQL(数据存在容器的可写层,需要保留)、Redis(数据存在容器里,需要备份);
  • 开发环境容器:比如你要在容器里做开发,需要频繁做快照(比如每次改代码前做个快照,改坏了可以回滚);
  • 批量备份容器:比如你要给多个容器做备份,用btrfs的快照功能,瞬间完成,不占空间。

四、实战:配置Containerd的snapshotter

4.1 准备工作:检查系统支持

首先,我们要先检查系统支持哪种snapshotter,或者要不要安装额外的软件。 先确认系统有没有安装Containerd,如果没装,先装:

# 以CentOS 7为例,安装Containerd
yum install -y containerd

然后检查系统的文件系统:

# 查看系统的根文件系统类型
df -T /

如果输出的Type是ext4或xfs,默认支持overlay2;如果是btrfs,支持btrfs;如果要装btrfs,执行:

# CentOS 7安装btrfs工具
yum install -y btrfs-progs

4.2 配置overlay2(最常用)

4.2.1 配置步骤

overlay2的配置特别简单,只需要改Containerd的配置文件:

# 备份原配置文件
cp /etc/containerd/config.toml /etc/containerd/config.toml.bak
# 编辑配置文件
vim /etc/containerd/config.toml

找到snapshotter = "overlay"(旧版可能是这个),改成snapshotter = "overlay2",或者如果找不到,直接在[plugins."io.containerd.grpc.v1.cri".containerd]下面加:

# 配置snapshotter为overlay2
snapshotter = "overlay2"

然后重启Containerd:

# 重启Containerd服务
systemctl restart containerd
# 检查服务状态
systemctl status containerd

4.2.2 验证配置

用ctr(Containerd的命令行工具)启动一个容器,验证snapshotter:

# 拉取CentOS镜像
ctr image pull docker.io/library/centos:7
# 启动一个容器,指定snapshotter为overlay2
ctr run --snapshotter overlay2 docker.io/library/centos:7 test-ctr /bin/bash
# 进入容器(另开一个终端)
ctr task exec --exec-id 1 test-ctr /bin/bash
# 验证可写层:改一个文件
echo "test" > /tmp/test.txt
# 退出容器,再启动容器,看文件还在不在(容器删了就没了,因为是临时的)
ctr task kill test-ctr
ctr task delete test-ctr
ctr container delete test-ctr
# 重新启动容器,看文件(会不存在,因为overlay2的可写层是临时的)
ctr run --snapshotter overlay2 docker.io/library/centos:7 test-ctr2 /bin/bash
ctr task exec --exec-id 1 test-ctr2 cat /tmp/test.txt
# 会提示没有这个文件,说明overlay2的可写层是临时的

4.3 配置btrfs(高级场景)

4.3.1 准备btrfs分区

首先,我们要给系统加一个btrfs分区(如果系统已经是btrfs,跳过这步):

# 假设我们有一个未分区的磁盘/dev/sdb
# 分区,创建btrfs分区
fdisk /dev/sdb
# 输入n(新建分区),p(主分区),1(分区号),回车(起始扇区),回车(结束扇区),w(保存)
# 格式化分区为btrfs
mkfs.btrfs /dev/sdb1
# 创建挂载点
mkdir /btrfs
# 挂载分区
mount /dev/sdb1 /btrfs
# 开机自动挂载,编辑/etc/fstab
echo "/dev/sdb1 /btrfs btrfs defaults 0 0" >> /etc/fstab

4.3.2 配置Containerd的btrfs snapshotter

编辑Containerd的配置文件:

vim /etc/containerd/config.toml

找到[plugins."io.containerd.grpc.v1.cri".containerd],改成:

[plugins."io.containerd.grpc.v1.cri".containerd]
snapshotter = "btrfs"
# 配置btrfs的根目录,也就是我们刚才挂载的/btrfs
[plugins."io.containerd.grpc.v1.cri".containerd.btrfs]
root = "/btrfs"

然后重启Containerd:

systemctl restart containerd
systemctl status containerd

4.3.3 验证配置

用ctr启动一个容器,验证btrfs的特性:

# 拉取CentOS镜像
ctr image pull docker.io/library/centos:7
# 启动一个容器,指定snapshotter为btrfs
ctr run --snapshotter btrfs docker.io/library/centos:7 test-btrfs /bin/bash
# 进入容器,改一个文件
ctr task exec --exec-id 1 test-btrfs echo "btrfs test" > /tmp/btrfs.txt
# 给容器做快照(btrfs的快照是瞬间的)
ctr snapshot create test-snap /containers/test-btrfs/snapshots/1
# 验证快照:启动一个新容器,用这个快照
ctr run --snapshotter btrfs --snapshot test-snap docker.io/library/centos:7 test-snap-ctr /bin/bash
# 进入新容器,看文件还在不在
ctr task exec --exec-id 1 test-snap-ctr cat /tmp/btrfs.txt
# 会输出"btrfs test",说明快照成功
# 验证空间:btrfs的快照不占额外空间
df -h /btrfs
# 可以看到总空间没有增加,因为快照是共享的

五、两种snapshotter的选择指南

很多朋友会问:我到底选overlay2还是btrfs?其实很简单,按下面的规则选:

  1. 如果是普通的无状态服务、测试容器、批量任务,选overlay2——兼容性好、速度快、配置简单;
  2. 如果是有状态服务(比如MySQL、Redis)、开发环境(需要频繁做快照)、批量备份,选btrfs——支持快照、压缩、配额,适合持久化场景;
  3. 如果不确定,先选overlay2——90%的场景都够用,等有高级需求再换btrfs。

六、常见问题和注意事项

  1. 配置snapshotter后,之前的容器会怎么样?
    • 不会受影响,因为每个容器的snapshotter是启动时指定的,新容器用新的配置,旧容器还是用原来的;
  2. 可以同时用两种snapshotter吗?
    • 可以,启动容器时指定--snapshotter参数就行,比如ctr run --snapshotter overlay2 ...ctr run --snapshotter btrfs ...
  3. btrfs的压缩怎么开?
    • 编辑btrfs的挂载选项,在/etc/fstab里加compress=zstd,比如:
    echo "/dev/sdb1 /btrfs btrfs defaults,compress=zstd 0 0" >> /etc/fstab
    
    然后重新挂载:mount -o remount /btrfs
  4. overlay2的空间不够了怎么办?
    • 清理旧的镜像和容器:ctr image prunectr container prune
  5. btrfs的子卷配额怎么设置?
    • btrfs quota enable /btrfs开启配额,然后用btrfs qgroup limit 1G /btrfs/containers/test-btrfs限制某个容器的存储大小为1G。

七、总结

这篇文章我们讲了Containerd的snapshotter的核心作用,对比了overlay2和btrfs的优缺点、适用场景,还实战配置了两种snapshotter。 简单总结一下:

  • overlay2:通用、快速、简单,适合临时、无状态的场景;
  • btrfs:高级、灵活、适合持久化、需要快照的场景;
  • 配置时,先检查系统支持,再改Containerd的配置文件,重启服务,最后用ctr验证。 希望这篇文章能帮你搞懂怎么选和配置snapshotter,遇到容器存储的问题不再懵。