Konteneryzowanie aplikacji Java

Ukończone

W tej lekcji konteneryzujesz aplikację Java.

Jak wspomniano wcześniej, kontenery działają bezpośrednio na systemie operacyjnym hosta, jądrze i sprzęcie jako zwykłe procesy systemowe. Kontenery wymagają mniejszej liczby zasobów systemowych, co skutkuje mniejszym zużyciem, mniejszym obciążeniem i krótszym czasem uruchamiania aplikacji. Te korzyści będą doskonałymi przykładami zastosowań skalowania na żądanie.

Istnieją kontenery systemu Windows i kontenery systemu Linux. W tym module używasz powszechnie używanego środowiska uruchomieniowego platformy Docker do kompilowania obrazu kontenera systemu Linux. Następnie wdrożysz obraz kontenera systemu Linux w systemie operacyjnym hosta komputera lokalnego. Na koniec wdrożysz obraz kontenera systemu Linux w usłudze Azure Kubernetes Service.

Omówienie platformy Docker

Środowisko uruchomieniowe platformy Docker służy do kompilowania, ściągania, uruchamiania i wypychania obrazów kontenerów, jak pokazano na poniższym diagramie:

Diagram przedstawiający polecenia platformy Docker.

W poniższej tabeli opisano każde polecenie platformy Docker:

Polecenie Docker Opis
docker build Tworzy obraz kontenera, który składa się z instrukcji lub warstw potrzebnych do uruchomienia kontenera na podstawie tego obrazu. Wynikiem tego polecenia jest obraz.
docker pull Kontenery są inicjowane z obrazów, które są pobierane z rejestrów, takich jak usługa Azure Container Registry. Ten rejestr to miejsce, z którego usługa Azure Kubernetes Service pobiera dane. Wynikiem tego polecenia jest pobieranie obrazu z sieci, który znajduje się na platformie Azure. Opcjonalnie możesz ściągać obrazy lokalnie. Ta opcja jest powszechna podczas kompilowania obrazów wymagających zależności lub warstw, których może potrzebować aplikacja, takich jak serwer aplikacji.
docker run Uruchomione wystąpienie obrazu jest kontenerem, a to polecenie wykonuje wszystkie warstwy potrzebne do uruchomienia i interakcji z uruchomioną aplikacją kontenera. Wynikiem tego polecenia jest uruchomiony proces aplikacji w systemie operacyjnym hosta.
docker push Usługa Azure Container Registry przechowuje obrazy, aby były łatwo dostępne i blisko sieci dla wdrożeń i skalowania platformy Azure.

Klonowanie aplikacji Java

Najpierw sklonuj repozytorium Flight Booking System for Airline Reservations i przejdź do folderu projektu aplikacji internetowej Airlines.

Notatka

Jeśli tworzenie usługi Azure Kubernetes Service zostało zakończone w zakładce terminala, użyj tej zakładki. Jeśli nadal trwa, otwórz nową zakładkę i przejdź do lokalizacji, w której wolisz sklonować system rezerwacji lotów dla linii lotniczych.

Uruchom następujące polecenia:

git clone https://github.com/Azure-Samples/containerize-and-deploy-Java-app-to-Azure.git
cd containerize-and-deploy-Java-app-to-Azure/Project/Airlines

Opcjonalnie, jeśli masz zainstalowane środowisko Java i Maven, możesz uruchomić następujące polecenie w konsoli terminalu, aby zrozumieć środowisko kompilowania aplikacji bez platformy Docker. Jeśli nie masz zainstalowanego środowiska Java i narzędzia Maven, możesz bezpiecznie przejść do następnej sekcji : Konstruowanie pliku platformy Docker. W tej sekcji użyjesz platformy Docker, aby ściągnąć środowisko Java i narzędzie Maven w celu wykonania kompilacji w Twoim imieniu.

mvn clean package

Notatka

Użyliśmy polecenia mvn clean package do zilustrowania wyzwań operacyjnych związanych z nienależytym użyciem wielostopniowych kompilacji w Dockerze, co omówimy w dalszej części. Ponownie ten krok jest opcjonalny. Tak czy inaczej, można bezpiecznie kontynuować bez wykonywania polecenia Maven.

