Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Registry 容器镜像服务端细节

Registry 容器镜像服务端细节

作者头像
腾讯云原生
发布于 2020-06-02 09:15:50
发布于 2020-06-02 09:15:50
2.1K00
代码可运行
举报
运行总次数:0
代码可运行

作者周宏宇,后台开发,目前负责腾讯云TKE的接入层网络组件(Ingress、Service)。在团队中负责接入层组件的技术方案、开发测试以及相关的服务技术支持。

引言

通常我们在使用集群或者容器的时候,都会接触到存储在本地的镜像,也或多或少对本地镜像存储有一定的了解。但是服务端的镜像存储细节呢?本文主要介绍容器镜像的服务端存储结构,对于自建镜像服务或是对容器镜像底层原理或优化有兴趣的同学可以了解一下。

相关开源项目

目前容器镜像服务相关的开源项目主要有以下两个。

  • Registry (https://github.com/docker/distribution)
  • Harbor (https://github.com/goharbor/harbor)

Registry具有基本的镜像上传、下载以及对接第三方鉴权的能力。Harbor则基于Registry做了相应的企业级扩展的项目。提供了更多权限、审计、镜像等功能,目前是CNCF孵化项目之一。其他详情参考相关文章。这篇文章主要讲解Registry项目的存储细节。

镜像细节

在了解服务端之前,我们来了解一下客户端的镜像容器的存储环境。

联合文件系统 UnionFS(Union File System)

Docker的存储驱动的实现是基于UnionFS。简单列举一下UnionFS下存储镜像的一些特点。

首先,UnionFS是一个分层的文件系统。一个Docker镜像可能有多个层组成(注意他们是有顺序的)。

其次,只有顶层是可写的,其它层都是只读的。这样的机制带来的好处是镜像层可以被多个镜像共享。对于Docker镜像来说,所有层都是只读的。当一个镜像运行时,会在该镜像上增加一个容器层。十个相同的镜像启动,仅仅是增加十个容器层。销毁容器时也仅仅是销毁一个容器层而已。

  • UnionFS是一个分层的文件系统。一个Docker镜像可能有多个层组成(注意他们是有顺序的)。
  • 只有顶层是可写的,其它层都是只读的。这样的机制带来的好处是镜像层可以被多个镜像共享。对于Docker镜像来说,所有层都是只读的。当一个镜像运行时,会在该镜像上增加一个容器层。十个相同的镜像启动,仅仅是增加十个容器层。销毁容器时也仅仅是销毁一个容器层而已。
    • 当容器需要读取文件的时候:从最上层镜像开始查找,往下找,找到文件后读取并放入内存,若已经在内存中了,直接使用。(即,同一台机器上运行的docker容器共享运行时相同的文件)。
    • 当容器需要添加文件的时候:直接在最上面的容器层可写层添加文件,不会影响镜像层。
    • 当容器需要修改文件的时候:从上往下层寻找文件,找到后,复制到容器可写层,然后,对容器来说,可以看到的是容器层的这个文件,看不到镜像层里的文件。容器在容器层修改这个文件。
    • 当容器需要删除文件的时候:从上往下层寻找文件,找到后在容器中记录删除。即,并不会真正的删除文件,而是软删除。这将导致镜像体积只会增加,不会减少。

由此可以思考很多安全和镜像优化上的问题。

  • 在镜像构建中记录敏感信息然后再下一个构建指令中删除安全吗?(不安全)
  • 在镜像构建中安装软件包然后再下一个构建指令中清理软件包能减小镜像体积吗?(并不能)

UnionFS一般有两种实现方案:1. 基于文件实现。文件整体的覆盖重写。2. 基于块实现,对文件的修改只修改少量块。

镜像的服务端存储细节

提供一个镜像元信息(manifest)用于参考:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
~ docker pull ccr.ccs.tencentyun.com/paas/service-controller:7b1c981c
7b1c981c: Pulling from paas/service-controller
Digest: sha256:e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419
Status: Image is up to date for ccr.ccs.tencentyun.com/paas/service-controller:7b1c981c
ccr.ccs.tencentyun.com/paas/service-controller:7b1c981c
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
   "schemaVersion": 2,
   "mediaType": "application/vnd.docker.distribution.manifest.v2+json",
   "config": {
      "mediaType": "application/vnd.docker.container.image.v1+json",
      "size": 4671,
      "digest": "sha256:785f4150a5d9f62562f462fa2d8b8764df4215f0f2e3a3716c867aa31887f827"
   },
   "layers": [
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 44144090,
         "digest": "sha256:e80174c8b43b97abb6bf8901cc5dade4897f16eb53b12674bef1eae6ae847451"
      },
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 529,
         "digest": "sha256:d1072db285cc5eb2f3415891381631501b3ad9b1a10da20ca2e932d7d8799988"
      },
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 849,
         "digest": "sha256:858453671e6769806e0374869acce1d9e5d97f5020f86139e0862c7ada6da621"
      },
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 170,
         "digest": "sha256:3d07b1124f982f6c5da7f1b85a0a12f9574d6ce7e8a84160cda939e5b3a1faad"
      },
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 8461461,
         "digest": "sha256:994dade28a14b2eac1450db7fa2ba53998164ed271b1e4b0503b1f89de44380c"
      },
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 22178452,
         "digest": "sha256:60a5bd5c14d0f37da92d2a5e94d6bbfc1e2a942d675aee24f055ced76e8a208f"
      },
      {
         "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
         "size": 22178452,
         "digest": "sha256:60a5bd5c14d0f37da92d2a5e94d6bbfc1e2a942d675aee24f055ced76e8a208f"
      }
   ]
}

