Bagaimana cara menghapus gambar dari registry buruh pelabuhan pribadi?

163

Saya menjalankan registry buruh pelabuhan pribadi, dan saya ingin menghapus semua gambar kecuali latestdari repositori. Saya tidak ingin menghapus seluruh repositori, hanya beberapa gambar di dalamnya. The docs API tidak menyebutkan cara untuk melakukan hal ini, tapi pasti itu mungkin?

Leo
sumber
2
Jawaban yang diterima sudah tidak benar lagi (meskipun pasti sangat bagus). Anda dapat menghapus gambar menggunakan DELETE / v2 / <name> / manifests / <reference>: docs.docker.com/registry/spec/api/#deleting-an-image
Michael Zelensky

Jawaban:

116

Saat ini Anda tidak dapat menggunakan API Pendaftaran untuk tugas itu. Ini hanya memungkinkan Anda untuk menghapus repositori atau tag tertentu.

Secara umum, menghapus repositori berarti bahwa semua tag yang terkait dengan repo ini dihapus.

Menghapus tag berarti, bahwa hubungan antara gambar dan tag dihapus.

Tidak satu pun di atas akan menghapus satu gambar. Mereka dibiarkan di disk Anda.


Penanganan masalah

Untuk solusi ini, Anda harus menyimpan gambar buruh pelabuhan Anda secara lokal.

Solusi untuk solusi Anda adalah menghapus semua kecuali tag terbaru dan dengan demikian berpotensi menghilangkan referensi ke gambar terkait. Kemudian Anda dapat menjalankan skrip ini untuk menghapus semua gambar, yang tidak dirujuk oleh tag apa pun atau keturunan dari gambar apa pun yang digunakan.

Terminologi (gambar dan tag)

Pertimbangkan grafik gambar seperti ini di mana huruf ( A, B, ...) mewakili ID image pendek dan <-sarana bahwa gambar didasarkan pada gambar lain:

 A <- B <- C <- D

Sekarang kita menambahkan tag ke gambar:

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

Di sini, tag <version1>referensi gambar Cdan tag <version2>referensi gambar D.

Saring pertanyaan Anda

Dalam pertanyaan Anda, Anda mengatakan ingin menghapus

semua gambar kecuali latest

. Sekarang, terminologi ini tidak sepenuhnya benar. Anda telah mencampur gambar dan tag. Melihat grafik saya pikir Anda akan setuju bahwa tag tersebut <version2>mewakili versi terbaru. Bahkan, menurut pertanyaan ini, Anda dapat memiliki tag yang mewakili versi terbaru:

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

Karena <latest>tag mereferensikan gambar, Dsaya bertanya: apakah Anda benar-benar ingin menghapus semua kecuali gambar D? Mungkin tidak!

Apa yang terjadi jika Anda menghapus tag?

Jika Anda menghapus tag <version1>menggunakan Docker REST API Anda akan mendapatkan ini:

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

Ingat: Docker tidak akan pernah menghapus gambar! Bahkan jika itu terjadi, dalam hal ini tidak dapat menghapus gambar, karena gambar Cadalah bagian dari keturunan untuk gambar Dyang ditandai.

Bahkan jika Anda menggunakan skrip ini , tidak ada gambar yang akan dihapus.

Kapan suatu gambar bisa dihapus

Di bawah kondisi yang dapat Anda kontrol ketika seseorang dapat menarik atau mendorong ke registri Anda (misalnya dengan menonaktifkan antarmuka REST). Anda dapat menghapus gambar dari grafik gambar jika tidak ada gambar lain yang didasarkan padanya dan tidak ada tag yang merujuknya.

Perhatikan bahwa dalam grafik berikut, gambar Dini tidak didasarkan pada Ctetapi pada B. Karena itu, Dtidak bergantung pada C. Jika Anda menghapus tag <version1>pada grafik ini, gambar Ctidak akan digunakan oleh gambar apa pun dan skrip ini dapat menghapusnya.

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

