Conteneuriser une application Java

Effectué

Dans cette unité, vous conteneurisez une application Java.

Comme mentionné précédemment, les conteneurs s’exécutent directement sur le système d’exploitation hôte, le noyau et le matériel en tant que processus système ordinaires. Les conteneurs nécessitent moins de ressources système, ce qui réduit l’encombrement, la surcharge et les temps de démarrage des applications plus rapides. Ces avantages sont de grands cas d’usage pour la mise à l’échelle à la demande.

Il existe des conteneurs Windows et des conteneurs Linux. Dans ce module, vous utilisez le runtime Docker largement utilisé pour générer une image conteneur Linux. Vous déployez ensuite l’image conteneur Linux sur le système d’exploitation hôte de votre ordinateur local. Enfin, vous déployez l’image conteneur Linux sur Azure Kubernetes Service.

Vue d’ensemble de Docker

Le runtime Docker est utilisé pour générer, extraire, exécuter et envoyer (push) des images conteneur, comme illustré dans le diagramme suivant :

Diagramme montrant les commandes Docker.

Le tableau suivant décrit chaque commande Docker :

Commande Docker Descriptif
docker build Génère une image conteneur composée des instructions ou des couches nécessaires à Docker pour créer un conteneur en cours d’exécution à partir d’une image. Le résultat de cette commande est une image.
docker pull Les conteneurs sont initialisés à partir d’images, qui sont extraites de registres tels qu’Azure Container Registry. Ce registre est l’emplacement d’extraction d’Azure Kubernetes Service. Le résultat de cette commande est une extraction réseau d’une image, qui se produit dans Azure. Si vous le souhaitez, vous pouvez extraire des images localement. Cette option est courante lors de la création d’images qui nécessitent des dépendances ou des couches dont votre application peut avoir besoin, comme un serveur d’applications.
docker run Une instance en cours d’exécution d’une image est un conteneur, et cette commande exécute toutes les couches nécessaires à l’exécution et à l’interaction avec l’application conteneur en cours d’exécution. Le résultat de cette commande est un processus d’application en cours d’exécution sur le système d’exploitation hôte.
docker push Azure Container Registry stocke les images afin qu’elles soient facilement disponibles et proches du réseau pour les déploiements et la mise à l’échelle d’Azure.

Cloner l’application Java

Tout d’abord, clonez le référentiel Flight Booking System for Airline Reservations et accédez au dossier du projet d’application web Airlines.

Remarque

Si la création d’Azure Kubernetes Service est terminée dans votre onglet CLI, utilisez cet onglet. S’il est toujours en cours d’exécution, ouvrez un nouvel onglet et accédez à l’emplacement où vous préférez cloner le système de réservations de vols pour les réservations de compagnies aériennes.

Exécutez les commandes suivantes :

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

Si Java et Maven sont installés, vous pouvez exécuter la commande suivante dans votre console de terminal pour avoir une idée de l’expérience de création de l’application sans Docker. Si vous n’avez pas installé Java et Maven, vous pouvez passer en toute sécurité à la section suivante, construire un fichier Docker. Dans cette section, vous utilisez Docker pour extraire Java et Maven pour exécuter les builds en votre nom.

mvn clean package

Remarque

Nous avons utilisé la mvn clean package commande pour illustrer les défis opérationnels liés à l’utilisation des builds Docker multistage, que nous abordons ensuite. Là encore, cette étape est facultative. Dans les deux cas, vous pouvez continuer en toute sécurité sans exécuter la commande Maven.

Si le processus a réussi, Maven a correctement créé le système de réservation de vols pour l’artefact d’archive des applications web de réservations aériennes AirlinesReservationSample-0.0.1-SNAPSHOT.war, comme indiqué dans la sortie suivante :

[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] ------------------------------------------------------------------------

Imaginez que vous êtes un développeur Java et que vous venez de créer AirlinesReservationSample-0.0.1-SNAPSHOT.war. L’étape suivante consiste probablement à travailler avec les ingénieurs d’opération pour déployer cet artefact sur un serveur local ou une machine virtuelle. Pour que l’application démarre et s’exécute correctement, les serveurs et les machines virtuelles doivent être disponibles et configurés avec les dépendances requises. Ce processus est difficile et fastidieux, en particulier à la demande quand une charge accrue atteint votre application. Avec les conteneurs, ces défis sont atténués.