Jeśli proces zakończył się pomyślnie, narzędzie Maven pomyślnie zbudowało system rezerwacji lotów dla aplikacji internetowej linii lotniczych jako artefakt Web Application Archive AirlinesReservationSample-0.0.1-SNAPSHOT.war, jak pokazano w poniższym wyniku.

[INFO] Building war: $PROJECT_PATH/containerize-and-deploy-Java-app-to-Azure/Project/Airlines/target/AirlinesReservationSample-0.0.1-SNAPSHOT.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  11.776 s
[INFO] Finished at: 2024-11-15T09:33:26+09:00
[INFO] ------------------------------------------------------------------------

Wyobraź sobie, że jesteś deweloperem Java i właśnie zbudowałeś AirlinesReservationSample-0.0.1-SNAPSHOT.war. Następnym krokiem jest prawdopodobnie współpraca z inżynierami operacji w celu wdrożenia tego artefaktu na serwerze lokalnym lub maszynie wirtualnej. Aby aplikacja mogła zostać uruchomiona i działać pomyślnie, serwery i maszyny wirtualne muszą być dostępne i skonfigurowane z wymaganymi zależnościami. Ten proces jest trudny i czasochłonny, zwłaszcza w sytuacjach, gdy zwiększa się obciążenie aplikacji. W przypadku kontenerów te wyzwania są złagodzone.

Utwórz plik Dockerfile

Teraz możesz utworzyć plik Dockerfile. Plik Dockerfile to dokument tekstowy zawierający wszystkie polecenia wykonywane przez użytkownika w wierszu polecenia w celu utworzenia obrazu kontenera. Każdy obraz jest warstwą, którą można buforować w celu zapewnienia wydajności. Warstwy układają się jedna na drugiej.

Na przykład system rezerwacji lotów dla rezerwacji linii lotniczych musi zostać wdrożony i uruchomiony na serwerze aplikacji. Serwer aplikacji nie jest zawarty w AirlinesReservationSample-0.0.1-SNAPSHOT.war. Jest to zależność zewnętrzna wymagana dla AirlinesReservationSample-0.0.1-SNAPSHOT.war do uruchamiania, nasłuchiwania i przetwarzania żądań HTTP, zarządzania sesjami użytkowników i ułatwienia rezerwacji lotów. Jeśli użyto tradycyjnego, niekontenerowego wdrożenia, inżynierowie operacji zainstalują i skonfigurują serwer aplikacji na pewnym serwerze fizycznym lub maszynie wirtualnej przed wdrożeniem w nim pliku AirlinesReservationSample-0.0.1-SNAPSHOT.war . Inżynierowie operacji musieliby również upewnić się, że zestaw JDK używany na maszynie — który jest używany mvn clean package do kompilowania pliku WAR — w rzeczywistości odpowiada temu samemu środowisku JRE używanemu przez serwer aplikacji. Zarządzanie tymi zależnościami jest trudne i czasochłonne.

Za pomocą pliku Dockerfile można napisać instrukcje lub warstwy potrzebne do automatycznego osiągnięcia tego celu, nakładając warstwy w krokach niezbędnych do zapewnienia, że system rezerwacji lotów ma wszystkie zależności wymagane do wdrożenia w środowisku uruchomieniowym Docker. To rozwiązanie jest przekonujące, gdy pracujesz ze skalowaniem na żądanie w nieplanowanych odstępach czasu. Każda warstwa używa pamięci podręcznej Docker, która zawiera stan obrazu kontenera na każdym etapie instruktażowym, co optymalizuje czas przetwarzania i ponowne wykorzystanie. Jeśli warstwa nie zmienia się, używane są buforowane warstwy. Typowe przypadki użycia buforowanych warstw to środowisko uruchomieniowe Java, serwer aplikacji i inne zależności dla aplikacji internetowej Flight Booking System for Airline Reservations. Jeśli i kiedy wersja zmieni się na wcześniej buforowanej warstwie, zostanie utworzony nowy buforowany wpis.

Na poniższym diagramie przedstawiono warstwy obrazu kontenera. Po wykonaniu poleceń w pliku Dockerfile zostaną utworzone warstwy. Górna warstwa to system rezerwacji lotów, który umożliwia odczyt i zapis, dla webowej warstwy aplikacji do rezerwacji lotów. Ta warstwa jest zbudowana na poprzednich warstwach, które są tylko do odczytu.