Setelah pembersihan grafik gambar Anda terlihat seperti ini:

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

Apa ini yang kau inginkan?

Konrad Kleine
sumber
Anda benar - menghapus tag sebenarnya tidak menghapus gambar terkait. Apakah ada cara untuk menghapus gambar yang diberikan akses ssh ke kotak, lalu?
Leo
1
Saya telah mengedit jawaban saya dengan solusi yang melakukan pekerjaan untuk saya. Saya harap ini membantu.
Konrad Kleine
Begitulah - Saya mengerti bahwa gambar dibangun secara bertahap, tetapi saya perlu cara untuk memangkas cabang-cabang yang mati itu. Terima kasih!
Leo
@KonradKleine bagaimana Anda membuat gambar grafik dari daftar gambar yang Anda dapatkan dari registri?
Rafael Barros
9
Pengumpulan sampah akhirnya tiba di Registry v2.4.0 docs.docker.com/registry/garbage-collection
Markus Lindberg
68

Saya telah menghadapi masalah yang sama dengan registri saya kemudian saya mencoba solusi yang tercantum di bawah ini dari halaman blog. Berhasil.

Langkah 1: Mendaftar katalog

Anda dapat mendaftar katalog Anda dengan menghubungi url ini:

http://YourPrivateRegistyIP:5000/v2/_catalog

Respons akan dalam format berikut:

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

Langkah 2: Cantumkan tag untuk katalog terkait

Anda dapat mencantumkan tag katalog Anda dengan menghubungi url ini:

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

Respons akan dalam format berikut:

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

}

Langkah 3: Daftar nilai manifes untuk tag terkait

Anda dapat menjalankan perintah ini dalam wadah register buruh pelabuhan:

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)}'

Respons akan dalam format berikut:

sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073

Jalankan perintah yang diberikan di bawah ini dengan nilai manifes:

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

Langkah 4: Hapus manifes yang ditandai

Jalankan perintah ini dalam wadah register buruh pelabuhan Anda:

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

Ini config.yml saya

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
Yavuz Sert
sumber
Perintah berhasil, termasuk pesan tentang " Deleteing blob: /docker/..." tetapi tidak mengubah ruang disk yang digunakan. Menggunakan bin / registry github.com/docker/distribution v2.4.1 .
JamesThomasMoon1979
3
untuk menghapus gambar, Anda harus menjalankan wadah registri dengan REGISTRY_STORAGE_DELETE_ENABLED = parameter benar.
Adil
3
Saya menetapkan nilai "delete: enabled" menjadi true dalam file /etc/docker/registry/config.yml. Untuk konfigurasi ini tidak perlu mengatur REGISTRY_STORAGE_DELETE_ENABLED variabel @AdilIlhan
Yavuz Sert
re: langkah 3, "Docker-Content-Digest" harus di header? (tidak melihatnya di output curl). Haruskah saya dapat melihat hasil menandai manifes sebelum menghapus manifes yang ditandai untuk mengetahui bahwa saya berhasil menandainya? Tampaknya memberi saya respons 202 tidak peduli apa yang saya kirimkan.
SteveW
yang Docker-Content-Digestbagian harus dalam huruf kecil (diuji pada mesin buruh pelabuhan v18.09.2) yaitucurl -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)}'
Muhammad Abdurrahman
63

v2Registri saat ini sekarang mendukung penghapusan viaDELETE /v2/<name>/manifests/<reference>

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

Penggunaan yang berfungsi: https://github.com/byrnedo/docker-reg-tool

Sunting: Manifes di <reference>atas dapat diambil dari meminta ke

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

dan memeriksa Docker-Content-Digestheader di respons.

Sunting 2: Anda mungkin harus menjalankan registri dengan set env berikut:

REGISTRY_STORAGE_DELETE_ENABLED="true"