接下来是本文最为重要的内容,通过对上面这张图的理解,我们就可以了解到Registry服务端存储的细节。

  • 图中蓝色的是服务端存储的目录。文字是目录名称,这个名称是固定的。
  • 图中紫色的是服务端存储的文件。文字是文件名称,link文件的内容都是一个sha256的哈希值。data文件存储了真正的元文件和镜像层。
  • 图中橙色的是服务端的动态目录。目录的名称和仓库名、镜像标签或者sha256有关的。

整个图是从上往下的。举个例子,我们上面描述的manifest如果是存储在服务端的话(文件哈希:sha256:e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419)。它存储的路径应该是:/docker/registry/v2/blobs/sha256/e8/e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419/data。对应图上应该是沿着左侧一直向下。

我们开始拆解分析其结构细节。

  • 左侧是镜像所有内容的实际存储,其几乎占据的绝大部分储存的空间,包括了镜像层和镜像元信息Manifest。
    • 例如镜像层sha256:e80174c8b43b97abb6bf8901cc5dade4897f16eb53b12674bef1eae6ae847451的存储位置,应该在/docker/registry/v2/blobs/sha256/e8/e80174c8b43b97abb6bf8901cc5dade4897f16eb53b12674bef1eae6ae847451/data
  • 右侧是镜像元信息存储的地方。镜像元信息是按照命名空间和仓库名称分两级目录存储的。
    • 每一个仓库下面又分为_layers_manifests两个部分
    • _layers负责记录该仓库引用了哪些镜像层文件。
    • _manifests负责记录镜像的元信息
      • revisions包含了仓库下曾经上传过的所有版本的镜像元信息
      • tags包含了仓库中的所有标签
        • current记录了当前标签指向的镜像
        • index目录则记录了标签指向的历史镜像。
    • 对上述提供的manifest计算sha256,会得到元信息文件的哈希值sha256:e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419,这个元信息的存储位置应该在/docker/registry/v2/blobs/sha256/e8/e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419/data

举个镜像下载的例子:

我们想要知道ccr.ccs.tencentyun.com/paas/service-controller:7b1c981c这个镜像现在的元信息,如何在服务端存储中找到。

  1. 找到/docker/registry/v2/paas/service-controller/_manifests/tags/7b1c981c/current/link文件。里面有元信息的sha256信息。内容应该是sha256:e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419
  2. 找到实际存储文件(/docker/registry/v2/blobs/sha256/e8/e8b84ce6c245f04e6e453532d676f7c7f0a94b3122f93a89a58f9ae49939e419/data)。前文中给出了该文件的json内容。
  3. 根据源文件信息,客户端依次下载对应文件就可以了。(鉴权过程参考参考文档)
  • ImageConfig sha256:785f4150a5d9f62562f462fa2d8b8764df4215f0f2e3a3716c867aa31887f827
  • ImageLayer sha256:e80174c8b43b97abb6bf8901cc5dade4897f16eb53b12674bef1eae6ae847451 sha256:d1072db285cc5eb2f3415891381631501b3ad9b1a10da20ca2e932d7d8799988 sha256:858453671e6769806e0374869acce1d9e5d97f5020f86139e0862c7ada6da621 sha256:3d07b1124f982f6c5da7f1b85a0a12f9574d6ce7e8a84160cda939e5b3a1faad sha256:994dade28a14b2eac1450db7fa2ba53998164ed271b1e4b0503b1f89de44380c sha256:60a5bd5c14d0f37da92d2a5e94d6bbfc1e2a942d675aee24f055ced76e8a208f

Tips:

  1. 很明显同样的镜像层文件在存储中只会有一个副本。使用相同基础镜像将节省大量的存储成本。
  2. 如果想要算上述元信息文件的哈希值,请保证你复制的文件内容尾部没有EOL。[noeol]

基于存储的几个问题

镜像构建如何优化?

根据UnionFS的特性,针对性的进行优化:

  1. 构建时,一个构建指令会生成一个镜像层,尽量避免在镜像层中出现垃圾文件,例如在安装软件之后删除软件包。
  2. 删除敏感资源并不能使得该内容真正消失,避免敏感内容造成的安全问题。例如编译镜像最后删除代码是无效的欺骗自己的行为。
  3. 通过多阶段构建,减少中间产物以及编译环境中的依赖内容。
上传到服务端镜像,再上传到其他仓库需要重新上传吗?

需要,在Registry的设计中仓库是权限的最小单位,用户是根据仓库进行权限管理与隔离的。考虑如果这里忽略了这一块的设计,镜像层存在就避免重复上传的话,客户端可以通过构造虚假镜像元信息的方式,越权获取到其他用户的镜像。_layers中记录了仓库有权限获取的所有镜像层的目的就在于此。

镜像复制场景下如何优化?

复制镜像的场景和上传场景的区别在于,源镜像是用户确实已经拥有的。这里可以通过上述问题的思考进行复制的优化,当镜像层在目的地址已经存在时,直接标记仓库拥有该层避免不必要的上传。

镜像历史版本

根据存储结构的特点,可以较为轻松的回答这个问题。理论上只要不做Registry GC,不删除仓库元信息,仓库历史版本的镜像都会在仓库中一直保存的。

怎么拿到镜像的元信息?

这里不做详细讲解了,有兴趣的同学可以参考以下文档:

  • DockerRegistry API V2——https://docs.docker.com/registry/spec/api/
  • Docker Registry TokenAuthentication Specification——https://docs.docker.com/registry/spec/auth/token/
  • DockerImage Manifests V2 Schema2——https://docs.docker.com/registry/spec/manifest-v2-2/

云服务的存储对接

Registry作为一个开源软件,适配各种云存储产品属于标配功能了。Registry提供了标准的存储驱动接口,只要实现了这一套接口就能适配运行起来了。

相关文章

  • 为什么有了Docker registry还需要Harbor?——https://cloud.tencent.com/developer/article/1080444
  • 理解Docker镜像分层——https://www.cnblogs.com/woshimrf/p/docker-container-lawyer.html
  • Docker Registry 存储驱动——https://docs.docker.com/registry/storage-drivers/

腾讯云容器

