Software Development

Docker dla programistów, dystrybucja aplikacji, cz.3

Kwiecień 7, 2016 0
Podziel się:

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 po stronie administratora.

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 technologią spada na administratorów lub operatorów docelowego środowiska. To znaczy, inaczej instaluje się aplikacje pisane w Java, inaczej w dotNET i jeszcze inaczej w Python 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, bo nie tylko deweloperzy ale również administratorzy muszą poznać nowości, aby skutecznie instalować aplikacje.

Docker na swój sposób eliminuje ryzyko związane ze znajomością technologi w zespole OPS i całość odpowiedzialności związanej z daną technologią przerzuca na zespół DEV. To właśnie deweloperzy dokonują niejako instalacji aplikacji po swojej stronie i dostarczają operatorom obrazy kontenerów z zainstalowaną aplikacją. Operatorzy posługują się już tylko gotowymi obrazami i często nawet nie muszą wiedzieć czy to dotNET czy Java. Jest to w pewien sposób realizacja zasady mówiącej o hermetyzowaniu zmienności: zmiana technologii jest ukryta i zamknięta w obszarze dewelopmentu, a operatorzy posługują się niezmienną technologią, czyli Docker’em.

Wracając do budowania obrazu naszego kontenera z aplikacją BPM, trzeba jeszcze zauważyć, że o ile z punktu widzenia administratorów, technologia wykonania aplikacji staje się nieznaczącym elementem, to deweloperzy muszą dostosować swoje aplikacje tak, aby dało się je prosto zapakować w kontener Docker’a. Z pomocą przychodzą wszelkiego rodzaju dodatkowe narzędzia i jednym z nich jest docker-maven-plugin stworzony przez zespół programistów usługi streamingowej Spotify. Wtyczka docker-maven-plugin pozwala w dość prosty sposób zbudować obraz kontenera w oparciu o istniejący już kontener i nadpisać pewne jego cechy. W naszym projekcie zbudujemy kontener bazując na standardowym obrazie Camundy i dodamy do jego systemu plików wynikowy moduł WAR tak, aby przy uruchomieniu, Wildfly automatycznie go wykrył i uruchomił.

Aby całość działała, docker-maven-plugin będziemy uruchamiać w fazie package, co gwarantuje nam dostęp do wszystkich zbudowanych artefaktów projektu maven. W fazie tej będziemy usuwać z Docker’a istniejący obraz kontenera (goal: removeImage) i w jego miejsce budować nowy obraz (goal: build). Fragment pom.xml dotyczący konfiguracji wtyczki widać poniżej:

<plugin>

    <groupId>com.spotify</groupId>

    <artifactId>docker-maven-plugin</artifactId>

    <version>0.3.7</version>

    <executions>

        <execution>

            <phase>package</phase>

            <goals>

                <goal>removeImage</goal>

                <goal>build</goal>

            </goals>

        </execution>

    </executions>

    <configuration>

        <baseImage>camunda/camunda-bpm-platform:wildfly-7.4.0</baseImage>

        <imageName>demo/${project.artifactId}</imageName>

        <forceTags>true</forceTags>

        <imageTags>

            <tag>latest</tag>

            <tag>${project.version}</tag>

        </imageTags>

        <resources>

            <resource>

                <targetPath>/camunda/standalone/deployments/</targetPath>

                <directory>${project.build.directory}</directory>

                <include>${project.build.finalName}.war</include>

            </resource>

        </resources>

    </configuration>

</plugin>

Konfiguracja wtyczki jest dość przejrzysta i w naszym przypadku ogranicza się do wskazania obrazu bazowego (tag baseImage), nazwy obrazu docelowego (tag imageName), która w naszym przypadku, jest oparta o nazwę artefaktu w projekcie maven. Dalej wymuszamy użycie etykiet w obrazach (tag forceTags) i wskazanie tychże (tagi imageTags oraz tag). Tutaj chwila na wyjaśnienie, dlaczego podajemy 2 etykiety. Jedna z nich jest związana z bieżącym numerem wersji projektu, co jest w miarę oczywiste, druga jest stałą o treści latest, co oznacza, że jeśli przy użyciu obrazu nie podamy konkretnej etykiety, to domyślnie zostanie użyta latest. Dzięki temu mamy gwarancję, że zawsze będziemy mieli wskazanie na ostatnią wersję projektu.

