180 gigabajtów, których nigdy nie było
Na NVIDIA DGX Spark kończyło się miejsce na dysku. Narzędzia kontenerowe raportowały 180 GB do odzyskania. Odzyskałem wszystko i dostałem z powrotem około jednego gigabajta.
Oczywisty ruch
Ta maszyna to NVIDIA DGX Spark, która całe życie pobiera obrazy kontenerów i wagi modeli. Miejsca było mało. Pierwszym przystankiem jest raport dysku samego środowiska uruchomieniowego kontenerów, a ten był zachęcający: obrazy, cache buildów, zatrzymane kontenery, w sumie około 180 GB do odzyskania.
Więc: prune osieroconych obrazów, prune cache buildów, prune zatrzymanych kontenerów. Narzędzia na każdym kroku zgłaszały sukces — łącznie z jedną satysfakcjonującą linią o usunięciu 160 osieroconych obrazów.
Potem sprawdziłem system plików.
przed po zwolnione docker df ~180 GB do odzyskania — df 848 G 847 G ~1 G
Około gigabajta. Ze stu osiemdziesięciu.
Dlaczego ta liczba była fikcją
Działy się dwie osobne rzeczy i obie warto znać, zanim zaufasz temu raportowi.
Rozmiary są logiczne, a nie fizyczne. Obrazy kontenerów są zbudowane z nałożonych warstw, a warstwy są współdzielone. Warstwa bazowa używana przez dwanaście obrazów jest w tym raporcie liczona dwanaście razy. Sumuje się to, ile obrazy twierdzą, że zajmują, a nie ile zajmują na dysku. „Do odzyskania” to górna granica złożona z podwójnego liczenia, a na maszynie z wieloma obrazami zbudowanymi z kilku wspólnych baz jest skrajnie optymistyczna.
Usunięcie 160 obrazów zwolniło dokładnie zero bajtów. To były artefakty pośrednie nowoczesnego systemu budowania, a ich faktyczna zawartość nie żyje w magazynie obrazów — żyje w cache buildów, który jest osobną pulą. Usunięcie rekordów obrazów usuwa wpisy księgowe wskazujące na dane, które zostają dokładnie tam, gdzie były. Licznik wygląda na postęp. Dysk się nie rusza. Tę pulę opróżnia zupełnie inne polecenie.
Oba błędy mają ten sam kształt: czytałem model świata narzędzia zamiast świata.
Gdzie faktycznie było miejsce
Dwa polecenia — całkowite zajęcie dysku, potem największe katalogi — i było.
Cache wag modeli: 506 GB. W ogóle nie kontenery. Miesiące pobranych modeli, w większości uśpionych, kilka zastąpionych nowszymi, jeden eksperyment sprzed tygodnia.
Usunięcie uśpionych wag przesunęło system plików dokładnie o usuniętą ilość, za pierwszym razem, bez niespodzianek:
848 G ──────────────────────────────► 574 G
~274 GB uśpionych wag modeli
Cały objazd przez czyszczenie kontenerów był zgadywaniem przebranym za diagnozę i kosztował więcej czasu niż faktyczna poprawka.
O włos
W trakcie sprzątania prawie usunąłem coś drogiego.
Obraz pobrany po digeście, a nie po tagu, pojawia się z ustawionym repozytorium, ale bez tagu — co wizualnie jest identyczne z „dangling”, czyli dokładnie kategorią, w którą celuje rutynowy prune. Jest chroniony tylko wtedy, gdy kontener go aktywnie używa. Zatrzymaj z jakiegokolwiek powodu tę usługę, uruchom to samo polecenie sprzątania, które przez całe popołudnie wydawało się nieszkodliwe, i obrazu nie ma.
W tym przypadku oznaczałoby to ponowne pobieranie 22,7 GB następnego ranka i usługę leżącą, dopóki się nie skończy.
Poprawka to jedno polecenie: nadaj obrazowi jawny tag, a już nigdy nie zostanie zaklasyfikowany jako dangling.
Blokada, która zapracowała na swoje
Drugie zagrożenie było bardziej dosadne. Listę do usunięcia wygenerowano wzorcami, a jeden ze wzorców był o jeden wildcard od dopasowania wolumenów danych innego projektu — wygenerowanych wyników, a nie cache, który można pobrać ponownie. Usunięte znaczyłoby stracone.
Uratowała je zasada przyjęta wcześniej: każde destrukcyjne czyszczenie działa za jawną blokadą nazw z listą chronionych wzorców, a blokada przerywa cały przebieg, zamiast pomijać dopasowanie. Nie ostrzeżenie, nie filtr — stop.
Pokrewny instynkt, to samo popołudnie: wolumen bez żadnych powiązań z kontenerami nie jest automatycznie śmieciem. Siostrzane artefakty na hoście — obrazy buildów należące do nazwanego projektu — wystarczyły, żeby rozpoznać pozornie osierocone wolumeny jako żywe dane projektu. „Nic się do tego nie odwołuje” i „nic tego nie potrzebuje” to różne stwierdzenia.
Wskazówki dla czytelnika
Weryfikuj systemem plików, a nie narzędziem, które jest właścicielem plików. Zrób prawdziwy odczyt dysku przed i po każdym sprzątaniu. Jeśli narzędzie twierdzi 180 GB, a system plików przesuwa się o 1 GB, narzędzie cię nie okłamało — odpowiadało na inne pytanie niż to, które zadałeś.
Uważaj na księgowość, która podwójnie liczy współdzielony storage. Wszystko, co warstwowe, deduplikowane lub copy-on-write — obrazy kontenerów, snapshoty, deduplikowane kopie zapasowe, wolumeny thin-provisioned — raportuje rozmiary logiczne, które sumują się do dużo więcej niż fizyczny ślad. Wartość „do odzyskania” to górna granica zbudowana z nakładania się.
Wysoka liczba usunięć to nie dowód zwolnionego miejsca. Usunięcie setek rekordów wskazujących na dane przechowywane w innej puli nie zwalnia niczego, za to daje bardzo przekonujący log postępu.
Znajdź konsumenta, zanim wybierzesz sprzątanie. Dwa polecenia wskazałyby prosto na katalog 506 GB, który nie miał nic wspólnego z kontenerami. Pominąłem ten krok, bo miałem już hipotezę, a do hipotezy było dołączone wygodne narzędzie.
Chroń destrukcyjne czyszczenia blokadą nazw i niech blokada przerywa. Każda lista do usunięcia wygenerowana wzorcem jest o jeden wildcard od objęcia czegoś niezastąpionego. Blokada, która pomija dopasowanie, jedzie dalej; blokada, która zatrzymuje przebieg, zmusza cię, żebyś spojrzał.
Wszystko, czego nie chciałbyś pobierać ponownie, zasługuje na jawną nazwę. Artefakty pobrane po digeście siedzą w tym samym koszyku, w który celuje rutynowe sprzątanie, chronione tylko tym, że akurat są w użyciu.