Skip to content

存储与快照:rootfs 怎么来的

每个沙箱都需要一个独立的 rootfs(根文件系统)。Cubelet 使用 containerd 的快照机制 + 自研存储池来高效管理 rootfs 的创建和回收。


1. 存储架构全景


2. 存储插件初始化

Cubelet/storage/plugin.go 注册了存储插件:

go
// storage/plugin.go
func init() {
    registry.Register(&plugin.Registration{
        Type:   constants.InternalPlugin,
        ID:     constants.StorageID.ID(),
        Config: &Config{},
        Requires: []plugin.Type{
            constants.CubeStorePlugin,
            constants.CubeMetaStorePlugin,
        },
        InitFn: func(ic *plugin.InitContext) (interface{}, error) {
            localStorage.config = ic.Config.(*Config)
            // 初始化存储池
            // 初始化快照管理
        },
    })
}

配置项

配置说明默认值
root_path存储根目录containerd state dir
data_path数据目录root_path
disksize磁盘大小限制-
pool_type存储池类型cp (copy-on-write)
pool_size池大小-
pool_worker_num池工作线程数-
pool_default_format_size_list预格式化大小列表-

3. 存储池:快照复用

3.1 池的工作原理

存储池预先创建一批格式化好的 ext4 快照,沙箱创建时直接从池中取出,避免每次都要格式化:

Cubelet/storage/pool_withreflink.go 实现了基于 reflink 的快速拷贝:

go
// pool_withreflink.go
func (p *pool) createWithReflink(src, dst string) error {
    // 使用 FICLONE ioctl 实现 copy-on-write 拷贝
    // 速度极快(几乎瞬间),且不占用额外磁盘空间
    // 直到写入时才真正分配空间
}

Reflink 的优势:

  • 速度快:只需复制元数据,不复制数据块
  • 空间省:共享未修改的数据块
  • 原子性:操作是原子的

3.3 池回收

沙箱销毁后,快照不会被删除,而是被回收到池中:


4. 快照创建流程

4.1 从模板创建快照

当创建沙箱时,Cubelet 需要从模板镜像创建一个可写的 rootfs:

4.2 Overlay 挂载

go
// Cubelet/plugins/snapshots/overlay/
// 使用 overlayfs 将只读模板层和可写层合并

Overlay 的层级结构:


5. 磁盘管理

5.1 磁盘检查

Cubelet/storage/local.go 实现了磁盘空间检查:

go
func (s *localStorage) checkDisk() error {
    stat := syscall.Statfs_t{}
    syscall.Statfs(s.config.DataPath, &stat)
    
    freePercent := int64(stat.Bfree * 100 / stat.Blocks)
    if freePercent < s.config.WarningPercent {
        return fmt.Errorf("disk usage warning: %d%% free", freePercent)
    }
    return nil
}

5.2 磁盘回收

当磁盘空间不足时,Cubelet 会:

  1. 停止创建新沙箱
  2. 清理过期的模板缓存
  3. 回收已销毁沙箱的存储

6. 卷挂载

除了 rootfs,沙箱还需要挂载各种卷:

卷插件

Cubelet/plugins/mount/manager.go 管理卷的生命周期:

卷类型实现方式生命周期
emptyDirtmpfs随沙箱销毁
configMapbind mount随沙箱销毁
secretbind mount随沙箱销毁
hostPath直接挂载需手动清理

7. 完整存储流程


延伸阅读