registry gc

registry存儲(chǔ)目錄


image.png

Registry 存儲(chǔ)目錄只有兩種文件名的文件:

  • data 文件:包括層文件(layer)凌唬、config 文件和 manifest 文件
  • link 文件:存放在 repository 目錄下羹呵,其內(nèi)容是指向 data 文件的 digest 值

目錄說(shuō)明

_layers/sha256

repositories 目錄下每個(gè) repository 的 _layers/sha256 目錄保存了此 repository 的所有層文件(layer)和 config 文件的 digest箱熬,該目錄下 link 文件指向?qū)?yīng) blobs 目錄下的 data 文件墩划,當(dāng) pull 一個(gè)鏡像的 layer 時(shí)韧献,是通過 link 文件找到 layer 在 registry 種實(shí)際存儲(chǔ)的存儲(chǔ)位置

_manifests/revisions/sha256

repositories 目錄下每個(gè) repository 的 _manifests/revisions/sha256 目錄保存了此 repository 的所有 manifest 文件的 link 文件

_manifests/tags/[tag]/current

repositories 目錄下每個(gè) repository 的 _manifests/tags/[tag]/current 保存了 tag 對(duì)應(yīng)的 manifest 文件的 link 文件

_manifests/tags/[tag]/index/sha256

Registry GC 原理

刪除鏡像文件變化分析

推送兩個(gè)鏡像 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'

刪除后放坏,文件變化,從文件變化可以看出來(lái)亿傅,delete 一個(gè)鏡像實(shí)質(zhì)上是刪除 repositories 元數(shù)據(jù)文件夾下的 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 后文件變化

執(zhí)行垃圾回收

# 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 過程簡(jiǎn)析

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

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

通過 registry API 刪除 manifest B 后慢宗,layer c 并沒有刪除坪蚁,只是刪除了對(duì)它的引用

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

GC 后奔穿,沒有任何引用 lay c 就會(huì)被刪掉

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

GC 階段

GC 主要分兩個(gè)階段:mark 和 sweep

mark 階段:掃描所有的 manifest 文件,標(biāo)記掃描到的 manifest 文件所包含的 layer敏晤。按倉(cāng)庫(kù)進(jìn)行贱田,獲取此倉(cāng)庫(kù)下所有 manifest 文件的索引(即 _manifests/revisions/sha256 文件夾下所有文件),根據(jù)索引獲取所有的 manifest 文件并標(biāo)記其包含 layer嘴脾,如果添加了 -m男摧,會(huì)進(jìn)一步此 manifest 文件索引在這個(gè)倉(cāng)庫(kù)下有沒有 tag 引用(不會(huì)掃描所有倉(cāng)庫(kù)),沒有引用則會(huì)標(biāo)記刪除此 manifest文件及其所以引用译打。

sweep 階段:將沒有標(biāo)記的 blob(layer 和 config 文件)就會(huì)被清除掉

總結(jié)

總結(jié)以上耗拓,用以下三張圖片就能直觀地理解這些過程

delete 鏡像之前的 registry 存儲(chǔ)目錄結(jié)構(gòu)

[圖片上傳失敗...(image-8cb64b-1666173662460)]

delete 鏡像之后的 registry 存儲(chǔ)目錄結(jié)構(gòu)

[圖片上傳失敗...(image-b8c961-1666173662460)]

GC 之后的 registry 存儲(chǔ)目錄結(jié)構(gòu)

[圖片上傳失敗...(image-adef3f-1666173662460)]

源碼解析

# 入口
# GC command distribution/registry/root.go L43
初始化driver, registry, 參數(shù)等

# 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 ——> 標(biāo)記階段
    ···

    // sweep ——> 刪除階段
    ···
    return err
}

mark 階段

    markSet := make(map[digest.Digest]struct{})
    manifestArr := make([]ManifestDel, 0)
    // 按倉(cāng)庫(kù)進(jìn)行遍歷
    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")
        }
        // 遍歷每個(gè) manifest 索引
        err = manifestEnumerator.Enumerate(ctx, func(dgst digest.Digest) error {
            // 如果開啟 -m,即 delete manifests that are not currently referenced via tag
            if opts.RemoveUntagged {
                // 此 manifest 關(guān)聯(lián) 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)
                }
                // 如果關(guān)聯(lián)的 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)
                    }
                    // 標(biāo)記此 manifest 文件需要?jiǎng)h除
                    manifestArr = append(manifestArr, ManifestDel{Name: repoName, Digest: dgst, Tags: allTags})
                    return nil
                }
            }
            // 標(biāo)記此 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 {
              // 標(biāo)記 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 {
      // 刪除無(wú) 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 存在的問題

