1. 程式人生 > 實用技巧 >docker 原理之本地儲存

docker 原理之本地儲存

導讀

> 在前面的文章docker 原理之儲存驅動中簡單的介紹了 Docker 的儲存驅動,這篇文章接著講儲存,目前的 docker 版本中預設的是overlay2,所以這篇文章就以overlay2為例帶大家看看,在我們執行docker builddocker pulldocker run等命令時本地儲存有何變化。 > > 這篇文章比較長,如果看不完可以收藏起來後續需要用到的時候再查閱,稱的上是乾貨滿滿,作者自己整理也花了較長的時間。 > > 原文:https://russellgao.cn/docker-local-storage/

背景

  • 檢視 dockerStorage 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 1111 08:49 builder
drwx--x--x 4 root root 4096 1111 08:49 buildkit
drwx------ 3 root root 4096 122 09:25 containers
drwx------ 3 root root 4096 1111 08:49 image
drwxr-x--- 3 root root 4096 1111 08:49 network
drwx------ 9 root root 4096 122 09:25 overlay2
drwx------ 4 root root 4096 1111 08:49 plugins
drwx------ 2 root root 4096 1111 08:49 runtimes
drwx------ 2 root root 4096 1111 08:49 swarm
drwx------ 2 root root 4096 1111 13:32 tmp
drwx------ 2 root root 4096 1111 08:49 trust
drwx------ 2 root root 4096 1111 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

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-alpinerussellgao/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-alpinerussellgao/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:

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 repositoryblobs目錄下可以找到。

可以檢視具體的檔案,如cat image/overlay2/distribution/diffid-by-digest/sha256/5682af42731d652bd98d2456ed3da4f0595ed5d9e5b13ac8bb9590bb74f72eb8

[root@iZuf685opgs9oyozju9i2bZ docker]# cat image/overlay2/distribution/diffid-by-digest/sha256/5682af42731d652bd98d2456ed3da4f0595ed5d9e5b13ac8bb9590bb74f72eb8 
sha256:9c572ba82b91e3ac35c7351bdacc6876c67f5d9bc69c5e51e8b2deeafae95e4f

不難發現它們之間是相互引用的,可以實現diffiddigest的相互轉換。

imagedb

