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.