您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關docker中的本地存儲是怎樣的,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
以 overlay2
為例帶大家看看,在我們執行 docker build
,docker pull
,docker run
等命令時本地存儲有何變化。
查看 docker Storage Driver
可以通過 docker info | grep "Storage Driver"
命令。
docker 的默認安裝目錄為: /var/lib/docker
,如果要修改可以通過修改啟動時的配置文件(默認為/usr/lib/systemd/system/docker.service
) 中的 ExecStart
,
查看 docker 啟動時的配置文件:
修改 docker 的存儲目錄:
修改(增加) --graph
即可。
[root@iZuf685opgs9oyozju9i2bZ docker]# ll 總用量 48 drwx------ 2 root root 4096 11月 11 08:49 builder drwx--x--x 4 root root 4096 11月 11 08:49 buildkit drwx------ 3 root root 4096 12月 2 09:25 containers drwx------ 3 root root 4096 11月 11 08:49 image drwxr-x--- 3 root root 4096 11月 11 08:49 network drwx------ 9 root root 4096 12月 2 09:25 overlay2 drwx------ 4 root root 4096 11月 11 08:49 plugins drwx------ 2 root root 4096 11月 11 08:49 runtimes drwx------ 2 root root 4096 11月 11 08:49 swarm drwx------ 2 root root 4096 11月 11 13:32 tmp drwx------ 2 root root 4096 11月 11 08:49 trust drwx------ 2 root root 4096 11月 11 08:49 volumes
可以用 tree
進行展開
[root@iZuf685opgs9oyozju9i2bZ docker]# tree -L 2 . ├── builder │ └── fscache.db ├── buildkit │ ├── cache.db │ ├── content │ ├── executor │ ├── metadata.db │ └── snapshots.db ├── containers │ └── 9bd6ac07a8c962e2403203e1c45f4fb54733f9953cf318b34fc3f155bf2c0c59 ├── image │ └── overlay2 ├── network │ └── files ├── overlay2 │ ├── 00b65b9c288df8c0ae7cdacba531a7dc5cb006e6c768e19ee36055717b782acc │ ├── 1e53dddb1a0bb04ee4ebd24a8edb94b96e2fd471a72bf1b8608096b38cb16646 │ ├── 1e53dddb1a0bb04ee4ebd24a8edb94b96e2fd471a72bf1b8608096b38cb16646-init │ ├── 5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4 │ ├── 8cbfb8b74c887e780747c8e6f4b3b9223a513ff6d69770bac16abb76da4e314f │ ├── f1cf8b173467c98e08f3d276d7ccd8f9892c7c71dec2c4b335c39c6f175ae744 │ └── l ├── plugins │ ├── storage │ └── tmp ├── runtimes ├── swarm ├── tmp ├── trust └── volumes └── metadata.db 26 directories, 5 files
這篇文章以分析存儲為主,涉及到的目錄有 image
,containers
,overlay2
,其他的目錄放在后續的文章討論。
在真正開始之前,先想想幾個問題(這也是我自己問我自己的問題) :
docker build 的過程是怎樣的?
docker pull 和 docker build 產生的鏡像存放在哪了?
docker run 運行一個容器的時候過程是怎么樣的?
帶著這些問題我們以一個例子進行說明 russellgao/openresty:1.17.8.2-5-alpine
image 目錄主要存放的鏡像相關的信息,我們執行 docker pull russellgao/openresty:1.17.8.2-5-alpine
看看:
[root@iZuf685opgs9oyozju9i2bZ docker]# docker pull russellgao/openresty:1.17.8.2-5-alpine 1.17.8.2-5-alpine: Pulling from russellgao/openresty df20fa9351a1: Already exists 5682af42731d: Pull complete 7c6cb2b54a9d: Pull complete aa74dc345098: Pull complete Digest: sha256:224ced85b5f8b679a8664a39b69c1b8feb09f8ba4343d834bd5b69433081389e Status: Downloaded newer image for openresty/openresty:1.17.8.2-5-alpine
可以看到 pull 了 4 層下來了,我們看看 image
目錄:
[root@iZuf685opgs9oyozju9i2bZ docker]# tree image image └── overlay2 ├── distribution │ ├── diffid-by-digest │ │ └── sha256 │ │ ├── 5682af42731d652bd98d2456ed3da4f0595ed5d9e5b13ac8bb9590bb74f72eb8 │ │ ├── 7c6cb2b54a9d9d40c4a03dd6615b1c8e791feb5d81464a7702a9bb921f7a73e9 │ │ ├── aa74dc3450985aee599c181d650da8f8880ca1d6e2bc01a43831ca59b6e2a7b6 │ │ └── df20fa9351a15782c64e6dddb2d4a6f50bf6d3688060a34c4014b0d9a752eb4c │ └── v2metadata-by-diffid │ └── sha256 │ ├── 1680a9f16b18732726d0656b6d6ff9611a3c4460ca870827b537a87bbe10cc22 │ ├── 50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a │ ├── 8521b614863046bf4bb604e3586feeca8b7ce1372f1d6664a5545e85ad9ca472 │ └── 9c572ba82b91e3ac35c7351bdacc6876c67f5d9bc69c5e51e8b2deeafae95e4f ├── imagedb │ ├── content │ │ └── sha256 │ │ └── 1ddc7a18ba0bcc20c61447f391bfff98ac559eea590e7ac59b5b5f588f1f47ed │ └── metadata │ └── sha256 │ └── 1ddc7a18ba0bcc20c61447f391bfff98ac559eea590e7ac59b5b5f588f1f47ed │ └── lastUpdated ├── layerdb │ ├── mounts │ │ └── 9bd6ac07a8c962e2403203e1c45f4fb54733f9953cf318b34fc3f155bf2c0c59 │ │ ├── init-id │ │ ├── mount-id │ │ └── parent │ ├── sha256 │ │ ├── 228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3 │ │ │ ├── cache-id │ │ │ ├── diff │ │ │ ├── parent │ │ │ ├── size │ │ │ └── tar-split.json.gz │ │ ├── 50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a │ │ │ ├── cache-id │ │ │ ├── diff │ │ │ ├── size │ │ │ └── tar-split.json.gz │ │ ├── 5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da │ │ │ ├── cache-id │ │ │ ├── diff │ │ │ ├── parent │ │ │ ├── size │ │ │ └── tar-split.json.gz │ │ └── fe267088885017d5e9a4621e68617a7f35e58dc2d0d747927882da21059854e3 │ │ ├── cache-id │ │ ├── diff │ │ ├── parent │ │ ├── size │ │ └── tar-split.json.gz │ └── tmp └── repositories.json 21 directories, 33 files
看看 repositories.json 中是內容 :
[root@iZuf685opgs9oyozju9i2bZ docker]# cat image/overlay2/repositories.json | jq . { "Repositories": { "openresty/openresty": { "openresty/openresty:1.17.8.2-5-alpine": "sha256:1ddc7a18ba0bcc20c61447f391bfff98ac559eea590e7ac59b5b5f588f1f47ed", "openresty/openresty@sha256:224ced85b5f8b679a8664a39b69c1b8feb09f8ba4343d834bd5b69433081389e": "sha256:1ddc7a18ba0bcc20c61447f391bfff98ac559eea590e7ac59b5b5f588f1f47ed" }, "russellgao/openresty": { "russellgao/openresty:1.17.8.2-5-alpine": "sha256:1ddc7a18ba0bcc20c61447f391bfff98ac559eea590e7ac59b5b5f588f1f47ed", "russellgao/openresty@sha256:84f53dc7517e9b6695fc8fd74916a1eb5970a92fc24a984f99bfb81508f3d261": "sha256:1ddc7a18ba0bcc20c61447f391bfff98ac559eea590e7ac59b5b5f588f1f47ed" } } }
repositories.json 中記錄了這個機器上所有的鏡像,可以看到這里有兩個鏡像 openresty/openresty:1.17.8.2-5-alpine
和 russellgao/openresty:1.17.8.2-5-alpine
,但其實只有一個鏡像,因為后面的 imageid
是相同的,這個可以 docker images
驗證一下
[root@iZuf685opgs9oyozju9i2bZ docker]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE openresty/openresty 1.17.8.2-5-alpine 1ddc7a18ba0b 2 months ago 104MB russellgao/openresty 1.17.8.2-5-alpine 1ddc7a18ba0b 2 months ago 104MB
openresty/openresty:1.17.8.2-5-alpine
和 russellgao/openresty:1.17.8.2-5-alpine
只是鏡像 1ddc7a18ba0b
的 tag 。
那么 1ddc7a18ba0b
鏡像是怎么組成的呢? image/overlay2/
下面除了 repositories.json 還有3個目錄 distribution
,imagedb
,layerdb
,作用分別如下:
distribution: 主要和鏡像倉庫的交互相關
imagedb: 保存了鏡像的元數據
layerdb: 保存了鏡像layer(層) 的數據
image/overlay2/
保存的是數據的鏈接,真正的鏡像數據是存放在 overlay2
目錄下,先看看 distribution
:
[root@iZuf685opgs9oyozju9i2bZ docker]# tree image/overlay2/distribution/ image/overlay2/distribution/ ├── diffid-by-digest │ └── sha256 │ ├── 5682af42731d652bd98d2456ed3da4f0595ed5d9e5b13ac8bb9590bb74f72eb8 │ ├── 7c6cb2b54a9d9d40c4a03dd6615b1c8e791feb5d81464a7702a9bb921f7a73e9 │ ├── aa74dc3450985aee599c181d650da8f8880ca1d6e2bc01a43831ca59b6e2a7b6 │ └── df20fa9351a15782c64e6dddb2d4a6f50bf6d3688060a34c4014b0d9a752eb4c └── v2metadata-by-diffid └── sha256 ├── 1680a9f16b18732726d0656b6d6ff9611a3c4460ca870827b537a87bbe10cc22 ├── 50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a ├── 8521b614863046bf4bb604e3586feeca8b7ce1372f1d6664a5545e85ad9ca472 └── 9c572ba82b91e3ac35c7351bdacc6876c67f5d9bc69c5e51e8b2deeafae95e4f 4 directories, 8 files
請注意看 image/overlay2/distribution/diffid-by-digest/sha256
下面,回過頭再看看 docker pull 的過程,這里的就是 digestid
,docker pull 的時候也是通過 digestid
實現的,這個id對應的是 docker repository
中的 blob id
,在 docker repository
的 blobs
目錄下可以找到。
可以查看具體的文件,如 cat image/overlay2/distribution/diffid-by-digest/sha256/5682af42731d652bd98d2456ed3da4f0595ed5d9e5b13ac8bb9590bb74f72eb8
[root@iZuf685opgs9oyozju9i2bZ docker]# cat image/overlay2/distribution/diffid-by-digest/sha256/5682af42731d652bd98d2456ed3da4f0595ed5d9e5b13ac8bb9590bb74f72eb8 sha256:9c572ba82b91e3ac35c7351bdacc6876c67f5d9bc69c5e51e8b2deeafae95e4f
不難發現它們之間是相互引用的,可以實現 diffid
和 digest
的相互轉換。
[root@iZuf685opgs9oyozju9i2bZ docker]# tree image/overlay2/imagedb/ image/overlay2/imagedb/ ├── content │ └── sha256 │ └── 1ddc7a18ba0bcc20c61447f391bfff98ac559eea590e7ac59b5b5f588f1f47ed └── metadata └── sha256 └── 1ddc7a18ba0bcc20c61447f391bfff98ac559eea590e7ac59b5b5f588f1f47ed └── lastUpdated 5 directories, 2 files
可以看到 imagedb
是以鏡像為單位進行存儲的,看一下 content
下面的具體內容 :
[root@iZuf685opgs9oyozju9i2bZ docker]# cat image/overlay2/imagedb/content/sha256/1ddc7a18ba0bcc20c61447f391bfff98ac559eea590e7ac59b5b5f588f1f47ed | jq . { "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:/usr/local/openresty/luajit/bin:/usr/local/openresty/nginx/sbin:/usr/local/openresty/bin" ], "Cmd": [ "/usr/local/openresty/bin/openresty", "-g", "daemon off;" ], "ArgsEscaped": true, "Image": "sha256:0b827067ad09ab8a0b9a73a45f5b1c408b84db1ca6883a4c544078ed43b8b5e3", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": { "maintainer": "Evan Wies <evan@neomantra.net>", "resty_add_package_builddeps": "", "resty_add_package_rundeps": "", "resty_config_deps": "--with-pcre --with-cc-opt='-DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl/include' --with-ld-opt='-L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl/lib -Wl,-rpath,/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl/lib' ", "resty_config_options": " --with-compat --with-file-aio --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_xslt_module=dynamic --with-ipv6 --with-mail --with-mail_ssl_module --with-md5-asm --with-pcre-jit --with-sha1-asm --with-stream --with-stream_ssl_module --with-threads ", "resty_config_options_more": "", "resty_eval_post_make": "", "resty_eval_pre_configure": "", "resty_image_base": "alpine", "resty_image_tag": "3.12", "resty_openssl_patch_version": "1.1.1f", "resty_openssl_url_base": "https://www.openssl.org/source", "resty_openssl_version": "1.1.1g", "resty_pcre_version": "8.44", "resty_version": "1.17.8.2" }, "StopSignal": "SIGQUIT" }, "container": "0ae35046dd1afef0f1f525360939abc524dbd469a92470c5836dfbb7dc666923", "container_config": { "Hostname": "0ae35046dd1a", "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:/usr/local/openresty/luajit/bin:/usr/local/openresty/nginx/sbin:/usr/local/openresty/bin" ], "Cmd": [ "/bin/sh", "-c", "#(nop) ", "STOPSIGNAL SIGQUIT" ], "ArgsEscaped": true, "Image": "sha256:0b827067ad09ab8a0b9a73a45f5b1c408b84db1ca6883a4c544078ed43b8b5e3", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": { "maintainer": "Evan Wies <evan@neomantra.net>", "resty_add_package_builddeps": "", "resty_add_package_rundeps": "", "resty_config_deps": "--with-pcre --with-cc-opt='-DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl/include' --with-ld-opt='-L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl/lib -Wl,-rpath,/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl/lib' ", "resty_config_options": " --with-compat --with-file-aio --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_xslt_module=dynamic --with-ipv6 --with-mail --with-mail_ssl_module --with-md5-asm --with-pcre-jit --with-sha1-asm --with-stream --with-stream_ssl_module --with-threads ", "resty_config_options_more": "", "resty_eval_post_make": "", "resty_eval_pre_configure": "", "resty_image_base": "alpine", "resty_image_tag": "3.12", "resty_openssl_patch_version": "1.1.1f", "resty_openssl_url_base": "https://www.openssl.org/source", "resty_openssl_version": "1.1.1g", "resty_pcre_version": "8.44", "resty_version": "1.17.8.2" }, "StopSignal": "SIGQUIT" }, "created": "2020-09-18T16:25:11.080239395Z", "docker_version": "18.06.0-ce", "history": [ { "created": "2020-05-29T21:19:46.192045972Z", "created_by": "/bin/sh -c #(nop) ADD file:c92c248239f8c7b9b3c067650954815f391b7bcb09023f984972c082ace2a8d0 in / " }, { "created": "2020-05-29T21:19:46.363518345Z", "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]", "empty_layer": true }, { "created": "2020-09-18T16:18:11.417409263Z", "created_by": "/bin/sh -c #(nop) LABEL maintainer=Evan Wies <evan@neomantra.net>", "empty_layer": true }, { "created": "2020-09-18T16:18:11.510209288Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_IMAGE_BASE=alpine", "empty_layer": true }, { "created": "2020-09-18T16:18:11.601623273Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_IMAGE_TAG=3.12", "empty_layer": true }, { "created": "2020-09-18T16:18:11.688966243Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_VERSION=1.17.8.2", "empty_layer": true }, { "created": "2020-09-18T16:18:11.783539793Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_OPENSSL_VERSION=1.1.1g", "empty_layer": true }, { "created": "2020-09-18T16:18:11.885734193Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_OPENSSL_PATCH_VERSION=1.1.1f", "empty_layer": true }, { "created": "2020-09-18T16:18:11.977916317Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_OPENSSL_URL_BASE=https://www.openssl.org/source", "empty_layer": true }, { "created": "2020-09-18T16:18:12.075117786Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_PCRE_VERSION=8.44", "empty_layer": true }, { "created": "2020-09-18T16:18:12.169065223Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_J=1", "empty_layer": true }, { "created": "2020-09-18T16:18:12.268734856Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_CONFIG_OPTIONS= --with-compat --with-file-aio --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_xslt_module=dynamic --with-ipv6 --with-mail --with-mail_ssl_module --with-md5-asm --with-pcre-jit --with-sha1-asm --with-stream --with-stream_ssl_module --with-threads ", "empty_layer": true }, { "created": "2020-09-18T16:18:12.363332751Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_CONFIG_OPTIONS_MORE=", "empty_layer": true }, { "created": "2020-09-18T16:18:12.462196367Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_LUAJIT_OPTIONS=--with-luajit-xcflags='-DLUAJIT_NUMMODE=2 -DLUAJIT_ENABLE_LUA52COMPAT'", "empty_layer": true }, { "created": "2020-09-18T16:18:12.553726712Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_ADD_PACKAGE_BUILDDEPS=", "empty_layer": true }, { "created": "2020-09-18T16:18:12.644512619Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_ADD_PACKAGE_RUNDEPS=", "empty_layer": true }, { "created": "2020-09-18T16:18:12.740127392Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_EVAL_PRE_CONFIGURE=", "empty_layer": true }, { "created": "2020-09-18T16:18:12.833898538Z", "created_by": "/bin/sh -c #(nop) ARG RESTY_EVAL_POST_MAKE=", "empty_layer": true }, { "created": "2020-09-18T16:18:12.93159843Z", "created_by": "/bin/sh -c #(nop) ARG _RESTY_CONFIG_DEPS=--with-pcre --with-cc-opt='-DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl/include' --with-ld-opt='-L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl/lib -Wl,-rpath,/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl/lib' ", "empty_layer": true }, { "created": "2020-09-18T16:18:13.022542363Z", "created_by": "/bin/sh -c #(nop) LABEL resty_image_base=alpine", "empty_layer": true }, { "created": "2020-09-18T16:18:13.120036187Z", "created_by": "/bin/sh -c #(nop) LABEL resty_image_tag=3.12", "empty_layer": true }, { "created": "2020-09-18T16:18:13.20899948Z", "created_by": "/bin/sh -c #(nop) LABEL resty_version=1.17.8.2", "empty_layer": true }, { "created": "2020-09-18T16:18:13.292383125Z", "created_by": "/bin/sh -c #(nop) LABEL resty_openssl_version=1.1.1g", "empty_layer": true }, { "created": "2020-09-18T16:18:13.385097561Z", "created_by": "/bin/sh -c #(nop) LABEL resty_openssl_patch_version=1.1.1f", "empty_layer": true }, { "created": "2020-09-18T16:18:13.476173083Z", "created_by": "/bin/sh -c #(nop) LABEL resty_openssl_url_base=https://www.openssl.org/source", "empty_layer": true }, { "created": "2020-09-18T16:18:13.564110015Z", "created_by": "/bin/sh -c #(nop) LABEL resty_pcre_version=8.44", "empty_layer": true }, { "created": "2020-09-18T16:18:13.653688493Z", "created_by": "/bin/sh -c #(nop) LABEL resty_config_options= --with-compat --with-file-aio --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_xslt_module=dynamic --with-ipv6 --with-mail --with-mail_ssl_module --with-md5-asm --with-pcre-jit --with-sha1-asm --with-stream --with-stream_ssl_module --with-threads ", "empty_layer": true }, { "created": "2020-09-18T16:18:13.747250902Z", "created_by": "/bin/sh -c #(nop) LABEL resty_config_options_more=", "empty_layer": true }, { "created": "2020-09-18T16:18:13.839314208Z", "created_by": "/bin/sh -c #(nop) LABEL resty_config_deps=--with-pcre --with-cc-opt='-DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl/include' --with-ld-opt='-L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl/lib -Wl,-rpath,/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl/lib' ", "empty_layer": true }, { "created": "2020-09-18T16:18:13.938461929Z", "created_by": "/bin/sh -c #(nop) LABEL resty_add_package_builddeps=", "empty_layer": true }, { "created": "2020-09-18T16:18:14.023327305Z", "created_by": "/bin/sh -c #(nop) LABEL resty_add_package_rundeps=", "empty_layer": true }, { "created": "2020-09-18T16:18:14.111176277Z", "created_by": "/bin/sh -c #(nop) LABEL resty_eval_pre_configure=", "empty_layer": true }, { "created": "2020-09-18T16:18:14.211102965Z", "created_by": "/bin/sh -c #(nop) LABEL resty_eval_post_make=", "empty_layer": true }, { "created": "2020-09-18T16:25:10.276243663Z", "created_by": "|16 RESTY_ADD_PACKAGE_BUILDDEPS= RESTY_ADD_PACKAGE_RUNDEPS= RESTY_CONFIG_OPTIONS= --with-compat --with-file-aio --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_xslt_module=dynamic --with-ipv6 --with-mail --with-mail_ssl_module --with-md5-asm --with-pcre-jit --with-sha1-asm --with-stream --with-stream_ssl_module --with-threads RESTY_CONFIG_OPTIONS_MORE= RESTY_EVAL_POST_MAKE= RESTY_EVAL_PRE_CONFIGURE= RESTY_IMAGE_BASE=alpine RESTY_IMAGE_TAG=3.12 RESTY_J=1 RESTY_LUAJIT_OPTIONS=--with-luajit-xcflags='-DLUAJIT_NUMMODE=2 -DLUAJIT_ENABLE_LUA52COMPAT' RESTY_OPENSSL_PATCH_VERSION=1.1.1f RESTY_OPENSSL_URL_BASE=https://www.openssl.org/source RESTY_OPENSSL_VERSION=1.1.1g RESTY_PCRE_VERSION=8.44 RESTY_VERSION=1.17.8.2 _RESTY_CONFIG_DEPS=--with-pcre --with-cc-opt='-DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl/include' --with-ld-opt='-L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl/lib -Wl,-rpath,/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl/lib' /bin/sh -c apk add --no-cache --virtual .build-deps build-base coreutils curl gd-dev geoip-dev libxslt-dev linux-headers make perl-dev readline-dev zlib-dev ${RESTY_ADD_PACKAGE_BUILDDEPS} && apk add --no-cache gd geoip libgcc libxslt zlib ${RESTY_ADD_PACKAGE_RUNDEPS} && cd /tmp && if [ -n \"${RESTY_EVAL_PRE_CONFIGURE}\" ]; then eval $(echo ${RESTY_EVAL_PRE_CONFIGURE}); fi && cd /tmp && curl -fSL \"${RESTY_OPENSSL_URL_BASE}/openssl-${RESTY_OPENSSL_VERSION}.tar.gz\" -o openssl-${RESTY_OPENSSL_VERSION}.tar.gz && tar xzf openssl-${RESTY_OPENSSL_VERSION}.tar.gz && cd openssl-${RESTY_OPENSSL_VERSION} && if [ $(echo ${RESTY_OPENSSL_VERSION} | cut -c 1-5) = \"1.1.1\" ] ; then echo 'patching OpenSSL 1.1.1 for OpenResty' && curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-${RESTY_OPENSSL_PATCH_VERSION}-sess_set_get_cb_yield.patch | patch -p1 ; fi && if [ $(echo ${RESTY_OPENSSL_VERSION} | cut -c 1-5) = \"1.1.0\" ] ; then echo 'patching OpenSSL 1.1.0 for OpenResty' && curl -s https://raw.githubusercontent.com/openresty/openresty/ed328977028c3ec3033bc25873ee360056e247cd/patches/openssl-1.1.0j-parallel_build_fix.patch | patch -p1 && curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-${RESTY_OPENSSL_PATCH_VERSION}-sess_set_get_cb_yield.patch | patch -p1 ; fi && ./config no-threads shared zlib -g enable-ssl3 enable-ssl3-method --prefix=/usr/local/openresty/openssl --libdir=lib -Wl,-rpath,/usr/local/openresty/openssl/lib && make -j${RESTY_J} && make -j${RESTY_J} install_sw && cd /tmp && curl -fSL https://ftp.pcre.org/pub/pcre/pcre-${RESTY_PCRE_VERSION}.tar.gz -o pcre-${RESTY_PCRE_VERSION}.tar.gz && tar xzf pcre-${RESTY_PCRE_VERSION}.tar.gz && cd /tmp/pcre-${RESTY_PCRE_VERSION} && ./configure --prefix=/usr/local/openresty/pcre --disable-cpp --enable-jit --enable-utf --enable-unicode-properties && make -j${RESTY_J} && make -j${RESTY_J} install && cd /tmp && curl -fSL https://openresty.org/download/openresty-${RESTY_VERSION}.tar.gz -o openresty-${RESTY_VERSION}.tar.gz && tar xzf openresty-${RESTY_VERSION}.tar.gz && cd /tmp/openresty-${RESTY_VERSION} && eval ./configure -j${RESTY_J} ${_RESTY_CONFIG_DEPS} ${RESTY_CONFIG_OPTIONS} ${RESTY_CONFIG_OPTIONS_MORE} ${RESTY_LUAJIT_OPTIONS} && make -j${RESTY_J} && make -j${RESTY_J} install && cd /tmp && if [ -n \"${RESTY_EVAL_POST_MAKE}\" ]; then eval $(echo ${RESTY_EVAL_POST_MAKE}); fi && rm -rf openssl-${RESTY_OPENSSL_VERSION}.tar.gz openssl-${RESTY_OPENSSL_VERSION} pcre-${RESTY_PCRE_VERSION}.tar.gz pcre-${RESTY_PCRE_VERSION} openresty-${RESTY_VERSION}.tar.gz openresty-${RESTY_VERSION} && apk del .build-deps && mkdir -p /var/run/openresty && ln -sf /dev/stdout /usr/local/openresty/nginx/logs/access.log && ln -sf /dev/stderr /usr/local/openresty/nginx/logs/error.log" }, { "created": "2020-09-18T16:25:10.712994475Z", "created_by": "/bin/sh -c #(nop) ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/openresty/luajit/bin:/usr/local/openresty/nginx/sbin:/usr/local/openresty/bin", "empty_layer": true }, { "created": "2020-09-18T16:25:10.806730628Z", "created_by": "/bin/sh -c #(nop) COPY file:871e3c814ada8b73d3bd53e819bd122b5612587624e3eb6ef6e97d83522238fc in /usr/local/openresty/nginx/conf/nginx.conf " }, { "created": "2020-09-18T16:25:10.8995482Z", "created_by": "/bin/sh -c #(nop) COPY file:1832501c6083278533ce3d09a4140cc30795ddf825ad6a0ad52ea84858291e53 in /etc/nginx/conf.d/default.conf " }, { "created": "2020-09-18T16:25:10.984062974Z", "created_by": "/bin/sh -c #(nop) CMD [\"/usr/local/openresty/bin/openresty\" \"-g\" \"daemon off;\"]", "empty_layer": true }, { "created": "2020-09-18T16:25:11.080239395Z", "created_by": "/bin/sh -c #(nop) STOPSIGNAL SIGQUIT", "empty_layer": true } ], "os": "linux", "rootfs": { "type": "layers", "diff_ids": [ "sha256:50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a", "sha256:9c572ba82b91e3ac35c7351bdacc6876c67f5d9bc69c5e51e8b2deeafae95e4f", "sha256:1680a9f16b18732726d0656b6d6ff9611a3c4460ca870827b537a87bbe10cc22", "sha256:8521b614863046bf4bb604e3586feeca8b7ce1372f1d6664a5545e85ad9ca472" ] } }
可以看到這個里面是保存了鏡像的元信息,這是再執行一下 docker inspect 1ddc7a18ba0b
,會發現它們的輸出是出奇的相似 :
[root@iZuf685opgs9oyozju9i2bZ docker]# docker inspect 1ddc7a18ba0b [ { "Id": "sha256:1ddc7a18ba0bcc20c61447f391bfff98ac559eea590e7ac59b5b5f588f1f47ed", "RepoTags": [ "openresty/openresty:1.17.8.2-5-alpine", "russellgao/openresty:1.17.8.2-5-alpine" ], "RepoDigests": [ "openresty/openresty@sha256:224ced85b5f8b679a8664a39b69c1b8feb09f8ba4343d834bd5b69433081389e", "russellgao/openresty@sha256:84f53dc7517e9b6695fc8fd74916a1eb5970a92fc24a984f99bfb81508f3d261" ], "Parent": "", "Comment": "", "Created": "2020-09-18T16:25:11.080239395Z", "Container": "0ae35046dd1afef0f1f525360939abc524dbd469a92470c5836dfbb7dc666923", "ContainerConfig": { "Hostname": "0ae35046dd1a", "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:/usr/local/openresty/luajit/bin:/usr/local/openresty/nginx/sbin:/usr/local/openresty/bin" ], "Cmd": [ "/bin/sh", "-c", "#(nop) ", "STOPSIGNAL SIGQUIT" ], "ArgsEscaped": true, "Image": "sha256:0b827067ad09ab8a0b9a73a45f5b1c408b84db1ca6883a4c544078ed43b8b5e3", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": { "maintainer": "Evan Wies <evan@neomantra.net>", "resty_add_package_builddeps": "", "resty_add_package_rundeps": "", "resty_config_deps": "--with-pcre --with-cc-opt='-DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl/include' --with-ld-opt='-L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl/lib -Wl,-rpath,/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl/lib' ", "resty_config_options": " --with-compat --with-file-aio --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_xslt_module=dynamic --with-ipv6 --with-mail --with-mail_ssl_module --with-md5-asm --with-pcre-jit --with-sha1-asm --with-stream --with-stream_ssl_module --with-threads ", "resty_config_options_more": "", "resty_eval_post_make": "", "resty_eval_pre_configure": "", "resty_image_base": "alpine", "resty_image_tag": "3.12", "resty_openssl_patch_version": "1.1.1f", "resty_openssl_url_base": "https://www.openssl.org/source", "resty_openssl_version": "1.1.1g", "resty_pcre_version": "8.44", "resty_version": "1.17.8.2" }, "StopSignal": "SIGQUIT" }, "DockerVersion": "18.06.0-ce", "Author": "", "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:/usr/local/openresty/luajit/bin:/usr/local/openresty/nginx/sbin:/usr/local/openresty/bin" ], "Cmd": [ "/usr/local/openresty/bin/openresty", "-g", "daemon off;" ], "ArgsEscaped": true, "Image": "sha256:0b827067ad09ab8a0b9a73a45f5b1c408b84db1ca6883a4c544078ed43b8b5e3", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": { "maintainer": "Evan Wies <evan@neomantra.net>", "resty_add_package_builddeps": "", "resty_add_package_rundeps": "", "resty_config_deps": "--with-pcre --with-cc-opt='-DNGX_LUA_ABORT_AT_PANIC -I/usr/local/openresty/pcre/include -I/usr/local/openresty/openssl/include' --with-ld-opt='-L/usr/local/openresty/pcre/lib -L/usr/local/openresty/openssl/lib -Wl,-rpath,/usr/local/openresty/pcre/lib:/usr/local/openresty/openssl/lib' ", "resty_config_options": " --with-compat --with-file-aio --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_xslt_module=dynamic --with-ipv6 --with-mail --with-mail_ssl_module --with-md5-asm --with-pcre-jit --with-sha1-asm --with-stream --with-stream_ssl_module --with-threads ", "resty_config_options_more": "", "resty_eval_post_make": "", "resty_eval_pre_configure": "", "resty_image_base": "alpine", "resty_image_tag": "3.12", "resty_openssl_patch_version": "1.1.1f", "resty_openssl_url_base": "https://www.openssl.org/source", "resty_openssl_version": "1.1.1g", "resty_pcre_version": "8.44", "resty_version": "1.17.8.2" }, "StopSignal": "SIGQUIT" }, "Architecture": "amd64", "Os": "linux", "Size": 103896354, "VirtualSize": 103896354, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/00b65b9c288df8c0ae7cdacba531a7dc5cb006e6c768e19ee36055717b782acc/diff:/var/lib/docker/overlay2/f1cf8b173467c98e08f3d276d7ccd8f9892c7c71dec2c4b335c39c6f175ae744/diff:/var/lib/docker/overlay2/8cbfb8b74c887e780747c8e6f4b3b9223a513ff6d69770bac16abb76da4e314f/diff", "MergedDir": "/var/lib/docker/overlay2/5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4/merged", "UpperDir": "/var/lib/docker/overlay2/5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4/diff", "WorkDir": "/var/lib/docker/overlay2/5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4/work" }, "Name": "overlay2" }, "RootFS": { "Type": "layers", "Layers": [ "sha256:50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a", "sha256:9c572ba82b91e3ac35c7351bdacc6876c67f5d9bc69c5e51e8b2deeafae95e4f", "sha256:1680a9f16b18732726d0656b6d6ff9611a3c4460ca870827b537a87bbe10cc22", "sha256:8521b614863046bf4bb604e3586feeca8b7ce1372f1d6664a5545e85ad9ca472" ] }, "Metadata": { "LastTagTime": "2020-11-11T13:35:12.051705855+08:00" } } ]
我自己的理解,docker inspect 執行時就是讀取 image/overlay2/imagedb/content
中的內容加工之后輸出的,這里面有些內容可以仔細理解一下(從上往下看) :
config: 后續如果根據這個鏡像啟動容器時,config 中的內容就是容器的默認參數,
container: 此處是一個容器ID,是在 docker build
階段用于生成鏡像的容器,此處可以簡單介紹下 docker build
的過程:
形如 RUN
、ADD
指令,會造成文件系統改變的指令,會生成新的層
形如 LABEL
、ENV
、CMD
指令,這類指令不會造成文件系統的改變,只會改變鏡像的配置,具體來說就是會改變 config
的值,會直接修改配置,不會生成新的層。
根據 Dockerfile 的指令,按理說每個指令就是一層,但實際情況并非如此喲,這里分兩種情況討論:
如果指令需要生成新的層,則根據上一層產生的鏡像啟動一個新的容器運行這個指令,正常運行結束以后會 docker commit
成一個新的鏡像
所以這個 container
就是剛剛起的容器的ID,后面會用一個例子說明。
container_config: 用來生成這層鏡像的容器的配置,換言之就是上述 container
的配置,可以看到 config
和 container_config
配置一致。
created: 鏡像的生成時間
docker_version: docker build
的執行環境
history: 鏡像的構建歷史(包含所有的歷史執行指令)。
rootfs: 鏡像所有包含所有層的 diff_id
,順序從上往下按照 layer
的順序排列。這里需要特別注意一下,rootfs 中存的是 diff_id,后面會一步一步解釋如何和真正 layer 關聯起來
前面我們說過,imagedb
存的是元數據,那么 layerdb
應該存的是 layer 相關信息?先看看這個目錄下面有什么:
[root@iZuf685opgs9oyozju9i2bZ docker]# ll image/overlay2/layerdb/ 總用量 12 drwxr-xr-x 3 root root 4096 12月 2 09:25 mounts drwxr-xr-x 6 root root 4096 11月 11 13:32 sha256 drwxr-xr-x 2 root root 4096 11月 11 13:32 tmp
tmp 是一個臨時目錄
sha256: 先看看這個下面有什么 ll image/overlay2/layerdb/sha256/
[root@iZuf685opgs9oyozju9i2bZ docker]# ll image/overlay2/layerdb/sha256/ 總用量 16 drwx------ 2 root root 4096 11月 11 13:32 228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3 drwx------ 2 root root 4096 11月 11 13:31 50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a drwx------ 2 root root 4096 11月 11 13:32 5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da drwx------ 2 root root 4096 11月 11 13:32 fe267088885017d5e9a4621e68617a7f35e58dc2d0d747927882da21059854e3
咋一看這里和 rootfs
中的 diff_id
并不相同,只有一層是一樣的(只有base layer是相同)。這里的是 chain_id
,那么什么是 chain_id
呢?
diff_id: 描述的是某一層的變化
chain_id: 描述的是一系列變化
diff_id 和 chain_id 的計算公式為:
ChainID(A) = DiffID(A) ChainID(A | B) = Digest(ChainID(A) + " " + DiffID(B)) ChainID(A | B | C) = Digest(ChainID(A | B) + " " + DiffID(C))
是不是有點繞,回到我們的例子看看: rootfs 中的 diff_id 為:
"diff_ids": [ "sha256:50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a", "sha256:9c572ba82b91e3ac35c7351bdacc6876c67f5d9bc69c5e51e8b2deeafae95e4f", "sha256:1680a9f16b18732726d0656b6d6ff9611a3c4460ca870827b537a87bbe10cc22", "sha256:8521b614863046bf4bb604e3586feeca8b7ce1372f1d6664a5545e85ad9ca472" ]
chain_id 為:
drwx------ 2 root root 4096 11月 11 13:32 228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3 drwx------ 2 root root 4096 11月 11 13:31 50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a drwx------ 2 root root 4096 11月 11 13:32 5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da drwx------ 2 root root 4096 11月 11 13:32 fe267088885017d5e9a4621e68617a7f35e58dc2d0d747927882da21059854e3
根據上面的公式 base layer 的 diff_id 和 chain_id 是相同的:
50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a -> 50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a
在繼續看看下面的算法
[root@iZuf685opgs9oyozju9i2bZ docker]# echo -n "sha256:50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a sha256:9c572ba82b91e3ac35c7351bdacc6876c67f5d9bc69c5e51e8b2deeafae95e4f" | sha256sum fe267088885017d5e9a4621e68617a7f35e58dc2d0d747927882da21059854e3 - [root@iZuf685opgs9oyozju9i2bZ docker]# [root@iZuf685opgs9oyozju9i2bZ docker]# echo -n "sha256:fe267088885017d5e9a4621e68617a7f35e58dc2d0d747927882da21059854e3 sha256:1680a9f16b18732726d0656b6d6ff9611a3c4460ca870827b537a87bbe10cc22" | sha256sum 5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da - [root@iZuf685opgs9oyozju9i2bZ docker]# echo -n "sha256:5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da sha256:8521b614863046bf4bb604e3586feeca8b7ce1372f1d6664a5545e85ad9ca472" | sha256sum 228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3 -
這么一演算就事情就變的清晰起來了:
50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a -> 50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a 9c572ba82b91e3ac35c7351bdacc6876c67f5d9bc69c5e51e8b2deeafae95e4f -> fe267088885017d5e9a4621e68617a7f35e58dc2d0d747927882da21059854e3 1680a9f16b18732726d0656b6d6ff9611a3c4460ca870827b537a87bbe10cc22 -> 5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da 8521b614863046bf4bb604e3586feeca8b7ce1372f1d6664a5545e85ad9ca472 -> 228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3
理清它們之間的關系就比較好辦了,在看看 chain_id 目錄下都有什么:
[root@iZuf685opgs9oyozju9i2bZ docker]# tree image/overlay2/layerdb/sha256/ image/overlay2/layerdb/sha256/ ├── 228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3 │ ├── cache-id │ ├── diff │ ├── parent │ ├── size │ └── tar-split.json.gz ├── 50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a │ ├── cache-id │ ├── diff │ ├── size │ └── tar-split.json.gz ├── 5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da │ ├── cache-id │ ├── diff │ ├── parent │ ├── size │ └── tar-split.json.gz └── fe267088885017d5e9a4621e68617a7f35e58dc2d0d747927882da21059854e3 ├── cache-id ├── diff ├── parent ├── size └── tar-split.json.gz 4 directories, 19 files
cache-id: 保存的是真正的 layer id 信息,可以看看:
[root@iZuf685opgs9oyozju9i2bZ docker]# cat image/overlay2/layerdb/sha256/50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a/cache-id 8cbfb8b74c887e780747c8e6f4b3b9223a513ff6d69770bac16abb76da4e314f[root@iZuf685opgs9oyozju9i2bZ docker]# [root@iZuf685opgs9oyozju9i2bZ docker]# ll overlay2/ 總用量 28 drwx------ 4 root root 4096 11月 11 13:32 00b65b9c288df8c0ae7cdacba531a7dc5cb006e6c768e19ee36055717b782acc drwx------ 5 root root 4096 12月 2 09:25 1e53dddb1a0bb04ee4ebd24a8edb94b96e2fd471a72bf1b8608096b38cb16646 drwx------ 4 root root 4096 12月 2 09:25 1e53dddb1a0bb04ee4ebd24a8edb94b96e2fd471a72bf1b8608096b38cb16646-init drwx------ 4 root root 4096 11月 11 13:48 5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4 drwx------ 3 root root 4096 11月 11 13:32 8cbfb8b74c887e780747c8e6f4b3b9223a513ff6d69770bac16abb76da4e314f drwx------ 4 root root 4096 11月 11 13:32 f1cf8b173467c98e08f3d276d7ccd8f9892c7c71dec2c4b335c39c6f175ae744 drwx------ 2 root root 4096 12月 2 09:25 l
可以看到 cache-id 中的內容是可以和 overlay2
目錄中的內容可以對應起來,overlay2 中的內容等會詳細介紹。
diff: 該層的 diff_id ,可以和上面的計算對應著看
size: 該層的大小,單位為字節,看看這個鏡像每層的大小信息:
[root@iZuf685opgs9oyozju9i2bZ docker]# cat image/overlay2/layerdb/sha256/50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a/size 5574537[root@iZuf685opgs9oyozju9i2bZ docker]# cat image/overlay2/layerdb/sha256/fe267088885017d5e9a4621e68617a7f35e58dc2d0d747927882da21059854e3/size 98318464[root@iZuf685opgs9oyozju9i2bZ docker]# cat image/overlay2/layerdb/sha256/5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da/size 1762[root@iZuf685opgs9oyozju9i2bZ docker]# cat image/overlay2/layerdb/sha256/228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3/size 1591[root@iZuf685opgs9oyozju9i2bZ docker]# [root@iZuf685opgs9oyozju9i2bZ docker]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE openresty/openresty 1.17.8.2-5-alpine 1ddc7a18ba0b 2 months ago 104MB russellgao/openresty 1.17.8.2-5-alpine 1ddc7a18ba0b 2 months ago 104MB
total = ceil((5574537 + 98318464 + 1762 + 1591) / 1000 + 1000)
可以看到和 docker images 中的 size 是一樣的
parent: 除了 base 層之外,其余每個層都有 parent 這個文件,這個文件保存了上一層的 chain_id
tar-split.json.gz: layer 層數據 tar 壓縮包的 split 文件,該文件生成需要 tar-split,通過它可以還原 layer 的 tar 包。
mounts 從名字就可以看出來掛載,沒錯,這里就是保存了容器的掛載信息,看看下面的命令輸出:
[root@iZuf685opgs9oyozju9i2bZ docker]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9bd6ac07a8c9 russellgao/openresty:1.17.8.2-5-alpine "/usr/local/openrest…" 10 days ago Up 2 days 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp openresty-app-1 [root@iZuf685opgs9oyozju9i2bZ docker]# ll containers/ 總用量 4 drwx------ 4 root root 4096 12月 12 09:56 9bd6ac07a8c962e2403203e1c45f4fb54733f9953cf318b34fc3f155bf2c0c59 [root@iZuf685opgs9oyozju9i2bZ docker]# [root@iZuf685opgs9oyozju9i2bZ docker]# cat image/overlay2/layerdb/mounts/9bd6ac07a8c962e2403203e1c45f4fb54733f9953cf318b34fc3f155bf2c0c59/init-id 1e53dddb1a0bb04ee4ebd24a8edb94b96e2fd471a72bf1b8608096b38cb16646-init[root@iZuf685opgs9oyozju9i2bZ docker]# [root@iZuf685opgs9oyozju9i2bZ docker]# cat image/overlay2/layerdb/mounts/9bd6ac07a8c962e2403203e1c45f4fb54733f9953cf318b34fc3f155bf2c0c59/mount-id 1e53dddb1a0bb04ee4ebd24a8edb94b96e2fd471a72bf1b8608096b38cb16646[root@iZuf685opgs9oyozju9i2bZ docker]# [root@iZuf685opgs9oyozju9i2bZ docker]# [root@iZuf685opgs9oyozju9i2bZ docker]# cat image/overlay2/layerdb/mounts/9bd6ac07a8c962e2403203e1c45f4fb54733f9953cf318b34fc3f155bf2c0c59/parent sha256:228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3[root@iZuf685opgs9oyozju9i2bZ docker]# [root@iZuf685opgs9oyozju9i2bZ docker]# [root@iZuf685opgs9oyozju9i2bZ docker]# ll overlay2/ 總用量 28 drwx------ 4 root root 4096 11月 11 13:32 00b65b9c288df8c0ae7cdacba531a7dc5cb006e6c768e19ee36055717b782acc drwx------ 5 root root 4096 12月 2 09:25 1e53dddb1a0bb04ee4ebd24a8edb94b96e2fd471a72bf1b8608096b38cb16646 drwx------ 4 root root 4096 12月 2 09:25 1e53dddb1a0bb04ee4ebd24a8edb94b96e2fd471a72bf1b8608096b38cb16646-init drwx------ 4 root root 4096 11月 11 13:48 5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4 drwx------ 3 root root 4096 11月 11 13:32 8cbfb8b74c887e780747c8e6f4b3b9223a513ff6d69770bac16abb76da4e314f drwx------ 4 root root 4096 11月 11 13:32 f1cf8b173467c98e08f3d276d7ccd8f9892c7c71dec2c4b335c39c6f175ae744 drwx------ 2 root root 4096 12月 2 09:25 l
可以看出來, mounts 保存了容器的鏡像的掛載信息,內容是具體的 layer id
>這里需要理解一下,這里的掛載指的是掛載容器的鏡像層,和 docker run
時 -v
掛載是沒有關系 > 簡單理解「容器=鏡像+讀寫層」,鏡像=「layer1 + layer2 + ... + layern」的疊加,這里掛載的所有layer 疊加之后的只讀層。
到這里 image
目錄就介紹結束了,接下來再看看 overlay2
目錄 。
overlay2 目錄存放的每一層的具體數據,先看看目錄結構:
[root@iZuf685opgs9oyozju9i2bZ docker]# tree overlay2/ -L 2 [root@iZuf685opgs9oyozju9i2bZ docker]# tree -L 2 overlay2/ overlay2/ ├── 00b65b9c288df8c0ae7cdacba531a7dc5cb006e6c768e19ee36055717b782acc │ ├── committed │ ├── diff │ ├── link │ ├── lower │ └── work ├── 5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4 │ ├── committed │ ├── diff │ ├── link │ ├── lower │ └── work ├── 8cbfb8b74c887e780747c8e6f4b3b9223a513ff6d69770bac16abb76da4e314f │ ├── committed │ ├── diff │ └── link ├── b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc │ ├── diff │ ├── link │ ├── lower │ ├── merged │ └── work ├── b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc-init │ ├── committed │ ├── diff │ ├── link │ ├── lower │ └── work ├── f1cf8b173467c98e08f3d276d7ccd8f9892c7c71dec2c4b335c39c6f175ae744 │ ├── committed │ ├── diff │ ├── link │ ├── lower │ └── work └── l ├── 2NFRHNZBFYCUAPMTFCKUR5R4DS -> ../b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc/diff ├── 33RV26M4VMX3ZUISOG26USXBKR -> ../f1cf8b173467c98e08f3d276d7ccd8f9892c7c71dec2c4b335c39c6f175ae744/diff ├── BGEYC7V6ULKFOOIITWCEKITQEU -> ../b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc-init/diff ├── HG76ICE67NTXFL7AYXCMI3EK4Y -> ../00b65b9c288df8c0ae7cdacba531a7dc5cb006e6c768e19ee36055717b782acc/diff ├── L5XCYQVZ6DOSLJNP6HXCZQZ7A5 -> ../5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4/diff └── MUHXHRXFSGNCBKQ2AUXDFOUDLF -> ../8cbfb8b74c887e780747c8e6f4b3b9223a513ff6d69770bac16abb76da4e314f/diff 25 directories, 16 files
可以看到 overlay2 一級目錄下有個特殊目錄 l
, l
下是各個layer 軟鏈接,防止mount 命令太長而發生錯誤,所以就用短鏈接了。
細心的你一定發現了這么幾個問題:
這個鏡像只有 4 個層,這里為啥會有 6 個層(目錄)
為啥具體layer 下的目錄/文件結構不一樣
有的 layer 為啥帶了 -init
后綴,有的沒有
有 6 個layer 層是因為我這里啟動了一個容器,會生成兩個層(讀寫層和這個鏡像merged之后的只讀層),刪除容器之后看看:
[root@iZuf685opgs9oyozju9i2bZ docker]# docker rm -f openresty-app-1 openresty-app-1 [root@iZuf685opgs9oyozju9i2bZ docker]# ll overlay2/ 總用量 20 drwx------ 4 root root 4096 11月 11 13:32 00b65b9c288df8c0ae7cdacba531a7dc5cb006e6c768e19ee36055717b782acc drwx------ 4 root root 4096 11月 11 13:48 5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4 drwx------ 3 root root 4096 11月 11 13:32 8cbfb8b74c887e780747c8e6f4b3b9223a513ff6d69770bac16abb76da4e314f drwx------ 4 root root 4096 11月 11 13:32 f1cf8b173467c98e08f3d276d7ccd8f9892c7c71dec2c4b335c39c6f175ae744 drwx------ 2 root root 4096 12月 12 13:29 l
這下和之前討論對上了, 和 cache-id
中的內容一一對應
[root@iZuf685opgs9oyozju9i2bZ docker]# ll image/overlay2/layerdb/sha256/*/cache-id -rw-r--r-- 1 root root 64 11月 11 13:32 image/overlay2/layerdb/sha256/228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3/cache-id -rw-r--r-- 1 root root 64 11月 11 13:31 image/overlay2/layerdb/sha256/50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a/cache-id -rw-r--r-- 1 root root 64 11月 11 13:32 image/overlay2/layerdb/sha256/5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da/cache-id -rw-r--r-- 1 root root 64 11月 11 13:32 image/overlay2/layerdb/sha256/fe267088885017d5e9a4621e68617a7f35e58dc2d0d747927882da21059854e3/cache-id
在看看具體鏡像 layer 層的內容:
diff: 這個層所做的改動,如通過 ADD
、RUN
等指令對做文件系統做出的改變都在這里了。
link: 自己的link值,在剛剛的 overlay2/l
目錄下可以看的到。
[root@iZuf685opgs9oyozju9i2bZ docker]# cat overlay2/00b65b9c288df8c0ae7cdacba531a7dc5cb006e6c768e19ee36055717b782acc/link HG76ICE67NTXFL7AYXCMI3EK4Y
lower: 該層所依賴的層的所有link,base layer 不依賴任何層,所以也就不會有 lower
這個文件,最后一層依賴之前的所有層,如:
[root@iZuf685opgs9oyozju9i2bZ docker]# cat overlay2/5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4/lower l/HG76ICE67NTXFL7AYXCMI3EK4Y:l/33RV26M4VMX3ZUISOG26USXBKR:l/MUHXHRXFSGNCBKQ2AUXDFOUDLF
這個鏡像的最后一層依賴前面的層
merged:容器的最終視圖,merge 了 鏡像層加讀寫層
> 啟動容器新建的兩層在 containers
中詳細說。
我們一直說 docker 鏡像是分層的, 容器 = 鏡像 + 讀寫層 ,如果還沒有什么感覺的話不妨再來看一個圖:
可以看到容器是依賴于鏡像,啟動容器時會先把鏡像的各個 layer 聯合掛載成一個統一的視圖(只讀層),就是我們在 overlay2
目錄中看到的 b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc-init
目錄, 去掉 -init
就是對應的讀寫層。
看看 containers
目錄下都有什么:
[root@iZuf685opgs9oyozju9i2bZ docker]# tree -L 2 containers/ containers/ └── 4ec800c3ec10654a6ea2b2317ac198514748464a217ef63bb58ef67874a79ae0 ├── 4ec800c3ec10654a6ea2b2317ac198514748464a217ef63bb58ef67874a79ae0-json.log ├── checkpoints ├── config.v2.json ├── hostconfig.json ├── hostname ├── hosts ├── mounts ├── resolv.conf └── resolv.conf.hash 3 directories, 7 files [root@iZuf685opgs9oyozju9i2bZ docker]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 4ec800c3ec10 russellgao/openresty:1.17.8.2-5-alpine "/usr/local/openrest…" About an hour ago Up About an hour 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp openresty-app-1
可以看到這個下面是以容器為單位進行存放的,保存了每個容器的詳細配置,在容器里看到的hostname
,/etc/hosts
,dns
等各種配置在這里都可以找得到,這里就不展開看每個具體文件了,有興趣者可以自行查看。
> 值得一提的是,通過 docker inspect containername
得到的內容在 containers/xxx/config.v2.json
都可以找的到哦,可以查看它們的輸出,會發現出奇的相似哦。
請注意好玩的事情來了
我們說到 容器=鏡像+讀寫層 ,那是不是以為著我們在讀寫層做修改,容器中可以看到,反之在容器中做的修改,在讀寫層也應該能看到才對。 > 讀寫層時各臨時的 layer 層(臨時目錄) ,當容器被刪除時,這個 layer 也會隨之被刪除。
做了實驗看看: 最初讀寫層的內容和容器的根目錄如下:
[root@iZuf685opgs9oyozju9i2bZ docker]# ll overlay2/b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc/diff/ 總用量 16 drwxr-xr-x 3 root root 4096 9月 19 00:25 run drwxr-xr-x 3 root root 4096 9月 19 00:25 usr [root@iZuf685opgs9oyozju9i2bZ docker]# [root@iZuf685opgs9oyozju9i2bZ docker]# docker exec openresty-app-1 ls -l / total 64 drwxr-xr-x 1 root root 4096 Sep 18 16:25 bin drwxr-xr-x 5 root root 340 Dec 12 05:29 dev drwxr-xr-x 1 root root 4096 Dec 12 05:29 etc drwxr-xr-x 2 root root 4096 May 29 2020 home drwxr-xr-x 1 root root 4096 Sep 18 16:25 lib drwxr-xr-x 5 root root 4096 May 29 2020 media drwxr-xr-x 2 root root 4096 May 29 2020 mnt drwxr-xr-x 2 root root 4096 May 29 2020 opt dr-xr-xr-x 114 root root 0 Dec 12 05:29 proc drwx------ 2 root root 4096 May 29 2020 root drwxr-xr-x 1 root root 4096 Sep 18 16:25 run drwxr-xr-x 2 root root 4096 May 29 2020 sbin drwxr-xr-x 2 root root 4096 May 29 2020 srv dr-xr-xr-x 13 root root 0 Nov 11 00:49 sys drwxrwxrwt 1 root root 4096 Sep 18 16:25 tmp drwxr-xr-x 1 root root 4096 Sep 18 16:25 usr drwxr-xr-x 1 root root 4096 May 29 2020 var
進入到容器并在根目錄生成一個文件:
[root@iZuf685opgs9oyozju9i2bZ docker]# docker exec -it openresty-app-1 sh / # echo "測試容器的讀寫層-20201209" > /test-layer.20201209.txt
讀寫層看看什么情況:
[root@iZuf685opgs9oyozju9i2bZ docker]# ll overlay2/b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc/diff/ 總用量 24 drwx------ 2 root root 4096 12月 12 15:22 root drwxr-xr-x 3 root root 4096 9月 19 00:25 run -rw-r--r-- 1 root root 34 12月 12 15:22 test-layer.20201209.txt drwxr-xr-x 3 root root 4096 9月 19 00:25 usr [root@iZuf685opgs9oyozju9i2bZ docker]# cat overlay2/b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc/diff/test-layer.20201209.txt 測試容器的讀寫層-20201209
可以看到在容器中新建的文件確實在讀寫層中可以看到,那么反過來再試試
在讀寫層新建一個文件:
[root@iZuf685opgs9oyozju9i2bZ docker]# echo "測試容器的讀寫層-20201209-abcdefg" > overlay2/b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc/diff/test-layer.20201209-abcdefg.txt [root@iZuf685opgs9oyozju9i2bZ docker]# ll overlay2/b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc/diff/ 總用量 28 drwx------ 2 root root 4096 12月 12 15:22 root drwxr-xr-x 3 root root 4096 9月 19 00:25 run -rw-r--r-- 1 root root 42 12月 12 15:26 test-layer.20201209-abcdefg.txt -rw-r--r-- 1 root root 34 12月 12 15:22 test-layer.20201209.txt drwxr-xr-x 3 root root 4096 9月 19 00:25 usr
進到容器中看看:
[root@iZuf685opgs9oyozju9i2bZ docker]# docker exec -it openresty-app-1 sh / # ls -l total 72 drwxr-xr-x 1 root root 4096 Sep 18 16:25 bin drwxr-xr-x 5 root root 340 Dec 12 05:29 dev drwxr-xr-x 1 root root 4096 Dec 12 05:29 etc drwxr-xr-x 2 root root 4096 May 29 2020 home drwxr-xr-x 1 root root 4096 Sep 18 16:25 lib drwxr-xr-x 5 root root 4096 May 29 2020 media drwxr-xr-x 2 root root 4096 May 29 2020 mnt drwxr-xr-x 2 root root 4096 May 29 2020 opt dr-xr-xr-x 114 root root 0 Dec 12 05:29 proc drwx------ 1 root root 4096 Dec 12 07:22 root drwxr-xr-x 1 root root 4096 Sep 18 16:25 run drwxr-xr-x 2 root root 4096 May 29 2020 sbin drwxr-xr-x 2 root root 4096 May 29 2020 srv dr-xr-xr-x 13 root root 0 Nov 11 00:49 sys -rw-r--r-- 1 root root 42 Dec 12 07:26 test-layer.20201209-abcdefg.txt -rw-r--r-- 1 root root 34 Dec 12 07:22 test-layer.20201209.txt drwxrwxrwt 1 root root 4096 Sep 18 16:25 tmp drwxr-xr-x 1 root root 4096 Sep 18 16:25 usr drwxr-xr-x 1 root root 4096 May 29 2020 var / # cat test-layer.20201209-abcdefg.txt 測試容器的讀寫層-20201209-abcdefg
可以看到和我們設想的一致。
> 這篇文章很長,難免表達邏輯上出現混亂,感謝能耐心看完的小伙伴,如果有不對之處歡迎批評指正。
image/overlay2
distribution: 和鏡像分發相關,記錄了diffid 與 digest 之間的關系。
imagedb: 記錄了鏡像的元信息,其中content
中的內容和docker inspect image
結果基本一直。
layerdb: 記錄了 layer 的元信息,如真正的 layerid, size 等信息。
repositories.json: 記錄這個主機上所有的鏡像。
overlay2: 鏡像的具體layer 層的內容,包括鏡像的只讀層和容器的讀寫層。其中讀寫層是臨時層,當容器刪除時也會隨之刪除,在這一層的 diff 目錄下做修改,容器內也會隨之看到。
containers: 容器的配置信息,通過 docker inspect containerid
得到的結果和 containers/xxx
下的內容基本一直。
關于docker中的本地存儲是怎樣的就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。