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 accélère le démarrage des applications. Ces avantages sont de bons exemples de recours à 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 |
Télécharge une image à partir d’un registre dans le magasin d’images du démon Docker sélectionné par le client. Les couches d’images existantes peuvent être réutilisées. Dans ce module, votre environnement Docker local utilise des images à partir de registres pendant le développement ; plus tard, les nœuds AKS extrayent l’image de l’application à partir de Azure Container Registry pour le déploiement. |
docker run |
Crée et démarre un conteneur à partir d’une image. Le conteneur exécute son processus de démarrage configuré, sous réserve de remplacements de ligne de commande. Les couches d’images fournissent le système de fichiers du conteneur ; Les instructions de build Dockerfile ne sont pas réexécutées au démarrage du conteneur. |
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 Azure. |
Clonez 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 Flight Booking System for Airline Reservations.
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 télécharger 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 au fait de ne pas utiliser les builds multistage de Docker, 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 généré correctement l’artefact d’archive d’application Web du Flight Booking System for Airline Reservations AirlinesReservationSample-0.0.1-SNAPSHOT.war, comme illustré par la sortie d’historique suivante. L’horodatage et la durée de votre build peuvent différer :
[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 s’avère difficile et fastidieux, surtout pour les opérations à la demande, lorsque l’augmentation de la charge atteint votre application. Avec les conteneurs, ces défis sont atténués.
Créer un 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. Une image conteneur peut contenir plusieurs couches de système de fichiers en lecture seule. Docker peut réutiliser les résultats de build mis en cache pour les étapes inchangées. Les couches se superposent.
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 installeraient et configureraient un serveur d’applications sur un serveur physique ou une machine virtuelle avant d’y 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 que mvn clean package a utilisé pour compiler le fichier WAR) correspond au même JRE qu’utilise 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 superposant les étapes nécessaires pour vous assurer que le système de réservation de vols des compagnies aériennes dispose de toutes les dépendances nécessaires au déploiement sur le runtime du conteneur Docker. Cette solution est particulièrement pertinente 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 de conteneur à chaque étape majeure de l’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.
Une image conteneur contient des couches de système de fichiers en lecture seule. Dans cet exemple, le fichier Dockerfile copie Tomcat et le fichier WAR flight Booking System dans l’image au moment de la génération. Docker ajoute une couche accessible en écriture distincte lorsqu’il crée un conteneur à partir de l’image. La couche accessible en écriture de chaque conteneur enregistre ses propres modifications de système de fichiers sans modifier les couches d’image.
Remarque
Pour les fichiers stockés dans la couche accessible en écriture du conteneur, les ajouts, les modifications et les suppressions affectent ce conteneur plutôt que l’image d’origine. La modification des fichiers provenant d’une couche d’image utilise le comportement de copie en écriture.
Docker propose des builds multi-étapes, 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 une image Linux Azure fournie par Microsoft.
La dernière étape utilise Build Microsoft d’OpenJDK 17 sur Azure Linux 3.0. La 17-azurelinux balise nomme explicitement cette base. L'ancienne balise 17-mariner reste un alias de compatibilité qui reflète l'image Azure Linux ; elle ne doit pas être confondue avec les images 17-mariner-cm2 et 17-mariner-cm1 retirées. Pour plus d’informations, consultez images de conteneur Build Microsoft d’OpenJDK.
Remarque
Microsoft fournit des images de conteneur regroupant OpenJDK, notamment des images Ubuntu, Azure Linux et distroless. 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 Quarkus.
Dans l’exemple suivant, la même version de Build Microsoft d’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 la version de Tomcat utilisée pour le déploiement du service, 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é à partir d’une archive Apache spécifique à la version, vérifié avec une somme de contrôle SHA-512 et extrait dans un répertoire spécifié par une variable d’environnement sur une image Ubuntu. La variable TOMCAT_VERSION spécifie la version publiée et l’argument de build TOMCAT_SHA512 spécifie sa somme de contrôle attendue. Mettez à jour les deux valeurs ensemble lors de la sélection d’une version plus récente prise en charge. Docker peut réutiliser la couche d’installation mise en cache tant que ses instructions et entrées sont inchangées. L’installation de Tomcat est copiée dans l’environnement de phase finale pour être utilisée.
À 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 à partir de ces modifications 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 target. Cet artefact est copié vers l’environnement final pour utilisation.
Au cours de l’étape finale, les artefacts de build Tomcat et Java de l’étape 0 et de l’étape 1, respectivement, sont copiés dans une image Build Microsoft d’OpenJDK 17 sur Azure Linux 3.0. 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’être exécutée avec les privilèges root. 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 Docker Desktop local, vous pouvez y accéder via l’URL http://localhost:8080/AirlinesReservationSample.
Dans containerize-and-deploy-Java-app-to-Azure/Project/Airlines, utilisez un éditeur de texte installé pour créer un fichier nommé Dockerfile. Ajoutez le contenu suivant et enregistrez le fichier :
Important
Avant de créer une image que vous allez exposer publiquement, vérifiez la version actuelle de Tomcat 10.1.x prise en charge sur la page de téléchargement Apache Tomcat et passez en revue les avis de sécurité. Mettez à jour TOMCAT_VERSION et TOMCAT_SHA512 ensemble à l’aide des informations de version publiées par Apache. Un artefact restant disponible dans l’archive Apache ne signifie pas que sa version est actuelle ou recommandée.
############################################
# Tomcat Intall stage
############################################
FROM mcr.microsoft.com/openjdk/jdk:17-ubuntu AS tomcat
ENV CATALINA_HOME=/usr/local/tomcat
# Configure the reviewed Tomcat version and checksum
ENV TOMCAT_VERSION=10.1.61
ARG TOMCAT_SHA512=35120a2b1182bac3d55438fbec0dc581d03b0f1c16ce692a930f3bb6a1097cf896b94b389152257071a87cb2928ac8c15f1bad08387c14acc7c17dbc1bb598fb
# Install Tomcat and required packages
RUN apt-get update && \
apt-get install -y --no-install-recommends curl ca-certificates && \
curl -fSL \
"https://archive.apache.org/dist/tomcat/tomcat-10/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz" \
-o /tmp/tomcat.tar.gz && \
echo "${TOMCAT_SHA512} /tmp/tomcat.tar.gz" | sha512sum -c - && \
mkdir -p "${CATALINA_HOME}" && \
tar -xzf /tmp/tomcat.tar.gz --strip-components=1 -C "${CATALINA_HOME}" && \
rm /tmp/tomcat.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-azurelinux
# 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
Utilisez le fichier Dockerfile indiqué dans cette unité pour cet exercice. L’application doit être copiée dans webapps/AirlinesReservationSample.war afin que les URL des unités suivantes utilisent le contexte /AirlinesReservationSample/. Un autre nom de fichier WAR modifie le contexte d’application Tomcat par défaut.
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.61définit la version tomcat épinglée pour cet exemple. Passez en revue les versions prises en charge et mettez-la à jour avecTOMCAT_SHA512, si nécessaire.ARGARG TOMCAT_SHA512fournit la somme de contrôle SHA-512 publiée d’Apache pour l’archive sélectionnée en tant qu’argument de build.RUNInstalle curl -fSLet les certificats d’autorité de certification, puis utilisecurlpour télécharger l’archive Apache spécifique à la version.-ffait échouer en cas d’erreurs HTTP ;-Lsuit les redirections. L’archive est vérifiée avecsha512sum -c -avant l’extraction dansCATALINA_HOMEavec--strip-components=1. La&&chaîne s’arrête en cas d’échec au lieu de masquer les erreurs pendant le nettoyage. Enfin, il supprime l’archive et les packages inutiles et nettoie le cache du package.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 dans le conteneur à/build, 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.Dernière étape du package :
Commande Docker Descriptif FROMFROM mcr.microsoft.com/openjdk/jdk:17-azurelinuxdéfinit l’image de base sur Build Microsoft d’OpenJDK 17 sur Azure Linux 3.0, 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 de Tomcat auPATHsystème, 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 la phasetomcat, 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 webapps de Tomcat, en définissant le propriétaire sur l’utilisateurapp.EXPOSEEXPOSE 8080indique que l’application est censée écouter sur le port TCP 8080. Il ne publie pas de port hôte. L’unité suivante publie le port avec l’option-p 8080:8080surdocker run.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.