概念性的东西:

1、layerID:

文档管理 镜像_5e

[root@tlzs diff]# docker pull nginx
Using default tag: latest
latest: Pulling from library/nginx
1fe172e4850f: Pull complete
35c195f487df: Pull complete
213b9b16f495: Pull complete
a8172d9e19b9: Pull complete
f5eee2cb2150: Pull complete
93e404ba8667: Pull complete
Digest: sha256:859ab6768a6f26a79bc42b231664111317d095a4f04e4b6fe79ce37b3d199097
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest

1fe172e4850f、35c195f487df、213b9b16f495、a8172d9e19b9、f5eee2cb2150、93e404ba8667为压缩的layer层的哈希值,这些值为layerID!!!

2、diffID

[root@tlzs diff]# docker inspect nginx:latest
......
......
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:9c1b6dd6c1e6be9fdd2b1987783824670d3b0dd7ae8ad6f57dc3cea5739ac71e",
                "sha256:4b7fffa0f0a4a72b2f901c584c1d4ffb67cce7f033cc7969ee7713995c4d2610",
                "sha256:f5ab86d69014270bcf4d5ce819b9f5c882b35527924ffdd11fecf0fc0dde81a4",
                "sha256:c876aa251c80272eb01eec011d50650e1b8af494149696b80a606bbeccf03d68",
                "sha256:7046505147d7f3edbf7c50c02e697d5450a2eebe5119b62b7362b10662899d85",
                "sha256:b6812e8d56d65d296e21a639b786e7e793e8b969bd2b109fd172646ce5ebe951"
            ]
        },
        "Metadata": {
            "LastTagTime": "0001-01-01T00:00:00Z"
        }
    }
]

这是镜像的底层的rootfs,但是我们发现这些sha256值和第一步拉取下来的层layerID不一致。这是为什么呢?

因为pull下来的是压缩的数据,layerID是压缩数据的sha256的值(Layer ID指Distribution根据layer compressed data计算的),而inspect rootfs中的值是解压后,对解压的内容进行sha256的值他们是diffID,是在本地由Docker根据layer uncompressed data计算的。

记住这里的rootfs layers的值是diffID。

3、chainID

从diffID组成chainID:

layer.ChainID只用本地,根据layer.DiffID计算,并用于layerdb的目录名称。

chainID唯一标识了一组(像糖葫芦一样的串的底层)diffID的hash值,包含了这一层和它的父层(底层),当然这个糖葫芦可以有一颗山楂,也就是chainID(layer0)==diffID(layer0);对于多颗山楂的糖葫芦,ChainID(layerN) = SHA256hex(ChainID(layerN-1) + " " + DiffID(layerN))

详解:

1、rootfs根目录的查看步骤

首先下载一个nginx的镜像:

文档管理 镜像_5e

文档管理 镜像_5e_03

1、查找nginx对应的短IMAGE ID的sha256:

文档管理 镜像_文档管理 镜像_04

[root@tlzs overlay2]# cat /var/lib/docker/image/overlay2/repositories.json | grep fa5269854a5e
{"Repositories":{"java":{"java:8":"sha256:d23bdf5b1b1b1afce5f1d0fd33e7ed8afbc084b594b9ccf742a5b27080d8a4a8","java@sha256:c1ff613e8ba25833d2e1940da0940c3824f03f802c449f3d1815a66b7f8c0e9d":"sha256:d23bdf5b1b1b1afce5f1d0fd33e7ed8afbc084b594b9ccf742a5b27080d8a4a8"},"nginx":{"nginx:latest":"sha256:fa5269854a5e615e51a72b17ad3fd1e01268f278a6684c8ed3c5f0cdce3f230b","nginx@sha256:859ab6768a6f26a79bc42b231664111317d095a4f04e4b6fe79ce37b3d199097":"sha256:fa5269854a5e615e51a72b17ad3fd1e01268f278a6684c8ed3c5f0cdce3f230b"}}}

