精简docker的导出镜像
Docker 镜像是由多个文件系统(只读层)叠加而成,每个层仅包含了前一层的差异部分。当我们启动一个容器的时候,Docker 会加载镜像层并在其上添加一个可写层。容器上所做的任何更改,譬如新建文件、更改文件、删除文件,都将记录与可写层上。当我们使docker save形式尝试导出镜像时会导出该镜像的所有文件层,当然这个行为是必要的,因为你不知道这个镜像的被导入环境是否已包含基础镜像的文件层。但是如果我们有一批镜像且都依赖某一个或两个基础镜像构建,且不具备批量 save的调价(必须一个一个分开了打包),这种情况下如果一个一个save的话对硬盘资源是极大的浪费,那么有没有办法去掉哪些重复的镜像层呢,答案是OK的。(也许有人会吐槽为啥不用docekrfile呢,是的一般情况下是ok的,但是用dockerfile build出来的镜像id时不一样的)
看下docker save 导出了写啥
以如下镜像为例子
FROM centos:7
COPY main /home/main
RUN chmod +x /home/main
CMD /home/mai
构建
docker build -t ip-server:1.0.0 .
导出
[root@localhost demo]# docker save -o ip-server.tar ip-server:1.0.0
[root@localhost demo]# du -sh ip-server.tar
212M ip-server.tar
[root@localhost demo]# docker save -o centos7.tar centos:7
[root@localhost demo]# du -sh centos7.tar
202M centos7.tar
可以看到基于centos7构建的ip-server镜像只是大了一丁,也就是我们COPY进来的一个可执行文件大小,那么在已知被导入环境存在centos7镜像的文件层是该如何减小ip-server.tar的体积呢?
拆解导出的镜像
[root@localhost demo]# mkdir ip-server && tar xf ip-server.tar -C ip-server
[root@localhost demo]# tree ip-server
ip-server
├── 3efdc87cec68e28bccf6c0d96894c903e12157ed0797651a2eaa565108de5bd8
│ ├── json
│ ├── layer.tar -> ../fad57ccc4dd192e49d3979f477525a4b4c8fb8532ae31c2c74b5403474a26e4d/layer.tar
│ └── VERSION
├── d8f46057879e2e8614caa5511934d403d7ebea0af9b196bf29b68161fda76766
│ ├── json
│ ├── layer.tar
│ └── VERSION
├── f898e9c3d94a1617bac63c962155327671957f2bcbd35e6411153b7730d6558e.json
├── fad57ccc4dd192e49d3979f477525a4b4c8fb8532ae31c2c74b5403474a26e4d
│ ├── json
│ ├── layer.tar
│ └── VERSION
├── manifest.json
└── repositories
3 directories, 12 files
# manifest.json
[
{
"Config": "f898e9c3d94a1617bac63c962155327671957f2bcbd35e6411153b7730d6558e.json",
"RepoTags": [
"ip-server:1.0.0"
],
"Layers": [
"d8f46057879e2e8614caa5511934d403d7ebea0af9b196bf29b68161fda76766/layer.tar",
"fad57ccc4dd192e49d3979f477525a4b4c8fb8532ae31c2c74b5403474a26e4d/layer.tar",
"3efdc87cec68e28bccf6c0d96894c903e12157ed0797651a2eaa565108de5bd8/layer.tar"
]
}
]
# f898e9c3d94a1617bac63c962155327671957f2bcbd35e6411153b7730d6558e.json
{
"architecture": "amd64",
"config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"/home/main"
],
"Image": "sha256:04da435eb95c963effbf9aba060e6f2ddd962b4861ce1bf7bdc5f3cbffceb4b5",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20201113",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS",
"org.opencontainers.image.created": "2020-11-13 00:00:00+00:00",
"org.opencontainers.image.licenses": "GPL-2.0-only",
"org.opencontainers.image.title": "CentOS Base Image",
"org.opencontainers.image.vendor": "CentOS"
}
},
"container": "5d3e8d3176babbe767294d6834bf1dc6e64ce9838bc08993751724a92231d6ac",
"container_config": {
"Hostname": "5d3e8d3176ba",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"/bin/sh\" \"-c\" \"/home/main\"]"
],
"Image": "sha256:04da435eb95c963effbf9aba060e6f2ddd962b4861ce1bf7bdc5f3cbffceb4b5",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20201113",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS",
"org.opencontainers.image.created": "2020-11-13 00:00:00+00:00",
"org.opencontainers.image.licenses": "GPL-2.0-only",
"org.opencontainers.image.title": "CentOS Base Image",
"org.opencontainers.image.vendor": "CentOS"
}
},
"created": "2022-10-26T15:53:47.898864929Z",
"docker_version": "20.10.17",
"history": [
{
"created": "2021-09-15T18:20:23.417639551Z",
"created_by": "/bin/sh -c #(nop) ADD file:b3ebbe8bd304723d43b7b44a6d990cd657b63d93d6a2a9293983a30bfc1dfa53 in / "
},
{
"created": "2021-09-15T18:20:23.819893035Z",
"created_by": "/bin/sh -c #(nop) LABEL org.label-schema.schema-version=1.0 org.label-schema.name=CentOS Base Image org.label-schema.vendor=CentOS org.label-schema.license=GPLv2 org.label-schema.build-date=20201113 org.opencontainers.image.title=CentOS Base Image org.opencontainers.image.vendor=CentOS org.opencontainers.image.licenses=GPL-2.0-only org.opencontainers.image.created=2020-11-13 00:00:00+00:00",
"empty_layer": true
},
{
"created": "2021-09-15T18:20:23.99863383Z",
"created_by": "/bin/sh -c #(nop) CMD [\"/bin/bash\"]",
"empty_layer": true
},
{
"created": "2022-10-26T15:53:46.693528022Z",
"created_by": "/bin/sh -c #(nop) COPY file:d0c12b416e2bad24636a0f240cc09c4a6b6a0def701b5aaeeca4963507e468c4 in /home/main "
},
{
"created": "2022-10-26T15:53:47.752968676Z",
"created_by": "/bin/sh -c chmod +x /home/main"
},
{
"created": "2022-10-26T15:53:47.898864929Z",
"created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\" \"-c\" \"/home/main\"]",
"empty_layer": true
}
],
"os": "linux",
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02",
"sha256:185d24f4ae72bebf9b31c3d26486d52163e38e6c09167507a6a4f28d491aeb28",
"sha256:185d24f4ae72bebf9b31c3d26486d52163e38e6c09167507a6a4f28d491aeb28"
]
}
}
参考docker-ce的相关导出模块的源代码(源代码解读就不做了,不算复杂)
docekr-ce/components/engin/save
docekr-ce/components/engin/load
可以找出打包出的tar包中放layer文件夹与diff_ids标记的文件层的对应关系。
1. 解压压缩包
2. 读取 centos7 和 ip-server 的inspect
3. 找出 centos7 和 ip-server 的diff_ids同的层数
4. 按照相同的层数依次找到manifest.json中记录的layers文件目录,并把layer.tar的压缩包置空
5. 重新打包
测试改处理的导出包在centos:7镜像已存在的环境中可以被正常导入操作。
代码实现
参考 github.com/zn-chen/dockerdiff
懒得琢磨也可以直接使用,在安装好go环境下git clone 下来 make && make install 后即可食用。
精简docker的导出镜像的更多相关文章
- docker 导入导出镜像
docker容器导入导出有两种方法: 一种是使用save和load命令 使用例子如下: docker save ubuntu:load>/root/ubuntu.tar docker load& ...
- docker导入导出镜像
docker容器导入导出有两种方法: 一种是使用save和load命令 使用例子如下: docker save ubuntu:load>/root/ubuntu.tar docker load& ...
- 精简Docker镜像的五种通用方法
http://dockone.io/article/8163 精简Docker镜像的好处很多,不仅可以节省存储空间和带宽,还能减少安全隐患.优化镜像大小的手段多种多样,因服务所使用的基础开发语言不同而 ...
- docker 保存 加载(导入 导出镜像
tensorflow 的docker镜像很大,pull一次由于墙经常失败.其实docker 可以将镜像导出再导入. 保存加载(tensorflow)镜像 1) 查看镜像 docker images 如 ...
- docker怎么导出导入镜像
https://blog.csdn.net/dest_dest/article/details/80612231 把某个docker镜像保存到本地文件,命令如下docker save -o 镜像名.t ...
- 精简Docker镜像的几个方法
一.使用更精简的镜像 常用的Linux系统镜像一般有 Debian.Ubuntu.CentOS和Alpine,其中Alpine是面向安全的轻量级Linux发行版本.Docker的Alpine镜像仅有不 ...
- docker镜像 - 下载、创建镜像和导入导出镜像
实验环境 CentOS 7.5 安装并启动docker yum install -y docker systemctl start docker 镜像 安装镜像 docker pull [OPTION ...
- Docker 学习之镜像导入导出及推送阿里云服务器(三)
在前面两节里主要就是记录一些docker的基本的操作,包括搜索镜像,拉取镜像,根据镜像创建容器等等,在这一节主要就是记录Docker对于镜像文件的导入导出,及推送到阿里云再从阿里云获取镜像. 一.镜像 ...
- docker save 保存导出镜像
Docker保存镜像 tag 镜像 # 镜像打 tag 标签 # docker tag 镜像id/名 新名字 docker tag fce91102e17d tomcat01 commit 镜像 注意 ...
随机推荐
- 百亿数据百亿花, 库若恒河沙复沙,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang数据库操作实践EP12
Golang可以通过Gorm包来操作数据库,所谓ORM,即Object Relational Mapping(数据关系映射),说白了就是通过模式化的语法来操作数据库的行对象或者表对象,对比相对灵活繁复 ...
- Codeforces 1715E - Long Way Home
又是废掉的一个div2啊 第一次在学校熬夜打cf,开心还看到了自己最喜欢的斜率优化ohhh 链接 :E - Long Way Home 看到那个平方就可以靠感觉认为是斜率优化了.... 感觉似不似有点 ...
- java中list集合的几种去重方式
public class ListDistinctExample { public static void main(String[] args) { List<Integer> list ...
- 为什么各大厂自研的内存泄漏检测框架都要参考 LeakCanary?因为它是真强啊!
请点赞关注,你的支持对我意义重大. Hi,我是小彭.本文已收录到 GitHub · AndroidFamily 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,关注公众号 [彭旭锐] ...
- HDFS的读写流程——宏观与微观
HDFS的读写流程--宏观与微观 HDFS:分布式文件系统,负责存放数据 分布式文件系统:就是将我们的数据放到多台电脑上存储. 写数据:就是将客户端上的数据上传到HDFS 宏观过程 客户端向HDFS发 ...
- PHP实现获取本地视频进行随机播放
创建一个文件夹,里面随便方视频文件即可 列如文件夹名字是assets代码如下 <? $handler = opendir('./assets/mp4/');//当前目录中的文件夹下的文件夹 需要 ...
- 检查原生 JavaScript 函数是否被覆盖
你如何确定一个JavaScript原生函数是否被覆盖? 你不能--或者至少无法可靠地确定.有一些检测方法很接近,但你不能完全相信它们. JavaScript原生函数 在JavaScript中,原生函数 ...
- KingbaseES V8R6集群管理运维案例之---repmgr standby switchover故障
案例说明: 在KingbaseES V8R6集群备库执行"repmgr standby switchover"时,切换失败,并且在执行过程中,伴随着"repmr stan ...
- Karmada v1.3:更优雅 更精准 更高效
摘要:最新发布的1.3版本中,Karmada重新设计了应用跨集群故障迁移功能,实现了基于污点的故障驱逐机制,并提供平滑的故障迁移过程,可以有效保障服务迁移过程的连续性(不断服). 本文分享自华为云社区 ...
- 【设计模式】Java设计模式 - 装饰者模式
Java设计模式 - 装饰者模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起记录分享自 ...