从零开始写 Docker(七)---实现 mydocker commit 打包容器成镜像

mydocker-commit.png

本文为从零开始写 Docker 系列第七篇,实现类似 docker commit 的功能,把运行状态的容器存储成镜像保存下来。


完整代码见:https://github.com/lixd/mydocker
欢迎 Star

推荐阅读以下文章对 docker 基本实现有一个大致认识:

  • 核心原理:深入理解 Docker 核心原理:Namespace、Cgroups 和 Rootfs
  • 基于 namespace 的视图隔离:探索 Linux Namespace:Docker 隔离的神奇背后
  • 基于 cgroups 的资源限制
    • 初探 Linux Cgroups:资源控制的奇妙世界
    • 深入剖析 Linux Cgroups 子系统:资源精细管理
    • Docker 与 Linux Cgroups:资源隔离的魔法之旅
  • 基于 overlayfs 的文件系统:Docker 魔法解密:探索 UnionFS 与 OverlayFS
  • 基于 veth pair、bridge、iptables 等等技术的 Docker 网络:揭秘 Docker 网络:手动实现 Docker 桥接网络

开发环境如下:

root@mydocker:~# lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 20.04.2 LTS
Release:	20.04
Codename:	focal
root@mydocker:~# uname -r
5.4.0-74-generic

注意:需要使用 root 用户

1. 概述

由于之前使用 pivotRoot + overlayfs 技术 将 /root/merged 目录作为容器的 rootfs,因此容器中的所有改动都发生在该目录下。

这里我们的 mydocker commit 命令只需要把该目录保存下来即可,因此简单实现为 使用 tar 命令将/root/merged 目录打成 tar 包

2. 实现

具体流程

整个打包流程如下图所示:

mydocker-commit-process.png

commitCommand

在 main_ command.go 文件中实现 commitCommand 命令,从用户的输入获取image name。

var commitCommand = cli.Command{
	Name:  "commit",
	Usage: "commit container to image",
	Action: func(context *cli.Context) error {
		if len(context.Args()) < 1 {
			return fmt.Errorf("missing image name")
		}
		imageName := context.Args().Get(0)
		commitContainer(imageName)
		return nil
	},
}

然后在 main 方法中添加 commit 命令:

func main() {
    app := cli.NewApp()
    app.Name = "mydocker"
    app.Usage = usage

    app.Commands = []cli.Command{
       initCommand,
       runCommand,
       commitCommand,
    }
    // 省略其他
}

commitContainer

添加 commit.go文件,通过 commitContainer 函数实现将容器文件系统打包成$ {imagename}.tar 文件。

func commitContainer(imageName string) {
	mntPath := "/root/merged"
	imageTar := "/root/" + imageName + ".tar"
	fmt.Println("commitContainer imageTar:", imageTar)
	if _, err := exec.Command("tar", "-czf", imageTar, "-C", mntPath, ".").CombinedOutput(); err != nil {
		log.Errorf("tar folder %s error %v", mntPath, err)
	}
}

如果你对云原生技术充满好奇,想要深入了解更多相关的文章和资讯,欢迎关注微信公众号。

搜索公众号【探索云原生】即可订阅


3. 测试

测试流程如下:

  • 1)启动容器
  • 2)创建新文件
  • 3)新终端中将容器打包为镜像
  • 4)解压该镜像,查看 2 中的内容是否存在

首先,启动容器

root@mydocker:~/feat-commit/mydocker# ./mydocker run -it /bin/sh
{"level":"info","msg":"resConf:\u0026{ 0  }","time":"2024-01-19T16:18:24+08:00"}
{"level":"info","msg":"busybox:/root/busybox busybox.tar:/root/busybox.tar","time":"2024-01-19T16:18:24+08:00"}
{"level":"info","msg":"mount overlayfs: [/usr/bin/mount -t overlay overlay -o lowerdir=/root/busybox,upperdir=/root/upper,workdir=/root/work /root/merged]","time":"2024-01-19T16:18:24+08:00"}
{"level":"info","msg":"command all is /bin/sh","time":"2024-01-19T16:18:24+08:00"}
{"level":"info","msg":"init come on","time":"2024-01-19T16:18:24+08:00"}
{"level":"info","msg":"Current location is /root/merged","time":"2024-01-19T16:18:24+08:00"}
{"level":"info","msg":"Find path /bin/sh","time":"2024-01-19T16:18:24+08:00"}

创建一个文件

/ # echo KubeExplorer > tmp/hello.txt
/ # cat /tmp/hello.txt
KubeExplorer

接着另外打开 terminal 执行 mydocker commit 命令,将当前容器提交为镜像

root@mydocker:~/feat-commit/mydocker# ./mydocker commit myimage
commitContainer imageTar: /root/myimage.tar

再次查看/root 目录的内容,多了 myimage.tar 文件,这个就是我们的镜像文件了

