Mamy następujący blok w naszym Dockerfile
:
RUN yum -y update
RUN yum -y install epel-release
RUN yum -y groupinstall "Development Tools"
RUN yum -y install python-pip git mysql-devel libxml2-devel libxslt-devel python-devel openldap-devel libffi-devel openssl-devel
Powiedziano mi, że powinniśmy zjednoczyć te RUN
polecenia, aby ograniczyć utworzone warstwy dokerów:
RUN yum -y update \
&& yum -y install epel-release \
&& yum -y groupinstall "Development Tools" \
&& yum -y install python-pip git mysql-devel libxml2-devel libxslt-devel python-devel openldap-devel libffi-devel openssl-devel
Jestem bardzo nowy w dockerze i nie jestem pewien, czy całkowicie rozumiem różnice między tymi dwiema wersjami określania wielu poleceń RUN. Kiedy należy łączyć RUN
polecenia w jedno i kiedy sensowne jest posiadanie wielu RUN
poleceń?
docker
dockerfile
alecxe
źródło
źródło
Odpowiedzi:
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
Ma to kilka konsekwencji dla sposobu budowania obrazów. Pierwsza i najważniejsza rada, jaką mogę udzielić, to:
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:
Dockerfile po tej rady będzie wyglądać
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órymsekwencje są zastępowane przez
gdzie
…
jest wersją zakodowaną w base64apt_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.
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
(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.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ń kilkuwith_whatever
funkcji, ale może nie jest to bardzo pożądane. (Używając bardziej ezoterycznych cech powłoki, z pewnością możliwe jestwith_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
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.źródło
Każda instrukcja utworzona w pliku Docker powoduje utworzenie nowej warstwy obrazu. Każda warstwa przynosi dodatkowe dane, które nie zawsze są częścią wynikowego obrazu. Na przykład, jeśli dodasz plik na jednej warstwie, ale usuniesz go później na innej warstwie, ostateczny rozmiar obrazu będzie zawierał dodany rozmiar pliku w postaci specjalnego pliku „białego”, mimo że go usunąłeś.
Załóżmy, że masz następujący plik Dockerfile:
Wynikowy rozmiar obrazu to
Przeciwnie, z „podobnym” Dockerfile:
Wynikowy rozmiar obrazu to
Otrzymasz jeszcze mniejszy rozmiar, jeśli wyczyścisz pamięć podręczną yum w pojedynczej instrukcji RUN.
Chcesz zachować równowagę między czytelnością / łatwością konserwacji a liczbą warstw / wielkości obrazu.
źródło
Te
RUN
wypowiedzi reprezentują każdą jedną warstwę. Wyobraź sobie, że ktoś pobiera pakiet, instaluje go i chciałby go usunąć. Jeśli użyjemy trzechRUN
instrukcji, rozmiar obrazu nie zmniejszy się, ponieważ istnieją osobne warstwy. Jeśli uruchomisz wszystkie polecenia za pomocą jednejRUN
instrukcji, rozmiar obrazu dysku może zostać zmniejszony.źródło