镜像层研究
镜像是分层,这个我们都知道,但是每层都是什么呢?哪些命令会导致增加一层呢?docker commit的方式跟使用Dockerfile构建的区别呢?它的层会不会少一些呢?
解压镜像
构建脚本
FROM harbor.yundasys.com/base/php:7315-46
ADD yum.repos.tar.gz /etc/yum.repos.d
ADD librdkafka-1.8.2.tar.gz /root/tools
ADD rdkafka-5.0.0.tgz /root/tools
RUN yum install -y gcc autoconf gcc-c++ make \
&& cd /root/tools/librdkafka-1.8.2 \
&& ./configure \
&& make \
&& make install \
&& cd /root/tools/rdkafka-5.0.0 \
&& /usr/local/php/bin/phpize \
&& ./configure --with-php-config=/usr/local/php/bin/php-config \
&& make \
&& make install \
&& echo 'extension=rdkafka.so' >> /usr/local/php/etc/php.ini \
&& yum remove -y gcc-c++ gcc autoconf make \
&& yum clean all \
&& rm -f /etc/yum.repos.d/* \
&& rm -rf /root/tools/
解压镜像
# 保存镜像
docker save phpkafka:1.0 > phpkafka.tar
# 解压
tar xvf phpkafka.tar
# 查看配置文件
cat manifest.json
内容如下:
[
{
"Config": "486a39027b1f1d90355f3e562f7fe577a190f877c958a8d24eedd8a44a33ede0.json",
"RepoTags": [
"phpkafka:1.0"
],
"Layers": [
"74987dedac495b87824542fef3462baad0b444a24d91a073f37390ccb80d9e88/layer.tar",
"c6a308179ed52f69befc7effb66c495657630cef177c2455b4967362b3417a07/layer.tar",
"bdf5fed7ddde7883f8eb6e02fedb6d297e0d6daba8eb4b90ac142095d09dcc90/layer.tar",
"cc7e75bdba53f49faed55eeeb9c59ee12c9b510089c11202ed5c35ed476c6cce/layer.tar",
"b2836d813e4d889e1574e22a5a98934712058316b4195007c60b5d6b25f83514/layer.tar",
"38a52ad1c085fdaa6f03e244f5c214c9b7620da4b88f75182e006310720f3064/layer.tar",
"b23092a0583c32b720d20e88b37d052e0b4585ce50ca1d4ec48c0708fc71327c/layer.tar"
]
}
]
cd b23092a0583c32b720d20e88b37d052e0b4585ce50ca1d4ec48c0708fc71327c/
cat json
# 输出如下,说明该镜像是如何来的
tar xvf layer.tar
ls -alh
# layer.tar 即为该层的数据 发现其大小为95M 正好是基于母镜像,增加的大小
{
"id": "b23092a0583c32b720d20e88b37d052e0b4585ce50ca1d4ec48c0708fc71327c",
"parent": "38a52ad1c085fdaa6f03e244f5c214c9b7620da4b88f75182e006310720f3064",
"created": "2021-11-10T01:51:04.205949795Z",
"container": "9b23fdbb81e2578fba22e3b9909698e975e8ef99b11e666ff1e2479b1c8a7848",
"container_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",
"LC_ALL=en_US.UTF-8",
"LANGUAGE=en_US.UTF-8",
"LANG=en_US.UTF-8"
],
"Cmd": [
"/bin/sh",
"-c",
"yum install -y gcc autoconf gcc-c++ make && cd /root/tools/librdkafka-1.8.2 && ./configure && make && make install && cd /root/tools/rdkafka-5.0.0 && /usr/local/php/bin/phpize && ./configure --with-php-config=/usr/local/php/bin/php-config && make && make install && echo 'extension=rdkafka.so' >> /usr/local/php/etc/php.ini && yum remove -y gcc autoconf make && yum clean all && rm -f /etc/yum.repos.d/* && rm -rf /root/tools/"
],
"Image": "sha256:ddd9303467088159756cd88ba79dcc707f55ed765594384ec7d0cd7f492757e3",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20181204",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
"docker_version": "20.10.6",
"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",
"LC_ALL=en_US.UTF-8",
"LANGUAGE=en_US.UTF-8",
"LANG=en_US.UTF-8"
],
"Cmd": [
"/run.sh"
],
"ArgsEscaped": true,
"Image": "sha256:ddd9303467088159756cd88ba79dcc707f55ed765594384ec7d0cd7f492757e3",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20181204",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
"architecture": "amd64",
"os": "linux"
}
上层镜像
上层的镜像执行同样的操作,结果如下,但是我比较好奇的是,明明是基于该镜像构建打包的,为啥,产是的层,跟前面的层不一样呢?好奇怪。
docker save harbor.yundasys.com/base/php:7315-46 > php.tar
tar xvf php.tar
cat manifest.json
# 输出内容如下:
[
{
"Config": "5c790d70b3ae8180128b000c275106ce3ac89e32cabf73b0cfab80e609b121a6.json",
"RepoTags": [
"harbor.yundasys.com/base/php:7315-46"
],
"Layers": [
"74987dedac495b87824542fef3462baad0b444a24d91a073f37390ccb80d9e88/layer.tar",
"c6a308179ed52f69befc7effb66c495657630cef177c2455b4967362b3417a07/layer.tar",
"e48fc8bda85db4c2ae7b8857c3d3c657dd41e8f7491c43e74510142dd6bd4f99/layer.tar"
]
}
]
cd e48fc8bda85db4c2ae7b8857c3d3c657dd41e8f7491c43e74510142dd6bd4f99
ls -alh # 发现layer.tar的大小 438M M 说明该层的内容比较多
cat VERSION # 输出 1.0
cat json
输出的内容如下:
{
"id": "e48fc8bda85db4c2ae7b8857c3d3c657dd41e8f7491c43e74510142dd6bd4f99",
"parent": "c6a308179ed52f69befc7effb66c495657630cef177c2455b4967362b3417a07",
"created": "2020-03-13T05:35:42.828788768Z",
"container": "c99ddca5cf9ca657e5312d85f5a058bbcfba505202b809677db1b850402c4b9f",
"container_config": {
"Hostname": "c99ddca5cf9c",
"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",
"LC_ALL=en_US.UTF-8",
"LANGUAGE=en_US.UTF-8",
"LANG=en_US.UTF-8"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"/run.sh\"]"
],
"ArgsEscaped": true,
"Image": "sha256:27de3d979a1b156285eacaa3c2fcb5ae64429447a7a1a12493adf9a0a5e359d8",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20181204",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
"docker_version": "18.09.0",
"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",
"LC_ALL=en_US.UTF-8",
"LANGUAGE=en_US.UTF-8",
"LANG=en_US.UTF-8"
],
"Cmd": [
"/run.sh"
],
"ArgsEscaped": true,
"Image": "sha256:27de3d979a1b156285eacaa3c2fcb5ae64429447a7a1a12493adf9a0a5e359d8",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20181204",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
"architecture": "amd64",
"os": "linux"
}
自动化工具
# 美化json数据
yum install -y jq
# 使用
cat json |jq
docker inspect
# 好像只能看见当前层的信息
docker inspect centos:7.9.2009 # centos:7.9.2009镜像名
docker history
# 每层的构建命令,从最新到最老的层的构建
docker history --no-trunc python:3.7 > tmp.json
总结
manifest.json中的,Layers越靠后,层越新。
每层都会有一个额外的hash.json说明该层的一些信息
经发现,上层的镜像仓库只有3层,但是,它是用一个build.sh脚本,批量执行安装的脚本。然后达到一次安装所有依赖的软件,然后形成最终的一层。而且,它里面也用到了gcc,也是在最后的阶段,来清理掉这些工具的。