registry gc

registry存储目录


image.png

Registry 存储目录只有两种文件名的文件:

  • data 文件:包括层文件(layer)、config 文件和 manifest 文件
  • link 文件:存放在 repository 目录下,其内容是指向 data 文件的 digest 值

目录说明

_layers/sha256

repositories 目录下每个 repository 的 _layers/sha256 目录保存了此 repository 的所有层文件(layer)和 config 文件的 digest,该目录下 link 文件指向对应 blobs 目录下的 data 文件,当 pull 一个镜像的 layer 时,是通过 link 文件找到 layer 在 registry 种实际存储的存储位置

_manifests/revisions/sha256

repositories 目录下每个 repository 的 _manifests/revisions/sha256 目录保存了此 repository 的所有 manifest 文件的 link 文件

_manifests/tags/[tag]/current

repositories 目录下每个 repository 的 _manifests/tags/[tag]/current 保存了 tag 对应的 manifest 文件的 link 文件

_manifests/tags/[tag]/index/sha256

Registry GC 原理

删除镜像文件变化分析

推送两个镜像 library/nginx:latest、library/nginx:v1

# tree
.
└── docker
    └── registry
        └── v2
            ├── blobs
            │   └── sha256
            │       ├── 18
            │       │   └── 186b1aaa4aa6c480e92fbd982ee7c08037ef85114fbed73dbb62503f24c1dd7d
            │       │       └── data
            │       ├── 58
            │       │   └── 589b7251471a3d5fe4daccdddfefa02bdc32ffcba0a6d6a2768bf2c401faf115
            │       │       └── data
            │       ├── 5c
            │       │   └── 5cc84ad355aaa64f46ea9c7bbcc319a9d808ab15088a27209c9e70ef86e5a2aa
            │       │       └── data
            │       ├── 60
            │       │   └── 605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85
            │       │       └── data
            │       ├── 62
            │       │   └── 62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee
            │       │       └── data
            │       ├── a0
            │       │   └── a0bcbecc962ed2552e817f45127ffb3d14be31642ef3548997f58ae054deb5b2
            │       │       └── data
            │       ├── a2
            │       │   └── a2abf6c4d29d43a4bf9fbb769f524d0fb36a2edab49819c1bf3e76f409f953ea
            │       │       └── data
            │       ├── a9
            │       │   └── a9edb18cadd1336142d6567ebee31be2a03c0905eeefe26cb150de7b0fbc520b
            │       │       └── data
            │       ├── b4
            │       │   └── b4df32aa5a72e2a4316aad3414508ccd907d87b4ad177abd7cbd62fa4dab2a2f
            │       │       └── data
            │       ├── be
            │       │   └── beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a
            │       │       └── data
            │       └── ee
            │           └── ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
            │               └── data
            └── repositories
                └── library
                    └── nginx
                        ├── _layers
                        │   └── sha256
                        │       ├── 186b1aaa4aa6c480e92fbd982ee7c08037ef85114fbed73dbb62503f24c1dd7d
                        │       │   └── link
                        │       ├── 589b7251471a3d5fe4daccdddfefa02bdc32ffcba0a6d6a2768bf2c401faf115
                        │       │   └── link
                        │       ├── 5cc84ad355aaa64f46ea9c7bbcc319a9d808ab15088a27209c9e70ef86e5a2aa
                        │       │   └── link
                        │       ├── 605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85
                        │       │   └── link
                        │       ├── a0bcbecc962ed2552e817f45127ffb3d14be31642ef3548997f58ae054deb5b2
                        │       │   └── link
                        │       ├── a2abf6c4d29d43a4bf9fbb769f524d0fb36a2edab49819c1bf3e76f409f953ea
                        │       │   └── link
                        │       ├── a9edb18cadd1336142d6567ebee31be2a03c0905eeefe26cb150de7b0fbc520b
                        │       │   └── link
                        │       ├── b4df32aa5a72e2a4316aad3414508ccd907d87b4ad177abd7cbd62fa4dab2a2f
                        │       │   └── link
                        │       └── beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a
                        │           └── link
                        ├── _manifests
                        │   ├── revisions
                        │   │   └── sha256
                        │   │       ├── 62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee
                        │   │       │   └── link
                        │   │       └── ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
                        │   │           └── link
                        │   └── tags
                        │       ├── latest
                        │       │   ├── current
                        │       │   │   └── link
                        │       │   └── index
                        │       │       └── sha256
                        │       │           └── ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
                        │       │               └── link
                        │       └── v1
                        │           ├── current
                        │           │   └── link
                        │           └── index
                        │               └── sha256
                        │                   └── 62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee
                        │                       └── link
                        └── _uploads

