Özel bir docker kayıt defterinden görüntüler nasıl silinir?


163

Özel bir docker kayıt defteri çalıştırıyorum ve latestbir depodan tüm resimleri silmek istiyorum . Deponun tamamını silmek istemiyorum, sadece içindeki bazı resimler. API dosyaları bunu yapmanın bir yolu söz etmeyin, ama kesinlikle bu mümkün?


2
Kabul edilen cevap artık doğru değil (kesinlikle çok iyi olsa da). DELETE / v2 / <name> / manifests / <reference> kullanarak görüntüleri kaldırabilirsiniz: docs.docker.com/registry/spec/api/#deleting-an-image
Michael Zelensky

Yanıtlar:


116

Şu anda bu görev için Kayıt Defteri API'sını kullanamazsınız. Yalnızca bir havuzu veya belirli bir etiketi silmenizi sağlar.

Genel olarak, bir havuzun silinmesi, bu depoyla ilişkili tüm etiketlerin silineceği anlamına gelir.

Bir etiketi silmek, bir resim ile bir etiket arasındaki ilişkinin silineceği anlamına gelir.

Yukarıdakilerin hiçbiri tek bir görüntüyü silmez. Diskinizde kalırlar.


Geçici çözüm

Bu geçici çözüm için docker görüntülerinizin yerel olarak depolanması gerekir.

Çözümünüz için geçici bir çözüm, en son etiketleri hariç tümünü silmek ve böylece ilişkili resimlere olan referansı kaldırmak olabilir. Daha sonra bu komut dosyasını , herhangi bir etiket tarafından kullanılmayan tüm görüntüleri veya kullanılan herhangi bir görüntünün atalarını kaldırmak için çalıştırabilirsiniz .

Terminoloji (resimler ve etiketler)

Büyük harfler (burada böyle bir görüntü grafiğini düşünün A, B, ...) kısa görüntü kimlikleri ve temsil <-bir görüntü başka görüntüde dayandığını araçlar:

 A <- B <- C <- D

Şimdi resme etiketler ekliyoruz:

 A <- B <- C <- D
           |    |
           |    <version2>
           <version1>

Burada, etiket <version1>resme C, etiket <version2>ise resme referansta bulunur D.

Sorunuzu hassaslaştırma

Sorunuzda, kaldırmak istediğinizi söylediniz

dışındaki tüm resimler latest

. Şimdi, bu terminoloji tam olarak doğru değil. Görüntüleri ve etiketleri karıştırdınız. Grafiğe baktığımızda, etiketin <version2>en son sürümü temsil ettiğini kabul edeceğinizi düşünüyorum . Aslında, bu soruya göre en son sürümü temsil eden bir etikete sahip olabilirsiniz:

 A <- B <- C <- D
           |    |
           |    <version2>
           |    <latest>
           <version1>

<latest>Etiket resme referans verdiğinden, Dsize soruyorum: gerçekten resim dışında hepsini silmek istiyor Dmusunuz? Muhtemelen değil!

Bir etiketi silerseniz ne olur?

Etiketi <version1>Docker REST API'sini kullanarak silerseniz bunu alırsınız:

 A <- B <- C <- D
                |
                <version2>
                <latest>

Unutmayın: Docker asla bir görüntüyü silmez! Olsa bile, bu görüntü bir görüntüyü silemez, çünkü görüntü etiketlenen Cgörüntünün soyunun bir parçasıdır D.

Bu komut dosyasını kullansanız bile , hiçbir görüntü silinmeyecektir.

Bir resim ne zaman silinebilir

Birisinin kayıt defterinizi ne zaman çekebileceğini veya kaydedebileceğini kontrol edebilmeniz koşuluyla (örneğin, REST arayüzünü devre dışı bırakarak). Bir görüntüyü temel alan başka bir resim yoksa ve ona hiçbir etiket referans göstermiyorsa, bir resmi resim grafiğinden silebilirsiniz.

Aşağıdaki grafikte, görüntü o Bildirimi Dedilir değil dayanan Cama üzerinde B. Bu nedenle, Dbağımlı değildir C. <version1>Bu grafikteki etiketi silerseniz , görüntü Chiçbir resim tarafından kullanılmaz ve bu komut dosyası bunu kaldırabilir.

 A <- B <--------- D
      \            |
       \           <version2>
        \          <latest>
         \ <- C
              |
              <version1>

Temizleme işleminden sonra görüntü grafiğiniz şöyle görünür:

 A <- B <- D
           |
           <version2>
           <latest>