root@mydocker:~# ls
busybox  busybox.tar merged  myimage.tar  upper  volume  work

查看 myimage.tar 中内容:

root@mydocker:~# tar -tf myimage.tar |grep hello.txt
./tmp/hello.txt

可以看到,前面在容器中创建的 hello.txt 是存在的。

4. 总结

本篇 mydocker commit 比较简单,就是使用 tar 命令将 rootfs 直接进行打包,没有太多需要注意的地方。

镜像构造部分到此就基本完成了,总结一下:

  • 1)首先使用 busybox 作为基础镜像创建了一个容器,理解了什么是 rootfs,以及如何使用 rootfs 来打造容器的基本运行环境。

  • 2)然后,使用 overlayfs 来构建了一个拥有二层模式的镜像,对于最上层可写层的修改不会影响到基础层。这里就基本解释了镜像分层存储的原理。

  • 3)之后使用 -v 参数做了一个 volume 挂载的例子,介绍了如何将容器外部的文件系统挂载到容器中,并且让它可以访问。

  • 4)最后(本文)实现了一个简单版本的容器镜像打包。

这一章主要针对镜像的存储及文件系统做了基本的原理性介绍,通过这几个例子,可以很好地理解镜像是如何构建的,后续会基于这些基础做更多的扩展。


**【从零开始写 Docker 系列】**持续更新中,搜索公众号【探索云原生】订阅,文章。



完整代码见:https://github.com/lixd/mydocker
欢迎 Star

相关代码见 feat-volume 分支,测试脚本如下:

需要提前在 /root 目录准备好 busybox.tar 文件,具体见第四篇第二节。

# 克隆代码
git clone -b feat-commit https://github.com/lixd/mydocker.git
cd mydocker
# 拉取依赖并编译
go mod tidy
go build .
# 测试 
./mydocker run -it  /bin/ls
./mydocker commit

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/471665.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

多个线程交替打印ABC

多个线程交替打印ABC package 多个线程交替打印ABC;import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier;/*** Created with IntelliJ IDEA.** Author: AlenXu* Date: 2024/03/20/10:10* Description:*/ public class ThreadLoopP…

数字功放VS模拟功放,选择适合你的音频解决方案

数字功放和模拟功放是音频系统中常用的两种功放技术&#xff0c;适用于不同的音频应用&#xff0c;都具有各自的优势和特点。本文将为您详细介绍数字功放和模拟功放的差异&#xff0c;并帮助您找到适合自己的音频解决方案。 1、数字功放是一种利用数字信号处理技术的功放。它将…

0基础 三个月掌握C语言(13)

数据在内存中的存储 整数在内存中的存储 在讲解操作符时 我们就已经学习了该部分的内容 这里我们回顾一下 整数的二进制表示方法有三种&#xff1a;原码 反码 补码 有符号的整数&#xff08;unsigned&#xff09; 三种表达方式均有符号位和数值位两部分 最高位的一位被当…

【C语言步行梯】C语言实现扫雷游戏(含详细分析)

&#x1f3af;每日努力一点点&#xff0c;技术进步看得见 &#x1f3e0;专栏介绍&#xff1a;【C语言步行梯】专栏用于介绍C语言相关内容&#xff0c;每篇文章将通过图片代码片段网络相关题目的方式编写&#xff0c;欢迎订阅~~ 文章目录 需求分析具体实现主函数体菜单实现游戏实…

AI预测福彩3D第14弹【2024年3月20日预测--新算法重新开始计算第11次测试】

今天继续对第一套算法进行测试。废话不多说了&#xff0c;直接上分析出的图表&#xff0c;再上结果。 最终&#xff0c;经过研判分析&#xff0c;2024年3月20日福彩3D的七码预测结果如下&#xff1a; 百位&#xff1a;7 8 4 3 5 6 9(1换9) 十位&#xff1a;5 4 3 6 1 2 0(07分一…

day14-SpringBoot 原理篇

一、配置优先级 SpringBoot 中支持三种格式的配置文件&#xff1a; 注意事项 虽然 springboot 支持多种格式配置文件&#xff0c;但是在项目开发时&#xff0c;推荐统一使用一种格式的配置 &#xff08;yml 是主流&#xff09;。 配置文件优先级排名&#xff08;从高到低&…

事务同步管理器TransactionSynchronizationManager

事务同步管理器的使用场景&#xff1a; 同步涉及的资源包括&#xff1a;SqlSession & Connection。同步资源核心目的是线程共享&#xff0c;意味着必须跟线程绑定。同步资源伴随着线程生存或者消亡&#xff0c;意味着线程结束之前必须手动清除其绑定的资源。事务同步管理器…

基于SpringBoot+Redis实现接口限流

前言 业务中需要对一些接口进行限流处理&#xff0c;防止机器人调用或者保证服务质量&#xff1b; 实现方式 基于redis的lua脚本 引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis&…

