Konteneryzowanie aplikacji Java
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:
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.
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:
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 FROMFROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS tomcatUstawia obraz podstawowy na Microsoft Build of OpenJDK 17 w systemie Ubuntu i nazywa ten etaptomcat. W tym miejscu jest instalowany serwer Tomcat.ENVENV CATALINA_HOME=/usr/local/tomcatUstawia zmienną środowiskową dla katalogu instalacyjnego serwera Tomcat.ENVENV TOMCAT_VERSION=10.1.33Ustawia wersję serwera Tomcat do zainstalowania. Ta aktualizacja powinna zostać zaktualizowana do najnowszej wersji zgodnie z potrzebami.RUNPolecenie RUNaktualizuje listę pakietów, instalujecurlprogram , 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 FROMFROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS buildUstawia obraz podstawowy na Microsoft Build of OpenJDK 17 w systemie Ubuntu i nazywa ten etapbuild. Ten etap służy do kompilowania aplikacji Java.WORKDIRWORKDIR /buildUstawia katalog roboczy wewnątrz kontenera na/build, gdzie kod źródłowy jest kopiowany i kompilowany.RUNRUN apt-get update && apt-get install -y maven && mvn --versioninstaluje narzędzie Maven, narzędzie automatyzacji kompilacji używane na potrzeby projektów Java i weryfikuje jego instalację.COPYCOPY pom.xml .kopiuje plik konfiguracji programu Maven do katalogu roboczego. Ten plik jest niezbędny do kompilowania projektu.COPYCOPY src ./srcKopiuje katalog kodu źródłowego do kontenera. W tym miejscu znajduje się kod aplikacji Java.COPYCOPY web ./webkopiuje katalog zasobów internetowych do kontenera. Obejmuje to zasoby aplikacji internetowej potrzebne do kompilacji.RUNRUN mvn clean packageWykonuje proces kompilacji narzędzia Maven, który kompiluje aplikację Java i pakuje ją do pliku WAR.Końcowy etap pakietu:
Polecenie Docker Opis FROMFROM mcr.microsoft.com/openjdk/jdk:17-marinerustawia obraz bazowy na Microsoft Build of OpenJDK 17 wCBL-Mariner, który jest używany do końcowego wdrożenia aplikacji.ENVENV CATALINA_HOME=/usr/local/tomcatUstawia zmienną środowiskową dla katalogu instalacyjnego serwera Tomcat, podobnie jak w przypadku etapu instalacji.ENVENV PATH=$CATALINA_HOME/bin:$PATHDodaje katalog bin tomcat do systemuPATH, co umożliwia łatwe uruchamianie poleceń serwera Tomcat.USERUSER appOkreśla użytkownika, w którym jest uruchamiany proces Tomcat, zwiększając bezpieczeństwo, nie uruchamiając go jako użytkownik główny.COPYCOPY --chown=app:app --from=tomcat ${CATALINA_HOME} ${CATALINA_HOME}kopiuje instalację Tomcata z etaputomcat, ustawiając jej własność na użytkownikaapp.COPYCOPY --chown=app:app tomcat-users.xml ${CATALINA_HOME}/confKopiuje plik konfiguracji użytkownika serwera Tomcat do kontenera, ustawiając własność użytkownikowiapp.COPYCOPY --chown=app:app --from=build /build/target/*.war ${CATALINA_HOME}/webapps/AirlinesReservationSample.warKopiuje skompilowany plik WAR z etapubuilddo katalogu Tomcat webapps, ustawiając własność na użytkownikaapp.EXPOSEEXPOSE 8080Uwidacznia port 8080, domyślny port serwera Tomcat, umożliwiając dostęp zewnętrzny do aplikacji.CMDCMD ["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.