Jak usunąć obrazy z prywatnego rejestru docker?

163

Prowadzę prywatny rejestr Dockera i chcę usunąć wszystkie obrazy poza latestrepozytorium. Nie chcę usuwać całego repozytorium, tylko niektóre obrazy w nim zawarte. Dokumentacja API nie wspomina o sposobie zrobienia tego, ale na pewno jest to możliwe?

Lew
źródło
2
Przyjęta odpowiedź nie jest już poprawna (choć zdecydowanie bardzo dobra). Możesz usunąć obrazy za pomocą DELETE / v2 / <nazwa> / manifest / <reference>: docs.docker.com/registry/spec/api/#deleting-an-image
Michael

Odpowiedzi:

116

Obecnie nie można używać interfejsu API rejestru do tego zadania. Pozwala tylko na usunięcie repozytorium lub określonego tagu.

Ogólnie rzecz biorąc, usunięcie repozytorium oznacza, że ​​wszystkie tagi powiązane z tym repozytorium zostaną usunięte.

Usunięcie tagu oznacza, że ​​powiązanie między obrazem a tagiem zostaje usunięte.

Żadne z powyższych nie spowoduje usunięcia pojedynczego obrazu. Pozostają na twoim dysku.


Obejście problemu

Aby obejść ten sposób, musisz przechowywać obrazy Dockera lokalnie.

Rozwiązaniem byłoby usunięcie wszystkich tagów oprócz najnowszych i tym samym potencjalnie usunięcie odniesienia do skojarzonych obrazów. Następnie możesz uruchomić ten skrypt, aby usunąć wszystkie obrazy, do których nie odwołuje się żaden znacznik ani pochodzenie żadnego użytego obrazu.

Terminologia (obrazy i tagi)

Rozważmy graf obrazu takiego, gdzie litery ( A, B...) stanowią krótkie identyfikatory obrazu i <-oznacza, że obraz jest oparty na innym obrazie:

 A <- B <- C <- D

Teraz dodajemy tagi do zdjęcia:

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

Tutaj znacznik <version1>odwołuje się do obrazu, Ca znacznik <version2>do obrazu D.

Udoskonalanie pytania

W swoim pytaniu powiedziałeś, że chcesz usunąć

wszystkie obrazy oprócz latest

. Otóż, ta terminologia nie jest całkiem poprawna. Pomieszałeś obrazy i tagi. Patrząc na wykres, myślę, że zgodzisz się, że tag <version2>reprezentuje najnowszą wersję. W rzeczywistości, zgodnie z tym pytaniem , możesz mieć tag reprezentujący najnowszą wersję:

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

Ponieważ <latest>tag odnosi się do obrazu D, pytam: czy naprawdę chcesz usunąć wszystko oprócz obrazu D? Prawdopodobnie nie!

Co się stanie, jeśli usuniesz tag?

Jeśli usuniesz tag <version1>za pomocą Docker REST API, otrzymasz to:

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

Pamiętaj: Docker nigdy nie usunie obrazu! Nawet jeśli tak się stało, w tym przypadku nie można usunąć obrazu, ponieważ Cjest on częścią pochodzenia obrazu, Dktóry jest oznaczony.

Nawet jeśli użyjesz tego skryptu , żaden obraz nie zostanie usunięty.

Kiedy obraz można usunąć

Pod warunkiem, że możesz kontrolować, kiedy ktoś może ściągać lub przesyłać do rejestru (np. Wyłączając interfejs REST). Możesz usunąć obraz z wykresu obrazu, jeśli żaden inny obraz nie jest na nim oparty i żaden tag nie odnosi się do niego.

Zauważ, że na poniższym wykresie obraz nieD jest oparty na, ale na . Dlatego nie zależy od . Jeśli usuniesz tag na tym wykresie, obraz nie będzie używany przez żaden obraz i ten skrypt może go usunąć.CBDC<version1>C

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

Po wyczyszczeniu wykres obrazu wygląda następująco:

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

Czy to jest to, czego chcesz?

Konrad Kleine
źródło
Masz rację - usunięcie tagów w rzeczywistości nie spowodowało usunięcia powiązanych obrazów. Czy w takim razie jest jakiś sposób na usunięcie obrazów otrzymanych przez ssh do skrzynki?
Leo
1
Zmieniłem odpowiedź, stosując obejście, które działa za mnie. Mam nadzieję, że to pomoże.
Konrad Kleine
To jest dokładnie to - rozumiem, że obrazy powstają stopniowo, ale potrzebuję sposobu na przycięcie tych martwych gałęzi. Dzięki!
Leo
@KonradKleine Jak zrobić wykres obrazów z listy obrazów, które otrzymujesz z rejestru?
Rafael Barros
9
Zbieranie śmieci w końcu dotarło do rejestru w wersji 2.4.0 docs.docker.com/registry/garbage-collection
Markus Lindberg
68

Napotkałem ten sam problem z moim rejestrem, a następnie wypróbowałem poniższe rozwiązanie ze strony bloga. To działa.

Krok 1: Wystawianie katalogów

Możesz wyświetlić swoje katalogi, dzwoniąc pod ten adres:

http://YourPrivateRegistyIP:5000/v2/_catalog

Odpowiedź będzie w następującym formacie:

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

Krok 2: Wystawianie tagów dla powiązanego katalogu

Możesz wyświetlić listę tagów swojego katalogu, dzwoniąc pod ten adres:

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

Odpowiedź będzie w następującym formacie:

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

}

Krok 3. Wymień wartość manifestu dla powiązanego tagu

Możesz uruchomić to polecenie w kontenerze rejestru Dockera:

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

Odpowiedź będzie w następującym formacie:

sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073

Uruchom polecenie podane poniżej z wartością manifestu:

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

Krok 4: Usuń zaznaczone manifesty

Uruchom to polecenie w kontenerze rejestru Dockera:

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

Oto mój 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
Yavuz Sert
źródło
Polecenia powiodły się, łącznie z komunikatami o „ Deleteing blob: /docker/...”, ale nie zmieniło to używanego miejsca na dysku. Korzystanie z bin / register github.com/docker/distribution v2.4.1 .
JamesThomasMoon1979
3
aby usunąć obraz, należy uruchomić kontener rejestru z parametrem REGISTRY_STORAGE_DELETE_ENABLED = true.
Adil
3
Ustawiłem wartość „delete: enabled” na true w pliku /etc/docker/registry/config.yml. W przypadku tej konfiguracji nie trzeba ustawiać zmiennej REGISTRY_STORAGE_DELETE_ENABLED @AdilIlhan
Yavuz Sert
re: step 3, „Docker-Content-Digest” musi znajdować się w nagłówku? (nie widząc tego na wyjściu curl). Czy powinienem być w stanie zobaczyć wyniki oznaczania manifestu przed usunięciem zaznaczonego manifestu (ów), aby wiedzieć, że pomyślnie go oznaczyłem? Wydaje się, że otrzymuję odpowiedź 202, bez względu na to, co ją wyślę.
SteveW
Docker-Content-Digestczęścią powinny być pisane małymi literami (testowane na Döcker v18.09.2 silnika) czylicurl -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

Bieżący v2rejestr obsługuje teraz usuwanie za pośrednictwemDELETE /v2/<name>/manifests/<reference>

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

Użycie w pracy: https://github.com/byrnedo/docker-reg-tool

Edycja: <reference>powyższy manifest można pobrać z prośby do

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

i sprawdzanie Docker-Content-Digestnagłówka w odpowiedzi.

Edycja 2: Konieczne może być uruchomienie rejestru z następującym zestawem ustawień środowiska:

REGISTRY_STORAGE_DELETE_ENABLED="true"

Edit3: Być może będziesz musiał uruchomić czyszczenie pamięci, aby zwolnić to miejsce na dysku: https://docs.docker.com/registry/garbage-collection/

