七天用Go写个docker(第四天)

镜像

前面我们用namespacecgroup构建了一个简单的容器,但是我们可以发现容器内的目录还是当前运行程序的目录,这里就缺少了镜像这么一个重要的特性。这里我们先用docker拉一个最精简的镜像busybox,它是一个集合了非常多unix工具的箱子,提供了一个非常完整而且小巧的系统。

# 拉取busybox
docker pull busybox
# 运行
docker run -d busybox top -b

# 查看容器ID
docker ps

# 导出容器
docker export -o busybox.tar 


可以看到我们成功导出了容器内容,下面我解压缩一下,然后将此文件夹作为容器的只读层。

mkdir busybox && tar -xvf busybox.tar -C busybox/

注意: 后面为了方便,我们把 busybox.tar 放到 /root 路径下

docker在启动容器时,会新建2个layer,write layer和container-layer,write layer 是容器的唯一可读写层,而container-layer是为容器新建的只读层,这里我们将busybox作为这一层,读写层,我们创建一个writeLayer文件夹作为这一层,然后将这两个文件夹挂载到同一个文件夹下,然后将此文件夹作为容器的启动目录即可,这个文件夹我们命名为mnt

Linux挂载文件夹

这里我们有3个文件夹,mnt writeLayer busybox,我们将writeLayer busybox这两个文件夹挂载到 mnt文件夹下,可以看到这时 mntwriteLayer文件夹都是空的,只有busybox文件夹下有东西,我们挂载之后再看一下

# 挂载
 mount -t aufs -o dirs=/root/writeLayer:/root/busybox none /root/mnt

可以看到,mnt已经出现了 busybox 文件夹里面的东西,这时我们在 writeLayer 文件夹下创建个新的文件夹,然后看看会发生什么

可以清楚的看到,我们对writeLayer做的操作会映射到mnt文件夹下,docker也是以这种方式来实现你每次修改容器内的东西之后并不会对镜像产生影响,因为你做的操作都是writeLayer层的,而镜像是在 busybox,也就是container-init层。

Go实现挂载

func NewWorkSpace(rootPath string, mntPath string, volume string) error {
	// 1. 创建只读层
	err := createReadOnlyLayer(rootPath)
	if err != nil {
		logrus.Errorf("create read only layer, err: %v", err)
		return err
	}
	// 2. 创建读写层
	err = createWriteLayer(rootPath)
	if err != nil {
		logrus.Errorf("create write layer, err: %v", err)
		return err
	}
	// 3. 创建挂载点,将只读层和读写层挂载到指定位置
	err = CreateMountPoint(rootPath, mntPath)
	if err != nil {
		logrus.Errorf("create mount point, err: %v", err)
		return err
	}
	return nil
}

简单来讲就三步,第一步创建只读层,第二步创建读写层,第三步将两者挂载到同一个文件夹下,具体实现也比较简单,就是创建文件夹罢了,这里重点看下怎么挂载吧

func CreateMountPoint(rootPath string, mntPath string) error {
	_, err := os.Stat(mntPath)
	if err != nil && os.IsNotExist(err) {
		err := os.MkdirAll(mntPath, os.ModePerm)
		if err != nil {
			logrus.Errorf("mkdir mnt path, err: %v", err)
			return err
		}
	}

	dirs := fmt.Sprintf("dirs=%s%s:%s%s", rootPath, common.WriteLayer, rootPath, common.BusyBox)
	cmd := exec.Command("mount", "-t", "aufs", "-o", dirs, "none", mntPath)
	if err := cmd.Run(); err != nil {
		logrus.Errorf("mnt cmd run, err: %v", err)
		return err
	}
	return nil
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值