删除 library/nginx:v1

curl -X "DELETE" -k 'http://localhost:5000/v2/library/nginx/manifests/sha256:62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee'

删除后,文件变化,从文件变化可以看出来,delete 一个镜像实质上是删除 repositories 元数据文件夹下的 tag 名文件夹和该 tag 的 revisions 下的 link 文件

# tree
.
└── docker
    └── registry
        └── v2
            ├── blobs
            │   └── sha256
            │       ├── 18
            │       │   └── 186b1aaa4aa6c480e92fbd982ee7c08037ef85114fbed73dbb62503f24c1dd7d
            │       │       └── data
            │       ├── 58
            │       │   └── 589b7251471a3d5fe4daccdddfefa02bdc32ffcba0a6d6a2768bf2c401faf115
            │       │       └── data
            │       ├── 5c
            │       │   └── 5cc84ad355aaa64f46ea9c7bbcc319a9d808ab15088a27209c9e70ef86e5a2aa
            │       │       └── data
            │       ├── 60
            │       │   └── 605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85
            │       │       └── data
            │       ├── 62
            │       │   └── 62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee
            │       │       └── data
            │       ├── a0
            │       │   └── a0bcbecc962ed2552e817f45127ffb3d14be31642ef3548997f58ae054deb5b2
            │       │       └── data
            │       ├── a2
            │       │   └── a2abf6c4d29d43a4bf9fbb769f524d0fb36a2edab49819c1bf3e76f409f953ea
            │       │       └── data
            │       ├── a9
            │       │   └── a9edb18cadd1336142d6567ebee31be2a03c0905eeefe26cb150de7b0fbc520b
            │       │       └── data
            │       ├── b4
            │       │   └── b4df32aa5a72e2a4316aad3414508ccd907d87b4ad177abd7cbd62fa4dab2a2f
            │       │       └── data
            │       ├── be
            │       │   └── beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a
            │       │       └── data
            │       └── ee
            │           └── ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
            │               └── data
            └── repositories
                └── library
                    └── nginx
                        ├── _layers
                        │   └── sha256
                        │       ├── 186b1aaa4aa6c480e92fbd982ee7c08037ef85114fbed73dbb62503f24c1dd7d
                        │       │   └── link
                        │       ├── 589b7251471a3d5fe4daccdddfefa02bdc32ffcba0a6d6a2768bf2c401faf115
                        │       │   └── link
                        │       ├── 5cc84ad355aaa64f46ea9c7bbcc319a9d808ab15088a27209c9e70ef86e5a2aa
                        │       │   └── link
                        │       ├── 605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85
                        │       │   └── link
                        │       ├── a0bcbecc962ed2552e817f45127ffb3d14be31642ef3548997f58ae054deb5b2
                        │       │   └── link
                        │       ├── a2abf6c4d29d43a4bf9fbb769f524d0fb36a2edab49819c1bf3e76f409f953ea
                        │       │   └── link
                        │       ├── a9edb18cadd1336142d6567ebee31be2a03c0905eeefe26cb150de7b0fbc520b
                        │       │   └── link
                        │       ├── b4df32aa5a72e2a4316aad3414508ccd907d87b4ad177abd7cbd62fa4dab2a2f
                        │       │   └── link
                        │       └── beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a
                        │           └── link
                        ├── _manifests
                        │   ├── revisions
                        │   │   └── sha256
                        │   │       ├── 62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee
                        │   │       └── ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
                        │   │           └── link
                        │   └── tags
                        │       └── latest
                        │           ├── current
                        │           │   └── link
                        │           └── index
                        │               └── sha256
                        │                   └── ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
                        │                       └── link
                        └── _uploads

