概念性的东西:
1、layerID:
[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))
详解:
?首先下载一个nginx的镜像:
1、查找nginx对应的短IMAGE ID的sha256:
[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"}}}
?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"]}}
?从上图可以看出,nginx:latest分层里有几个分层,第一个分层为rootfs分层(该分层位于镜像的最底层),其他的为中间分层。
3、根据rootfs分层进行查看该分层的目录结构信息
(1) 根据rootfs分层的sha256找到该分层的cache-id
[root@tlzs sha256]# ls /var/lib/docker/image/overlay2/layerdb/sha256/9c1b6dd6c1e6be9fdd2b1987783824670d3b0dd7ae8ad6f57dc3cea5739ac71e
?(2)查看cache-id文件里的内容(里面存放的就是目录路径)?
[root@tlzs 9c1b6dd6c1e6be9fdd2b1987783824670d3b0dd7ae8ad6f57dc3cea5739ac71e]# cat cache-id
8d8d934d9a1843b57e3ba7a6228d6683d71d3ba89639e574abfc3a2c1eebb99f
?(3)根据cache-id里的内容查看该层(rootfs分层)的目录结构(即根目录)
cd /var/lib/docker/overlay2/8d8d934d9a1843b57e3ba7a6228d6683d71d3ba89639e574abfc3a2c1eebb99f
?上图中diff文件夹里就是目录结构:
4、查找除了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:
echo -n "sha256:9c1b6dd6c1e6be9fdd2b1987783824670d3b0dd7ae8ad6f57dc3cea5739ac71e sha256:4b7fffa0f0a4a72b2f901c584c1d4ffb67cce7f033cc7969ee7713995c4d2610" | sha256sum | awk '{print $1}'
(2)查看cache-id文件里的内容(里面存放的就是目录路径)?
[root@tlzs docker]# cat /var/lib/docker/image/overlay2/layerdb/sha256/186315e6b3b440e7935f059ccdaea035e03ccdb3133bc87055a299469d51717c/cache-id
d303be7c7a879cc62477eb35d89d0bebea4805b437d5f246e7df1a5428c7e1f8
(3)根据cache-id里的内容查看该层(rootfs分层)的目录结构(即根目录)
[root@tlzs docker]# cd /var/lib/docker/overlay2/d303be7c7a879cc62477eb35d89d0bebea4805b437d5f246e7df1a5428c7e1f8/
?上图中diff文件夹里就是目录结构:
|