关于docker:集群镜像中的overlay2使用剖析

14次阅读

共计 2507 个字符,预计需要花费 7 分钟才能阅读完成。

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

正文完
 0