文档管理 镜像_nginx_05

 2、根据查找出来的nginx的长IMAGE ID进行查询镜像各分层的信息以及其他信息:

cat /var/lib/docker/image/overlay2/imagedb/content/sha256/fa5269854a5e615e51a72b17ad3fd1e01268f278a6684c8ed3c5f0cdce3f230b
[root@tlzs sha256]# cat /var/lib/docker/image/overlay2/imagedb/content/sha256/fa5269854a5e615e51a72b17ad3fd1e01268f278a6684c8ed3c5f0cdce3f230b
{"architecture":"amd64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"ExposedPorts":{"80/tcp":{}},"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","NGINX_VERSION=1.21.6","NJS_VERSION=0.7.2","PKG_RELEASE=1~bullseye"],"Cmd":["nginx","-g","daemon off;"],"Image":"sha256:e158bbfdf1201dbc8876232cef4465c5f69c1fd0986f05ee48291a92debc21a0","Volumes":null,"WorkingDir":"","Entrypoint":["/docker-entrypoint.sh"],"OnBuild":null,"Labels":{"maintainer":"NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e"},"StopSignal":"SIGQUIT"},"container":"3c8758320eb6a5293e75ce1ff5afe91584a72b4ee400792f34985a27673ffbc2","container_config":{"Hostname":"3c8758320eb6","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"ExposedPorts":{"80/tcp":{}},"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","NGINX_VERSION=1.21.6","NJS_VERSION=0.7.2","PKG_RELEASE=1~bullseye"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"nginx\" \"-g\" \"daemon off;\"]"],"Image":"sha256:e158bbfdf1201dbc8876232cef4465c5f69c1fd0986f05ee48291a92debc21a0","Volumes":null,"WorkingDir":"","Entrypoint":["/docker-entrypoint.sh"],"OnBuild":null,"Labels":{"maintainer":"NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e"},"StopSignal":"SIGQUIT"},"created":"2022-04-20T10:43:12.055940177Z","docker_version":"20.10.12","history":[{"created":"2022-04-20T04:43:27.318712902Z","created_by":"/bin/sh -c #(nop) ADD file:8b1e79f91081eb527b455431af58e823d8b84d9d0c8e5c47cb7bda7507954ae4 in / "},{"created":"2022-04-20T04:43:27.692067537Z","created_by":"/bin/sh -c #(nop)  CMD [\"bash\"]","empty_layer":true},{"created":"2022-04-20T10:42:53.18912297Z","created_by":"/bin/sh -c #(nop)  LABEL maintainer=NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e","empty_layer":true},{"created":"2022-04-20T10:42:53.284644364Z","created_by":"/bin/sh -c #(nop)  ENV NGINX_VERSION=1.21.6","empty_layer":true},{"created":"2022-04-20T10:42:53.377551587Z","created_by":"/bin/sh -c #(nop)  ENV NJS_VERSION=0.7.2","empty_layer":true},{"created":"2022-04-20T10:42:53.474229449Z","created_by":"/bin/sh -c #(nop)  ENV PKG_RELEASE=1~bullseye","empty_layer":true},{"created":"2022-04-20T10:43:11.169975933Z","created_by":"/bin/sh -c set -x     \u0026\u0026 addgroup --system --gid 101 nginx     \u0026\u0026 adduser --system --disabled-login --ingroup nginx --no-create-home --home /nonexistent --gecos \"nginx user\" --shell /bin/false --uid 101 nginx     \u0026\u0026 apt-get update     \u0026\u0026 apt-get install --no-install-recommends --no-install-suggests -y gnupg1 ca-certificates     \u0026\u0026     NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62;     found='';     for server in         hkp://keyserver.ubuntu.com:80         pgp.mit.edu     ; do         echo \"Fetching GPG key $NGINX_GPGKEY from $server\";         apt-key adv --keyserver \"$server\" --keyserver-options timeout=10 --recv-keys \"$NGINX_GPGKEY\" \u0026\u0026 found=yes \u0026\u0026 break;     done;     test -z \"$found\" \u0026\u0026 echo \u003e\u00262 \"error: failed to fetch GPG key $NGINX_GPGKEY\" \u0026\u0026 exit 1;     apt-get remove --purge --auto-remove -y gnupg1 \u0026\u0026 rm -rf /var/lib/apt/lists/*     \u0026\u0026 dpkgArch=\"$(dpkg --print-architecture)\"     \u0026\u0026 nginxPackages=\"         nginx=${NGINX_VERSION}-${PKG_RELEASE}         nginx-module-xslt=${NGINX_VERSION}-${PKG_RELEASE}         nginx-module-geoip=${NGINX_VERSION}-${PKG_RELEASE}         nginx-module-image-filter=${NGINX_VERSION}-${PKG_RELEASE}         nginx-module-njs=${NGINX_VERSION}+${NJS_VERSION}-${PKG_RELEASE}     \"     \u0026\u0026 case \"$dpkgArch\" in         amd64|arm64)             echo \"deb https://nginx.org/packages/mainline/debian/ bullseye nginx\" \u003e\u003e /etc/apt/sources.list.d/nginx.list             \u0026\u0026 apt-get update             ;;         *)             echo \"deb-src https://nginx.org/packages/mainline/debian/ bullseye nginx\" \u003e\u003e /etc/apt/sources.list.d/nginx.list                         \u0026\u0026 tempDir=\"$(mktemp -d)\"             \u0026\u0026 chmod 777 \"$tempDir\"                         \u0026\u0026 savedAptMark=\"$(apt-mark showmanual)\"                         \u0026\u0026 apt-get update             \u0026\u0026 apt-get build-dep -y $nginxPackages             \u0026\u0026 (                 cd \"$tempDir\"                 \u0026\u0026 DEB_BUILD_OPTIONS=\"nocheck parallel=$(nproc)\"                     apt-get source --compile $nginxPackages             )                         \u0026\u0026 apt-mark showmanual | xargs apt-mark auto \u003e /dev/null             \u0026\u0026 { [ -z \"$savedAptMark\" ] || apt-mark manual $savedAptMark; }                         \u0026\u0026 ls -lAFh \"$tempDir\"             \u0026\u0026 ( cd \"$tempDir\" \u0026\u0026 dpkg-scanpackages . \u003e Packages )             \u0026\u0026 grep '^Package: ' \"$tempDir/Packages\"             \u0026\u0026 echo \"deb [ trusted=yes ] file://$tempDir ./\" \u003e /etc/apt/sources.list.d/temp.list             \u0026\u0026 apt-get -o Acquire::GzipIndexes=false update             ;;     esac         \u0026\u0026 apt-get install --no-install-recommends --no-install-suggests -y                         $nginxPackages                         gettext-base                         curl     \u0026\u0026 apt-get remove --purge --auto-remove -y \u0026\u0026 rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx.list         \u0026\u0026 if [ -n \"$tempDir\" ]; then         apt-get purge -y --auto-remove         \u0026\u0026 rm -rf \"$tempDir\" /etc/apt/sources.list.d/temp.list;     fi     \u0026\u0026 ln -sf /dev/stdout /var/log/nginx/access.log     \u0026\u0026 ln -sf /dev/stderr /var/log/nginx/error.log     \u0026\u0026 mkdir /docker-entrypoint.d"},{"created":"2022-04-20T10:43:11.389412383Z","created_by":"/bin/sh -c #(nop) COPY file:65504f71f5855ca017fb64d502ce873a31b2e0decd75297a8fb0a287f97acf92 in / "},{"created":"2022-04-20T10:43:11.492647157Z","created_by":"/bin/sh -c #(nop) COPY file:0b866ff3fc1ef5b03c4e6c8c513ae014f691fb05d530257dfffd07035c1b75da in /docker-entrypoint.d "},{"created":"2022-04-20T10:43:11.595228483Z","created_by":"/bin/sh -c #(nop) COPY file:0fd5fca330dcd6a7de297435e32af634f29f7132ed0550d342cad9fd20158258 in /docker-entrypoint.d "},{"created":"2022-04-20T10:43:11.696928206Z","created_by":"/bin/sh -c #(nop) COPY file:09a214a3e07c919af2fb2d7c749ccbc446b8c10eb217366e5a65640ee9edcc25 in /docker-entrypoint.d "},{"created":"2022-04-20T10:43:11.783761903Z","created_by":"/bin/sh -c #(nop)  ENTRYPOINT [\"/docker-entrypoint.sh\"]","empty_layer":true},{"created":"2022-04-20T10:43:11.877035082Z","created_by":"/bin/sh -c #(nop)  EXPOSE 80","empty_layer":true},{"created":"2022-04-20T10:43:11.966420855Z","created_by":"/bin/sh -c #(nop)  STOPSIGNAL SIGQUIT","empty_layer":true},{"created":"2022-04-20T10:43:12.055940177Z","created_by":"/bin/sh -c #(nop)  CMD [\"nginx\" \"-g\" \"daemon off;\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:9c1b6dd6c1e6be9fdd2b1987783824670d3b0dd7ae8ad6f57dc3cea5739ac71e","sha256:4b7fffa0f0a4a72b2f901c584c1d4ffb67cce7f033cc7969ee7713995c4d2610","sha256:f5ab86d69014270bcf4d5ce819b9f5c882b35527924ffdd11fecf0fc0dde81a4","sha256:c876aa251c80272eb01eec011d50650e1b8af494149696b80a606bbeccf03d68","sha256:7046505147d7f3edbf7c50c02e697d5450a2eebe5119b62b7362b10662899d85","sha256:b6812e8d56d65d296e21a639b786e7e793e8b969bd2b109fd172646ce5ebe951"]}}