Diagram przedstawiający warstwy platformy Docker.

Platforma Docker ma koncepcję kompilacji wieloeeżowych, czyli funkcji, która umożliwia tworzenie mniejszego obrazu kontenera z lepszym buforowaniem i mniejszym zużyciem zabezpieczeń, co pozwala zwiększyć optymalizację i konserwację pliku Dockerfile w czasie. Na przykład można oddzielić etap kompilacji kontenera na potrzeby kompilowania i kompilowania aplikacji z etapu uruchamiania aplikacji. Ta funkcja umożliwia kopiowanie tylko artefaktów wygenerowanych podczas kompilacji do obrazu kontenera produkcyjnego, co zmniejsza jego rozmiar. Ponieważ obrazy kontenerów są buforowane, jeśli nie ma żadnych zmian, obrazy buforowane mogą być ponownie używane, co zmniejsza koszt i czas pobierania z sieci.

Usługi uwidocznione w środowisku produkcyjnym muszą być starannie zarządzane pod kątem zabezpieczeń. W związku z tym środowisko produkcyjne używa i zarządza bezpiecznym obrazem kontenera. W przykładzie użyto dostarczonego przez firmę Microsoft CBL-Mariner obrazu.

CBL-Mariner Linux jest uproszczonym systemem operacyjnym zawierającym tylko pakiety potrzebne do środowiska chmury. Można go dostosować za pomocą niestandardowych pakietów i narzędzi, aby dopasować je do wymagań aplikacji. CBL-Mariner przechodzi testy weryfikacji platformy Azure i jest zgodny z agentami platformy Azure. Firma Microsoft kompiluje i testuje CBL-Mariner w celu obsługi różnych przypadków użycia, począwszy od usług platformy Azure po zasilanie infrastruktury IoT. Jest to wewnętrzna zalecana dystrybucja systemu Linux do użycia z usługami w chmurze firmy Microsoft i powiązanymi produktami.

Notatka

Firma Microsoft udostępnia obrazy kontenerów połączone z zestawem OpenJDK, w tym Ubuntu, CBL-Marineri distroless obrazami. Obraz distroless ma najmniejszy rozmiar obrazu, ale uruchomienie serwera Tomcat na nim jest trudne. Aby uzyskać lekki projekt, distroless obraz usuwa wiele poleceń i narzędzi, w tym powłokę, co oznacza, że nie można wywołać catalina.sh, aby uruchomić Tomcat. Obraz distroless jest odpowiedni do uruchamiania wykonywalnych plików JAR, takich jak te używane z Spring Boot lub Quarkus.

W poniższym przykładzie ta sama wersja zestawu Microsoft Build openJDK jest używana zarówno na etapie kompilacji, jak i na ostatnim etapie. Takie podejście zapewnia utworzenie kodu źródłowego z tą samą wersją zestawu JDK używanego przez wdrożenie usługi Tomcat, co pomaga uniknąć nieoczekiwanego zachowania z powodu niezgodności wersji.

Na poniższej ilustracji przedstawiono kompilację wieloetapową i elementy występujące na każdym etapie na podstawie poleceń określonych w pliku Dockerfile:

Diagram przedstawiający wielostopniową budowę Docker.

Na etapie 0 Tomcat jest pobierany i wyodrębniany do katalogu wskazanego przez zmienną środowiskową na obrazie Ubuntu. Zmienna TOMCAT_VERSION określa wersję Tomcat do pobrania. Jeśli zostanie wydana nowa wersja serwera Tomcat, należy zaktualizować numer wersji, ponieważ nowy obraz jest pobierany tylko po zmianie numeru wersji. W przeciwnym razie jest używany buforowany obraz. Pobrany serwer Tomcat jest kopiowany do końcowego środowiska etapu do użycia.