İstediğiniz bu mu?


Haklısınız - etiketleri silmek ilişkilendirilmiş resimleri gerçekten silmemiştir. O zaman kutuya ssh erişimi verilen görüntüleri silmenin bir yolu var mı?
Leo

1
Cevabımı işi benim için yapan bir geçici çözümle düzenledim. Umut ediyorum bu yardım eder.
Konrad Kleine

Aynen öyle - görüntülerin aşamalı olarak oluşturulduğunu anlıyorum, ancak bu ölü dalları budamak için bir yola ihtiyacım var. Teşekkürler!
Leo

@KonradKleine Görüntü grafiğini kayıt defterinden aldığınız görüntü listesinden nasıl çıkarırsınız?
Rafael Barros

9
Çöp toplama nihayet sicile v2.4.0
Markus Lindberg

68

Benim kayıt defteri ile aynı sorunla karşılaştım sonra bir blog sayfasından aşağıda listelenen çözüm çalıştı. İşe yarıyor.

1. Adım: Katalogları listeleme

Bu URL'yi arayarak kataloglarınızı listeleyebilirsiniz:

http://YourPrivateRegistyIP:5000/v2/_catalog

Yanıt şu biçimde olacaktır:

{
  "repositories": [
    <name>,
    ...
  ]
}

2. Adım: İlgili katalog için etiketleri listeleme

Bu URL'yi çağırarak kataloğunuzun etiketlerini listeleyebilirsiniz:

http://YourPrivateRegistyIP:5000/v2/<name>/tags/list

Yanıt şu biçimde olacaktır:

{
"name": <name>,
"tags": [
    <tag>,
    ...
]

}

3. Adım: İlgili etiket için manifest değerini listeleyin

Bu komutu docker kayıt defteri kapsayıcısında çalıştırabilirsiniz:

curl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://localhost:5000/v2/<name>/manifests/<tag> 2>&1 | grep Docker-Content-Digest | awk '{print ($3)}'

Yanıt şu biçimde olacaktır:

sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073

Aşağıda verilen komutu manifest değeriyle çalıştırın:

curl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE http://127.0.0.1:5000/v2/<name>/manifests/sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073

4. Adım: İşaretli manifest'leri silin

Docker kayıt kapsayıcısında bu komutu çalıştırın:

bin/registry garbage-collect  /etc/docker/registry/config.yml  

İşte benim config.yml

root@c695814325f4:/etc# cat /etc/docker/registry/config.yml
version: 0.1
log:
  fields:
  service: registry
storage:
    cache:
        blobdescriptor: inmemory
    filesystem:
        rootdirectory: /var/lib/registry
    delete:
        enabled: true
http:
    addr: :5000
    headers:
        X-Content-Type-Options: [nosniff]
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3

" Deleteing blob: /docker/..." İle ilgili mesajlar da dahil olmak üzere komutlar başarılı oldu, ancak kullanılan disk alanını değiştirmedi. Bin / kayıt defteri kullanma github.com/docker/distribution v2.4.1 .
JamesThomasMoon1979

3
bir görüntüyü silmek için kayıt defteri kapsayıcısını REGISTRY_STORAGE_DELETE_ENABLED = true parametresiyle çalıştırmalısınız.
Adil

3
/Etc/docker/registry/config.yml dosyasında "delete: etkin" değerini true olarak ayarladım. Bu yapılandırma için REGISTRY_STORAGE_DELETE_ENABLED değişkenini @AdilIlhan
Yavuz Sert

re: adım 3, "Docker-Content-Digest" başlıkta olmalıdır? (kıvrılma çıktısında görmüyor). Başarılı bir şekilde işaretlediğimi bilmek için işaretli manifest (ler) i silmeden önce manifest işaretlemenin sonuçlarını görebilmeli miyim? Ne gönderirsem göndereyim 202 yanıt veriyor gibi görünüyor.
SteveW

Docker-Content-Digestbölüm yani küçük harf (liman işçisi motor v18.09.2 üzerinde test) olmalıdırcurl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://localhost:5000/v2/<name>/manifests/<tag> 2>&1 | grep docker-content-digest | awk '{print ($3)}'
Muhammed Abdurrahman

63

Mevcut v2kayıt defteri artık üzerinden silinmeyi destekliyorDELETE /v2/<name>/manifests/<reference>

Bkz. Https://github.com/docker/distribution/blob/master/docs/spec/api.md#deleting-an-image