Construire un fichier Dockerfile

Vous êtes maintenant prêt à construire un fichier Dockerfile. Un fichier Dockerfile est un document texte qui contient toutes les commandes qu’un utilisateur exécuterait sur la ligne de commande pour assembler une image conteneur. Chaque image est une couche qui peut être mise en cache pour une efficacité. Les couches s’appuient sur les autres.

Par exemple, flight Booking System for Airline Reservations doit être déployé et exécuté à l’intérieur d’un serveur d’applications. Un serveur d’applications n’est pas empaqueté à l’intérieur de AirlinesReservationSample-0.0.1-SNAPSHOT.war. Il s’agit d’une dépendance externe nécessaire pour que AirlinesReservationSample-0.0.1-SNAPSHOT.war s’exécute, écoute et traite les requêtes HTTP, gère les sessions utilisateur et facilite les réservations de vols. Si vous avez utilisé un déploiement traditionnel et non conteneurisé, les ingénieurs d’opérations installent et configurent un serveur d’applications sur un serveur physique ou une machine virtuelle avant de déployer AirlinesReservationSample-0.0.1-SNAPSHOT.war . Ces ingénieurs d’exploitation doivent également s’assurer que le JDK utilisé sur votre ordinateur , qui est ce qui mvn clean package est utilisé pour compiler le fichier WAR, correspond en fait au même JRE utilisé par le serveur d’applications. La gestion de ces dépendances est difficile et fastidieuse.

Avec un fichier Dockerfile, vous pouvez écrire les instructions ou les couches nécessaires pour atteindre cet objectif automatiquement, en couches dans les étapes nécessaires pour vous assurer que le système de réservation de vols pour les réservations de compagnies aériennes dispose de toutes les dépendances nécessaires au déploiement sur le runtime du conteneur Docker. Cette solution est intéressante lorsque vous travaillez avec une mise à l’échelle à la demande à intervalles non planifiés. Chaque couche utilise le cache Docker, qui contient l’état de l’image conteneur à chaque jalon d’instruction, en optimisant le temps de calcul et la réutilisation. Si une couche ne change pas, les couches mises en cache sont utilisées. Les cas d’usage courants pour les couches mises en cache sont le runtime Java, le serveur d’applications et d’autres dépendances pour l’application Web Flight Booking System for Airline Reservations. Si et quand une version change sur une couche précédemment mise en cache, une nouvelle entrée mise en cache est créée.

Le diagramme suivant illustre les couches d’une image conteneur. Lorsque les commandes du fichier Dockerfile sont exécutées, les couches sont créées. La couche supérieure est le système de réservation de vols en lecture/écriture pour la couche d’application web Réservations de compagnies aériennes. Cette couche est basée sur les couches en lecture seule précédentes.

Diagramme montrant les couches Docker.

Docker a le concept de builds multistages, une fonctionnalité qui vous permet de créer une image conteneur plus petite avec une meilleure mise en cache et une empreinte de sécurité plus petite, ce qui permet une optimisation et une maintenance accrues du fichier Dockerfile au fil du temps. Par exemple, vous pouvez séparer l’étape de génération de conteneur pour la compilation et la génération de l’application à partir de la phase d’exécution de l’application. Cette fonctionnalité vous permet de copier uniquement les artefacts générés pendant la génération vers l’image conteneur de production, ce qui réduit l’encombrement. Étant donné que les images conteneur sont mises en cache, si aucune modification n’est apportée, les images mises en cache peuvent être réutilisées, ce qui réduit le coût et le temps de téléchargement à partir du réseau.

Les services exposés dans l’environnement de production doivent être gérés avec soin pour la sécurité. Par conséquent, l’environnement de production utilise et exploite une image conteneur sécurisée. L’exemple utilise l’image CBL-Mariner fournie par Microsoft.