Linux Deepin系统安装x11vnc+cpolar实现Windows系统电脑远程其桌面

文章目录 1. 安装x11vnc2. 本地远程连接测试3. Deepin安装Cpolar4. 配置公网远程地址5. 公网远程连接Deepin桌面6. 固定连接公网地址7. 固定公网地址连接测试 x11vnc是一种在Linux系统中实现远程桌面控制的工具&#xff0c;它的原理是通过X Window系统的协议来实现远程桌面的展…

linux用git拉取我云端以及git处理冲突

拉取后切换一个跟云端分支(dev)一样的 git branch --set-upstream-toorigin/dev dev 之后就同步了 A在dev分支写了iii,提交 B在dev分支写了hhh,提交,冲突 怎么修改,B把云端的拉下来,随便改改就行

YOLOv7 | 添加GSConv,VoVGSCSP等多种卷积,有效提升目标检测效果,代码改进(超详细)

⭐欢迎大家订阅我的专栏一起学习⭐ &#x1f680;&#x1f680;&#x1f680;订阅专栏&#xff0c;更新及时查看不迷路&#x1f680;&#x1f680;&#x1f680; YOLOv5涨点专栏&#xff1a;http://t.csdnimg.cn/QdCj6 YOLOv7专栏&#xff1a; http://t.csdnimg.cn/dy…

Qt 多元素控件

Qt开发 多元素控件 Qt 中提供的多元素控件有: QListWidgetQListViewQTableWidgetQTableViewQTreeWidgetQTreeView xxWidget 和 xxView 之间的区别 以 QTableWidget 和 QTableView 为例. QTableView 是基于 MVC 设计的控件. QTableView 自身不持有数据. 使用QTableView 的 …

latex如何让标题section取消数字标号

解决方法——加一个*号 在LaTeX中&#xff0c;如果你想让section标题取消数字标号&#xff0c;可以使用section*代替section。section*将生成一个不带数字标号的节标题。 例如&#xff0c;你可以这样写&#xff1a; \section*{这是不带数字标号的节标题}这将生成一个标题&am…

给老婆整了个短剧搜索机器人APP

最近短剧挺火&#xff0c;很多群友们都在做一些资源分享&#xff0c;老胡于是基于这些资源做了个短剧搜索引擎&#xff0c;挺多朋友喜欢看的&#xff0c;我老婆也在看哈哈&#xff0c;真上头&#xff0c;废话不多说&#xff0c;上短剧机器人。 短剧机器人 直接在微信群输入&…

解决由于历史原因解析tflite失败的问题

文章目录 0. 背景1. tflite 历史遗留问题2. schema3. flatbuffers 编译器3.1 安装 FlatBuffers 编译器3.2. 编译 FlatBuffers schema 文件3.3 使用生成的 Python 文件 4 问题未解决终极解决方案 写在最前面&#xff1a;解决方法是升级tensorflow版本&#xff0c;重新生成tflite…

【go从入门到精通】if else 条件控制

Go 语言条件语句&#xff1a; 在 Go 语言中&#xff0c;条件语句用于根据不同的条件执行不同的代码。Go 语言提供了两种条件语句&#xff1a;if 语句和switch 语句。 if语句 if由一个布尔表达式后紧跟一个或多个语句组成。 语法 Go 编程语言中 if 语句的语法如下&#xff…

反向海淘系统中的数据安全挑战与解决方案探讨

**反向海淘系统中的数据安全挑战与解决方案探讨** **一、背景** 随着反向海淘市场的不断扩大&#xff0c;涉及的数据安全挑战也日益增多。本文旨在探讨反向海淘系统中面临的数据安全挑战&#xff0c;以及相应的解决方案。 **二、数据安全挑战** 1. **数据传输安全**&#x…

微信支付宝--充ChatGPTPLUS/openAI key

ChatGPT是人工智能技术驱动的自然语言处理工具&#xff0c;它能够基于在预训练阶段所见的模式和统计规律&#xff0c;来生成回答&#xff0c;还能根据聊天的上下文进行互动&#xff0c;真正像人类一样来聊天交流&#xff0c;甚至能完成撰写论文、邮件、脚本、文案、翻译、代码等…

【Python】反编译PyInstaller打包的exe

查看exe基本信息 需要反编译的exe 查看exe文件的打包工具&#xff0c;查看exe信息的软件叫Detect It Easy(查壳工具) 由图我们可以看出当前选中的exe文件是由名叫PyInstaller的打包工具打包好的exe 反编译 exe反编译工具&#xff1a;pyinstxtractor.py 使用方法 python py…

面试算法-65-二叉树的层平均值

题目 给定一个非空二叉树的根节点 root , 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5 以内的答案可以被接受。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[3.00000,14.50000,11.00000] 解释&#xff1a;第 0 层的…