文档管理 镜像_docker_06

 从上图可以看出,nginx:latest分层里有几个分层,第一个分层为rootfs分层(该分层位于镜像的最底层),其他的为中间分层。

3、根据rootfs分层进行查看该分层的目录结构信息

(1) 根据rootfs分层的sha256找到该分层的cache-id

[root@tlzs sha256]# ls /var/lib/docker/image/overlay2/layerdb/sha256/9c1b6dd6c1e6be9fdd2b1987783824670d3b0dd7ae8ad6f57dc3cea5739ac71e

文档管理 镜像_文档管理 镜像_07

 (2)查看cache-id文件里的内容(里面存放的就是目录路径) 

[root@tlzs 9c1b6dd6c1e6be9fdd2b1987783824670d3b0dd7ae8ad6f57dc3cea5739ac71e]# cat cache-id
8d8d934d9a1843b57e3ba7a6228d6683d71d3ba89639e574abfc3a2c1eebb99f

 (3)根据cache-id里的内容查看该层(rootfs分层)的目录结构(即根目录)

cd /var/lib/docker/overlay2/8d8d934d9a1843b57e3ba7a6228d6683d71d3ba89639e574abfc3a2c1eebb99f

文档管理 镜像_docker_08

 上图中diff文件夹里就是目录结构:

文档管理 镜像_nginx_09

2、查找除了rootfs分层的其他的中间分层的目录结构

备注:由于根据第3步骤的方式查找其他分层信息,就是查找不到。

其原因:

docker引入了内容寻址机制,该机制会根据文件内容来索引镜像和镜像层,docker利用rootfs中的cache-id计算出内容寻址的cache-id,通过cache-id的内容获取layer相关信息,最终索引到镜像层文件内容。

对于最底层镜像层其cache-id的内容即是layerId,因此我们可以查找到它的文件内容信息。除最底层外,layerId需通过ChainID(layerN) = SHA256hex(ChainID(layerN-1) + " " + DiffID(layerN))。

从diffID组成chainID:

layer.ChainID只用本地,根据layer.DiffID计算,并用于layerdb的目录名称。

chainID唯一标识了一组(像糖葫芦一样的串的底层)diffID的hash值,包含了这一层和它的父层(底层),当然这个糖葫芦可以有一颗山楂,也就是chainID(layer0)==diffID(layer0);对于多颗山楂的糖葫芦,ChainID(layerN) = SHA256hex(ChainID(layerN-1) + " " + DiffID(layerN))

(1)计算中间层layerId(即chainID):

echo -n "sha256:9c1b6dd6c1e6be9fdd2b1987783824670d3b0dd7ae8ad6f57dc3cea5739ac71e sha256:4b7fffa0f0a4a72b2f901c584c1d4ffb67cce7f033cc7969ee7713995c4d2610" | sha256sum | awk '{print $1}'

 结果为:186315e6b3b440e7935f059ccdaea035e03ccdb3133bc87055a299469d51717c

