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 原理分析

你可能感兴趣的:(registry gc)