
Kiedy uczyłem się jeździć samochodem, podczas pierwszej lekcji instruktor wjechał na skrzyżowanie tyłem, a potem powiedział, że tak nie wolno — w żadnym wypadku. Tę zasadę zapamiętałem od razu i na całe życie.
Czytasz dzieciom „Szkodliwe rady” Grigorija Ostera i widzisz, jak łatwo i naturalnie do nich dociera, że tak nie wolno.
O tym, jak poprawnie pisać Dockerfile, napisano mnóstwo artykułów. Ale nie spotkałem instrukcji dotyczących tego, jak pisać niepoprawne Dockerfile. Uzupełniam tę lukę. I może w projektach, które dostaję do wsparcia, takich Dockerfile będzie mniej.
Wszyscy bohaterowie, sytuacje i Dockerfile są fikcyjne. Jeśli się rozpoznasz, przepraszam.
Tworzymy Dockerfile, złowrogi i przerażający
Piotr (starszy programista java/ruby/php): Kolego Wasilij, czy już wrzuciłeś nowy moduł do Docker?
Wasilij (junior): Nie, nie zdążyłem, jakoś nie mogę zrozumieć tego Dockera. Tyle artykułów na ten temat, oczy mi się rozchodzą.
Piotr: Nasz deadline minął rok temu. Chodź, pomogę, w procesie się ogarniemy. Opowiadaj, co tam ci nie wychodzi.
Wasilij: Nie mogę wybrać obrazu bazowego, żeby był jak najmniejszy, ale z wszystkim, co potrzebne.
Piotr: Weź obraz ubuntu, tam jest wszystko, co potrzebujesz. A jeśli jest za dużo zbędnych rzeczy, to później jeszcze się przydadzą. I nie zapomnij dodać tagu latest, żeby zawsze była najnowsza wersja.
I w Dockerfile pojawia się pierwszy wiersz:
FROM ubuntu:latestPiotr: Co dalej, na czym pisaliśmy nasz moduł?
Wasilij: No ruby, tam musi działać serwer WWW i para pomocniczych demonów.
Piotr: Aha, co nam potrzebne: ruby, bundler, nodejs, imagemagick no i co tam jeszcze… I przy okazji, zrób upgrade, żeby na pewno dostać nowe pakiety.
Wasilij: A nie zrobimy użytkownika, żeby nie działać z konta root?
Piotr: Nie, potem jeszcze będą z tym kłopoty z prawami.
Wasilij: Potrzebuję trochę czasu, 15 minut, żeby to wszystko złożyć w jedną komendę, czytałem, że…
(Piotr brutalnie przerywa dociekliwemu i zbyt mądremu juniorowi.)
Piotr: Pisz oddzielnymi komendami, tak będzie łatwiej czytać.
Dockerfile rośnie:
FROM ubuntu:latest
RUN apt-get update
RUN apt-get upgrade
RUN apt-get -y install libpq-dev imagemagick gsfonts ruby-full
RUN gem install bundler
RUN curl -sL https://deb.nodesource.com/setup_9.x | sudo bash -
RUN apt-get install -y nodejs
RUN bundle install --without development test --path vendor/bundle
RUN rm -rf /usr/local/bundle/cache/*.gem
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*W tym momencie do biura wchodzi Igor Iwanowicz, DevOps (ale bardziej Ops niż Dev), krzycząc:
II: Pietia, twoi programiści znowu zepsuli produkcyjną bazę danych, kiedy to się skończy….
Po krótkiej wymianie zdań Igor Ivanowicz się uspokaja i zaczyna dowiadywać się, czym zajmują się koledzy.
AI: Czym się zajmujecie?
Wasilij: Piotr pomaga mi stworzyć Dockerfile dla nowego modułu.
AI: Daj mi spojrzeć… Co wy tu narobiliście, przecież repozytorium czyści się osobnym poleceniem, to dodatkowa warstwa… A jak wy instalujecie zależności, skoro nie skopiowaliście Gemfile'a! I w ogóle, to nie ma sensu.
Piotr: Proszę odejdź, zajmij się swoimi sprawami, my tu jakoś sobie poradzimy.
Igor Ivanowicz smutno wzdycha i odchodzi, aby sprawdzić, kto złamał bazę danych.
Piotr: Tak, ale ma rację mówiąc o kodzie, trzeba go wrzucić do obrazu. A ustawmy od razu ssh i supervisora, bo jak będziemy uruchamiać demony.
Wasilij: Najpierw skopiuję Gemfile i Gemfile.lock, potem wszystko zainstaluję, a na końcu skopiuję cały projekt. Jeśli Gemfile się nie zmienia, warstwa weźmie się z cache.
Piotr: Po co wy wszyscy z tymi warstwami, kopiujcie od razu wszystko. Kopiujcie od razu. Pierwszą linijką.
Dockerfile teraz wygląda tak:
FROM ubuntu:latest
COPY ./ /app
WORKDIR /app
RUN apt-get update
RUN apt-get upgrade
RUN apt-get -y install libpq-dev imagemagick gsfonts ruby-full ssh supervisor
RUN gem install bundler
RUN curl -sL https://deb.nodesource.com/setup_9.x | sudo bash -
RUN apt-get install -y nodejs
RUN bundle install --without development test --path vendor/bundle
RUN rm -rf /usr/local/bundle/cache/*.gem
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* Piotr: No to co dalej. Masz konfiguracje dla supervisora?
Wasilij: Nie, nie mam. Ale szybko to zrobię.
Piotr: Potem to zrobisz. Najpierw stworzymy skrypt init, który wszystko uruchomi. No więc, uruchamiasz ssh, z nohup, żebyśmy mogli podłączyć się do kontenera i zobaczyć, co poszło nie tak. Potem również uruchamiasz supervisora. A na końcu po prostu uruchomisz passenger.
W: Ale czytałem, że powinien być jeden proces, wtedy Docker będzie wiedział, że coś poszło nie tak i będzie mógł zrestartować kontener.
P: Nie zawracaj sobie głowy bzdurami. I w ogóle, jak? Jak to wszystko uruchomisz w jednym procesie? Niech o stabilność martwi się Igor Ivanowicz, nie bez powodu dostaje pensję. Naszą sprawą jest pisać kod. W ogóle, niech podziękuje, że napisaliśmy za niego Dockerfile.
Po 10 minutach i dwóch filmikach o kotach.
W: Wszystko zrobiłem. Dodałem też kilka komentarzy.
P: Pokaż!
Świeża wersja Dockerfile:
FROM ubuntu:latest
# Kopiujemy kod źródłowy
COPY . /app
WORKDIR /app
# Aktualizujemy listę pakietów
RUN apt-get update
# Aktualizujemy pakiety
RUN apt-get upgrade
# Instalujemy wymagane pakiety
RUN apt-get -y install libpq-dev imagemagick gsfonts ruby-full ssh supervisor
# Instalujemy bundler
RUN gem install bundler
# Instalujemy nodejs, używanego do budowania statyki
RUN curl -sL https://deb.nodesource.com/setup_9.x | sudo bash -
RUN apt-get install -y nodejs
# Instalujemy zależności
RUN bundle install --without development test --path vendor/bundle
# Sprzątamy po sobie cache
RUN rm -rf /usr/local/bundle/cache/*.gem
RUN apt-get clean
RUN rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Uruchamiamy skrypt, przy starcie kontenera, który uruchomi wszystko inne.
CMD ["/app/init.sh"]P: Świetnie, podoba mi się. I komentarze po rosyjsku, wygodne i czytelne, wszyscy powinni tak pracować. Nauczyłem cię wszystkiego, teraz możesz działać samodzielnie. Chodźmy na kawę…
No cóż, dostaliśmy idealnie okropny Dockerfile, na widok którego Igor Iwanowicz będzie chciał zwolnić się i przez jeszcze tydzień będą go boleć oczy. Dockerfile mógł być oczywiście jeszcze gorszy, nie ma granic doskonałości. Ale na początek i tak wystarczy.
Chciałbym zakończyć cytatem Grigorija Ostera:
Jeśli jeszcze nie twardo
W życiu wybraliście drogę,
I nie wiecie, od czego zacząć
Swoją drogę zawodową,
To wbijajcie żarówki w klatkach schodowych —
Ludzie powiedzą wam "Dziękuję".
Pomożecie ludziom
Os conserve electricity.
Źródło: habr.com