Registry GC 后文件变化

执行垃圾回收

# docker exec -it 7987b19396bb registry garbage-collect /etc/docker/registry/config.yml
library/nignx
library/nignx: marking manifest sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3 
library/nignx: marking blob sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85
library/nignx: marking blob sha256:a2abf6c4d29d43a4bf9fbb769f524d0fb36a2edab49819c1bf3e76f409f953ea
library/nignx: marking blob sha256:a9edb18cadd1336142d6567ebee31be2a03c0905eeefe26cb150de7b0fbc520b
library/nignx: marking blob sha256:589b7251471a3d5fe4daccdddfefa02bdc32ffcba0a6d6a2768bf2c401faf115
library/nignx: marking blob sha256:186b1aaa4aa6c480e92fbd982ee7c08037ef85114fbed73dbb62503f24c1dd7d
library/nignx: marking blob sha256:b4df32aa5a72e2a4316aad3414508ccd907d87b4ad177abd7cbd62fa4dab2a2f
library/nignx: marking blob sha256:a0bcbecc962ed2552e817f45127ffb3d14be31642ef3548997f58ae054deb5b2

8 blobs marked, 3 blobs and 0 manifests eligible for deletion
blob eligible for deletion: sha256:5cc84ad355aaa64f46ea9c7bbcc319a9d808ab15088a27209c9e70ef86e5a2aa
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/5c/5cc84ad355aaa64f46ea9c7bbcc319a9d808ab15088a27209c9e70ef86e5a2aa  go.version=go1.11.2 instance.id=54fcc304-f5ca-40b1-8be4-e43a6c1f3fa6 service=registry
blob eligible for deletion: sha256:62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/62/62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee  go.version=go1.11.2 instance.id=54fcc304-f5ca-40b1-8be4-e43a6c1f3fa6 service=registry
blob eligible for deletion: sha256:beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/be/beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a  go.version=go1.11.2 instance.id=54fcc304-f5ca-40b1-8be4-e43a6c1f3fa6 service=registry

垃圾回收后,文件变化