Na etapie 1 narzędzie Maven jest instalowane na obrazie systemu Ubuntu, a utworzone pliki źródłowe i pliki konfiguracji są kopiowane przed utworzeniem projektu Maven. Każda warstwa jest buforowana, więc warstwy obrazu systemu operacyjnego i obrazu Maven wykorzystują pamięć podręczną ponownie. Jeśli pliki konfiguracji, pliki kodu źródłowego lub katalog internetowy zostaną zaktualizowane, warstwy z poziomu zmian zostaną ponownie skompilowane. Jeśli kompilacja zakończy się pomyślnie bez błędów podczas kompilacji, w katalogu docelowym zostanie wygenerowany artefakt o nazwie AirlinesReservationSample-0.0.1-SNAPSHOT.war. Ten artefakt jest kopiowany do środowiska końcowego etapu, aby być używanym.

Na ostatnim etapie bezpieczny CBL-Mariner obraz dostarczony przez firmę Microsoft służy do kopiowania artefaktów kompilacji Tomcat i Java z etapu 0 i etapu 1. Użytkownik app jest właścicielem wszystkich plików używanych w projekcie, a aplikacja jest również uruchamiana jako użytkownik app zamiast posiadać uprawnienia root. Ta konfiguracja gwarantuje, że obraz kontenera może być bezpiecznie użytkowany bez udzielania niepotrzebnych uprawnień. Na koniec numer portu 8080 jest uwidoczniony, a skrypt catalina.sh jest wykonywany w celu uruchomienia serwera Tomcat. Po uruchomieniu tego polecenia na lokalnym pulpicie platformy Docker możesz uzyskać do niego dostęp za pośrednictwem adresu URL http://localhost:8080/AirlinesReservationSample.

W folderze głównym projektu containerize-and-deploy-Java-app-to-Azure/Project/Airlines użyj następującego polecenia, aby utworzyć plik o nazwie Dockerfile:

vi Dockerfile

Dodaj następującą zawartość do pliku Dockerfile, a następnie zapisz i zamknij. Aby zapisać i zakończyć, naciśnij ESC, wpisz :wq!, a następnie naciśnij Enter.

############################################
# Tomcat Intall stage
############################################
FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS tomcat

ENV CATALINA_HOME=/usr/local/tomcat

# Configure Tomcat Version (Be sure to use the latest version)
ENV TOMCAT_VERSION=10.1.33

# Install Tomcat and required packages
RUN apt-get update ; \
    apt-get install -y curl ; \
    curl -O https://downloads.apache.org/tomcat/tomcat-10/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz ; \
    tar xzf apache-tomcat-${TOMCAT_VERSION}.tar.gz ; \
    mv apache-tomcat-${TOMCAT_VERSION} ${CATALINA_HOME} ; \
    rm apache-tomcat-${TOMCAT_VERSION}.tar.gz && \
    apt-get remove --purge -y curl && \
    apt-get autoremove -y && \
    apt-get clean

############################################
# Build stage (Compiles with Java 17)
############################################
FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS build

WORKDIR /build

# Install Maven
RUN apt-get update && apt-get install -y maven && mvn --version

# Copy source code
COPY pom.xml .
COPY src ./src
COPY web ./web

# Build the project
RUN mvn clean package

############################################
# Package final stage
############################################
FROM mcr.microsoft.com/openjdk/jdk:17-mariner

# Configure the location of the Tomcat installation
ENV CATALINA_HOME=/usr/local/tomcat
# Configure the path to the Tomcat binaries
ENV PATH=$CATALINA_HOME/bin:$PATH

# This is the user that runs the Tomcat process
USER app

