Conteneuriser une application Java
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 :
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.
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 :
À 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 FROMFROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS tomcatdéfinit l’image de base sur Microsoft Build d’OpenJDK 17 sur Ubuntu et nomme cette étapetomcat. C’est là que Tomcat est installé.ENVENV CATALINA_HOME=/usr/local/tomcatdéfinit une variable d’environnement pour le répertoire d’installation de Tomcat.ENVENV TOMCAT_VERSION=10.1.33définit la version de Tomcat à installer. Cette opération doit être mise à jour vers la dernière version si nécessaire.RUNLa RUNcommande met à jour la liste des packages, installecurl, 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 FROMFROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS builddéfinit l’image de base sur Microsoft Build d’OpenJDK 17 sur Ubuntu et nomme cette étapebuild. Cette étape est utilisée pour compiler l’application Java.WORKDIRWORKDIR /builddéfinit le répertoire de travail à l’intérieur du conteneur/buildsur , où le code source est copié et compilé.RUNRUN apt-get update && apt-get install -y maven && mvn --versioninstalle Maven, un outil d’automatisation de build utilisé pour les projets Java et vérifie son installation.COPYCOPY pom.xml .copie le fichier de configuration Maven dans le répertoire de travail. Ce fichier est essentiel pour la création du projet.COPYCOPY src ./srccopie le répertoire de code source dans le conteneur. C’est là que réside le code de l’application Java.COPYCOPY web ./webcopie le répertoire des ressources web dans le conteneur. Cela inclut les ressources d’application web nécessaires à la génération.RUNRUN mvn clean packageexé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 FROMFROM mcr.microsoft.com/openjdk/jdk:17-marinerdéfinit l’image de base sur Microsoft Build d’OpenJDK 17 surCBL-Mariner, qui est utilisée pour le déploiement final de l’application.ENVENV CATALINA_HOME=/usr/local/tomcatdéfinit la variable d’environnement pour le répertoire d’installation tomcat, similaire à la phase d’installation.ENVENV PATH=$CATALINA_HOME/bin:$PATHajoute le répertoire bin Tomcat au systèmePATH, ce qui permet aux commandes Tomcat d’être exécutées facilement.USERUSER appspé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.COPYCOPY --chown=app:app --from=tomcat ${CATALINA_HOME} ${CATALINA_HOME}copie l’installation de Tomcat à partir de latomcatphase, en définissant la propriété sur l’utilisateurapp.COPYCOPY --chown=app:app tomcat-users.xml ${CATALINA_HOME}/confcopie le fichier de configuration de l’utilisateur Tomcat dans le conteneur, en définissant la propriété sur l’utilisateurapp.COPYCOPY --chown=app:app --from=build /build/target/*.war ${CATALINA_HOME}/webapps/AirlinesReservationSample.warcopie le fichier WAR compilé à partir de labuildphase dans le répertoire des applications web Tomcat, en définissant la propriété sur l’utilisateurapp.EXPOSEEXPOSE 8080expose le port 8080, le port par défaut de Tomcat, autorisant l’accès externe à l’application.CMDCMD ["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.