多架構(gòu)鏡像 GC 后無(wú)法拉取

將多個(gè)架構(gòu)鏡像存儲(chǔ)在不同的 repository 時(shí)乔询,存儲(chǔ)目錄如下,重點(diǎn)觀察索引的組織方式韵洋,其他目錄已省略

每個(gè)倉(cāng)庫(kù)下竿刁,tag 對(duì)應(yīng)的 manifest 文件的索引在 revisions 目錄均有對(duì)應(yīng)

但在多架構(gòu)倉(cāng)庫(kù) nginx 中,revisions 目錄下卻多了 2 個(gè)索引搪缨,分別對(duì)應(yīng) amd64食拜、arm 架構(gòu)鏡像

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

此時(shí)如果添加 -m 參數(shù)進(jìn)行 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

可以發(fā)現(xiàn),在多架構(gòu)倉(cāng)庫(kù) nginx 中副编,revisions 目錄下對(duì)應(yīng) amd64负甸、arm 架構(gòu)鏡像的索引被刪除了,此時(shí) 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 標(biāo)記是按倉(cāng)庫(kù)進(jìn)行的齿桃,由于在多架構(gòu)倉(cāng)庫(kù) nginx 中惑惶,amd64、arm 架構(gòu)鏡像的索引并沒有 tag 對(duì)應(yīng)短纵,GC 時(shí)就會(huì)被刪除带污,多架構(gòu)鏡像在拉取制定 platform 的鏡像時(shí),由于索引缺失香到,報(bào)了如上錯(cuò)誤

GC 不徹底

_layers/sha256/digest/link刪除不徹底

registry 無(wú)論是刪除一個(gè)鏡像還是進(jìn)行 GC 操作鱼冀,都不會(huì)刪除 repositories 目錄下的 _layers/sha256/digest/link 文件,在進(jìn)行 GC 之后悠就,一些鏡像 layer 和 config 文件已經(jīng)在 blobs 存儲(chǔ)目錄下刪除了千绪,但指向它的 layers/link 文件依舊保存在 repositories 目錄下。GitHub 上有個(gè) PR Remove the layer’s link by garbage-collect #2288 就是專門來(lái)清理這些無(wú)用的 layer link 文件的梗脾,最早的一個(gè)是三年前的荸型,但是還沒有合并

不使用 -m 參數(shù)時(shí),blob 文件刪除不徹底

在不使用 -m 參數(shù)時(shí)炸茧,沒有 tag 引用的 manifest 文件所對(duì)應(yīng)的 blob 文件也不會(huì)被刪除瑞妇,雖然添加 -m 參數(shù)可以解決此問題稿静,但會(huì)導(dǎo)致多架構(gòu)鏡像 GC 后無(wú)法拉取

多架構(gòu)鏡像 pull 流程

待補(bǔ)充

參考資料

garbage-collection

docker registry GC 原理分析

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市辕狰,隨后出現(xiàn)的幾起案子改备,更是在濱河造成了極大的恐慌,老刑警劉巖蔓倍,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件悬钳,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡偶翅,警方通過查閱死者的電腦和手機(jī)默勾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)倒堕,“玉大人灾测,你說(shuō)我怎么就攤上這事】寻停” “怎么了媳搪?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)骤宣。 經(jīng)常有香客問我秦爆,道長(zhǎng),這世上最難降的妖魔是什么憔披? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任等限,我火速辦了婚禮,結(jié)果婚禮上芬膝,老公的妹妹穿的比我還像新娘望门。我一直安慰自己,他們只是感情好锰霜,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布筹误。 她就那樣靜靜地躺著,像睡著了一般癣缅。 火紅的嫁衣襯著肌膚如雪厨剪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天友存,我揣著相機(jī)與錄音祷膳,去河邊找鬼。 笑死屡立,一個(gè)胖子當(dāng)著我的面吹牛直晨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼抡秆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼奕巍!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起儒士,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎檩坚,沒想到半個(gè)月后着撩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡匾委,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年拖叙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赂乐。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡薯鳍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出挨措,到底是詐尸還是另有隱情挖滤,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布浅役,位于F島的核電站斩松,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏觉既。R本人自食惡果不足惜惧盹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瞪讼。 院中可真熱鬧钧椰,春花似錦、人聲如沸符欠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)背亥。三九已至秒际,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間狡汉,已是汗流浹背娄徊。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盾戴,地道東北人寄锐。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親橄仆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子剩膘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容