[docker 容器技术]- registry 镜像管理

335 阅读10分钟

最近在搞 docker 镜像管理套件 harbor 的高可用和 hard gc ,对 docker 镜像管理有了更深的理解,Docker registry 就是官方提供的镜像管理服务,而 harbor 也依赖它,整理一下docker 镜像的管理和认识。

docker build

首先从构建一个 docker image 开始

Dockerfile

FROM alpine:3.7
ADD venv.tg /venv.tg

build

$ docker build -f Dockerfile -t alpine-build-test:2020-07-28 . --no-cache
Sending build context to Docker daemon  18.29MB
Step 1/2 : FROM hub.guazi-cloud.com/library/alpine:3.7
 ---> 6d1ef012b567
Step 2/2 : ADD venv.tg /venv.tg
 ---> c02816e88c1b
Successfully built c02816e88c1b
Successfully tagged alpine-build-test:2020-07-28

查看构建

# 查看镜像的 history
$ docker history alpine-build-test:2020-07-28 --no-trunc
IMAGE                                                                     CREATED             CREATED BY                                                                                                 SIZE                COMMENT
sha256:c02816e88c1bdf4528dcfccec58edc2373d3c3b95c15f98ef208f2229ecae0a8   2 minutes ago       /bin/sh -c #(nop) ADD file:0b7e80d8489683c5c7f8f07cdba46a2c085cbd571ac23f2bfddfa808415da214 in /venv.tg    44.9MB
sha256:6d1ef012b5674ad8a127ecfa9b5e6f5178d171b90ee462846974177fd9bdd39f   17 months ago       /bin/sh -c #(nop)  CMD ["/bin/sh"]                                                                         0B
<missing>                                                                 17 months ago       /bin/sh -c #(nop) ADD file:aa17928040e31624cad9c7ed19ac277c5402c4b9ba39f834250affca40c4046e in /           4.21MB

# docker images inspect info
$ docker image inspect alpine-build-test:2020-07-28
[
    {
        "Id": "sha256:c02816e88c1bdf4528dcfccec58edc2373d3c3b95c15f98ef208f2229ecae0a8",
        "RepoTags": [
            "alpine-build-test:2020-07-28"
        ],
        "RepoDigests": [],
        "Parent": "sha256:6d1ef012b5674ad8a127ecfa9b5e6f5178d171b90ee462846974177fd9bdd39f",
        "Comment": "",
        "Created": "2020-08-05T13:37:09.821307Z",
        "Container": "",
        "ContainerConfig": {
            "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"
            ],
            "Cmd": [
                "/bin/sh",
                "-c",
                "#(nop) ADD file:0b7e80d8489683c5c7f8f07cdba46a2c085cbd571ac23f2bfddfa808415da214 in /venv.tg "
            ],
            "ArgsEscaped": true,
            "Image": "sha256:6d1ef012b5674ad8a127ecfa9b5e6f5178d171b90ee462846974177fd9bdd39f",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "DockerVersion": "19.03.8",
        "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"
            ],
            "Cmd": [
                "/bin/sh"
            ],
            "ArgsEscaped": true,
            "Image": "sha256:6d1ef012b5674ad8a127ecfa9b5e6f5178d171b90ee462846974177fd9bdd39f",
            "Volumes": null,
            "WorkingDir": "",
            "Entrypoint": null,
            "OnBuild": null,
            "Labels": null
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 49077843,
        "VirtualSize": 49077843,
        "GraphDriver": {
            "Data": {
                "LowerDir": "/var/lib/docker/overlay2/f2700a34d68f3dba52fc7e07580d295cf87b8a45a6ea46d24895e79a5a00875a/diff",
                "MergedDir": "/var/lib/docker/overlay2/6596ea2712ea2d96b0f4eb0159de9657a0fbbee996d0881bd38514b9f7e7260a/merged",
                "UpperDir": "/var/lib/docker/overlay2/6596ea2712ea2d96b0f4eb0159de9657a0fbbee996d0881bd38514b9f7e7260a/diff",
                "WorkDir": "/var/lib/docker/overlay2/6596ea2712ea2d96b0f4eb0159de9657a0fbbee996d0881bd38514b9f7e7260a/work"
            },
            "Name": "overlay2"
        },
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:3fc64803ca2de7279269048fe2b8b3c73d4536448c87c32375b2639ac168a48b",
                "sha256:6f8d036b97086be616fee7f45b5e6d41f7fdd05ee0c358208b2669dbda5f05ec"
            ]
        },
        "Metadata": {
            "LastTagTime": "2020-08-05T13:37:10.4280472Z"
        }
    }
]