CBL-Mariner Linux est un système d’exploitation léger, contenant uniquement les packages nécessaires pour un environnement cloud. Vous pouvez le personnaliser par le biais de packages et d’outils personnalisés pour répondre aux exigences de votre application. CBL-Mariner subit des tests de validation Azure et est compatible avec les agents Azure. Microsoft génère et teste CBL-Mariner pour alimenter différents cas d’usage, allant des services Azure à l’alimentation de l’infrastructure IoT. Il s’agit de la distribution Linux recommandée en interne pour une utilisation avec les services cloud Microsoft et les produits associés.

Remarque

Microsoft fournit des images conteneur groupées avec OpenJDK, notamment Ubuntu, CBL-Marineret distroless des images. L’image distroless a la plus petite taille d’image, mais l’exécution de Tomcat sur elle est difficile. Pour obtenir une conception légère, l’image distroless supprime de nombreuses commandes et outils, y compris l’interpréteur de commandes, ce qui signifie que vous ne pouvez pas appeler catalina.sh pour démarrer Tomcat. L’image distroless est adaptée à l’exécution des fichiers JARs exécutables, tels que ceux utilisés avec Spring Boot ou Dockerus.

Dans l’exemple suivant, la même version de Microsoft Build of OpenJDK est utilisée à la fois dans l’étape de génération et dans la phase finale. Cette approche garantit que vous générez le code source avec la même version du JDK que le déploiement de service que Tomcat utilise, ce qui permet d’éviter un comportement inattendu en raison d’incompatibilités de version.

L’image suivante illustre la build multistage et ce qui se produit dans chaque étape en fonction des commandes spécifiées dans le fichier Dockerfile :

Diagramme montrant la build Docker multistage.

À l’étape 0, Tomcat est téléchargé et extrait dans un répertoire spécifié par une variable d’environnement sur une image Ubuntu. La TOMCAT_VERSION variable spécifie la version de Tomcat à télécharger. Si une nouvelle version de Tomcat est publiée, vous devez mettre à jour le numéro de version, car une nouvelle image est extraite uniquement lorsque le numéro de version change. Sinon, l’image mise en cache est utilisée. Le tomcat téléchargé est copié dans l’environnement de phase finale à utiliser.

À l’étape 1, Maven est installé sur une image Ubuntu, et les fichiers de code source et de configuration créés sont copiés avant de générer le projet Maven. Chaque couche est mise en cache, de sorte que les couches image du système d’exploitation et Maven réutilisent le cache. Si les fichiers de configuration, les fichiers de code source ou le répertoire web sont mis à jour, les couches des modifications ultérieures sont reconstruites. Si la build se termine correctement sans erreur pendant la compilation, un artefact nommé AirlinesReservationSample-0.0.1-SNAPSHOT.war est généré sous le répertoire cible . Cet artefact est copié dans l’environnement de phase finale à utiliser.

Dans la dernière étape, l’image sécurisée CBL-Mariner fournie par Microsoft est utilisée pour copier les artefacts de build Tomcat et Java de l’étape 0 et de l’étape 1, respectivement. Un utilisateur nommé app possède tous les fichiers utilisés dans le projet et l’application est également exécutée en tant qu’utilisateur app au lieu d’avoir root des privilèges. Cette configuration garantit que l’image conteneur peut être exploitée en toute sécurité sans accorder d’autorisations inutiles. Enfin, le numéro de port 8080 est exposé et le script catalina.sh est exécuté pour démarrer Tomcat. Quand cette opération est exécutée sur votre Bureau Docker local, vous pouvez y accéder via l’URL http://localhost:8080/AirlinesReservationSample.

Dans le dossier racine de votre projet, containerize-and-deploy-Java-app-to-Azure/Project/Airlines, utilisez la commande suivante pour créer un fichier appelé Dockerfile :

vi Dockerfile

Ajoutez le contenu suivant à votre fichier Dockerfile, puis enregistrez et quittez. Pour enregistrer et quitter, appuyez sur Échap, tapez :wq!, puis appuyez sur Entrée.

############################################
# 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"]

Remarque