# Copy the Tomcat installation from the Tomcat stage
COPY --chown=app:app --from=tomcat ${CATALINA_HOME} ${CATALINA_HOME}
# Copy the Tomcat configuration files
COPY --chown=app:app tomcat-users.xml ${CATALINA_HOME}/conf
# Copy the compiled WAR file from the build stage
COPY --chown=app:app --from=build /build/target/*.war ${CATALINA_HOME}/webapps/AirlinesReservationSample.war

# Expose the default Tomcat port
EXPOSE 8080
# Start Tomcat
CMD ["catalina.sh", "run"]

Notatka

Opcjonalnie możesz użyć pliku Dockerfile_Solution w katalogu głównym projektu, który zawiera potrzebną zawartość.

Plik Dockerfile jest podzielony na trzy etapy, które są opisane w następujących tabelach:

  • Etap instalacji serwera Tomcat:

    Polecenie Docker Opis
    FROM FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS tomcat Ustawia obraz podstawowy na Microsoft Build of OpenJDK 17 w systemie Ubuntu i nazywa ten etap tomcat. W tym miejscu jest instalowany serwer Tomcat.
    ENV ENV CATALINA_HOME=/usr/local/tomcat Ustawia zmienną środowiskową dla katalogu instalacyjnego serwera Tomcat.
    ENV ENV TOMCAT_VERSION=10.1.33 Ustawia wersję serwera Tomcat do zainstalowania. Ta aktualizacja powinna zostać zaktualizowana do najnowszej wersji zgodnie z potrzebami.
    RUN Polecenie RUN aktualizuje listę pakietów, instaluje curlprogram , pobiera określoną wersję serwera Tomcat, wyodrębnia go, przenosi go do określonego katalogu i czyści niepotrzebne pliki i pakiety. Gwarantuje to, że obraz pozostanie lekki.
  • Etap kompilacji, który kompiluje się z językiem Java 17:

    Polecenie Docker Opis
    FROM FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS build Ustawia obraz podstawowy na Microsoft Build of OpenJDK 17 w systemie Ubuntu i nazywa ten etap build. Ten etap służy do kompilowania aplikacji Java.
    WORKDIR WORKDIR /build Ustawia katalog roboczy wewnątrz kontenera na /build, gdzie kod źródłowy jest kopiowany i kompilowany.
    RUN RUN apt-get update && apt-get install -y maven && mvn --version instaluje narzędzie Maven, narzędzie automatyzacji kompilacji używane na potrzeby projektów Java i weryfikuje jego instalację.
    COPY COPY pom.xml . kopiuje plik konfiguracji programu Maven do katalogu roboczego. Ten plik jest niezbędny do kompilowania projektu.
    COPY COPY src ./src Kopiuje katalog kodu źródłowego do kontenera. W tym miejscu znajduje się kod aplikacji Java.
    COPY COPY web ./web kopiuje katalog zasobów internetowych do kontenera. Obejmuje to zasoby aplikacji internetowej potrzebne do kompilacji.
    RUN RUN mvn clean package Wykonuje proces kompilacji narzędzia Maven, który kompiluje aplikację Java i pakuje ją do pliku WAR.
  • Końcowy etap pakietu:

    Polecenie Docker Opis
    FROM FROM mcr.microsoft.com/openjdk/jdk:17-mariner ustawia obraz bazowy na Microsoft Build of OpenJDK 17 w CBL-Mariner, który jest używany do końcowego wdrożenia aplikacji.
    ENV ENV CATALINA_HOME=/usr/local/tomcat Ustawia zmienną środowiskową dla katalogu instalacyjnego serwera Tomcat, podobnie jak w przypadku etapu instalacji.
    ENV ENV PATH=$CATALINA_HOME/bin:$PATH Dodaje katalog bin tomcat do systemu PATH, co umożliwia łatwe uruchamianie poleceń serwera Tomcat.
    USER USER app Określa użytkownika, w którym jest uruchamiany proces Tomcat, zwiększając bezpieczeństwo, nie uruchamiając go jako użytkownik główny.
    COPY COPY --chown=app:app --from=tomcat ${CATALINA_HOME} ${CATALINA_HOME} kopiuje instalację Tomcata z etapu tomcat, ustawiając jej własność na użytkownika app.
    COPY COPY --chown=app:app tomcat-users.xml ${CATALINA_HOME}/conf Kopiuje plik konfiguracji użytkownika serwera Tomcat do kontenera, ustawiając własność użytkownikowi app .
    COPY COPY --chown=app:app --from=build /build/target/*.war ${CATALINA_HOME}/webapps/AirlinesReservationSample.war Kopiuje skompilowany plik WAR z etapu build do katalogu Tomcat webapps, ustawiając własność na użytkownika app.
    EXPOSE EXPOSE 8080 Uwidacznia port 8080, domyślny port serwera Tomcat, umożliwiając dostęp zewnętrzny do aplikacji.
    CMD CMD ["catalina.sh", "run"] Określa polecenie uruchamiania serwera Tomcat po uruchomieniu kontenera.

Aby uzyskać więcej informacji na temat konstrukcji pliku Dockerfile, zobacz dokumentację pliku Dockerfile.