写点什么

自己动手写 Docker 系列 -- 4.4 实现简单镜像打包

作者:
  • 2022 年 3 月 20 日
  • 本文字数:1927 字

    阅读完需:约 6 分钟

简介

在上篇中,我们实现了 volume,让容器能挂载宿主机文件,实现持久化。本篇中将实现 commit 命令,将运行中的容器进行保存

源码说明

同时放到了 Gitee 和 Github 上,都可进行获取



本章节对应的版本标签是:4.4,防止后面代码过多,不好查看,可切换到标签版本进行查看

代码实现

上篇中,我们实现了-v 命令,通过挂载宿主机上的文件,类似文件共享,实现了容器的文件持久化


但我们的容器在退出后,已经会把可写层的内容删除掉


在我们使用 docker 的过程,我们会使用 commit 命令,将正在运行中的容器进行保存,成一个新的镜像,当启动这个镜像时,我们在可写层的东西依旧存在


本篇中我们就要实现这个功能的基础,当然没有像 docker 那样,能直接 commit 成一个新的镜像


本篇中如书中所说,简单的镜像打包


其中核心的就是将我们的挂载点镜像打包即可,因为挂载点中,挂载着 busybox 基础只读层、可写层、宿主机的挂载数据卷,即存放着我们当前的所有数据


所以我们直接将其进行打包即可


核心的代码就是:


1.新增 commit 命令:后面的参数是打包的镜像名称


main 函数中新增 commit 命令:


func main() {  ......
app.Commands = []cli.Command{ command.InitCommand, command.RunCommand, command.CommitCommand, }
......}
复制代码


Commit 命令的新增,在 main_command.go 文件中


var CommitCommand = cli.Command{  Name:  "commit",  Usage: "commit a container into image",  Action: func(context *cli.Context) error {    if len(context.Args()) < 1 {      return fmt.Errorf("Missing container name")    }    imageName := context.Args().Get(0)    return run.CommitContainer(imageName)  },}
复制代码


2.commit 的具体实现:将挂载点进行打包


和书中不同,它是固定的 root 目录作为容器固定挂载父目录


这里我意识到,自己去取当前命令运行的目前是不恰当,可以将/root 看出我们 docker 的安装目录,相关的存储都放到/root 下


这里是我考虑不当了,所以导致我们的 commit 运行都必须在工程目录下,这样才能正确打包


但问题不大,就当暂时设置的存储目录是工程源码跟路径了


或许后期可以把这个路径抽出来,做成可以配置的


func CommitContainer(imageName string) error {  pwd, err := os.Getwd()  if err != nil {    return fmt.Errorf("Run get pwd err: %v", err)  }  mntUrl := pwd + "/mnt/"  imageTar := pwd + "/" + imageName + ".tar"  log.Infof("commit file path: %s", imageTar)  if _, err := exec.Command("tar", "-czf", imageTar, "-C", mntUrl, ".").CombinedOutput(); err != nil {    return fmt.Errorf("tar folder err: %s, %v", mntUrl, err)  }  log.Infof("end commit file: %s", imageTar)  return nil}
复制代码

运行测试

首先我们启动一个容器


➜  dockerDemo git:(main) ✗ ./main run -ti sh{"level":"info","msg":"memory cgroup path: /sys/fs/cgroup/memory/mydocker-cgroup","time":"2022-03-20T14:08:36+08:00"}{"level":"info","msg":"memory cgroup path: /sys/fs/cgroup/memory/mydocker-cgroup","time":"2022-03-20T14:08:36+08:00"}{"level":"info","msg":"all command is : sh","time":"2022-03-20T14:08:36+08:00"}{"level":"info","msg":"parent process run","time":"2022-03-20T14:08:36+08:00"}{"level":"info","msg":"init come on","time":"2022-03-20T14:08:36+08:00"}{"level":"info","msg":"current location: /home/lw/code/go/dockerDemo/mnt","time":"2022-03-20T14:08:36+08:00"}{"level":"info","msg":"find path: /bin/sh","time":"2022-03-20T14:08:36+08:00"}/ #
复制代码


然后新开一个 shell,运行 commit 命令


➜  dockerDemo git:(main) ✗ ./main commit image{"level":"info","msg":"commit file path: /home/lw/code/go/dockerDemo/image.tar","time":"2022-03-20T14:13:00+08:00"}
➜ dockerDemo git:(main) ✗➜ dockerDemo git:(main) ✗ lsbusybox docs example go.mod go.sum image.tar LICENSE main mnt mydocker mydocker.tar README.md untar writeLayer➜ dockerDemo git:(main) ✗ mkdir ./untar➜ dockerDemo git:(main) ✗ cd untar➜ untar git:(main) ✗ tar -xvf ../image.tar
➜ untar git:(main) ✗ lsbin dev etc home main proc root sys tmp usr var➜ untar git:(main) ✗
复制代码


如上面所示,我们将我们正在运行中的达成 image.tar,然后解压查看里面的内容,和我们的运行容器时的跟目录一样


注:打包花的时间有一定的时间,需要耐心等 20 秒左右

发布于: 刚刚阅读数: 2
用户头像

关注

还未添加个人签名 2018.09.09 加入

代码是门手艺活,也是门艺术活

评论

发布
暂无评论
自己动手写Docker系列 -- 4.4实现简单镜像打包_Docker_萧_InfoQ写作平台