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

本文档介绍了如何实现Docker的commit功能,将运行中的容器保存为新的镜像。主要内容包括源码说明、代码实现及运行测试。通过打包挂载点,包含busybox基础只读层、可写层和数据卷,从而保存容器的所有数据。在测试中,成功将运行中的容器打包成image.tar,并验证了内容与容器根目录一致。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介

在上篇中,我们实现了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)ls
busybox  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)ls
bin  dev  etc  home  main  proc  root  sys  tmp  usr  var
➜  untar git:(main)

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值