自己动手写docker-4

4.构造镜像

示例代码(更新到4.2)

4.1 使用busybox基本镜像构造容器
  • docker export -o busybox.tar c5a45bda498e(容器id) 可以起一个busybox的后台运行容器,通过export导出文件系统,查看下结构
  • pivot_root系统调用,用于改变root文件系统
    • int pivot_root(const char *new_root, const char *put_old); 会将原先的root文件系统move到put_old,然后以new_root作为调用进程的新的root文件系统
  • pivot_rootchroot的区别:
    • pivot_root把进程切换到一个新的root目录,对之前root文件系统的不再有依赖,这样你就能够umount原先的root文件系统。
    • chroot只是更改了root目录,还会依赖老的文件系统,主要使用的目的一般是为了限制用户的访问。
  • pivot_root相关代码:
func pivotRoot(root string) error {
	//这个root目录在之前通过cmd.Dir='/path/busybox'设置好了
	// new_root 和put_old 必须不能同时存在当前root 的同一个文件系统中,需要通过--bind重新挂载一下
	if err := syscall.Mount(root, root, "bind", syscall.MS_BIND|syscall.MS_REC, ""); err != nil {
		return fmt.Errorf("mount --bind PWD PWD error ")
	}
	pivotDir := filepath.Join(root, old_root)
	if err := os.Mkdir(pivotDir, 0777); err != nil {
		return err
	}
	if err := syscall.PivotRoot(root, pivotDir); err != nil {
		return fmt.Errorf("privot_root error %v", err)
	}
	log.Infof("now change dir to root")
	if err := syscall.Chdir("/"); err != nil {
		return fmt.Errorf("chdir / %v", err)
	}
	// 更新下文件路径
	pivotDir = filepath.Join("/", old_root)
	if err := syscall.Unmount(pivotDir, syscall.MNT_DETACH); err != nil {
		return fmt.Errorf("umount pivot_root dir %v", err)
	}
	return os.Remove(pivotDir)
}
复制代码
4.2 使用AUFS包装busybox
  • 上一步构建好之后其实所有的操作都会影响busybox目录,需要将镜像和容器做隔离
  • 大致的思路是在进入init进程进行pivotRoot之前,需要加上以下操作
    • 启动容器时,将两个目录AUFS挂载到(ex:path/mnt),一个是read-wirte一个是read-only(一般是镜像文件,ex:busybox的文件系统)
    • 退出时卸载并且删除read-write文件系统
  • 流程如下

比较关键的就一步挂载AUFS

func CreateMountPoint(rootUrl string, mntUrl string) {
	if err := os.Mkdir(mntUrl, 0777); err != nil {
		log.Errorf("Mkdir dir %s error. %v", mntUrl, err)
	}
	dirs := "dirs=" + rootUrl + "writeLayer:" + rootUrl + "busybox"
	cmd := exec.Command("mount", "-t", "aufs", "-o", dirs, "none", mntUrl)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		log.Errorf("%v", err)
	}
}
复制代码
4.3实现volumn数据卷

就是实现docker run -v xxx:yyy,支持挂载外部文件到容器中去

  • 相较于4.2的实现,在启动容器时在mnt挂载完成后多了一步挂载volumn
func MountVolume(rootURL string, mntURL string, volumeURLs []string)  {
	parentUrl := volumeURLs[0]
	if err := os.Mkdir(parentUrl, 0777); err != nil {
		log.Infof("Mkdir parent dir %s error. %v", parentUrl, err)
	}
	containerUrl := volumeURLs[1]
	containerVolumeURL := mntURL + containerUrl
	if err := os.Mkdir(containerVolumeURL, 0777); err != nil {
		log.Infof("Mkdir container dir %s error. %v", containerVolumeURL, err)
	}
	dirs := "dirs=" + parentUrl
	cmd := exec.Command("mount", "-t", "aufs", "-o", dirs, "none", containerVolumeURL)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		log.Errorf("Mount volume failed. %v", err)
	}

}
复制代码
  • 在退出时加一步umount操作,和挂载顺序相反。
  • 大致流程
4.4 实现简单镜像打包(略)

实现类似docker commit xxx的功能

  • 比较简单就是在容器运行时 tar 压缩下 path/mnt的文件
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值