[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 <[email protected]>",
      "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 <[email protected]>",
      "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 <[email protected]>",
      "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}     &amp;&amp; apk add --no-cache         gd         geoip         libgcc         libxslt         zlib         ${RESTY_ADD_PACKAGE_RUNDEPS}     &amp;&amp; cd /tmp     &amp;&amp; if [ -n \"${RESTY_EVAL_PRE_CONFIGURE}\" ]; then eval $(echo ${RESTY_EVAL_PRE_CONFIGURE}); fi     &amp;&amp; cd /tmp     &amp;&amp; curl -fSL \"${RESTY_OPENSSL_URL_BASE}/openssl-${RESTY_OPENSSL_VERSION}.tar.gz\" -o openssl-${RESTY_OPENSSL_VERSION}.tar.gz     &amp;&amp; tar xzf openssl-${RESTY_OPENSSL_VERSION}.tar.gz     &amp;&amp; cd openssl-${RESTY_OPENSSL_VERSION}     &amp;&amp; if [ $(echo ${RESTY_OPENSSL_VERSION} | cut -c 1-5) = \"1.1.1\" ] ; then         echo 'patching OpenSSL 1.1.1 for OpenResty'         &amp;&amp; curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-${RESTY_OPENSSL_PATCH_VERSION}-sess_set_get_cb_yield.patch | patch -p1 ;     fi     &amp;&amp; if [ $(echo ${RESTY_OPENSSL_VERSION} | cut -c 1-5) = \"1.1.0\" ] ; then         echo 'patching OpenSSL 1.1.0 for OpenResty'         &amp;&amp; curl -s https://raw.githubusercontent.com/openresty/openresty/ed328977028c3ec3033bc25873ee360056e247cd/patches/openssl-1.1.0j-parallel_build_fix.patch | patch -p1         &amp;&amp; curl -s https://raw.githubusercontent.com/openresty/openresty/master/patches/openssl-${RESTY_OPENSSL_PATCH_VERSION}-sess_set_get_cb_yield.patch | patch -p1 ;     fi     &amp;&amp; ./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     &amp;&amp; make -j${RESTY_J}     &amp;&amp; make -j${RESTY_J} install_sw     &amp;&amp; cd /tmp     &amp;&amp; curl -fSL https://ftp.pcre.org/pub/pcre/pcre-${RESTY_PCRE_VERSION}.tar.gz -o pcre-${RESTY_PCRE_VERSION}.tar.gz     &amp;&amp; tar xzf pcre-${RESTY_PCRE_VERSION}.tar.gz     &amp;&amp; cd /tmp/pcre-${RESTY_PCRE_VERSION}     &amp;&amp; ./configure         --prefix=/usr/local/openresty/pcre         --disable-cpp         --enable-jit         --enable-utf         --enable-unicode-properties     &amp;&amp; make -j${RESTY_J}     &amp;&amp; make -j${RESTY_J} install     &amp;&amp; cd /tmp     &amp;&amp; curl -fSL https://openresty.org/download/openresty-${RESTY_VERSION}.tar.gz -o openresty-${RESTY_VERSION}.tar.gz     &amp;&amp; tar xzf openresty-${RESTY_VERSION}.tar.gz     &amp;&amp; cd /tmp/openresty-${RESTY_VERSION}     &amp;&amp; eval ./configure -j${RESTY_J} ${_RESTY_CONFIG_DEPS} ${RESTY_CONFIG_OPTIONS} ${RESTY_CONFIG_OPTIONS_MORE} ${RESTY_LUAJIT_OPTIONS}     &amp;&amp; make -j${RESTY_J}     &amp;&amp; make -j${RESTY_J} install     &amp;&amp; cd /tmp     &amp;&amp; if [ -n \"${RESTY_EVAL_POST_MAKE}\" ]; then eval $(echo ${RESTY_EVAL_POST_MAKE}); fi     &amp;&amp; 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}     &amp;&amp; apk del .build-deps     &amp;&amp; mkdir -p /var/run/openresty     &amp;&amp; ln -sf /dev/stdout /usr/local/openresty/nginx/logs/access.log     &amp;&amp; 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 <[email protected]>",
                "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 <[email protected]>",
                "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的過程:
    • 根據 Dockerfile 的指令,按理說每個指令就是一層,但實際情況並非如此喲,這裡分兩種情況討論:
      • 形如RUNADD指令,會造成檔案系統改變的指令,會生成新的層
      • 形如LABELENVCMD指令,這類指令不會造成檔案系統的改變,只會改變映象的配置,具體來說就是會改變config的值,會直接修改配置,不會生成新的層。
    • 如果指令需要生成新的層,則根據上一層產生的映象啟動一個新的容器執行這個指令,正常執行結束以後會docker commit成一個新的映象
    • 所以這個container就是剛剛起的容器的ID,後面會用一個例子說明。
  • container_config:用來生成這層映象的容器的配置,換言之就是上述container的配置,可以看到configcontainer_config配置一致。
  • created:映象的生成時間
  • docker_version:docker build的執行環境
  • history:映象的構建歷史(包含所有的歷史執行指令)。
  • rootfs:映象所有包含所有層的diff_id,順序從上往下按照layer的順序排列。這裡需要特別注意一下,rootfs 中存的是 diff_id,後面會一步一步解釋如何和真正 layer 關聯起來

layerdb

前面我們說過,imagedb存的是元資料,那麼layerdb應該存的是 layer 相關資訊?先看看這個目錄下面有什麼:

[root@iZuf685opgs9oyozju9i2bZ docker]# ll  image/overlay2/layerdb/
總用量 12
drwxr-xr-x 3 root root 4096 122 09:25 mounts
drwxr-xr-x 6 root root 4096 1111 13:32 sha256
drwxr-xr-x 2 root root 4096 1111 13:32 tmp

tmp

tmp 是一個臨時目錄

sha256

sha256: 先看看這個下面有什麼ll image/overlay2/layerdb/sha256/

[root@iZuf685opgs9oyozju9i2bZ docker]# ll  image/overlay2/layerdb/sha256/
總用量 16
drwx------ 2 root root 4096 1111 13:32 228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3
drwx------ 2 root root 4096 1111 13:31 50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a
drwx------ 2 root root 4096 1111 13:32 5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da
drwx------ 2 root root 4096 1111 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 1111 13:32 228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3
drwx------ 2 root root 4096 1111 13:31 50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a
drwx------ 2 root root 4096 1111 13:32 5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da
drwx------ 2 root root 4096 1111 13:32 fe267088885017d5e9a4621e68617a7f35e58dc2d0d747927882da21059854e3

根據上面的公式 base layer 的 diff_id 和 chain_id 是相同的:

50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a -&gt; 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 -&gt; 50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a
9c572ba82b91e3ac35c7351bdacc6876c67f5d9bc69c5e51e8b2deeafae95e4f -&gt; fe267088885017d5e9a4621e68617a7f35e58dc2d0d747927882da21059854e3
1680a9f16b18732726d0656b6d6ff9611a3c4460ca870827b537a87bbe10cc22 -&gt; 5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da
8521b614863046bf4bb604e3586feeca8b7ce1372f1d6664a5545e85ad9ca472 -&gt; 228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3

理清它們之間的關係就比較好辦了,在看看 chain_id 目錄下都有什麼:

[root@iZuf685opgs9oyozju9i2bZ docker]# tree image/overlay2/layerdb/sha256/
image/overlay2/layerdb/sha256/
├── 228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3
│&nbsp;&nbsp; ├── cache-id
│&nbsp;&nbsp; ├── diff
│&nbsp;&nbsp; ├── parent
│&nbsp;&nbsp; ├── size
│&nbsp;&nbsp; └── tar-split.json.gz
├── 50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a
│&nbsp;&nbsp; ├── cache-id
│&nbsp;&nbsp; ├── diff
│&nbsp;&nbsp; ├── size
│&nbsp;&nbsp; └── tar-split.json.gz
├── 5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da
│&nbsp;&nbsp; ├── cache-id
│&nbsp;&nbsp; ├── diff
│&nbsp;&nbsp; ├── parent
│&nbsp;&nbsp; ├── size
│&nbsp;&nbsp; └── 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 1111 13:32 00b65b9c288df8c0ae7cdacba531a7dc5cb006e6c768e19ee36055717b782acc
drwx------ 5 root root 4096 122 09:25 1e53dddb1a0bb04ee4ebd24a8edb94b96e2fd471a72bf1b8608096b38cb16646
drwx------ 4 root root 4096 122 09:25 1e53dddb1a0bb04ee4ebd24a8edb94b96e2fd471a72bf1b8608096b38cb16646-init
drwx------ 4 root root 4096 1111 13:48 5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4
drwx------ 3 root root 4096 1111 13:32 8cbfb8b74c887e780747c8e6f4b3b9223a513ff6d69770bac16abb76da4e314f
drwx------ 4 root root 4096 1111 13:32 f1cf8b173467c98e08f3d276d7ccd8f9892c7c71dec2c4b335c39c6f175ae744
drwx------ 2 root root 4096 122 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

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-&gt;80/tcp, 0.0.0.0:443-&gt;443/tcp   openresty-app-1
[root@iZuf685opgs9oyozju9i2bZ docker]# ll containers/
總用量 4
drwx------ 4 root root 4096 1212 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 1111 13:32 00b65b9c288df8c0ae7cdacba531a7dc5cb006e6c768e19ee36055717b782acc
drwx------ 5 root root 4096 122 09:25 1e53dddb1a0bb04ee4ebd24a8edb94b96e2fd471a72bf1b8608096b38cb16646
drwx------ 4 root root 4096 122 09:25 1e53dddb1a0bb04ee4ebd24a8edb94b96e2fd471a72bf1b8608096b38cb16646-init
drwx------ 4 root root 4096 1111 13:48 5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4
drwx------ 3 root root 4096 1111 13:32 8cbfb8b74c887e780747c8e6f4b3b9223a513ff6d69770bac16abb76da4e314f
drwx------ 4 root root 4096 1111 13:32 f1cf8b173467c98e08f3d276d7ccd8f9892c7c71dec2c4b335c39c6f175ae744
drwx------ 2 root root 4096 122 09:25 l

可以看出來, mounts 儲存了容器的映象的掛載資訊,內容是具體的layer id>這裡需要理解一下,這裡的掛載指的是掛載容器的映象層,和docker run-v掛載是沒有關係> 簡單理解「容器=映象+讀寫層」,映象=「layer1 + layer2 + ... + layern」的疊加,這裡掛載的所有layer 疊加之後的只讀層。

到這裡image目錄就介紹結束了,接下來再看看overlay2目錄 。

overlay2

overlay2 目錄存放的每一層的具體資料,先看看目錄結構:

[root@iZuf685opgs9oyozju9i2bZ docker]# tree overlay2/ -L 2
[root@iZuf685opgs9oyozju9i2bZ docker]# tree -L 2 overlay2/
overlay2/
├── 00b65b9c288df8c0ae7cdacba531a7dc5cb006e6c768e19ee36055717b782acc
│&nbsp;&nbsp; ├── committed
│&nbsp;&nbsp; ├── diff
│&nbsp;&nbsp; ├── link
│&nbsp;&nbsp; ├── lower
│&nbsp;&nbsp; └── work
├── 5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4
│&nbsp;&nbsp; ├── committed
│&nbsp;&nbsp; ├── diff
│&nbsp;&nbsp; ├── link
│&nbsp;&nbsp; ├── lower
│&nbsp;&nbsp; └── work
├── 8cbfb8b74c887e780747c8e6f4b3b9223a513ff6d69770bac16abb76da4e314f
│&nbsp;&nbsp; ├── committed
│&nbsp;&nbsp; ├── diff
│&nbsp;&nbsp; └── link
├── b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc
│&nbsp;&nbsp; ├── diff
│&nbsp;&nbsp; ├── link
│&nbsp;&nbsp; ├── lower
│&nbsp;&nbsp; ├── merged
│&nbsp;&nbsp; └── work
├── b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc-init
│&nbsp;&nbsp; ├── committed
│&nbsp;&nbsp; ├── diff
│&nbsp;&nbsp; ├── link
│&nbsp;&nbsp; ├── lower
│&nbsp;&nbsp; └── work
├── f1cf8b173467c98e08f3d276d7ccd8f9892c7c71dec2c4b335c39c6f175ae744
│&nbsp;&nbsp; ├── committed
│&nbsp;&nbsp; ├── diff
│&nbsp;&nbsp; ├── link
│&nbsp;&nbsp; ├── lower
│&nbsp;&nbsp; └── work
└── l
    ├── 2NFRHNZBFYCUAPMTFCKUR5R4DS -&gt; ../b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc/diff
    ├── 33RV26M4VMX3ZUISOG26USXBKR -&gt; ../f1cf8b173467c98e08f3d276d7ccd8f9892c7c71dec2c4b335c39c6f175ae744/diff
    ├── BGEYC7V6ULKFOOIITWCEKITQEU -&gt; ../b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc-init/diff
    ├── HG76ICE67NTXFL7AYXCMI3EK4Y -&gt; ../00b65b9c288df8c0ae7cdacba531a7dc5cb006e6c768e19ee36055717b782acc/diff
    ├── L5XCYQVZ6DOSLJNP6HXCZQZ7A5 -&gt; ../5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4/diff
    └── MUHXHRXFSGNCBKQ2AUXDFOUDLF -&gt; ../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 1111 13:32 00b65b9c288df8c0ae7cdacba531a7dc5cb006e6c768e19ee36055717b782acc
drwx------ 4 root root 4096 1111 13:48 5da215c4f218cbb1d9825fa111c21bf381dc35a9e6c7c6cd5c3ea952316031e4
drwx------ 3 root root 4096 1111 13:32 8cbfb8b74c887e780747c8e6f4b3b9223a513ff6d69770bac16abb76da4e314f
drwx------ 4 root root 4096 1111 13:32 f1cf8b173467c98e08f3d276d7ccd8f9892c7c71dec2c4b335c39c6f175ae744
drwx------ 2 root root 4096 1212 13:29 l

這下和之前討論對上了, 和cache-id中的內容一一對應

[root@iZuf685opgs9oyozju9i2bZ docker]# ll image/overlay2/layerdb/sha256/*/cache-id
-rw-r--r-- 1 root root 64 1111 13:32 image/overlay2/layerdb/sha256/228fb92e31891f472e9857ee11d13c404ff7c88e808b05ce4ebdc80d785d71f3/cache-id
-rw-r--r-- 1 root root 64 1111 13:31 image/overlay2/layerdb/sha256/50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a/cache-id
-rw-r--r-- 1 root root 64 1111 13:32 image/overlay2/layerdb/sha256/5f72760956a669e4c9b33aa3f2f04baa84b0f4cf1e11676049981bafcbba74da/cache-id
-rw-r--r-- 1 root root 64 1111 13:32 image/overlay2/layerdb/sha256/fe267088885017d5e9a4621e68617a7f35e58dc2d0d747927882da21059854e3/cache-id

在看看具體映象 layer 層的內容:

  • diff: 這個層所做的改動,如通過ADDRUN等指令對做檔案系統做出的改變都在這裡了。
  • 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中詳細說。

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-&gt;80/tcp, 0.0.0.0:443-&gt;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 919 00:25 run
drwxr-xr-x 3 root root 4096 919 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" &gt; /test-layer.20201209.txt

讀寫層看看什麼情況:

[root@iZuf685opgs9oyozju9i2bZ docker]# ll overlay2/b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc/diff/
總用量 24
drwx------ 2 root root 4096 1212 15:22 root
drwxr-xr-x 3 root root 4096 919 00:25 run
-rw-r--r-- 1 root root   34 1212 15:22 test-layer.20201209.txt
drwxr-xr-x 3 root root 4096 919 00:25 usr
[root@iZuf685opgs9oyozju9i2bZ docker]# cat overlay2/b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc/diff/test-layer.20201209.txt 
測試容器的讀寫層-20201209

可以看到在容器中新建的檔案確實在讀寫層中可以看到,那麼反過來再試試

在讀寫層新建一個檔案:

[root@iZuf685opgs9oyozju9i2bZ docker]# echo "測試容器的讀寫層-20201209-abcdefg" &gt; overlay2/b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc/diff/test-layer.20201209-abcdefg.txt 
[root@iZuf685opgs9oyozju9i2bZ docker]# ll overlay2/b04b728c94b5a269e9d102329c930e3781212717e830e1941e1008088d823cdc/diff/
總用量 28
drwx------ 2 root root 4096 1212 15:22 root
drwxr-xr-x 3 root root 4096 919 00:25 run
-rw-r--r-- 1 root root   42 1212 15:26 test-layer.20201209-abcdefg.txt
-rw-r--r-- 1 root root   34 1212 15:22 test-layer.20201209.txt
drwxr-xr-x 3 root root 4096 919 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下的內容基本一直。

來源:友情連結