W ostatnim artykule zbudowaliśmy środowisko dla aplikacji uruchamianych na platformie Camunda BPM z wykorzystaniem PostgreSQL i serwera Wildfly. Do tej pory mogliśmy uruchomić aplikację, startując kontener serwera Wildfly z zamontowanym modułem WAR, zawierającym naszą przykładową aplikację.
Taki sposób uruchomienia jest wygodny dla dewelopera, ale operator środowiska produkcyjnego raczej nie będzie zadowolony. Docker pozwala na znacznie wygodniejsze przygotowanie paczki dystrybucyjnej pod postacią obrazu kontenera z zainstalowaną w nim aplikacją. Dzięki temu, na środowisko produkcyjne można dostarczyć gotowy do uruchomienia kontener i znacznie ograniczyć ilość kroków koniecznych do wykonania przez administratora.
Instalacja aplikacji na serwerach
Warto w tym miejscu na moment się zatrzymać i zwrócić uwagę na ciekawą rzecz. W tradycyjnym podejściu do instalacji aplikacji na serwerach, ciężar związany z technikaliami spada na administratorów lub operatorów docelowego środowiska.
To znaczy, że inaczej wdraża się aplikacje pisane w Javie, inaczej w .NET, a jeszcze inaczej w Pythonie lub Ruby. Wynika to, jak wiemy, z ogromnych różnic pomiędzy tymi platformami i wbudowanymi w nie mechanizmami dystrybucji i uruchomienia paczek. Powoduje to często problemy i trudności a przede wszystkim opory przed nowymi technologiami wdrażanymi w organizacji, ponieważ nie tylko deweloperzy, ale również administratorzy, muszą być na bieżąco z nowościami, aby skutecznie instalować aplikacje.
Docker wspiera zaangażowanie deweloperów w proces uruchamiania aplikacji na kolejnych środowiskach oraz (na swój sposób) eliminuje ryzyko związane z brakiem znajomości technologii w zespole OPS. To właśnie deweloperzy dokonują niejako instalacji aplikacji po swojej stronie i dostarczają operatorom obrazy kontenerów z zainstalowaną aplikacją.
Jest to sposób na zrealizowanie zasady mówiącej o hermetyzowaniu zmienności: zmiana technologii jest ukryta i zamknięta w obszarze developmentu, a operatorzy posługują się niezmienną technologią, czyli Dockerem.
Wracając do budowania obrazu naszego kontenera z aplikacją BPM, warto jeszcze zauważyć, że o ile z punktu widzenia administratorów technologia wykonania aplikacji staje się mniej znaczącym elementem, to deweloperzy muszą dostosować swoje aplikacje tak, aby dało się je prosto zapakować w kontener Dockera.
Jak przygotować obraz na produkcję?
Na początku chciałbym skupić się na możliwie prostym podejściu do przygotowania obrazu wykorzystywanego na kolejnych środowiskach. Następnie, mam nadzieję, zachęcić do poszerzania wiedzy i stosowania dobrych praktyk.
W poprzednim artykule przygotowaliśmy plik docker-compose.yml, dzięki któremu po uruchomieniu mieliśmy działającą aplikację. Z punktu widzenia programisty było to wygodne – aplikacja uruchomiona wraz z potrzebnymi zależnościami. Jednak uruchamianie w ten sposób na kolejnych środowiskach jest oczywiście karkołomne. Można by zapytać: gdzie ten kompletny obraz dla kontenera…?
Krótko odpowiadając, a jednocześnie nawiązując do pierwszego z serii artykułu:
# Dockerfile
FROM camunda/camunda-bpm-platform:wildfly-7.16.0
COPY ./target/pizza-order.war /camunda/standalone/deployments/pizza-order.war
Budowanie obrazu:
$ docker build . -t someorganization/pizza-order:1.0
Plik Dockerfile jest plikiem, który zawiera polecenia do zbudowania obrazu.
Prostym i przejrzystym opisem wspomnianego pliku jest strona z dokumentacją. Zachęcam również do zapoznania się z dobrymi praktykami tworzenia obrazów.
Polecenie build wykonuje instrukcje zawarte w pilku Dockerfile. Parametr . (kropka) oznacza bieżący katalog, a przez -t przekazuje się nazwę taga, pod jakim obraz będzie dostępny.
Po wykonaniu powyższego polecenia powinniśmy otrzymać nowy obraz, oczekiwany wynik:
$ docker images someorganization/pizza-order
REPOSITORY TAG IMAGE ID CREATED SIZE
someorganization/pizza-order 1.0 18105f66f15e 2 minutes ago 527MB
Dla podanej nazwy repozytorium “someorganization/pizza-order” otrzymujemy wcześniej utworzonego taga 1.0.
Rejestr obrazów
Co dalej? Zbudowany obraz trzeba udostępnić. W pierwszej cześci zapoznaliśmy się z dwiema metodami udostępniania.
Dzisiaj skupimy się na rejestrze obrazów – najbardziej popularnym jest Docker Hub. Rejestr może być publicznie dostępny lub prywatny. Wybór jest tutaj szczególnie ważny – nie zawsze chcemy udostępniać całemu światu aplikację, którą piszemy dla klienta.
Sposób korzystania z obu dostępów jest podobny, dodanie lub aktualizacja obrazu wymaga logowania do rejestru. Jedynie w przypadku prywatnego rejestru trzeba zalogować się przed pobraniem obrazu. Poniższe polecenie loguje do wspomnianego rejestru (uprzednio należy założyć konto):
$ docker login
Wykonując poniższe polecenie, wysyłamy obraz do rejestru:
$ docker push someorganization/pizza-order:1.0
Następnie, aby użyć obraz na produkcji albo dowolnym innym środowisku, pobieramy go przez znane nam już polecenie:
$ docker pull someorganization/pizza-order:1.0
Dzięki powyższemu uzyskaliśmy obraz z aplikacją. Jednak w tym miejscu należy zrobić pauzę. Gdzieś „zgubił się” postgres i co stało się z docker-compose.yml – czy jego też trzeba dostarczyć na kolejne środowiska?
Docker compose nadaje się do lokalnej pracy z obrazami, jednak uruchamianie kontenerów na kolejnych środowiskach to zadanie dla bardziej wyspecjalizowanych narzędzi.
Orkiestracja kontenerów
W naszej przykładowej aplikacji potrzebujemy do działania przynajmniej dwóch kontenerów – pierwszy z aplikacją, drugi z bazą danych. Co, jeśli jeden kontener z aplikacją to za mało i potrzebnych jest ich kilka?
Tutaj właśnie pojawiają się narzędzia umożliwiające orkiestrację, ciągłą dostępność oraz łatwe wdrażanie aplikacji. Przykładami są Kubernetes, OpenShift, Azure AKS czy AWS ECS – są to kompleksowe rozwiązania, które wychodzą daleko poza prosty docker compose.
Opisanie tych technologii wykracza poza zakres tego artykułu, jednak myśląc poważnie o dystrybuowaniu swojej aplikacji, zdecydowanie należy wziąć je pod uwagę, mając już gotowy obraz – zbudowany w przedstawiony sposób 🙂
Kubernetes
Wspomnę tylko krótko o Kubernetes. Jest jednym z bardziej popularnych narzędzi, opisując za Wikipedią: „Kubernetes to otwartoźródłowa platforma do zarządzania, automatyzacji i skalowania aplikacji kontenerowych. Jego pierwotna wersja została stworzona w 2014 roku przez Google, a obecnie rozwijany jest przez Cloud Native Computing Foundation”.
Na naszym blogu znajduje się artykuł stanowiący wprowadzenie do tej technologii.
Podsumowanie
Poznaliśmy wcześniej Docker compose, który nadaje się do lokalnej pracy. W tym artykule przedstawiłem prosty sposób budowania obrazu dla kolejnych środowisk, łącznie ze środowiskiem produkcyjnym.
Cały ten proces budowania obrazu powinien być zautomatyzowany i w połączeniu z praktykami Continous Integration, Continous Developement lub Continous Delivery stanowić sposób na wdrażanie naszych aplikacji.
Na koniec jeszcze małe słowo wyjaśnienia. Budując obraz, posłużyłem się bezpośrednim wykorzystaniem polecenia „docker build”. Istnieją też inne rozwiązania, które wspomagają ten proces (np.: S2I, kubernetes maven plugin). Jednak celowo o nich nie wspomniałem, ponieważ dodają dodatkową warstwę abstrakcji do projektu i takie wybory powinny być świadome po poznaniu podstaw.
Dodatkowo, trzymając się reguły KISS (ang. Keep It Simple, Stupid) nasz proces powinien być możliwie prosty. Dzięki temu łatwiej jest go zautomatyzować 🙂
***
Zaktualizowane w 2021 i 2022 artykuły nt. Dockera
Zostaw komentarz