文档管理 镜像_nginx_10

文档管理 镜像_镜像分层_11

(2)查看cache-id文件里的内容(里面存放的就是目录路径) 

[root@tlzs docker]# cat /var/lib/docker/image/overlay2/layerdb/sha256/186315e6b3b440e7935f059ccdaea035e03ccdb3133bc87055a299469d51717c/cache-id 
d303be7c7a879cc62477eb35d89d0bebea4805b437d5f246e7df1a5428c7e1f8

(3)根据cache-id里的内容查看该层的目录结构

[root@tlzs docker]# cd /var/lib/docker/overlay2/d303be7c7a879cc62477eb35d89d0bebea4805b437d5f246e7df1a5428c7e1f8/

文档管理 镜像_镜像分层_12

 上图中diff文件夹里就是目录结构:

文档管理 镜像_5e_13

3、第三层的chainID的计算方式

对于最底层镜像层其cache-id的内容即是layerId,因此我们可以查找到它的文件内容信息。除最底层外,layerId需通过ChainID(layerN) = SHA256hex(ChainID(layerN-1) + " " + DiffID(layerN))。

chainID):

红框区域是第三层的diffID:

文档管理 镜像_文档管理 镜像_14

 

echo -n "sha256:186315e6b3b440e7935f059ccdaea035e03ccdb3133bc87055a299469d51717c sha256:f5ab86d69014270bcf4d5ce819b9f5c882b35527924ffdd11fecf0fc0dde81a4" | sha256sum | awk '{print $1}'

结果:1c4fd4da0a6c4dec7037b57b8b24ca6a346209983cbe63264afe4e724a8a9976 

文档管理 镜像_nginx_15

cd /var/lib/docker/image/overlay2/layerdb/sha256/1c4fd4da0a6c4dec7037b57b8b24ca6a346209983cbe63264afe4e724a8a9976

文档管理 镜像_nginx_16

 (2)查看cache-id文件里的内容(里面存放的就是目录路径) 

[root@tlzs 1c4fd4da0a6c4dec7037b57b8b24ca6a346209983cbe63264afe4e724a8a9976]# cat cache-id 
fc77798305e89bb3802b4da7ab7b8ae1e9f7337f45d6182884d7a590d79ea0c7

cache-id的内容:fc77798305e89bb3802b4da7ab7b8ae1e9f7337f45d6182884d7a590d79ea0c7 

(3)根据cache-id里的内容查看该层的目录结构

[root@tlzs overlay2]# cd /var/lib/docker/overlay2/fc77798305e89bb3802b4da7ab7b8ae1e9f7337f45d6182884d7a590d79ea0c7

文档管理 镜像_docker_17

 上图中diff文件夹里就是目录结构:

文档管理 镜像_镜像分层_18

备注:以上过程讲述了rootfs最底层的查看方式,以及第二层和第三层的查看方式,如果还有其他的中间层,可以参照第三层的查看方式进行查看!!!