Çalışma kullanımı: https://github.com/byrnedo/docker-reg-tool

Düzenleme: Yukarıdaki bildirim <reference>istekte bulunarak alınabilir

GET /v2/<name>/manifests/<tag>

ve Docker-Content-Digestyanıttaki başlığı kontrol etme .

Edit 2: Kayıt defterinizi aşağıdaki env setiyle çalıştırmanız gerekebilir:

REGISTRY_STORAGE_DELETE_ENABLED="true"

Edit3: Bu disk alanını boşaltmak için çöp toplama çalıştırmanız gerekebilir: https://docs.docker.com/registry/garbage-collection/


3
Buradaki diğer bazı cevaplar, manifest referans karmasının nasıl çıkarılacağını gösterir. Bu, bir etiketi iletilecek bir şeye dönüştürmek için gereklidir DELETE.
JamesThomasMoon1979

Desteklenmeyen hata alınıyor. Referans olarak uygun özet değeri verdim.
Winster

1
@ JamesThomasMoon1979 referans karmasını alma talimatları ile güncellendi.
byrnedo

11
V2 de ve hata alıyorum{"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]}
Gadelkareem

1
@Gadelkareem
byrnedo

17

Sorun 1

Bunun özel docker kayıt defteriniz olduğunu belirttiniz, bu nedenle muhtemelen sağladığınız bağlantı olan Hub kayıt defteri API belgesi yerine Kayıt Defteri API'sını kontrol etmeniz gerekir .

Sorun 2

docker kayıt defteri API'si bir istemci / sunucu protokolüdür, arka uçtaki görüntülerin kaldırılıp kaldırılmayacağı sunucunun uygulamasına bağlıdır. (Sanırım)

DELETE /v1/repositories/(namespace)/(repository)/tags/(tag*)

Detay açıklama

Aşağıda, sorularınız için anlayışım olarak açıklamanızdan şimdi nasıl çalıştığını gösteriyorum.

Özel docker kayıt defterini çalıştırdığınızda, varsayılanı kullanıyorum ve 5000bağlantı noktasında dinliyorum

docker run -d -p 5000:5000 registry

Sonra yerel görüntüyü etiketleyip içine itiyorum.

$ docker tag ubuntu localhost:5000/ubuntu
$ docker push localhost:5000/ubuntu
The push refers to a repository [localhost:5000/ubuntu] (len: 1)
Sending image list
Pushing repository localhost:5000/ubuntu (1 tags)
511136ea3c5a: Image successfully pushed
d7ac5e4f1812: Image successfully pushed
2f4b4d6a4a06: Image successfully pushed
83ff768040a0: Image successfully pushed
6c37f792ddac: Image successfully pushed
e54ca5efa2e9: Image successfully pushed
Pushing tag for rev [e54ca5efa2e9] on {http://localhost:5000/v1/repositories/ubuntu/tags/latest}

Bundan sonra özel docker kayıt defterinizde var olup olmadığını kontrol etmek için Kayıt Defteri API'sını kullanabilirsiniz

$ curl -X GET localhost:5000/v1/repositories/ubuntu/tags
{"latest": "e54ca5efa2e962582a223ca9810f7f1b62ea9b5c3975d14a5da79d3bf6020f37"}

Şimdi bu API kullanarak etiketi silebilirim !!

$ curl -X DELETE localhost:5000/v1/repositories/ubuntu/tags/latest
true

Tekrar kontrol edin, etiket özel kayıt sunucunuzda mevcut değil

$ curl -X GET localhost:5000/v1/repositories/ubuntu/tags/latest
{"error": "Tag not found"}

2
Bu komutun neden yardımcı olmadığını açıklamak için lütfen aşağıdaki cevabımı inceleyin.
Konrad Kleine

2
Etiketleri silersiniz, ancak görüntü verilerini silmezsiniz. İkincisi, bir etiketi sildikten sonra referans verdiğim komut dosyası tarafından yapılır. Bir etiketi silmek için kayıt defteri API'sını da kullanıyorum.
Konrad Kleine

3
her kayıt defteri API sunucusunun uygulamasına bağlıdır, protokolün bakış açısından, mevcut değildir.
Larry Cai

Bunun uygulamaya bağlı olduğunu doğru söylüyorsunuz - ancak resim verilerini standart registryresimden silmenin bir yolunu arıyordum . Bir komut dosyası içinde SSHing yapmak ve çalıştırmak, ideal olmasa bile çalışır. Bir yan not olarak bunun hala eksik bir API olduğunu düşünüyorum - etiketleri silebilirsiniz, ancak /imagesGETElerseniz artık tüm görüntü verilerini görürsünüz.
Leo

Kayıt Defteri API'sından bahsettiğiniz için teşekkür ederiz, özel kayıt defterindeki bir resmi SİLMenin bir yolunu arıyordu. Bu yöntem, disk alanı boşaltmadan sadece 'etiketsiz' olsa bile benim için yeterince iyi.
Howard Lee

16

Bu gerçekten çirkin ama işe yarıyor, metin kayıt defterinde test ediliyor: 2.5.1. Silme özelliğini etkinleştirmek için yapılandırmayı güncelledikten sonra bile silme işleminin sorunsuz şekilde yapılmasını başaramadım. Kimlik almak gerçekten zordu, almak için giriş yapmak zorunda kaldı, belki bazı yanlış anlama. Her neyse, aşağıdaki işler:

  1. Konteynere giriş

    docker exec -it registry sh
    
  2. Kapsayıcı ve kapsayıcı sürümünüzle eşleşen değişkenleri tanımlayın:

    export NAME="google/cadvisor"
    export VERSION="v0.24.1"
    
  3. Kayıt defteri dizinine gidin:

    cd /var/lib/registry/docker/registry/v2
    
  4. Karma ile ilgili dosyaları silin:

    find . | grep `ls ./repositories/$NAME/_manifests/tags/$VERSION/index/sha256`| xargs rm -rf $1
    
  5. Manifestleri sil:

    rm -rf ./repositories/$NAME/_manifests/tags/$VERSION
    
  6. Çıkış Yap

    exit
    
  7. GC'yi çalıştırın:

    docker exec -it registry  bin/registry garbage-collect  /etc/docker/registry/config.yml
    
  8. Her şey düzgün yapılmışsa, silinmiş lekeler hakkında bazı bilgiler gösterilir.


i yukarıda belirtilen adımları izledi, ancak docker kayıt {konteyner} disk kullanımını kontrol zaman adımları yapmadan önce aynı gösteriliyordu ... neden herhangi bir fikir?
Savio Mathew

çalışmıyor. Kontrol edilmesi kolay. Aşağıdaki adımları uyguladığınızda ve repo'yu tekrar ittiğinizde "064794e955a6: Katman zaten var"
yazıyor

8

Tam olarak bunu yapan bazı müşteriler (Python, Ruby, vb.) Vardır. Benim zevkime göre, kayıt defteri sunucuma bir çalışma zamanı (örn. Python) yüklemek, sadece kayıt defterimi temizlemek için sürdürülebilir değildir!


Yani deckschrubberbenim çözümdür:

go get github.com/fraunhoferfokus/deckschrubber
$GOPATH/bin/deckschrubber

belirli bir yaştan daha eski görüntüler otomatik olarak silinir. Yaş kullanılarak belirtilebilir -year, -month, -dayveya bunların kombinasyonu:

$GOPATH/bin/deckschrubber -month 2 -day 13 -registry http://registry:5000

GÜNCELLEME : İşte deckschrubber hakkında kısa bir giriş .


1
deckschrubberoldukça iyi - kurulumu çok kolay (tek ikili) ve görüntüleri isme (regex eşleşmesi ile) ve yaşa göre silmenizi sağlar.
RichVel

ERRO[0000] Could not delete image! repo=.... tag=latest: /
scythargon

@scythargon'un belirtiminizin doğru olup olmadığını söylemek imkansız.
Jitter

Uyarı: havuzumda hiçbir şey yapmadı.
Richard Warburton

Ne yazık ki, etiketi olmayan görüntüleri kaldırmayacak. Dolayısıyla, görüntüleri tek bir etikete aktarmaya devam ederseniz, yalnızca etiketlenmiş olanı kontrol eder, diğerini kontrol etmez.
Krystian

1

Kısaca;

1) Bir docker deposunun RepoDigest'leri için aşağıdaki komutu yazmanız gerekir;

## docker inspect <registry-host>:<registry-port>/<image-name>:<tag>
> docker inspect 174.24.100.50:8448/example-image:latest


[
    {
        "Id": "sha256:16c5af74ed970b1671fe095e063e255e0160900a0e12e1f8a93d75afe2fb860c",
        "RepoTags": [
            "174.24.100.50:8448/example-image:latest",
            "example-image:latest"
        ],
        "RepoDigests": [
            "174.24.100.50:8448/example-image@sha256:5580b2110c65a1f2567eeacae18a3aec0a31d88d2504aa257a2fecf4f47695e6"
        ],
...
...

$ {digest} = sha256: 5580b2110c65a1f2567eeacae18a3aec0a31d88d2504aa257a2fecf4f47695e6

2) REST API kayıt defterini kullanın

  ##curl -u username:password -vk -X DELETE registry-host>:<registry-port>/v2/<image-name>/manifests/${digest}


  >curl -u example-user:example-password -vk -X DELETE http://174.24.100.50:8448/v2/example-image/manifests/sha256:5580b2110c65a1f2567eeacae18a3aec0a31d88d2504aa257a2fecf4f47695e6

Başarılı bir çağırma için 202 Kabul edildi.

3-) Çöp Toplayıcıyı Çalıştırın

docker exec registry bin/registry garbage-collect --dry-run /etc/docker/registry/config.yml

kayıt defteri - kayıt defteri kapsayıcı adı.

Daha ayrıntılı açıklama için bağlantı açıklamasını buraya girin



0

Bash Script Altında En son kayıt defteri dışında bulunan tüm etiketleri siler.

for D in /registry-data/docker/registry/v2/repositories/*; do
if [ -d "${D}" ]; then
    if [ -z "$(ls -A ${D}/_manifests/tags/)" ]; then
        echo ''
    else
        for R in $(ls -t ${D}/_manifests/tags/ | tail -n +2); do
            digest=$(curl -k -I -s -H -X GET http://xx.xx.xx.xx:5000/v2/$(basename  ${D})/manifests/${R} -H 'accept: application/vnd.docker.distribution.manifest.v2+json'  | grep Docker-Content-Digest | awk '{print $2}' )
            url="http://xx.xx.xx.xx:5000/v2/$(basename  ${D})/manifests/$digest"
            url=${url%$'\r'}
            curl -X DELETE -k -I -s   $url -H 'accept: application/vnd.docker.distribution.manifest.v2+json' 
        done
    fi
fi
done

Bu Koşudan Sonra

docker exec $(docker ps | grep registry | awk '{print $1}') /bin/registry garbage-collect /etc/docker/registry/config.yml

Bu güzel betiğin nasıl kullanılacağı hakkında biraz daha ayrıntı verebilir misiniz?
Khalil Gharbaoui

0

Bu yanıta dayanan basit yakut komut dosyası : Registry_cleaner .

Yerel makinede çalıştırabilirsiniz:

./registry_cleaner.rb --host=https://registry.exmpl.com --repository=name --tags_count=4

Ve sonra kayıt defteri makinesinde lekeleri kaldırın /bin/registry garbage-collect /etc/docker/registry/config.yml.


0

İşte Yavuz Sert'in cevabına dayanan bir senaryo. En son sürüm olmayan tüm etiketleri siler ve etiketleri 950'den büyüktür.

#!/usr/bin/env bash


CheckTag(){
    Name=$1
    Tag=$2

    Skip=0
    if [[ "${Tag}" == "latest" ]]; then
        Skip=1
    fi
    if [[ "${Tag}" -ge "950" ]]; then
        Skip=1
    fi
    if [[ "${Skip}" == "1" ]]; then
        echo "skip ${Name} ${Tag}"
    else
        echo "delete ${Name} ${Tag}"
        Sha=$(curl -v -s -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://127.0.0.1:5000/v2/${Name}/manifests/${Tag} 2>&1 | grep Docker-Content-Digest | awk '{print ($3)}')
        Sha="${Sha/$'\r'/}"
        curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE "http://127.0.0.1:5000/v2/${Name}/manifests/${Sha}"
    fi
}

ScanRepository(){
    Name=$1
    echo "Repository ${Name}"
    curl -s http://127.0.0.1:5000/v2/${Name}/tags/list | jq '.tags[]' |
    while IFS=$"\n" read -r line; do
        line="${line%\"}"
        line="${line#\"}"
        CheckTag $Name $line
    done
}


JqPath=$(which jq)
if [[ "x${JqPath}" == "x" ]]; then
  echo "Couldn't find jq executable."
  exit 2
fi

curl -s http://127.0.0.1:5000/v2/_catalog | jq '.repositories[]' |
while IFS=$"\n" read -r line; do
    line="${line%\"}"
    line="${line#\"}"
    ScanRepository $line
done
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.