Kontenery stały się jedną z najważniejszych zmian technologicznych w kontekście wytwarzania oprogramowania ostatnich lat. Niezależnie od języka programowania, bycia frontend lub backend deweloperem, testerem czy devopsem, każdy ma dzisiaj styczność z Dockerem i aplikacjami uruchamianymi z kontenera.
W jaki sposób umieścić naszą aplikację Springową w kontenerze? Zapraszam.
Więc aby stworzyć obraz Dockerowy dla naszej aplikacji potrzebujemy wykonać następujące kroki:
- Stworzyć aplikację ;)
- Stworzyć
Dockerfile
- plik opisujący jak ma wyglądać nasz obraz, - Dodać plugin do automatycznego budowania obrazu.
Pełny kod źródłowy przedstawianego przykładu znajdziesz na https://github.com/darek1024/sk-spring-boot-docker
Tworzymy aplikację #
W najprostszy możliwy sposób pobieramy aplikację ze Spring Initializr-a. Ja wybieram:
- projekt typu: Maven,
- język: Java,
- Spring Boot: 2.1.6.
Do listy zależności dokładamy Spring Web Starter. Pomoże nam on zweryfikować działanie naszej aplikacji.
Pobraną paczkę rozpakowujemy i dodajemy REST-owy kontroler - do obsługi prostego żądania HTTP.
@RestController
public class HelloController {
@RequestMapping(method = RequestMethod.GET)
public String hello(@RequestParam Optional<String> name) {
return name.map(n -> "Hello " + n + "!").orElse("Hello, World!");
}
}
Budujemy naszą aplikację.
./mvnw package
I uruchamiamy - jak każdą aplikację Javową.
java -jar ./target/dockerdemo-0.0.1-SNAPSHOT.jar
Gdy aplikacja się uruchomi, sprawdzamy, czy działa jak powinna.
$ curl localhost:8080
$ curl 'localhost:8080?name=Adam'
Przygotowanie Dockerfile #
Drugim ważnym elementem układanki jest stworzenie pliku Dockerfile
- czyli opisu obrazu, który chcemy zbudować. Dzięki niemu Docker będzie w stanie skonteneryzować naszą aplikację.
Przykładowy plik umieszczamy w głównym katalogu z aplikacją pod nazwą Dockerfile
.
FROM openjdk:12-jdk-alpine
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
EXPOSE 8080
Co my tu mamy?
Obraz źródłowy
FROM openjdk:12-jdk-alpine
Tworzymy obraz dockerowy na podstawie obrazu openjdk:12-jdk-alpine
. Bardzo małego obrazu z Javą w wersji 12 wydawaną przez OpenJDK.
Paczkę z aplikacją
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
Definiujemy zmienną JAR_FILE i prosimy aby plik na który wskazuje skopiować na ścieżkę app.jar
w kontenerze.
Komendę uruchomieniową
ENTRYPOINT ["java","-jar","/app.jar"]
Wskazujemy komendę, która ma zostać wywołana w momencie startu aplikacji. W tym wypadku jest to najzwyklejsze java -jar /app.jar
.
Dokumentację wystawianego portu
EXPOSE 8080
Polecenie EXPOSE
informuje jaki port wystawia nasza aplikacja.
Uwaga: jest to tylko polecenie informujące, nie ma ono wpływu na to, które faktycznie porty aplikacja uruchomi.
Budujemy nasz obraz #
Teraz gdy mam gotowy plik Dockerfile
możemy zbudować obraz Dockerowy poleceniem:
docker build -t darek1024/myapp .
Gdzie wskazujemy tag, pod którym aplikacja ma się zbudować - darek1024/myapp
oraz katalog źrodłowy, z którego paczka ma zostać zbudowana. W tym wypadku obecny katalog.
A, zapomnielibyśmy jeszcze o JAR_FILE
. Więc tym razem już pełna komenda.
docker build --build-arg JAR_FILE=target/dockerdemo-0.0.1-SNAPSHOT.jar \
-t darek1024:myapp .
Teraz możemy uruchomić naszą aplikację w dockerze.
docker run darek1024:myapp
Potrzebujemy jednak jeszcze wystawić porty aplikacji by móc się z nią skomunikować. Mamy dwie opcje - automatyczną publikację wszystkich portów (udokumentowanych poleceniem EXPOSE).
docker run -P darek1024:myapp
Lub wyspecyfikowanie potrzebnych portów i ich mapowań na nasz system.
docker run -p 9090:8080 darek1024:myapp
W pierwszym przypadku (-P
) aplikacja uruchomi się na losowym porcie, który możemy podejrzeć komendą docker ps
.
W drugim, po prostu wystarczy jak sprawdzimy stronę localhost:9080
. Tam powinna stać nasza aplikacja.
Automatyzacja #
Wszystko fajnie, ale jeśli zauważyłeś to mamy w całym procesie dwa manualne kroki, które musimy wykonać jeden po drugim:
- Zbudować aplikację komendą
./mnvw package
- to utworzy pliktarget/dockerdemo-0.0.1-SNAPSHOT.jar
. - Zbudować obraz dockerowy komendą
docker build
- z odpowiednimi parametrami.
Za każdym razem, kiedy chcemy stworzyć nowy obraz dockerowy, musielibyśmy wołać te dwie komendy. Czy możemy zrobić to lepiej?
dockerfile-maven-plugin
Z pomocą - w przypadku Mavena - przychodzi nam dockerfile-maven-plugin. Wystarczy do sekcji build
pliku pom.xml
dodać następujący wpis:
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.4.12</version>
<configuration>
<repository>${docker.image.prefix}/${project.artifactId}</repository>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
</configuration>
</plugin>
</plugins>
</build>
A do sekcji properties
określić prefix naszego obrazu.
<properties>
<docker.image.prefix>darek1024</docker.image.prefix>
</properties>
I… to wszystko!
Co teraz? Za pomocą jednej komendy budujemy nowy obraz.
./mvnw dockerfile:build
Aby upewnić się, że wszystko przebiegło pomyślnie wystarczy zawołać docker images
i upewnić się, że nasz nowy obraz został pomyślnie zbudowany.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
darek1024/dockerdemo latest f19eed76dee0 12 seconds ago 356MB
Zauważ, że w dodanym pluginie wykorzystujemy zmienną JAR_FILE
, której przekazujemy ścieżkę wynikową do zbudowanej aplikacji w Springu.
Podsumowanie #
Teraz możemy już z łatwością uruchamiać i dystrybuować naszą aplikację w formie obrazu Dockerowego. Jeśli chcesz wiedzieć więcej proszę daj znać w komentarzu jakie treści interesowałyby Cię najbardziej.