Come eliminare le immagini da un registro docker privato?


163

Eseguo un registro docker privato e desidero eliminare tutte le immagini tranne quelle latestda un repository. Non voglio cancellare l'intero repository, solo alcune delle immagini al suo interno. I documenti API non menzionano un modo per farlo, ma sicuramente è possibile?


2
La risposta accettata non è più corretta (anche se sicuramente molto buona). Puoi rimuovere le immagini usando DELETE / v2 / <name> / manifests / <reference>: docs.docker.com/registry/spec/api/#deleting-an-image
Michael Zelensky

Risposte:


116

Attualmente non è possibile utilizzare l'API del registro per tale attività. Ti consente solo di eliminare un repository o un tag specifico.

In generale, l'eliminazione di un repository significa che tutti i tag associati a questo repository vengono eliminati.

L'eliminazione di un tag significa che viene eliminata l'associazione tra un'immagine e un tag.

Nessuna delle precedenti eliminerà una singola immagine. Sono lasciati sul tuo disco.


Soluzione

Per questa soluzione alternativa è necessario che le immagini della finestra mobile siano memorizzate localmente.

Una soluzione alternativa per la soluzione sarebbe quella di eliminare tutti i tag tranne gli ultimi e quindi rimuovere potenzialmente il riferimento alle immagini associate. Quindi è possibile eseguire questo script per rimuovere tutte le immagini, a cui non fa riferimento alcun tag o la provenienza di alcuna immagine utilizzata.

Terminologia (immagini e tag)

Si consideri un grafico di immagini come questo, dove le lettere maiuscole ( A, B, ...) rappresentano gli ID immagine brevi e <-mezzi che un'immagine si basa su un'altra immagine:

 A <- B <- C <- D

Ora aggiungiamo tag all'immagine:

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

Qui, il tag fa <version1>riferimento all'immagine Ce il tag fa <version2>riferimento all'immagine D.

Affina la tua domanda

Nella tua domanda hai detto che volevi rimuovere

tutte le immagini tranne il latest

. Ora, questa terminologia non è del tutto corretta. Hai mescolato immagini e tag. Guardando il grafico, penso che saresti d'accordo sul fatto che il tag <version2>rappresenti l'ultima versione. In effetti, secondo questa domanda puoi avere un tag che rappresenta l'ultima versione:

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

Dal momento che il <latest>tag fa riferimento all'immagine che Dti chiedo: vuoi veramente eliminare tutto tranne l'immagine D? Probabilmente no!

Cosa succede se elimini un tag?

Se elimini il tag <version1>utilizzando l'API REST Docker otterrai questo:

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

Ricorda: Docker non cancellerà mai un'immagine! Anche se lo facesse, in questo caso non può cancellare un'immagine, poiché l'immagine Cfa parte degli antenati per l'immagine Dche è taggata.

Anche se usi questo script , nessuna immagine verrà eliminata.

Quando un'immagine può essere cancellata

A condizione che tu possa controllare quando qualcuno può estrarre o spingere nel tuo registro (es. Disabilitando l'interfaccia REST). È possibile eliminare un'immagine da un grafico immagine se nessun'altra immagine è basata su di essa e nessun tag fa riferimento ad essa.

Si noti che nel grafico seguente, l'immagine Dè non basata su Cma su B. Pertanto, Dnon dipende da C. Se elimini il tag <version1>in questo grafico, l'immagine Cnon verrà utilizzata da nessuna immagine e questo script può rimuoverla.

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

Dopo la pulizia, il grafico dell'immagine appare così:

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

È questo che vuoi?


Hai ragione: l'eliminazione dei tag non ha effettivamente eliminato le immagini associate. Esiste un modo per eliminare le immagini a cui è stato dato l'accesso ssh alla casella, quindi?
Leone,

1
Ho modificato la mia risposta con una soluzione alternativa che fa il lavoro per me. Spero possa essere d'aiuto.
Konrad Kleine,

Esatto, capisco che le immagini sono costruite in modo incrementale, ma ho bisogno di un modo per potare quei rami morti. Grazie!
Leone

@KonradKleine come si fa a rappresentare graficamente le immagini dall'elenco delle immagini ottenute dal registro?
Rafael Barros,

9
La raccolta dei rifiuti è finalmente arrivata al Registro di sistema v2.4.0 docs.docker.com/registry/garbage-collection
Markus Lindberg

68

Ho riscontrato lo stesso problema con il mio registro, quindi ho provato la soluzione elencata di seguito da una pagina del blog. Funziona.

Passaggio 1: elenco dei cataloghi

Puoi elencare i tuoi cataloghi chiamando questo url:

http://YourPrivateRegistyIP:5000/v2/_catalog

La risposta sarà nel seguente formato:

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

Passaggio 2: elencare i tag per il catalogo correlato

Puoi elencare i tag del tuo catalogo chiamando questo url:

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

La risposta sarà nel seguente formato:

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

}