致力于提供云上一站式使用kubernetes的解决方案,助力业务快速上云,拥抱云原生

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-05-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯云容器团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Docker容器镜像仓库存储原理(前世今身)与搬运技巧
在深入学习镜像之前我们需要知道镜像是如何(炼制/搓)成的(等同于构建镜像),当然是通过我们DockerFile一条条指令为镜像生成每一层,按照执行顺序镜像文件系统复写封装从下到上;
全栈工程师修炼指南
2022/09/29
3.5K0
Docker容器镜像仓库存储原理(前世今身)与搬运技巧
如何搭建及使用 docker registry
腾讯云容器服务团队
2016/12/26
3.4K0
如何搭建及使用 docker registry
清理镜像库空间的一个思路
最近遇到一个有趣的状况,某镜像仓库占用了大量的磁盘空间。通常要解决这种问题,给 Registry 发删除指令,并进行 GC 就可以了。然而很多时候,所有镜像都正常,在删除多个 Tag 甚至是 Repository 之后,问题仍然没能缓解,原理也很容易理解——删除的镜像虽然大,可能只是复用了一些比较大的层,删除镜像并不会真正的发出,所以还是需要对镜像库的存储进行更多的了解,进行进一步的统计,在层一级对镜像仓库进行分析,才能获取更有效的途径。
崔秀龙
2020/11/04
9830
Docker容器Registry私有镜像仓库安全配置与GC回收实践
描述:本来我想直接写Harbor的Docker镜像仓库搭建配置与使用,但是觉得还是应该从基础的Docker的Registry镜像讲起从安全构建到GC回收同时加深学习映像;
全栈工程师修炼指南
2022/09/29
2.4K0
Docker容器Registry私有镜像仓库安全配置与GC回收实践
K8S 1.20 弃用 Docker 评估之:Docker 和 OCI 镜像格式的差别
2020 年 12 月初,Kubernetes 在其最新的 Changelog 中宣布,自 Kubernetes 1.20 之后将弃用 Docker 作为容器运行时。
东风微鸣
2022/04/22
3.1K0
云原生制品那些事(2):OCI 镜像规范
题图摄于故宫角楼 注:微信公众号不按照时间排序,请关注“亨利笔记”,并加星标以置顶,以免错过更新。 《Harbor权威指南》招募英文版翻译人员 本篇继续和大家说说镜像那些事,是连载之二,从《Harbor权威指南》一书节选的纯技术干货,敬请关注、转发和收藏。 第一篇:容器镜像的结构 第二篇:OCI 镜像规范 第三篇:OCI 制品 第四篇:Registry 的作用原理 《Harbor权威指南》目前当当网优惠中,点击下图直接购买。 1.5  OCI镜像规范 OCI 镜像规范是以 Docker 镜像规范 v2
Henry Zhang
2023/04/18
1.2K0
云原生制品那些事(2):OCI 镜像规范
如何保存/同步多架构容器 Docker 镜像
随着容器、芯片技术的进一步发展,以及绿色、节能、信创等方面的要求,多 CPU 架构的场景越来越常见。典型的应用场景包括:
东风微鸣
2022/12/01
2.3K0
如何保存/同步多架构容器 Docker 镜像
Docker镜像竟然也是容器?!Docker 到底为什么这么快!?
Docker虚拟化技术是基于容器化,容器化技术的本质其实是基于内核资源调度的再分配! 并不是什么新技术,只是近年Linux内核更加成熟,在资源调度隔离更成熟,所以容器化技术再被提上议程。
运维部落
2020/04/27
1.3K0
如何使用Skopeo做一个优雅的镜像搬运工
[TOC] 0x00 基础介绍 描述: 作为公司内部 PaaS toB 产品的打包发布人员,容器镜像对我们打工人而言就像是工地上的砖头 🧱,而我的一部分工作就是将这些砖头在各个仓库之间搬来搬去,最终
全栈工程师修炼指南
2022/09/29
4.4K0
如何使用Skopeo做一个优雅的镜像搬运工
6.Docker使用辅助工具汇总
more information: https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface
全栈工程师修炼指南
2020/10/23
2.2K0
6.Docker使用辅助工具汇总
n2.Docker家文件目录介绍和配置文件与守护进程命令参数一览
/var/lib/docker - docker 根(家)目录 描述:它是Docker中镜像、容器、容器配置的本地存储目录;
全栈工程师修炼指南
2022/09/28
1.1K0
n2.Docker家文件目录介绍和配置文件与守护进程命令参数一览
Harbor记异常迁移恢复实践
描述: Harbor 是一个用于存储和分发Docker镜像的企业级Registry服务器,通过添加一些企业必需的功能特性,例如安全、标识和管理等,扩展了开源 Docker Distribution。作为一个企业级私有Registry服务器,Harbor提供了更好的性能和安全。提升用户使用Registry构建和运行环境传输镜像的效率。
全栈工程师修炼指南
2022/09/29
9450
Harbor记异常迁移恢复实践
多平台容器镜像构建就看这一篇
孔矾建,腾讯高级工程师。多年云原生技术实践经验,聚焦容器镜像与存储领域,负责腾讯云容器镜像仓库产品开发,Harbor 社区 Maintainer,《Harbor 权威指南》联名作者。 前言 愿景与现实 早在1995年,就有“write once and run anywhere”(WORA,编写一次即可在任何地方运行)用于描述 Java 应用程序。时过20年,Docker 高声喊出了自己的口号——“Build Once, Run Anywhere”(一次构建,随处可用)。 愿望是美好的,然而,现实总比理想
腾讯云原生
2020/12/28
2K0
Docker 进阶之镜像分层详解
1.构建测试镜像v1.0:docker build -t image_test:1.0 .
看、未来
2022/06/30
1.5K0
Docker 进阶之镜像分层详解
Docker多架构容器镜像构建方式
在运行任何 docker 镜像或 Kubernetes pod 时,您是否在服务器上看到过exec /docker-entrypoint.sh: exec format error错误消息?这很可能是因为您正在服务器上运行一些其他 CPU 架构的容器镜像,或者您是否曾经 在 Apple Silicon M1、M2 MacBook 上使用过--platform linux/x86_64选项?如果是,那么您无法获得 Apple 芯片的本机性能,并且可能会耗尽 MacBook 的电池电量。为了避免这种错误和性能问题,我们需要运行正确的多架构容器镜像,或者我们可能需要构建自己的镜像,因为所有容器公共镜像都没有可用的多架构镜像。
DevOps云学堂
2023/08/22
1.5K0
Docker多架构容器镜像构建方式
kubernetes 问题排查: 高版本 containerd 下载镜像失败
在 containerd 运行时的 kubernetes 线上环境中,出现了镜像无法下载的情况,具体报错如下:
CNCF
2021/05/27
9.7K2
kubernetes 问题排查: 高版本 containerd 下载镜像失败
云原生时代下的容器镜像安全(上)
Kubernetes 作为云原生的基石,为我们带来了极大的便利性,越来越多的公司也都将 Kubernetes 应用到了生产环境中。然而,在享受其带来的便利性的同时,我们也需要关注其中的一些安全隐患。
Jintao Zhang
2021/12/01
7330
云原生时代下的容器镜像安全(上)
OCI 与容器镜像构建
2013 年 3 月 dotCloud 公司在 PyCon 上进行了 Docker 的首次展示,随后宣布开源。自此 Docker 开始被众人知晓,随后掀起了一股容器化的热潮。
Jintao Zhang
2021/11/16
1.9K0
镜像搬运工具 Skopeo 使用
一个好的镜像传输工具能节省大量的人力和 CPU 算力,本文将为大家介绍一个能够完全替代 docker-cli 的工具:Skopeo。
我是阳明
2021/07/23
5.5K0
好奇宝宝看 Docker 底层原理(中)
前面两篇分别探究了 docker 的底层架构和 docker 的容器隔离机制,那么本篇就来一探 docker 是如何实现多文件联合系统的!!!
看、未来
2022/05/31
5030
好奇宝宝看 Docker 底层原理(中)
相关推荐
Docker容器镜像仓库存储原理(前世今身)与搬运技巧
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验