Na koniec najważniejszy element, czyli dodanie wynikowej paczki do systemu plików kontenera. Tag resource pozwala wskazać:

  • docelowe miejsce w kontenerze, czyli targetPath o wartości /camunda/standalone/deployments/,
  • katalog źródłowy (tag directory), skąd brany jest wynikowy moduł WAR, oraz
  • nazwę modułu wynikowego wskazaną w tagu includeName.

Przykładowe uruchomienie i prezentację działania przy zmieniających się wersjach projektu załączam w postaci nagrania poniżej:

Jak widać, z powodzeniem rozszerzyliśmy proces budowania aplikacji o etap instalowania jej w kontenerze Docker. Teraz możemy przekazać gotowy obraz kontenera dalej, do uruchomienia na kolejnych środowiskach. W tym celu musimy wykonać jeszcze 2 rzeczy: pierwszą jest wgranie obrazu do repozytorium, kolejną przygotowanie pliku docker-compose.yml, używającego nasz gotowy obraz kontenera. Repozytoriami zajmiemy się w jednym z następnych artykułów na blogu, a zmiana w docker-compose.yml będzie łatwa i polegać będzie na usunięciu z sekcji volumes wskazania na naszą paczkę WAR (bo ta już znajduje się w kontenerze) i wskazaniu nazwy obrazu kontenera na tę, którą ustaliliśmy w trakcie konfiguracji w pom.xml. Wynikowy fragment docker-compose.yml znajduje się poniżej:

bpm:

  image: demo/pizza-order:0.0.2

  environment:

    – DB_DRIVER=postgresql

    – DB_URL=jdbc:postgresql://db:5432/camunda

    – DB_USERNAME=camunda

    – DB_PASSWORD=camunda

    – TZ=Europe/Warsaw

  links:

    – db:db

  ports:

    – “8080:8080”

Na zakończenie podsumujmy co zostało zrobione do tej pory. Tak więc mamy przykładowy projekt maven, w którym budujemy proces biznesowy na platformie Camunda BPM i mamy przygotowane 2 sposoby na uruchomienie: pierwszy nie wymaga budowania obrazu kontenera i wykorzystuje istniejący kontener Camundy, w którym w trakcie uruchomienia dodajemy moduł aplikacji WAR i drugi sposób rozszerzający proces budowania projektu maven o budowanie nowego kontenera z zainstalowaną aplikacją. Pierwszy sposób jest wygodniejszy dla deweloperów, drugi dla operatorów środowisk. Nakład pracy w obu podejściach wydaje się znikomy w stosunku do tego co osiągamy, czyli powtarzalność środowiska uruchomieniowego i łatwość jego odtworzenia w każdej chwili.

W następnych wpisach postaram się podejść do tematu repozytoriów, konfiguracji kontenerów i automatyzacji procesu budowania aplikacji.

Oceń ten post
Wojciech Paciorkowski
Autor: Wojciech Paciorkowski
Programista Java, architekt EAI, zwolennik open-source i współdzielenia się wiedzą. Fanatycznie zgłębia nowe technologie i dzieli się wrażeniami z kolegami. Prywatnie mąż, ojciec i fotograf amator. Aparat zarasta kurzem, rower gnije w garażu. Jedynie gitara czasem dostaje w kość. Relaksują go dobre książki, filmy i seriale zwłaszcza o tematyce sci-fi.

Imię i nazwisko (wymagane)

Adres email (wymagane)

Temat

Treść wiadomości

Zostaw komentarz