Passaggio 3: elencare il valore manifest per il tag correlato

È possibile eseguire questo comando nel contenitore del registro della finestra mobile:

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

La risposta sarà nel seguente formato:

sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073

Esegui il comando indicato di seguito con il valore manifest:

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

Passaggio 4: eliminare i manifesti contrassegnati

Esegui questo comando nel contenitore di registrazione della finestra mobile:

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

Ecco il mio 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

I comandi sono riusciti, inclusi i messaggi su " Deleteing blob: /docker/..." ma non ha modificato lo spazio su disco utilizzato. Uso bin / register github.com/docker/distribution v2.4.1 .
JamesThomasMoon1979,

3
per eliminare un'immagine, è necessario eseguire il contenitore del registro con REGISTRY_STORAGE_DELETE_ENABLED = parametro true.
Adil,

3
Ho impostato il valore "delete: enabled" su true nel file /etc/docker/registry/config.yml. Per questa configurazione non è necessario impostare REGISTRY_STORAGE_DELETE_ENABLED variabile @AdilIlhan
Yavuz Sert

ri: passaggio 3, il "Docker-Content-Digest" deve essere nell'intestazione? (non vedendolo nell'output del ricciolo). Dovrei essere in grado di vedere i risultati della marcatura di un manifest prima di eliminare i manifest contrassegnati per sapere di averlo contrassegnato correttamente? Sembra che mi dia una risposta 202, qualunque cosa io la mandi.
SteveW

la Docker-Content-Digestparte dovrebbe essere in minuscolo (testata sul motore docker v18.09.2) cioè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)}'
Muhammad Abdurrahman,

63

L'attuale v2registro ora supporta l'eliminazione tramiteDELETE /v2/<name>/manifests/<reference>

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

Utilizzo lavorativo: https://github.com/byrnedo/docker-reg-tool

Modifica: il manifest <reference>sopra può essere recuperato dalla richiesta a

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

e controllando l' Docker-Content-Digestintestazione nella risposta.

Modifica 2: potrebbe essere necessario eseguire il registro con il seguente set di env:

REGISTRY_STORAGE_DELETE_ENABLED="true"

Edit3: potrebbe essere necessario eseguire garbage collection per liberare questo spazio su disco: https://docs.docker.com/registry/garbage-collection/


3
Alcune altre risposte qui mostrano come estrarre l'hash di riferimento manifest. Questo è necessario per tradurre un tag in qualcosa a cui passare DELETE.
JamesThomasMoon1979,

Errore non supportato. Ho dato il giusto valore digest come riferimento.
Winster,

1
@ JamesThomasMoon1979 aggiornato con le istruzioni su come ottenere l'hash di riferimento.
byrnedo,