那 docker registry 如果管理镜像的 layer、配置和历史信息的呢?

Docker registry manage image

Docker image 主要被分为三部分

  • manifest:主描述文件,描述一个镜像管理的配置 layer、文件layer
  • config :配置描述文件,描述该镜像的配置、启动命令、历史等一系列配置信息
  • layers:真正文件的压缩层,按照先后顺序依次排列

manifest 文件内容:

{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
   "config": {
      "mediaType": "application/vnd.docker.container.image.v1+json",
      "size": 2862,
      "digest": "sha256:dda1f455646c10d58dcc05d9f7a893b2e785967652a3417dc95f46004f1d0b24"
   },
   "layers": [
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 28058333,
         "digest": "sha256:26687f18c250ea259f4c3adc62b2d2421b204078146daf592a6cb6149fff12e7"
      },
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 24047030,
         "digest": "sha256:3db37b8c8581bc315682a25f04ad0f272e50cd8a2a22c2eb212c5f09437f41cb"
      }
   ]
}

config 文件内容

{
    "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"
        ],
        "Cmd": [
            "/bin/sh"
        ],
        "ArgsEscaped": true,
        "Image": "sha256:534c86f7312dbbab3a8f724cc87fa82f0770ec171659112c975315a7a6166a94",
        "Volumes": null,
        "WorkingDir": "",
        "Entrypoint": null,
        "OnBuild": null,
        "Labels": null
    },
    "container": "953e5de88d11a4e81e21b1c7c1957519b8ff21e6e638981f21ea5ef845e308c4",
    "container_config": {
        "Hostname": "953e5de88d11",
        "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"
        ],
        "Cmd": [
            "/bin/sh",
            "-c",
            "#(nop) ",
            "CMD [\"/bin/sh\"]"
        ],
        "ArgsEscaped": true,
        "Image": "sha256:534c86f7312dbbab3a8f724cc87fa82f0770ec171659112c975315a7a6166a94",
        "Volumes": null,
        "WorkingDir": "",
        "Entrypoint": null,
        "OnBuild": null,
        "Labels": {}
    },
    "created": "2019-03-07T22:19:53.447205048Z",
    "docker_version": "18.06.1-ce",
    "history": [
        {
            "created": "2019-03-07T22:19:53.313789681Z",
            "created_by": "/bin/sh -c #(nop) ADD file:aa17928040e31624cad9c7ed19ac277c5402c4b9ba39f834250affca40c4046e in / "
        },
        {
            "created": "2019-03-07T22:19:53.447205048Z",
            "created_by": "/bin/sh -c #(nop)  CMD [\"/bin/sh\"]",
            "empty_layer": true
        }
    ],
    "os": "linux",
    "rootfs": {
        "type": "layers",
        "diff_ids": [
            "sha256:3fc64803ca2de7279269048fe2b8b3c73d4536448c87c32375b2639ac168a48b"
        ]
    }
}

文件管理方式

先看一下整体的数据存储结构