# tree
.
└── docker
    └── registry
        └── v2
            ├── blobs
            │   └── sha256
            │       ├── 18
            │       │   └── 186b1aaa4aa6c480e92fbd982ee7c08037ef85114fbed73dbb62503f24c1dd7d
            │       │       └── data
            │       ├── 58
            │       │   └── 589b7251471a3d5fe4daccdddfefa02bdc32ffcba0a6d6a2768bf2c401faf115
            │       │       └── data
            │       ├── 5c
            │       ├── 60
            │       │   └── 605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85
            │       │       └── data
            │       ├── 62
            │       ├── a0
            │       │   └── a0bcbecc962ed2552e817f45127ffb3d14be31642ef3548997f58ae054deb5b2
            │       │       └── data
            │       ├── a2
            │       │   └── a2abf6c4d29d43a4bf9fbb769f524d0fb36a2edab49819c1bf3e76f409f953ea
            │       │       └── data
            │       ├── a9
            │       │   └── a9edb18cadd1336142d6567ebee31be2a03c0905eeefe26cb150de7b0fbc520b
            │       │       └── data
            │       ├── b4
            │       │   └── b4df32aa5a72e2a4316aad3414508ccd907d87b4ad177abd7cbd62fa4dab2a2f
            │       │       └── data
            │       ├── be
            │       └── ee
            │           └── ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
            │               └── data
            └── repositories
                └── library
                    └── nginx
                        ├── _layers
                        │   └── sha256
                        │       ├── 186b1aaa4aa6c480e92fbd982ee7c08037ef85114fbed73dbb62503f24c1dd7d
                        │       │   └── link
                        │       ├── 589b7251471a3d5fe4daccdddfefa02bdc32ffcba0a6d6a2768bf2c401faf115
                        │       │   └── link
                        │       ├── 5cc84ad355aaa64f46ea9c7bbcc319a9d808ab15088a27209c9e70ef86e5a2aa
                        │       │   └── link
                        │       ├── 605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85
                        │       │   └── link
                        │       ├── a0bcbecc962ed2552e817f45127ffb3d14be31642ef3548997f58ae054deb5b2
                        │       │   └── link
                        │       ├── a2abf6c4d29d43a4bf9fbb769f524d0fb36a2edab49819c1bf3e76f409f953ea
                        │       │   └── link
                        │       ├── a9edb18cadd1336142d6567ebee31be2a03c0905eeefe26cb150de7b0fbc520b
                        │       │   └── link
                        │       ├── b4df32aa5a72e2a4316aad3414508ccd907d87b4ad177abd7cbd62fa4dab2a2f
                        │       │   └── link
                        │       └── beae173ccac6ad749f76713cf4440fe3d21d1043fe616dfbe30775815d1d0f6a
                        │           └── link
                        ├── _manifests
                        │   ├── revisions
                        │   │   └── sha256
                        │   │       ├── 62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee
                        │   │       └── ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
                        │   │           └── link
                        │   └── tags
                        │       └── latest
                        │           ├── current
                        │           │   └── link
                        │           └── index
                        │               └── sha256
                        │                   └── ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
                        │                       └── link
                        └── _uploads

GC 原理分析

GC 过程简析

假如有 manifest A 和manifest B,分别引用了layer a、b 和 a、c

A -----> a <----- B
    \--> b     |
         c <--/

通过 registry API 删除 manifest B 后,layer c 并没有删除,只是删除了对它的引用

A -----> a     B
    \--> b
         c

GC 后,没有任何引用 lay c 就会被删掉

A -----> a
    \--> b

GC 阶段

GC 主要分两个阶段:mark 和 sweep

mark 阶段:扫描所有的 manifest 文件,标记扫描到的 manifest 文件所包含的 layer。按仓库进行,获取此仓库下所有 manifest 文件的索引(即 _manifests/revisions/sha256 文件夹下所有文件),根据索引获取所有的 manifest 文件并标记其包含 layer,如果添加了 -m,会进一步此 manifest 文件索引在这个仓库下有没有 tag 引用(不会扫描所有仓库),没有引用则会标记删除此 manifest文件及其所以引用。

sweep 阶段:将没有标记的 blob(layer 和 config 文件)就会被清除掉

总结

总结以上,用以下三张图片就能直观地理解这些过程

delete 镜像之前的 registry 存储目录结构

[图片上传失败...(image-8cb64b-1666173662460)]

delete 镜像之后的 registry 存储目录结构

[图片上传失败...(image-b8c961-1666173662460)]

GC 之后的 registry 存储目录结构

[图片上传失败...(image-adef3f-1666173662460)]

源码解析

# 入口
# GC command distribution/registry/root.go L43
初始化driver, registry, 参数等

# distribution/registry/storage/garbagecollect.go
func MarkAndSweep(ctx context.Context, storageDriver driver.StorageDriver, registry distribution.Namespace, opts GCOpts) error {
    repositoryEnumerator, ok := registry.(distribution.RepositoryEnumerator)
    if !ok {
        return fmt.Errorf("unable to convert Namespace to RepositoryEnumerator")
    }

    // mark ——> 标记阶段
    ···

    // sweep ——> 删除阶段
    ···
    return err
}