11
anche su V2 e errore{"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]}
Gadelkareem,

1
Controlla la modifica @Gadelkareem
byrnedo

17

Problema 1

Hai detto che era il tuo registro docker privato, quindi probabilmente devi controllare l' API del registro invece del documento dell'API del registro Hub , che è il link che hai fornito.

Problema 2

L'API del registro docker è un protocollo client / server, dipende dall'implementazione del server se rimuovere le immagini nel back-end. (Suppongo)

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

Spiegazione dettagliata

Di seguito ho dimostrato come funziona ora dalla tua descrizione come mia comprensione per le tue domande.

Corri, esegui un registro docker privato, io uso quello predefinito e ascolto in 5000porta

docker run -d -p 5000:5000 registry

Quindi taggo l'immagine locale e la inserisco.

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

Successivamente è possibile utilizzare l' API del registro per verificare che esista nel registro della finestra mobile privata

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

Ora posso eliminare il tag usando quell'API !!

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

Controlla di nuovo, il tag non esiste nel tuo server di registro privato

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

2
Per favore, vedi la mia risposta sotto per una spiegazione del perché questo comando non aiuta.
Konrad Kleine,

2
Elimina i tag ma non i dati dell'immagine. Quest'ultimo viene eseguito dallo script a cui faccio riferimento dopo aver eliminato un tag. Uso anche l'API del registro per eliminare un tag.
Konrad Kleine,

3
dipende dall'implementazione di ciascun server API del registro, dal punto di vista del protocollo, non esiste.
Larry Cai,

Hai ragione che dipende dall'implementazione, ma stavo / sto cercando un modo per eliminare i dati dell'immagine registrydall'immagine canonica . Entrare ed eseguire uno script funziona, anche se non è l'ideale. Come nota a margine penso ancora che sia un'API incompleta: puoi eliminare i tag, ma se OTTIENI /imagesvedi ancora tutti i dati immagine rimanenti.
Leone,

Grazie per aver menzionato l'API del registro, stava cercando un modo per ELIMINARE un'immagine nel registro privato. Questo metodo è abbastanza buono per me, anche se è solo "senza tag" senza liberare spazio su disco.
Howard Lee,

16

Questo è davvero brutto ma funziona, il testo è testato sul registro: 2.5.1. Non sono riuscito a far funzionare l'eliminazione senza problemi anche dopo aver aggiornato la configurazione per abilitare l'eliminazione. L'ID è stato davvero difficile da recuperare, è stato necessario accedere per ottenerlo, forse un malinteso. Ad ogni modo, le seguenti opere:

  1. Accedi al contenitore

    docker exec -it registry sh
    
  2. Definire le variabili corrispondenti al contenitore e alla versione del contenitore:

    export NAME="google/cadvisor"
    export VERSION="v0.24.1"
    
  3. Passa alla directory del registro:

    cd /var/lib/registry/docker/registry/v2
    
  4. Elimina i file relativi al tuo hash:

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

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

    exit
    
  7. Esegui il GC:

    docker exec -it registry  bin/registry garbage-collect  /etc/docker/registry/config.yml
    
  8. Se tutto è stato eseguito correttamente, vengono visualizzate alcune informazioni sui BLOB eliminati.


ho seguito gli stessi passaggi sopra menzionati, ma quando ho controllato l'utilizzo del disco del registro docker {container} si stava mostrando lo stesso di prima di fare i passaggi ... hai idea del perché?
Savio Mathew,

non funziona Facile da controllare Quando esegui i seguenti passaggi e invii nuovamente il repository, viene visualizzato il messaggio "064794e955a6: il livello esiste già"
Oduvan

8

Ci sono alcuni client (in Python, Ruby, ecc.) Che fanno esattamente questo. Per quanto mi riguarda, non è sostenibile installare un runtime (ad esempio Python) sul mio server di registro, solo per mantenere il mio registro!


Quindi deckschrubberè la mia soluzione:

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

le immagini più vecchie di una determinata età vengono automaticamente eliminate. L'età può essere specificato usando -year, -month, -dayo una combinazione di essi:

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

AGGIORNAMENTO : ecco una breve introduzione su deckschrubber.


1
deckschrubberè abbastanza buono - molto facile da installare (binario singolo) e ti permette di eliminare le immagini per nome (con regex match) oltre che per età.
RichVel,

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

@scythargon impossibile dire se la tua specifica è corretta.
jitter

Attenzione: non ho fatto letteralmente nulla sul mio repository.
Richard Warburton,

Sfortunatamente, non rimuoverà le immagini che non hanno tag. Quindi se continui a spingere le immagini su un singolo tag, controllerà solo quello che è taggato, non gli altri.
Krystian,

1

Brevemente;

1) È necessario digitare il comando seguente per RepoDigests di un repository docker;

## 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) Utilizzare l'API REST del registro

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

Dovresti ottenere un 202 accettato per una corretta invocazione.

3-) Esegui Garbage Collector

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

Registro di sistema - nome contenitore del registro.

Per maggiori dettagli, inserisci la descrizione del link qui



0

Below Bash Script Elimina tutti i tag che si trovano nel registro, tranne l'ultimo.

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

Dopo questa corsa

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

Potresti approfondire un po 'di più su come usare questa bella sceneggiatura?
Khalil Gharbaoui,

0

Script ruby ​​semplice basato su questa risposta: register_cleaner .

Puoi eseguirlo sul computer locale:

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

E quindi sul computer del registro rimuovere i BLOB con /bin/registry garbage-collect /etc/docker/registry/config.yml.


0

Ecco una sceneggiatura basata sulla risposta di Yavuz Sert. Elimina tutti i tag che non sono la versione più recente e il loro tag è maggiore di 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.