.
└── docker
    └── registry
        └── v2
            ├── blobs
            │   └── sha256
            │       ├── 3d
            │       │   └── 3dd72560ec4ecc993af6324c93c93fa12fc2a817cd89193854805f0967f4617f
            │       │       └── data
            │       ├── 48
            │       │   └── 48e8f8b4d1d5b3fc320aa546e65a8cbf91ff6bcfbcbb3604ade41ee8c9fc65f8
            │       │       └── data
            │       ├── 52
            │       │   └── 52179b638f890fdd03b83484b534daccfd9c9d9ea61b3e518ef899971b05892e
            │       │       └── data
            │       ├── 5d
            │       │   └── 5d20c808ce198565ff70b3ed23a991dd49afac45dece63474b27ce6ed036adc6
            │       │       └── data
            │       ├── 6d
            │       │   └── 6d1ef012b5674ad8a127ecfa9b5e6f5178d171b90ee462846974177fd9bdd39f
            │       │       └── data
            │       ├── 92
            │       │   └── 92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b
            │       │       └── data
            │       └── a3
            │           └── a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
            │               └── data
            └── repositories
                ├── library
                │   └── alpine
                │       ├── _layers
                │       │   └── sha256
                │       │       ├── 5d20c808ce198565ff70b3ed23a991dd49afac45dece63474b27ce6ed036adc6
                │       │       │   └── link
                │       │       └── 6d1ef012b5674ad8a127ecfa9b5e6f5178d171b90ee462846974177fd9bdd39f
                │       │           └── link
                │       └── _manifests
                │           ├── revisions
                │           │   └── sha256
                │           │       └── 92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b
                │           │           └── link
                │           └── tags
                │               └── 3.7
                │                   ├── current
                │                   │   └── link
                │                   └── index
                │                       └── sha256
                │                           └── 92251458088c638061cda8fd8b403b76d661a4dc6b7ee71b6affcf1872557b2b
                │                               └── link
                └── zhaogaolong
                    ├── app-test
                    │   ├── _layers
                    │   │   └── sha256
                    │   │       ├── 265345b84d5c4a25b900ca94d0b19a3f0c11271e56ca354c80eb45637d5e09d2
                    │   │       │   └── link
                    │   │       ├── 5d20c808ce198565ff70b3ed23a991dd49afac45dece63474b27ce6ed036adc6
                    │   │       │   └── link
                    │   │       ├── 8c70b080af60d13c3e04212132c17a7a52ca81166c7c48088dbfee16c9815f56
                    │   │       │   └── link
                    │   │       ├── a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4
                    │   │       │   └── link
                    │   │       ├── a67c4c15aee645045dc03fe9595a04b04167687ab8d6db0f1f547e68ea04f304
                    │   │       │   └── link
                    │   │       └── afbd3a0eed148d332d9809dd274dd9213a1baccffe9fa8b9836b20ff2ae108b2
                    │   │           └── link
                    │   └── _manifests
                    │       ├── revisions
                    │       │   └── sha256
                    │       │       └── 440d59188c7bb022b89225df3f0ce2aa5f0bd1eec0c2a54f555e38ddc1ecc975
                    │       │           └── link
                    │       └── tags
                    │           └── 2020-07-27-1
                    │               ├── current
                    │               │   └── link
                    │               └── index
                    │                   └── sha256
                    │                       └── 440d59188c7bb022b89225df3f0ce2aa5f0bd1eec0c2a54f555e38ddc1ecc975
                    │                           └── link
                    └── build-test
                        └── _layers
                            └── sha256
                                ├── 48e8f8b4d1d5b3fc320aa546e65a8cbf91ff6bcfbcbb3604ade41ee8c9fc65f8
                                │   └── link
                                ├── 52179b638f890fdd03b83484b534daccfd9c9d9ea61b3e518ef899971b05892e
                                │   └── link
                                └── 5d20c808ce198565ff70b3ed23a991dd49afac45dece63474b27ce6ed036adc6
                                    └── link

通过文件树状结构很清晰,主目录分为两个

  • blobs:存储layer 的真实内容,不管是 manifest、config、layer 压缩包
  • repositories: 是维护一个子目录结构,形成 docker 镜像的 repo path + tag

blobs 很简单,通过sha256 的前两位做成子目录,然后吧文件放入目录下的中,最终文件被命名为data

repositories 不存储数据,只存储链接, 通过维护子目录结构形成完整的 repo path + tag , 例如:

镜像名称 : xxxxxxxx.com/library/alpine:3.7 registry path: repositories/library/alpine/_manifests/tag/3.7

而该镜像的 mainfest 文件就在 repositories/library/alpine/_manifests/tag/3.7/current/link的 hash265 的 blob layer 里,剩下的就容易了,顺着 mainifest 找到 config 、layers ,形成完整的镜像数据链。

关联关系

efcccabf9334d2ff5fdb7e5cbc7d1d2a.png

总结

docker registry 的设计还是很精巧的,没有复杂的设计,通过把文件内容集中存储,这样在有相同layer 的 镜像,直接能找到该layer 是否已经存在,避免数据重复存储。通过文件目录来维护 repo path + tag 的精巧设计,简单易懂。