mark 阶段

    markSet := make(map[digest.Digest]struct{})
    manifestArr := make([]ManifestDel, 0)
    // 按仓库进行遍历
    err := repositoryEnumerator.Enumerate(ctx, func(repoName string) error {
        emit(repoName)

        var err error
        named, err := reference.WithName(repoName)
        if err != nil {
            return fmt.Errorf("failed to parse repo name %s: %v", repoName, err)
        }
        repository, err := registry.Repository(ctx, named)
        if err != nil {
            return fmt.Errorf("failed to construct repository: %v", err)
        }

        manifestService, err := repository.Manifests(ctx)
        if err != nil {
            return fmt.Errorf("failed to construct manifest service: %v", err)
        }

        manifestEnumerator, ok := manifestService.(distribution.ManifestEnumerator)
        if !ok {
            return fmt.Errorf("unable to convert ManifestService into ManifestEnumerator")
        }
        // 遍历每个 manifest 索引
        err = manifestEnumerator.Enumerate(ctx, func(dgst digest.Digest) error {
            // 如果开启 -m,即 delete manifests that are not currently referenced via tag
            if opts.RemoveUntagged {
                // 此 manifest 关联 tag 列表
                tags, err := repository.Tags(ctx).Lookup(ctx, distribution.Descriptor{Digest: dgst})
                if err != nil {
                    return fmt.Errorf("failed to retrieve tags for digest %v: %v", dgst, err)
                }
                // 如果关联的 tag 列表未空,则表示此 manifest 文件需要被删除
                if len(tags) == 0 {
                    emit("manifest eligible for deletion: %s", dgst)
                    // fetch all tags from repository
                    // all of these tags could contain manifest in history
                    // which means that we need check (and delete) those references when deleting manifest
                    allTags, err := repository.Tags(ctx).All(ctx)
                    if err != nil {
                        return fmt.Errorf("failed to retrieve tags %v", err)
                    }
                    // 标记此 manifest 文件需要删除
                    manifestArr = append(manifestArr, ManifestDel{Name: repoName, Digest: dgst, Tags: allTags})
                    return nil
                }
            }
            // 标记此 manifest 文件的所有层文件
            emit("%s: marking manifest %s ", repoName, dgst)
            markSet[dgst] = struct{}{}
            // 获取 manifest 文件
            manifest, err := manifestService.Get(ctx, dgst)
            if err != nil {
                return fmt.Errorf("failed to retrieve manifest for digest %v: %v", dgst, err)
            }
            // 获取所有 layer
            descriptors := manifest.References()
            for _, descriptor := range descriptors {
              // 标记 layer
                markSet[descriptor.Digest] = struct{}{}
                emit("%s: marking blob %s", repoName, descriptor.Digest)
            }

            return nil
        })

        // In certain situations such as unfinished uploads, deleting all
        // tags in S3 or removing the _manifests folder manually, this
        // error may be of type PathNotFound.
        //
        // In these cases we can continue marking other manifests safely.
        if _, ok := err.(driver.PathNotFoundError); ok {
            return nil
        }

        return err
    })

    if err != nil {
        return fmt.Errorf("failed to mark: %v", err)
    }

删除阶段

  vacuum := NewVacuum(ctx, storageDriver)
  // 非 dryrun 模式
    if !opts.DryRun {
      // 删除无 tag 引用的 manifest 索引
        for _, obj := range manifestArr {
            err = vacuum.RemoveManifest(obj.Name, obj.Digest, obj.Tags)
            if err != nil {
                return fmt.Errorf("failed to delete manifest %s: %v", obj.Digest, err)
            }
        }
    }
    // 获取所有需要被删除的 blob 文件的 digest
    blobService := registry.Blobs()
    deleteSet := make(map[digest.Digest]struct{})
    err = blobService.Enumerate(ctx, func(dgst digest.Digest) error {
        // check if digest is in markSet. If not, delete it!
        if _, ok := markSet[dgst]; !ok {
            deleteSet[dgst] = struct{}{}
        }
        return nil
    })
    if err != nil {
        return fmt.Errorf("error enumerating blobs: %v", err)
    }
    emit("\n%d blobs marked, %d blobs and %d manifests eligible for deletion", len(markSet), len(deleteSet), len(manifestArr))
    // 删除层文件
    for dgst := range deleteSet {
        emit("blob eligible for deletion: %s", dgst)
        if opts.DryRun {
            continue
        }
        err = vacuum.RemoveBlob(string(dgst))
        if err != nil {
            return fmt.Errorf("failed to delete blob %s: %v", dgst, err)
        }
    }

    return err