byrnedo
źródło
3
Niektóre inne odpowiedzi pokazują, jak wyodrębnić skrót odwołania manifestu. Jest to konieczne, aby przetłumaczyć tag na coś do przekazania DELETE.
JamesThomasMoon1979
Otrzymuję nieobsługiwany błąd. Jako odniesienie podałem odpowiednią wartość skrótu.
Winster,
1
@ JamesThomasMoon1979 zaktualizowany o instrukcje dotyczące uzyskiwania skrótu referencyjnego.
byrnedo
11
również w wersji 2 i {"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]}
pojawia
1
Sprawdź edycję @Gadelkareem
byrnedo
17

Zadanie 1

Wspomniałeś, że był to twój prywatny rejestr docker, więc prawdopodobnie musisz sprawdzić Registry API zamiast dokumentu Hub Registry API , który jest podanym linkiem.

Zadanie 2

docker register API jest protokołem klient / serwer, od implementacji serwera zależy, czy usunąć obrazy z zaplecza. (Zgaduję)

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

Szczegółowe wyjaśnienie

Poniżej pokazuję, jak to działa teraz z twojego opisu jako mojego zrozumienia dla twoich pytań.

Uruchamiasz, uruchamiasz prywatny rejestr dockera, ja używam domyślnego i nasłuchuję na 5000porcie

docker run -d -p 5000:5000 registry

Następnie oznaczam lokalny obraz i wsuwam do niego.

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

Następnie możesz użyć Registry API, aby sprawdzić, czy istnieje w prywatnym rejestrze dockera

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

Teraz mogę usunąć tag za pomocą tego API !!

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

Sprawdź ponownie, tag nie istnieje na Twoim prywatnym serwerze rejestru

$ curl -X GET localhost:5000/v1/repositories/ubuntu/tags/latest
{"error": "Tag not found"}
Larry Cai
źródło
2
Zobacz moją odpowiedź poniżej, aby wyjaśnić, dlaczego to polecenie nie pomaga.
Konrad Kleine
2
Usuwasz tagi, ale nie dane obrazu. To drugie jest wykonywane przez skrypt, do którego się odwołuję, po usunięciu tagu. Używam również interfejsu API rejestru, aby usunąć tag.
Konrad Kleine
3
zależy to od implementacji każdego serwera API rejestru, z punktu widzenia protokołu nie istnieje.
Larry Cai
Masz rację, że to zależy od implementacji - ale szukałem / szukam sposobu na usunięcie danych obrazu z registryobrazu kanonicznego . SSH i uruchamianie skryptu działa, nawet jeśli nie jest idealne. Na marginesie, nadal uważam, że jest to niekompletny interfejs API - możesz usunąć tagi, ale jeśli GET /images, nadal widzisz wszystkie pozostałe dane obrazu.
Leo,
Dziękujemy za wspomnienie Registry API, szukałem sposobu na USUNIĘCIE obrazu z prywatnego rejestru. Ta metoda jest dla mnie wystarczająco dobra, nawet jeśli jest to po prostu „odznaczanie” bez faktycznego zwolnienia miejsca na dysku.
Howard Lee,
16

To jest naprawdę brzydkie, ale działa, tekst jest testowany w rejestrze: 2.5.1. Nie udało mi się sprawić, aby usuwanie działało płynnie nawet po zaktualizowaniu konfiguracji, aby umożliwić usuwanie. Identyfikator był naprawdę trudny do odzyskania, musiałem się zalogować, aby go uzyskać, może jakieś nieporozumienie. W każdym razie działa:

  1. Zaloguj się do kontenera

    docker exec -it registry sh
    
  2. Zdefiniuj zmienne pasujące do kontenera i jego wersji:

    export NAME="google/cadvisor"
    export VERSION="v0.24.1"
    
  3. Przejdź do katalogu rejestru:

    cd /var/lib/registry/docker/registry/v2
    
  4. Usuń pliki związane z hashem:

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

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

    exit
    
  7. Uruchom GC:

    docker exec -it registry  bin/registry garbage-collect  /etc/docker/registry/config.yml
    
  8. Jeśli wszystko zostało wykonane poprawnie, zostaną wyświetlone informacje o usuniętych obiektach blob.

hirro
źródło
Wykonałem te same kroki, które wymieniono powyżej, ale kiedy sprawdziłem użycie dysku {kontenera} rejestru docker, pokazywało się to samo, co przed wykonaniem tych kroków ... jakiś pomysł dlaczego?
Savio Mathew
nie działa. Łatwe do sprawdzenia. Po wykonaniu następujących kroków i ponownym naciśnięciu repozytorium wyświetla się komunikat „064794e955a6: Warstwa już istnieje”
Oduvan
8

Jest kilku klientów (w Pythonie, Ruby itp.), Którzy dokładnie to robią. Jak na mój gust, instalacja środowiska wykonawczego (np. Pythona) na moim serwerze rejestru, tylko po to, aby uporządkować mój rejestr, nie jest zrównoważona!


Tak deckschrubberjest moje rozwiązanie:

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

obrazy starsze niż podany wiek są automatycznie usuwane. Wiek może być określona za pomocą -year, -month, -daylub ich kombinacji:

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

AKTUALIZACJA : oto krótkie wprowadzenie do deckschrubber.

Yan Foto
źródło
1
deckschrubberjest całkiem niezły - bardzo łatwy do zainstalowania (pojedynczy plik binarny) i pozwala usuwać obrazy według nazwy (z dopasowaniem wyrażenia regularnego), a także wieku.
RichVel,
ERRO[0000] Could not delete image! repo=.... tag=latest: /
scythargon
@scythargon nie można powiedzieć, czy twoja specyfikacja jest poprawna.
drgania
Ostrzeżenie: dosłownie nic nie zrobiłem w moim repozytorium.
Richard Warburton,
Niestety, nie usunie obrazów, które nie mają tagów. Jeśli więc będziesz nadal przesyłać obrazy na jednym tagu, będzie on sprawdzał tylko ten, który jest otagowany, a nie pozostałe.
Krystian
1

Krótko;

1) Musisz wpisać następujące polecenie dla RepoDigests repozytorium 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) Użyj interfejsu API REST rejestru

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

Powinieneś otrzymać 202 Accepted dla pomyślnego wywołania.

3-) Uruchom Garbage Collector

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

rejestr - nazwa kontenera rejestru.

Aby uzyskać bardziej szczegółowe wyjaśnienie, wprowadź opis łącza tutaj

fgul
źródło
0

Poniżej Bash Script Usuwa wszystkie tagi znajdujące się w rejestrze oprócz najnowszych.

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

Po tym Run

docker exec $(docker ps | grep registry | awk '{print $1}') /bin/registry garbage-collect /etc/docker/registry/config.yml
Shrijan Tiwari
źródło
Czy mógłbyś wyjaśnić trochę więcej na temat korzystania z tego świetnego skryptu?
Khalil Gharbaoui
0

Prosty skrypt ruby ​​oparty na tej odpowiedzi: register_cleaner .

Możesz go uruchomić na komputerze lokalnym:

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

A następnie na komputerze rejestru usuń obiekty blob za pomocą /bin/registry garbage-collect /etc/docker/registry/config.yml.

Ilya Krigouzov
źródło
0

Oto skrypt oparty na odpowiedzi Yavuza Serta. Usuwa wszystkie tagi, które nie są najnowszą wersją, a ich tag jest większy niż 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
źródło