Si vous le souhaitez, vous pouvez utiliser le fichier Dockerfile_Solution à la racine de votre projet, qui contient le contenu dont vous avez besoin.

Le fichier Dockerfile est divisé en trois étapes, qui sont décrites dans les tableaux suivants :

  • Étape d’installation de Tomcat :

    Commande Docker Descriptif
    FROM FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS tomcat définit l’image de base sur Microsoft Build d’OpenJDK 17 sur Ubuntu et nomme cette étape tomcat. C’est là que Tomcat est installé.
    ENV ENV CATALINA_HOME=/usr/local/tomcat définit une variable d’environnement pour le répertoire d’installation de Tomcat.
    ENV ENV TOMCAT_VERSION=10.1.33 définit la version de Tomcat à installer. Cette opération doit être mise à jour vers la dernière version si nécessaire.
    RUN La RUN commande met à jour la liste des packages, installe curl, télécharge la version spécifiée de Tomcat, l’extrait, la déplace vers le répertoire spécifié et nettoie les fichiers et packages inutiles. Cela garantit que l’image reste légère.
  • Phase de génération, qui se compile avec Java 17 :

    Commande Docker Descriptif
    FROM FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS build définit l’image de base sur Microsoft Build d’OpenJDK 17 sur Ubuntu et nomme cette étape build. Cette étape est utilisée pour compiler l’application Java.
    WORKDIR WORKDIR /build définit le répertoire de travail à l’intérieur du conteneur /buildsur , où le code source est copié et compilé.
    RUN RUN apt-get update && apt-get install -y maven && mvn --version installe Maven, un outil d’automatisation de build utilisé pour les projets Java et vérifie son installation.
    COPY COPY pom.xml . copie le fichier de configuration Maven dans le répertoire de travail. Ce fichier est essentiel pour la création du projet.
    COPY COPY src ./src copie le répertoire de code source dans le conteneur. C’est là que réside le code de l’application Java.
    COPY COPY web ./web copie le répertoire des ressources web dans le conteneur. Cela inclut les ressources d’application web nécessaires à la génération.
    RUN RUN mvn clean package exécute le processus de génération Maven, qui compile l’application Java et les empaquet dans un fichier WAR.
  • Étape finale du package :

    Commande Docker Descriptif
    FROM FROM mcr.microsoft.com/openjdk/jdk:17-mariner définit l’image de base sur Microsoft Build d’OpenJDK 17 sur CBL-Mariner, qui est utilisée pour le déploiement final de l’application.
    ENV ENV CATALINA_HOME=/usr/local/tomcat définit la variable d’environnement pour le répertoire d’installation tomcat, similaire à la phase d’installation.
    ENV ENV PATH=$CATALINA_HOME/bin:$PATH ajoute le répertoire bin Tomcat au système PATH, ce qui permet aux commandes Tomcat d’être exécutées facilement.
    USER USER app spécifie l’utilisateur sous lequel le processus Tomcat s’exécute, ce qui améliore la sécurité en ne s’exécutant pas en tant qu’utilisateur racine.
    COPY COPY --chown=app:app --from=tomcat ${CATALINA_HOME} ${CATALINA_HOME} copie l’installation de Tomcat à partir de la tomcat phase, en définissant la propriété sur l’utilisateur app .
    COPY COPY --chown=app:app tomcat-users.xml ${CATALINA_HOME}/conf copie le fichier de configuration de l’utilisateur Tomcat dans le conteneur, en définissant la propriété sur l’utilisateur app .
    COPY COPY --chown=app:app --from=build /build/target/*.war ${CATALINA_HOME}/webapps/AirlinesReservationSample.war copie le fichier WAR compilé à partir de la build phase dans le répertoire des applications web Tomcat, en définissant la propriété sur l’utilisateur app .
    EXPOSE EXPOSE 8080 expose le port 8080, le port par défaut de Tomcat, autorisant l’accès externe à l’application.
    CMD CMD ["catalina.sh", "run"] spécifie la commande pour démarrer Tomcat lors de l’exécution du conteneur.

Pour plus d’informations sur la construction de Dockerfile, consultez la référence dockerfile.