美文网首页
集群镜像中的overlay2使用剖析

集群镜像中的overlay2使用剖析

作者: sealyun | 来源:发表于2021-07-27 11:28 被阅读0次

    sealer是阿里巴巴开源的基于kuberentes的集群镜像开源技术,可以把整个集群整体打包。

    sealer中集群镜像的存储和docker镜像很像,也采用了写时复制的技术来提升复用性。

    本文聊一下overlay2。

    写时复制

    COPY on Write在很多地方都会用到,比如git的存储,去修改一个文件并非真的修改,

    而是把文件拷贝出来修改,读的时候读取上层的修改层,同样比如在ceph的后段存储

    等系统中都存在应用。好处是可以非常方便的进行回滚,以及存储复用,比如给虚拟机

    做快照,那我们并不需要把整个系统盘复制一份,而只需要用指针指一下快照的地方就好。

    容器镜像同理,写时复制可以让多个应用共享一个基础镜像。

    集群镜像中的写时复制

    集群镜像把整个集群打包,用写时复制的方法可以帮助分布式应用共享k8s基础镜像。

    以及可以很方便的把各种分布式应用镜像进行融合。

    操作系统中使用overlay2

    mount -t overlay overlay -o lowerdir=./lower,upperdir=./upper,workdir=./work ./merged
    

    overlay文件系统分为lowerdir、upperdir、merged, 对外统一展示为merged,uperdir和lower的同名文件会被upperdir覆盖

    workdir必须和upperdir是mount在同一个文件系统下, 而lower不是必须的

    mount -t overlay overlay -o lowerdir=/lower1:/lower2:/lower3,upperdir=/upper,workdir=/work /merged
    

    lowerdir可以是多个目录(前面覆盖后面),如果没有upperdir,那merged是read only.

    overlay只支持两层,upper文件系统通常是可写的;lower文件系统则是只读,这就表示着,当我们对 overlay 文件系统做任何的变更,都只会修改 upper 文件系统中的文件

    来个实际操作:

    overlay2
    ├── lower1
    │   ├── a
    │   └── b
    ├── lower2
    │   └── a
    ├── merged
    ├── upper
    │   └── c
    └── work
    
    mount -t overlay overlay -o lowerdir=lower1:lower2,upperdir=upper,workdir=work merged
    

    以上overlay2下面的几个目录就被合并了

    对只在 lower 有的文件写时,则会做一个copy_up 的操作,先从 lower将文件拷贝一份到upper,同时为文件创建一个硬链接。此时可以看到 upper 目录下生成了两个新文件,写的操作只对从lower 复制到 upper 的文件生效,而 lower 还是原文件

    删除 lower 和 upper 都有的文件时,upper 的会被删除,在 upper 目录下创建一个 ‘without’ 文件,而 lower 的不会被删除

    代码实现

    有了上述理论基础,我们先看一段docker里面的源码

        if len(mountData) > pageSize {
            opts = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", string(lowers), path.Join(id, "diff"), path.Join(id, "work"))
            mountData = label.FormatMountLabel(opts, mountLabel)
            if len(mountData) > pageSize {
                return "", fmt.Errorf("cannot mount layer, mount label too large %d", len(mountData))
            }
    
            mount = func(source string, target string, mType string, flags uintptr, label string) error {
                return mountFrom(d.home, source, target, mType, flags, label)
            }
            mountTarget = path.Join(id, "merged")
        }
    
        if err := mount("overlay", mountTarget, "overlay", 0, mountData); err != nil {
            return "", fmt.Errorf("error creating overlay mount to %s: %v", mergedDir, err)
        }
    

    mountTarget就是目标目录, mountData是: fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", string(lowers), path.Join(id, "diff"), path.Join(id, "work"))

    可以看到SDK的使用和命令行很像

    我们可以做一个封装:

    package mount
    
    import (
        "syscall"
    )
    
    func mount(device, target, mType string, flag uintptr, data string) error {
        if err := syscall.Mount(device, target, mType, flag, data); err != nil {
            return err
        }
    
        // If we have a bind mount or remount, remount...
        if flag&syscall.MS_BIND == syscall.MS_BIND && flag&syscall.MS_RDONLY == syscall.MS_RDONLY {
            return syscall.Mount(device, target, mType, flag|syscall.MS_REMOUNT, data)
        }
        return nil
    }
    
    func unmount(target string, flag int) error {
        return syscall.Unmount(target, flag)
    }
    

    主要是syscall.Mount这个系统调用,参数基本和命令行一一对应

    sealer中overlay2源码地址
    kubernetes一键安装

    sealer集群整体打包!

    相关文章

      网友评论

          本文标题:集群镜像中的overlay2使用剖析

          本文链接:https://www.haomeiwen.com/subject/oqxomltx.html