镜像层研究

镜像是分层,这个我们都知道,但是每层都是什么呢?哪些命令会导致增加一层呢?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,也是在最后的阶段,来清理掉这些工具的。