Obraz dokera jest w rzeczywistości połączoną listą warstw systemu plików. Każda instrukcja w Dockerfile tworzy warstwę systemu plików, która opisuje różnice w systemie plików przed i po wykonaniu odpowiedniej instrukcji. docker inspect
Komenda może być stosowany na obrazie Döcker ujawnić swój charakter będąc związany lista warstw systemu plików.
Ważna jest liczba warstw użytych w obrazie
- podczas pchania lub ciągnięcia obrazów, ponieważ wpływa to na liczbę jednoczesnych wysyłanych lub pobieranych plików.
- podczas uruchamiania kontenera, ponieważ warstwy są łączone razem, aby utworzyć system plików używany w kontenerze; im więcej warstw jest zaangażowanych, tym gorsza jest wydajność, ale wpływ na to ma różny backend systemu plików.
Ma to kilka konsekwencji dla sposobu budowania obrazów. Pierwsza i najważniejsza rada, jaką mogę udzielić, to:
Porada 1 Upewnij się, że kroki kompilacji, w których jest zaangażowany kod źródłowy, pojawią się w pliku Docker tak późno, jak to możliwe i nie są powiązane z poprzednimi poleceniami za pomocą a &&
lub a ;
.
Powodem tego jest to, że wszystkie poprzednie kroki zostaną zapisane w pamięci podręcznej, a odpowiednie warstwy nie będą musiały być pobierane w kółko. Oznacza to szybsze kompilacje i szybsze wydania, co prawdopodobnie jest tym, czego chcesz. Co ciekawe, zaskakująco trudno jest optymalnie wykorzystać pamięć podręczną dokera.
Moja druga rada jest mniej ważna, ale uważam ją za bardzo przydatną z punktu widzenia konserwacji:
Rada # 2 Nie pisz skomplikowanych poleceń w Dockerfile, ale raczej używaj skryptów, które mają być kopiowane i wykonywane.
Dockerfile po tej rady będzie wyglądać
COPY apt_setup.sh /root/
RUN sh -x /root/apt_setup.sh
COPY install_pacakges.sh /root/
RUN sh -x /root/install_packages.sh
i tak dalej. Porada dotycząca wiązania kilku poleceń &&
ma jedynie ograniczony zakres. Znacznie łatwiej jest pisać za pomocą skryptów, w których można używać funkcji itp., Aby uniknąć nadmiarowości lub do celów dokumentacji.
Osoby zainteresowane procesorami wstępnymi i chcące uniknąć niewielkiego narzutu spowodowanego przez te COPY
kroki i faktycznie generują w locie plik dokowania, w którym
COPY apt_setup.sh /root/
RUN sh -x /root/apt_setup.sh
sekwencje są zastępowane przez
RUN base64 --decode … | sh -x
gdzie …
jest wersją zakodowaną w base64 apt_setup.sh
.
Moja trzecia rada jest dla osób, które chcą ograniczyć rozmiar i liczbę warstw przy możliwym koszcie dłuższych wersji.
Rada # 3 Użyj with
-idiom, aby uniknąć plików znajdujących się w warstwach pośrednich, ale nie w wynikowym systemie plików.
Plik dodany przez jakąś instrukcję dokera i usunięty przez późniejszą instrukcję nie jest obecny w wynikowym systemie plików, ale jest wspomniany dwa razy w warstwach dokera tworzących obraz dokera w budowie. Raz, z nazwą i pełną zawartością w warstwie wynikającej z dodania instrukcji, a raz jako powiadomienie o usunięciu warstwy w wyniku usunięcia instrukcji.
Załóżmy na przykład, że tymczasowo potrzebujemy kompilatora C i jakiegoś obrazu, i rozważmy
# !!! THIS DISPLAYS SOME PROBLEM --- DO NOT USE !!!
RUN apt-get install -y gcc
RUN gcc --version
RUN apt-get --purge autoremove -y gcc
(Bardziej realistycznym przykładem byłoby zbudowanie jakiegoś oprogramowania za pomocą kompilatora, zamiast jedynie zapewnienia jego obecności za pomocą --version
flagi).
Fragment pliku Dockerfile tworzy trzy warstwy, pierwsza zawiera pełny pakiet gcc, więc nawet jeśli nie jest obecny w końcowym systemie plików, odpowiednie dane są nadal częścią obrazu w ten sam sposób i muszą być pobierane, przesyłane i rozpakowywane za każdym razem, gdy ostateczny obraz to.
with
-Idiom jest powszechną formą programowania funkcjonalnego w celu wyodrębnienia własności zasobów i zasobów zwolnieniu z logiką jej stosowania. Łatwo jest przetransponować ten idiom na wykonywanie skryptów powłoki, a my możemy przeformułować poprzednie polecenia jako następujący skrypt, z którego można korzystać COPY & RUN
tak jak w Poradzie nr 2.
# with_c_compiler SIMPLE-COMMAND
# Execute SIMPLE-COMMAND in a sub-shell with gcc being available.
with_c_compiler()
(
set -e
apt-get install -y gcc
"$@"
trap 'apt-get --purge autoremove -y gcc' EXIT
)
with_c_compiler\
gcc --version
Złożone polecenia można przekształcić w funkcję, aby można je było przekazać do with_c_compiler
. Możliwe jest również łączenie wywołań kilku with_whatever
funkcji, ale może nie jest to bardzo pożądane. (Używając bardziej ezoterycznych cech powłoki, z pewnością możliwe jest with_c_compiler
przyjmowanie złożonych poleceń, ale we wszystkich aspektach lepiej jest zawinąć te złożone polecenia w funkcje).
Jeśli chcemy zignorować poradę nr 2, wynikowy fragment pliku Dockerfile będzie
RUN apt-get install -y gcc\
&& gcc --version\
&& apt-get --purge autoremove -y gcc
który nie jest tak łatwy do odczytania i utrzymania z powodu zaciemnienia. Zobacz, jak wariant skryptu powłoki kładzie nacisk na ważną część, gcc --version
podczas gdy &&
wariant łańcuchowy zakrywa tę część w środku hałasu.