Sunting3: Anda mungkin harus menjalankan pengumpulan sampah untuk membebaskan ruang disk ini: https://docs.docker.com/registry/garbage-collection/

byrnedo
sumber
3
Beberapa jawaban lain di sini menunjukkan cara mengekstrak hash referensi manifes. Ini diperlukan untuk menerjemahkan tag menjadi sesuatu untuk dilewatkan DELETE.
JamesThomasMoon1979
Mendapatkan kesalahan yang tidak didukung. Saya telah memberikan nilai intisari yang tepat sebagai referensi.
Winster
1
@ JamesThomasMoon1979 diperbarui dengan instruksi tentang mendapatkan referensi hash.
byrnedo
11
pada V2 juga dan mendapatkan kesalahan{"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]}
Gadelkareem
1
Periksa edit @Gadelkareem
byrnedo
17

Masalah 1

Anda menyebutkan itu adalah registry buruh pelabuhan pribadi Anda, jadi Anda mungkin perlu memeriksa API Registri alih-alih Hub registry API doc , yang merupakan tautan yang Anda berikan.

Masalah 2

API docker registry adalah protokol klien / server, terserah implementasi server apakah akan menghapus gambar di back-end. (Saya kira)

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

Penjelasan detail

Di bawah ini saya mendemonstrasikan cara kerjanya sekarang dari deskripsi Anda sebagai pemahaman saya untuk pertanyaan Anda.

Anda menjalankan Anda menjalankan registry buruh pelabuhan pribadi, saya menggunakan yang default dan mendengarkan di 5000port

docker run -d -p 5000:5000 registry

Lalu saya memberi tag pada gambar lokal dan mendorongnya.

$ 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}

Setelah itu Anda dapat menggunakan API Pendaftaran untuk memeriksa keberadaannya di registri buruh pelabuhan pribadi Anda

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

Sekarang saya dapat menghapus tag menggunakan API itu !!

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

Periksa lagi, tag tidak ada di server registri pribadi Anda

$ curl -X GET localhost:5000/v1/repositories/ubuntu/tags/latest
{"error": "Tag not found"}
Larry Cai
sumber
2
Silakan, lihat jawaban saya di bawah ini untuk penjelasan mengapa perintah ini tidak membantu.
Konrad Kleine
2
Anda menghapus tag tetapi bukan data gambar. Yang terakhir dilakukan oleh referensi script saya setelah Anda menghapus tag. Saya juga menggunakan API pendaftaran untuk menghapus tag.
Konrad Kleine
3
terserah implementasi server API setiap registri, dari sudut pandang protokol, itu tidak ada.
Larry Cai
Anda benar bahwa ini tergantung implementasi - tapi saya sedang mencari cara untuk menghapus data gambar dari registrygambar kanonik . SSHing dan menjalankan skrip berfungsi, bahkan jika itu tidak ideal. Sebagai catatan saya masih berpikir itu adalah API yang tidak lengkap - Anda dapat menghapus tag, tetapi jika Anda MENDAPAT /imagesAnda masih melihat semua data gambar yang tersisa.
Leo
Terima kasih telah menyebutkan API Pendaftaran, sedang mencari cara untuk HAPUS gambar di registri pribadi. Metode ini cukup baik bagi saya bahkan jika itu hanya 'tanpa tanda' tanpa benar-benar membebaskan ruang disk.
Howard Lee
16