Registry GC 存在的问题

多架构镜像 GC 后无法拉取

将多个架构镜像存储在不同的 repository 时,存储目录如下,重点观察索引的组织方式,其他目录已省略

每个仓库下,tag 对应的 manifest 文件的索引在 revisions 目录均有对应

但在多架构仓库 nginx 中,revisions 目录下却多了 2 个索引,分别对应 amd64、arm 架构镜像

repositories
                └── library
                    ├── nginx-amd64
                    │   ├── _manifests
                    │   │   ├── revisions
                    │   │   │   └── sha256
                    │   │   │       └── ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
                    │   │   │           └── link
                    │   │   └── tags
                    │   │       └── v1
                    │   │           ├── current
                    │   │           │   └── link
                    │   │           └── index
                    │   │               └── sha256
                    │   │                   └── ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
                    │   │                       └── link
                    ├── nginx-arm
                    │   ├── _manifests
                    │   │   ├── revisions
                    │   │   │   └── sha256
                    │   │   │       └── 6575132f2098216b9ac0140aaa4603ef55054891d7917200f4b827e8aa557ed3
                    │   │   │           └── link
                    │   │   └── tags
                    │   │       └── v1
                    │   │           ├── current
                    │   │           │   └── link
                    │   │           └── index
                    │   │               └── sha256
                    │   │                   └── 6575132f2098216b9ac0140aaa4603ef55054891d7917200f4b827e8aa557ed3
                    │   │                       └── link
                    └── nignx
                        ├── _manifests
                        │   ├── revisions
                        │   │   └── sha256
                        │   │       ├── 62ffc2ed7554e4c6d360bce40bbcf196573dd27c4ce080641a2c59867e732dee
                        │   │       ├── 6575132f2098216b9ac0140aaa4603ef55054891d7917200f4b827e8aa557ed3
                        │   │       │   └── link
                        │   │       ├── 91b09d6ba61abfdb0da82f0d4cab86a3ebb1c60848c1735c419b652e45f0767e
                        │   │       │   └── link
                        │   │       └── ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
                        │   │           └── link
                        │   └── tags
                        │       └── v1
                        │           ├── current
                        │           │   └── link
                        │           └── index
                        │               └── sha256
                        │                   └── 91b09d6ba61abfdb0da82f0d4cab86a3ebb1c60848c1735c419b652e45f0767e
                        │                       └── link
                        └── _uploads

此时如果添加 -m 参数进行 GC

