Cześć wszystkim!
Bardzo chcę od razu przejść do tematu, ale lepiej będzie najpierw opowiedzieć o mojej historii:
Wprowadzenie
Jestem programistą z doświadczeniem w tworzeniu aplikacji frontendowych typu single-page, scala/java oraz nodejs na serwerze.
Przez dość długi czas (już na pewno kilka — kilkanaście lat) byłem zdania, że docker to manna z nieba i w ogóle bardzo fajne narzędzie, które absolutnie każdy programista powinien umieć obsługiwać. Z tego wynika, że każdy programista powinien mieć docker na lokalnej maszynie. Co ja mówię o swoim zdaniu, wystarczy spojrzeć na ogłoszenia, które są zamieszczane na tym samym hh. W co drugim jest wzmianka o dockerze i jeśli go posiadasz — to będzie twoja przewaga konkurencyjna ;)
Na swojej drodze spotkałem wielu ludzi, z ich różnym podejściem do dockera i jego ekosystemu. Niektórzy mówili, że to wygodna rzecz, gwarantująca multiplatformowość. Inni nie rozumieli, po co mają uruchamiać się w kontenerach i jaki mają z tego zysk, a trzeci w ogóle się tym nie przejmowali (po prostu pisali kod i szli do domu — zazdroszczę im, nawiasem mówiąc 🙂)
Powody korzystania
Dlaczego używałem dockera? Pewnie z następujących powodów:
- uruchomienie bazy danych, 99% aplikacji z nich korzysta
- uruchomienie nginx do serwowania frontendu i proxy do backendu
- można zapakować aplikację w obraz dockera, dzięki czemu moja aplikacja będzie działać wszędzie tam, gdzie jest docker, problem dystrybucji zostaje rozwiązany od razu
- service discovery z pudełka, można tworzyć mikroserwisy, każdy kontener (podłączony do wspólnej sieci) łatwo skontaktuje się z innym po aliasie, bardzo wygodne
- Fajnie jest stworzyć kontener i 'pobawić się' w nim.
Co zawsze MI się nie podobało w dockerze:
- Aby moja aplikacja działała, potrzebny jest sam docker na serwerze. A po co mi to, skoro moje aplikacje działają na jre lub na nodejs, a środowisko dla nich już jest na serwerze?
- jeśli chcę uruchomić swój (prywatny) lokalnie zbudowany obraz na zdalnym serwerze, potrzebuję swojego repozytorium dockera, musi gdzieś działać registry i trzeba jeszcze skonfigurować https, ponieważ docker cli działa tylko przez https. O kurczę… są opcje, oczywiście, aby zapisać obraz lokalnie przez
docker savei za pomocą scp po prostu przesłać obraz... Ale to tyle działań. A ponadto wygląda to na 'kulejące' rozwiązanie, dopóki nie pojawi się własne repozytorium. docker-compose. Jest potrzebny tylko do uruchamiania kontenerów. I to wszystko. Nic więcej nie może.Docker-composema mnóstwo wersji swoich plików, swój własny składnik. Bez względu na to, jak deklaratywny by nie był, nie chcę czytać ich dokumentacji. Nie przyda mi się ona nigdzie indziej.- gdy pracuje się w zespole, większość ludzi pisze Dockerfile bardzo źle, nie rozumie, jak to jest buforowane, dodają do obrazu wszystko, co trzeba i nie trzeba, dziedziczą z obrazów, których nie ma w dockerhub lub prywatnym repozytorium, tworzą jakieś
docker-composepliki z bazami danych i nic nie jest trwałe. Przy tym deweloperzy dumnie ogłaszają, że docker jest świetny, wszystko działa lokalnie, a HR istotnie pisze w ogłoszeniach: „Używamy dockera i szukamy kandydata z takim doświadczeniem”. - ciągle chodzi po głowie myśl o uruchomieniu w dockerze wszystkiego: postgresql, kafka, redis. Szkoda, że nie wszystko działa w kontenerach, nie wszystko łatwo skonfigurować i uruchomić. Wspierają to deweloperzy zewnętrzni, a nie sami dostawcy. I od razu pojawia się pytanie, dlaczego dostawcy nie dbają o wsparcie swoich produktów w dockerze, może oni coś wiedzą?
- zawsze pojawia się pytanie o trwałość danych kontenera. I tu myślisz, czy po prostu zamontować katalog hosta, czy stworzyć volume dockerowy, czy zrobić kontener danych, który teraz
deprecated? Если я монтирую директорию то мне нужно убедиться что uid и gid пользователя в контейнере соответствует id пользователя запустившего контейнер, иначе файлы созданные контейнером будут созданы с правами владельца root. Если используюvolumewięc dane po prostu zostaną stworzone w jakimś/usr/*i będzie taka sama historia z uid i gid jak w pierwszym przypadku. Jeśli uruchamiasz komponent zewnętrzny, musisz dokładnie zapoznać się z dokumentacją i poszukać odpowiedzi na pytanie: „do jakich katalogów kontenera komponent zapisuje pliki?”
Zawsze nie podobało mi się, że musiałem za długo bawić się z dockerem. na początku: wymyślałem, jak uruchamiać kontenery, z jakich obrazów uruchamiać, tworzyłem Makefile, które zawierały aliasy do długich komend dockera. Nie znosiłem docker-compose, ponieważ nie chciałem uczyć się jeszcze jednego narzędzia z ekosystemu dockera. A docker-compose up denerwował mnie, zwłaszcza, jeśli pojawiały się tam także build konstrukcje, a nie już zbudowane obrazy. Wszystko, co naprawdę chciałem, to po prostu tworzyć produkt efektywnie i szybko. Ale nie mogłem w żaden sposób uporządkować użycia dockera.
Poznanie Ansible
Niedawno (około trzech miesięcy temu) pracowałem z zespołem DevOps, niemal każdy członek którego miał negatywne nastawienie do dockera. Z powodów:
- Docker zarządza iptables (chociaż można to wyłączyć w daemon.json)
- Docker jest niezbędny i nie będziemy go uruchamiać w produkcji
- Jeśli daemon Dockera pada, to odpowiednio wszystkie kontenery z infrastrukturą również padają
- W Dockerze nie ma potrzeby
- Po co Docker, skoro są Ansible i maszyny wirtualne
W tej samej pracy poznałem jeszcze jedno narzędzie – Ansible. Kiedyś słyszałem o nim, ale nie próbowałem pisać swoich playbooków. A teraz zacząłem pisać swoje zadania i moje spojrzenie zmieniło się całkowicie! Zrozumiałem, że Ansible ma moduły do uruchamiania tych samych kontenerów Docker, budowy obrazów, sieci itp., przy czym kontenery można uruchomić nie tylko lokalnie, ale także na zdalnych serwerach! Moja radość nie miała granic – znalazłem NORMANLNE narzędzie i wyrzuciłem swoje pliki Makefile i docker-compose, które zostały zastąpione zadaniami w yaml. Kod został zmniejszony dzięki zastosowaniu konstrukcji typu loop, when, itp.
Docker do uruchamiania zewnętrznych komponentów typu bazy danych
Ostatnio poznałem tunelowanie SSH. Okazało się, że bardzo łatwo jest „przepuścić” port zdalnego serwera na lokalny port. Zdalny serwer może być zarówno maszyną w chmurze, jak i maszyną wirtualną uruchomioną w VirtualBox. Jeśli ja lub mój kolega potrzebujemy bazy danych (lub jakiegoś innego zewnętrznego komponentu), wystarczy uruchomić serwer z tym komponentem i zamknąć go, gdy serwer nie jest potrzebny. Przepuszczenie portów daje taki sam efekt, jak baza danych uruchomiona w kontenerze Docker.
Ten polecenie przepuszcza mój lokalny port na zdalny serwer z postgresql:
ssh -L 9000:localhost:5432 user@example.com
Używanie zdalnego serwera rozwiązuje problem z pracą w zespole. Z takiego serwera mogą korzystać jednocześnie wielu programistów, nie muszą znać się na konfiguracji postgresql, dockerze i innych złożonościach. Na zdalnym serwerze można zainstalować tę samą bazę danych w Dockerze, jeśli zainstalowanie specyficznej wersji jest trudne. Wszystko, co programiści będą potrzebować, to dostęp SSH!
Ostatnio przeczytałem, że tunelowanie SSH to ograniczona funkcjonalność zwykłego VPN! Można po prostu skonfigurować OpenVPN lub inne realizacje VPN, skonfigurować infrastrukturę i udostępnić ją programistom. To przecież takie świetne!
Na szczęście AWS, GoogleCloud i inne oferują rok darmowego korzystania, więc warto to wykorzystać! Są niedrogie, jeśli je wyłączasz, gdy nie są używane. Zawsze zastanawiałem się, w jakich celach mógłbym potrzebować zdalnego serwera typu gcloud, wydaje się, że teraz odnalazłem ich zastosowanie.
Jako maszyna wirtualna można użyć tego samego Alpine, który jest aktywnie wykorzystywany w kontenerach dockerowych. Lub inne lekkie dystrybucje, aby maszyna ładowała się szybciej.
Podsumowując: uruchamianie baz danych i innych infrastrukturalnych rzeczy można i należy na zdalnych serwerach lub w virtualboxie. Nie potrzebuję dockera do tych celów.
Trochę o obrazach dockera i dystrybucji
Już o tym pisałem chciałem przekazać, że korzystanie z obrazów dockera nie daje żadnych gwarancji. Obrazy dockera są potrzebne tylko do stworzenia kontenera dockera. Jeśli używasz obrazu dockera, to znaczy, że wykorzystujesz kontenery dockera i będziesz miał do czynienia tylko z nimi.
Czy widziałeś gdziekolwiek, aby deweloperzy oprogramowania portowali swoje produkty tylko w obrazie dockera?
Wynikiem większości produktów są pliki binarne dla konkretnej platformy, które po prostu dodaje się do obrazu dockera, dziedzicząc z odpowiedniej platformy. Nie zastanawiałeś się, dlaczego w dockerhubie jest tak wiele podobnych obrazów? Wpisz na przykład nginx, a zobaczysz 100500 obrazów od różnych osób. Ci ludzie nie rozwijali samego nginx, tylko dodali oficjalny nginx do swojego obrazu dockera i wzbogacili go swoimi konfiguracjami dla wygody uruchamiania kontenerów.
Generalnie można przechowywać w tgz, jeśli ktoś będzie chciał to uruchomić w dockerze, niech doda tgz w Dockerfile, dziedziczy z odpowiedniego środowiska i tworzy dodatkowe rzeczy, które nie zmieniają samej aplikacji w tgz. Ten, kto stworzy obraz dockera, będzie wiedział, czym jest to tgz i co potrzebuje do pracy. Tak właśnie używam dockera.
Podsumowując: nie potrzebuję rejestru dockera, skorzystam z S3 lub po prostu z przechowalni plików typu google drive/dropbox.
Docker w CI
Wszystkie firmy, w których pracowałem, są do siebie podobne. Zazwyczaj są to firmy produktowe. To znaczy mają jedno konkretne aplikację, jeden stos technologii (może dwa lub trzy języki programowania).
Te firmy używają Dockera na swoich serwerach, na których uruchamiany jest proces CI. Pytanie brzmi: po co budować projekty w kontenerze Docker na swoich serwerach? Dlaczego po prostu nie przygotować środowiska do kompilacji, na przykład nie napisać playbooka Ansible, który zainstaluje odpowiednie wersje Node.js, PHP, JDK i skopiuje klucze SSH itp. na serwerze, na którym odbywa się kompilacja?
Teraz rozumiem, że to strzał w kolano, ponieważ Docker nie przynosi żadnych korzyści ze swojej izolacji. Problemy z CI w Dockerze, z którymi się spotkałem:
- znowu potrzebny jest obraz Dockera do kompilacji. Trzeba szukać obrazu lub pisać własny Dockerfile.
- 90% szans, że trzeba przeprowadzić jakieś klucze SSH, dane poufne, których nie chcę wpisywać w obraz Dockera.
- kontener jest tworzony i umiera, wszystkie cache są tracone razem z nim. Kolejna kompilacja będzie musiała ponownie pobrać wszystkie zależności projektu, co jest długie i nieefektywne, a czas to pieniądz.
Programiści nie kompilują projektów w kontenerach Docker (kiedyś byłem takim fanatykiem, szkoda mnie w przeszłości xD). W Javie można mieć kilka wersji i zmieniać je za pomocą jednego polecenia na tę, która jest teraz potrzebna. W Node.js jest to samo, jest nvm.
Wnioski
Uważam, że Docker to bardzo potężne i elastyczne narzędzie, w tym tkwi jego wada (brzmi dziwnie, prawda?). Dzięki niemu firmy łatwo uzależniają się od niego, używają tam, gdzie to konieczne i niekonieczne. Programiści uruchamiają swoje kontenery, swoje środowisko, a potem wszystko to gładko przechodzi do CI, produkcji. Zespół DevOps pisze jakieś koła, aby uruchomić te kontenery.
Używaj Dockera tylko na najbardziej zaawansowanym etapie w swoim procesie pracy, nie wprowadzaj go do projektu na początku. On nie rozwiąże twoich problemów biznesowych. Tylko przeniesie problemy na INNY poziom i zaproponuje swoje rozwiązania, będziesz wykonywać podwójną pracę.
Kiedy Docker jest potrzebny: doszedłem do wniosku, że Docker jest bardzo dobry w optymalizacji ustalonego procesu, ale nie w budowaniu podstawowej funkcjonalności.
Jeśli jednak zdecydujesz się używać Dockera, to:
- bądź niezwykle ostrożny
- nie narzucaj używania Dockera programistom
- lokalizuj jego użycie w jednym miejscu, nie rozprzestrzeniaj po wszystkich repozytoriach Dockefile i docker-compose
PS:
- Niedawno natknąłem się na Mówią, że bardzo dobrze działa z Ansible i umożliwia ujednolicenie procesu budowy obrazów (w tym obrazu docker).
Dziękuję za przeczytanie, życzę Państwu przejrzystych rozwiązań w Państwa sprawach i owocnych dni roboczych!
Źródło: habr.com