Ini benar-benar jelek tetapi berfungsi, teks diuji pada registri: 2.5.1. Saya tidak berhasil menghapus berfungsi dengan lancar bahkan setelah memperbarui konfigurasi untuk mengaktifkan penghapusan. ID itu benar-benar sulit untuk diambil, harus masuk untuk mendapatkannya, mungkin beberapa kesalahpahaman. Bagaimanapun, yang berikut ini berfungsi:

  1. Login ke wadah

    docker exec -it registry sh
    
  2. Tentukan variabel yang cocok dengan versi wadah dan wadah Anda:

    export NAME="google/cadvisor"
    export VERSION="v0.24.1"
    
  3. Pindah ke direktori registri:

    cd /var/lib/registry/docker/registry/v2
    
  4. Hapus file yang terkait dengan hash Anda:

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

    rm -rf ./repositories/$NAME/_manifests/tags/$VERSION
    
  6. Keluar

    exit
    
  7. Jalankan GC:

    docker exec -it registry  bin/registry garbage-collect  /etc/docker/registry/config.yml
    
  8. Jika semua dilakukan dengan benar, beberapa informasi tentang gumpalan yang dihapus ditampilkan.

hirro
sumber
saya mengikuti langkah-langkah yang sama yang disebutkan di atas, tetapi ketika saya memeriksa penggunaan disk docker {container} registry itu menunjukkan hal yang sama seperti sebelum melakukan langkah-langkah ... tahu mengapa?
Savio Mathew
tidak bekerja Mudah diperiksa. Ketika Anda melakukan langkah-langkah berikut dan mendorong repo itu lagi tertulis "064794e955a6: Layer sudah ada"
Oduvan
8

Ada beberapa klien (dengan Python, Ruby, dll) yang melakukan hal itu. Untuk selera saya, itu tidak berkelanjutan untuk menginstal runtime (misalnya Python) di server registri saya, hanya untuk mengurus registri saya!


Jadi deckschrubbersolusi saya:

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

gambar yang lebih tua dari usia tertentu akan dihapus secara otomatis. Umur dapat ditentukan dengan menggunakan -year, -month, -day, atau kombinasi dari mereka:

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

UPDATE : inilah pengantar singkat tentang deckschrubber.

Yan Foto
sumber
1
deckschrubbercukup bagus - sangat mudah untuk menginstal (biner tunggal), dan memungkinkan Anda menghapus gambar berdasarkan nama (dengan pencocokan regex) serta usia.
RichVel
ERRO[0000] Could not delete image! repo=.... tag=latest: /
scythargon
@scythargon tidak mungkin mengatakan apakah spesifikasi Anda benar.
Jitter
Peringatan: benar-benar tidak melakukan apa pun di repositori saya.
Richard Warburton
Sayangnya, itu tidak akan menghapus gambar yang tidak memiliki tag. Jadi jika Anda terus mendorong gambar pada satu tag, itu hanya akan memeriksa yang ditandai, bukan yang lain.
Krystian
1

Secara singkat;

1) Anda harus mengetik perintah berikut untuk RepoDigests dari repo buruh pelabuhan;

## 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) Gunakan API REST registri

  ##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

Anda harus mendapatkan 202 diterima untuk doa yang berhasil.

3-) Jalankan Pengumpul Sampah

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

registri - nama wadah registri.

Untuk penjelasan lebih rinci, masukkan deskripsi tautan di sini

fgul
sumber
0

Di Bawah Bash Script Menghapus semua tag yang terletak di registri kecuali yang terbaru.

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

Setelah Jalankan ini

docker exec $(docker ps | grep registry | awk '{print $1}') /bin/registry garbage-collect /etc/docker/registry/config.yml
Shrijan Tiwari
sumber
Bisakah Anda menguraikan lebih banyak tentang cara menggunakan skrip halus ini?
Khalil Gharbaoui
0

Skrip ruby ​​sederhana berdasarkan jawaban ini : registry_cleaner .

Anda dapat menjalankannya di mesin lokal:

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

Dan kemudian pada mesin registry hapus gumpalan dengan /bin/registry garbage-collect /etc/docker/registry/config.yml.

Ilya Krigouzov
sumber
0

Berikut ini skrip berdasarkan jawaban Yavuz Sert. Itu menghapus semua tag yang bukan versi terbaru, dan tag mereka lebih besar dari 950.

#!/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
alonana
sumber