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 mountimport (    "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集群整体打包!