# registry  garbage-collect -m  /etc/docker/registry/config.yml
library/nginx-amd64
library/nginx-amd64: marking manifest sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3 
library/nginx-amd64: marking blob sha256:605c77e624ddb75e6110f997c58876baa13f8754486b461117934b24a9dc3a85
library/nginx-amd64: marking blob sha256:a2abf6c4d29d43a4bf9fbb769f524d0fb36a2edab49819c1bf3e76f409f953ea
library/nginx-amd64: marking blob sha256:a9edb18cadd1336142d6567ebee31be2a03c0905eeefe26cb150de7b0fbc520b
library/nginx-amd64: marking blob sha256:589b7251471a3d5fe4daccdddfefa02bdc32ffcba0a6d6a2768bf2c401faf115
library/nginx-amd64: marking blob sha256:186b1aaa4aa6c480e92fbd982ee7c08037ef85114fbed73dbb62503f24c1dd7d
library/nginx-amd64: marking blob sha256:b4df32aa5a72e2a4316aad3414508ccd907d87b4ad177abd7cbd62fa4dab2a2f
library/nginx-amd64: marking blob sha256:a0bcbecc962ed2552e817f45127ffb3d14be31642ef3548997f58ae054deb5b2
library/nginx-arm
library/nginx-arm: marking manifest sha256:6575132f2098216b9ac0140aaa4603ef55054891d7917200f4b827e8aa557ed3 
library/nginx-arm: marking blob sha256:b7dd3d7d83385d0bad882b2a2e1298d2c2003dd58eeae7d959e183b8d8392b9b
library/nginx-arm: marking blob sha256:1dd75a3a9c893a7dc313f683dd62464b7eab6c6d522ee62c8a17022631830f32
library/nginx-arm: marking blob sha256:7db321c265d888c6653db5939cfefe58dcd57184beedea3d273c4e1b413087ee
library/nginx-arm: marking blob sha256:30e66ba016bdf4dae566ccaeae31a2b217de50fca6f913c746e8c818c556480f
library/nginx-arm: marking blob sha256:7365dfc955ef5860c3334f28683a9bb695f64e8a8da05a1f34419ff91ff207eb
library/nginx-arm: marking blob sha256:f3e27355fff573b08f5b87c2fcc4dfa1d32ae64c26cd1e19fbe48a29de009fd5
library/nginx-arm: marking blob sha256:de0fdbb1c0c24ca36b9d51aff08d75f9a14cb1af42155599b8d0cff7ec7b20ea
library/nignx
manifest eligible for deletion: sha256:6575132f2098216b9ac0140aaa4603ef55054891d7917200f4b827e8aa557ed3
library/nignx: marking manifest sha256:91b09d6ba61abfdb0da82f0d4cab86a3ebb1c60848c1735c419b652e45f0767e 
library/nignx: marking blob sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
library/nignx: marking blob sha256:6575132f2098216b9ac0140aaa4603ef55054891d7917200f4b827e8aa557ed3
manifest eligible for deletion: sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
INFO[0000] deleting manifest: /docker/registry/v2/repositories/library/nignx/_manifests/revisions/sha256/6575132f2098216b9ac0140aaa4603ef55054891d7917200f4b827e8aa557ed3  go.version=go1.11.2 instance.id=cefd807b-a4e5-4c1d-b705-9b484da1acdc service=registry
INFO[0000] deleting manifest: /docker/registry/v2/repositories/library/nignx/_manifests/revisions/sha256/ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3  go.version=go1.11.2 instance.id=cefd807b-a4e5-4c1d-b705-9b484da1acdc service=registry

可以发现,在多架构仓库 nginx 中,revisions 目录下对应 amd64、arm 架构镜像的索引被删除了,此时 pull 镜像

# # docker pull localhost:5000/library/nginx:v1
v1: Pulling from library/nginx
manifest for localhost:5000/library/nginx:v1 not found: manifest unknown: manifest unknown

根因分析:


image.png

image.png
image.png

manifest 标记是按仓库进行的,由于在多架构仓库 nginx 中,amd64、arm 架构镜像的索引并没有 tag 对应,GC 时就会被删除,多架构镜像在拉取制定 platform 的镜像时,由于索引缺失,报了如上错误

GC 不彻底

_layers/sha256/digest/link删除不彻底

registry 无论是删除一个镜像还是进行 GC 操作,都不会删除 repositories 目录下的 _layers/sha256/digest/link 文件,在进行 GC 之后,一些镜像 layer 和 config 文件已经在 blobs 存储目录下删除了,但指向它的 layers/link 文件依旧保存在 repositories 目录下。GitHub 上有个 PR Remove the layer’s link by garbage-collect #2288 就是专门来清理这些无用的 layer link 文件的,最早的一个是三年前的,但是还没有合并

不使用 -m 参数时,blob 文件删除不彻底

在不使用 -m 参数时,没有 tag 引用的 manifest 文件所对应的 blob 文件也不会被删除,虽然添加 -m 参数可以解决此问题,但会导致多架构镜像 GC 后无法拉取

多架构镜像 pull 流程

待补充

参考资料

garbage-collection

docker registry GC 原理分析

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容