Migrer des applications Tomcat vers des conteneurs sur Azure Kubernetes Service

Ce guide décrit ce que vous devez savoir quand vous voulez migrer une application Tomcat existante pour pouvoir l’exécuter sur Azure Kubernetes Service (AKS).

Prémigration

Pour garantir la réussite de la migration, avant de commencer, effectuez les étapes d’évaluation et d’inventaire décrites dans les sections suivantes.

Inventorier les ressources externes

Les ressources externes, comme les sources de données, les répartiteurs de messages JMS, etc., sont injectées par le biais de l’interface JNDI (Java Naming and Directory Interface). Certaines de ces ressources peuvent nécessiter une migration ou une reconfiguration.

Au sein de votre application

Examinez le fichier META-INF/context.xml. Recherchez les éléments <Resource> à l’intérieur de l’élément <Context>.

Sur le ou les serveurs d’applications

Examinez les fichiers $CATALINA_BASE/conf/context.xml et $CATALINA_BASE/conf/server.xml, ainsi que les fichiers .xml trouvés dans les répertoires $CATALINA_BASE/conf/[engine-name]/[host-name].

Dans les fichiers context.xml, les ressources JNDI sont décrites par les éléments <Resource> à l’intérieur de l’élément <Context> de niveau supérieur.

Dans les fichiers server.xml, les ressources JNDI sont décrites par les éléments <Resource> à l’intérieur de l’élément <GlobalNamingResources>.

Sources de données

Les sources de données sont des ressources JNDI dont l’attribut type a la valeur javax.sql.DataSource. Pour chaque source de données, réunissez les informations suivantes :

  • Quel est le nom de la source de données ?
  • Quelle est la configuration du pool de connexions ?
  • Où trouver le fichier JAR du pilote JDBC ?

Pour plus d’informations, consultez JNDI Datasource HOW-TO (Guide pratique sur les sources de données JNDI) dans la documentation Tomcat.

Toutes les autres ressources externes

Il n’est pas possible de décrire toutes les dépendances externes possibles dans ce guide. Il incombe à votre équipe de vérifier que vous pouvez satisfaire à toutes les dépendances externes de votre application après la migration.

Inventorier les secrets

Mots de passe et chaînes sécurisées

Recherchez dans l’ensemble des propriétés et fichiers de configuration présents sur les serveurs de production d’éventuels chaînes secrètes et mots de passe. Pensez à vérifier server.xml et context.xml dans $CATALINA_BASE/conf. Vous pouvez également trouver des fichiers de configuration contenant des mots de passe ou des informations d’identification à l’intérieur de votre application. Il peut s’agir du fichier META-INF/context.xml et, pour les applications Spring Boot, des fichiers application.properties ou application.yml.

Déterminer si le système de fichiers est utilisé et de quelle manière

Toute utilisation du système de fichiers sur le serveur d’applications nécessite une reconfiguration ou, dans de rares cas, des modifications architecturales. Vous pouvez identifier une partie ou l’ensemble des scénarios suivants.

Contenu statique en lecture seule

Si votre application sert actuellement du contenu statique, vous aurez besoin d’un autre emplacement pour lui. Vous pouvez envisager de déplacer du contenu statique vers le Stockage Blob Azure et d’ajouter Azure CDN pour accélérer globalement les téléchargements. Pour plus d’informations, consultez Hébergement de sites web statiques dans le service Stockage Azure et Démarrage rapide : Intégrer un compte de stockage Azure à Azure CDN. Vous pouvez également déployer directement le contenu statique sur une application dans le plan Azure Spring Apps Enterprise. Pour plus d’informations, consultez Déployer des fichiers statiques web.

Contenu statique publié dynamiquement

Si votre application autorise le contenu statique chargé/produit par votre application mais immuable après sa création, vous pouvez utiliser le Stockage Blob Azure et Azure CDN comme décrit ci-dessus, avec une fonction Azure pour gérer les chargements et l’actualisation du réseau CDN. Nous avons mis à votre disposition un exemple d’implémentation dans Chargement et préchargement CDN de contenu statique avec Azure Functions. Vous pouvez également déployer directement le contenu statique sur une application dans le plan Azure Spring Apps Enterprise. Pour plus d’informations, consultez Déployer des fichiers statiques web.

Contenu dynamique ou interne

Pour les fichiers fréquemment écrits et lus par votre application (comme les fichiers de données temporaires) ou les fichiers statiques uniquement visibles pour votre application, vous pouvez monter des partages de stockage Azure en tant que volumes persistants. Pour plus d’informations, consultez Créer et utiliser un volume persistant de manière dynamique avec Azure Files dans Azure Kubernetes Service.

Identifier le mécanisme de persistance de session

Pour identifier le gestionnaire de persistance de session en cours d’utilisation, examinez les fichiers context.xml dans votre application et votre configuration Tomcat. Recherchez l’élément <Manager>, puis notez la valeur de l’attribut className.

Les implémentations PersistentManager intégrées de Tomcat, comme StandardManager ou FileStore ne sont pas conçues pour être utilisées avec une plateforme adaptée distribuée comme Kubernetes. Étant donné qu’AKS peut équilibrer la charge entre plusieurs pods et redémarrer de manière transparente tout pod à tout moment, rendre persistant l’état mutable dans un système de fichiers n’est pas recommandé.

Si la persistance de session est nécessaire, vous devez utiliser une autre implémentation PersistentManager qui écrit dans un magasin de données externe, comme VMware Tanzu Session Manager avec le cache Redis. Pour plus d’informations, consultez Utiliser Redis comme cache de session avec Tomcat.

Cas particuliers

Certains scénarios de production peuvent nécessiter d’autres changements ou imposer d’autres limites. Même si de tels scénarios peuvent être rares, il est important de s’assurer qu’ils ne sont pas applicables à votre application ou qu’ils sont correctement résolus.

Déterminer si l’application s’appuie sur des tâches planifiées

Les tâches planifiées, comme les tâches Quartz Scheduler ou les travaux Cron, ne peuvent pas être utilisées avec des déploiements Tomcat conteneurisés. Si votre application a fait l’objet d’un scale-out, une seule tâche planifiée peut s’exécuter plusieurs fois par période planifiée. Cette situation peut entraîner des conséquences inattendues.

Inventoriez toutes les tâches planifiées à l’intérieur ou à l’extérieur du serveur d’applications.

Déterminer si votre application contient du code propre au système d’exploitation

Si votre application contient du code adapté au système d’exploitation sur lequel elle s’exécute, alors elle doit être refactorisée pour ne PAS reposer sur le système d’exploitation sous-jacent. Par exemple, toutes les utilisations de / ou \ dans les chemins de système de fichiers peuvent avoir besoin d’être remplacées par File.Separator ou Path.get.

Déterminer si MemoryRealm est utilisé

MemoryRealm nécessite un fichier XML persistant. Sur Kubernetes, ce fichier doit être ajouté à l’image conteneur ou chargé sur le stockage partagé mis à la disposition des conteneurs. Le paramètre pathName doit être modifié en conséquence.

Pour déterminer si MemoryRealm est actuellement utilisé, examinez vos fichiers server.xml et context.xml et recherchez les éléments <Realm> dont l’attribut className a la valeur org.apache.catalina.realm.MemoryRealm.

Déterminer si le suivi de session SSL est utilisé

Dans les déploiements conteneurisés, les sessions SSL sont généralement déplacées en dehors du conteneur d’application, généralement par le contrôleur d’entrée. Si votre application nécessite un suivi de session SSL, vérifiez que le trafic SSL est transmis directement au conteneur d’application.

Déterminer si AccessLogValve est utilisé

Si AccessLogValve est utilisé, le paramètre directory doit être défini sur un partage Azure Files monté ou l’un de ses sous-répertoires.

Test sur place

Avant de créer des images conteneur, migrez votre application vers les kits JDK et Tomcat que vous envisagez d’utiliser sur AKS. Testez votre application minutieusement pour garantir sa compatibilité et ses performances.

Paramétrer la configuration

Lors de la prémigration, vous aurez probablement identifié des secrets et des dépendances externes, comme des sources de données, dans les fichiers server.xml et context.xml. Pour chaque élément ainsi identifié, remplacez le nom d’utilisateur, le mot de passe, la chaîne de connexion ou l’URL par une variable d’environnement.

Par exemple, supposons que le fichier context.xml contienne l’élément suivant :

<Resource
    name="jdbc/dbconnection"
    type="javax.sql.DataSource"
    url="jdbc:postgresql://postgresdb.contoso.com/wickedsecret?ssl=true"
    driverClassName="org.postgresql.Driver"
    username="postgres"
    password="t00secure2gue$$"
/>

Dans ce cas, vous pouvez le changer comme indiqué dans l’exemple suivant :

<Resource
    name="jdbc/dbconnection"
    type="javax.sql.DataSource"
    url="${postgresdb.connectionString}"
    driverClassName="org.postgresql.Driver"
    username="${postgresdb.username}"
    password="${postgresdb.password}"
/>

Migration

À l’exception de la première étape (« Provisionner un registre de conteneurs et AKS »), nous vous recommandons de suivre les étapes ci-dessous individuellement pour chaque application (fichier WAR) à migrer.

Remarque

Certains déploiements Tomcat peuvent avoir plusieurs applications en cours d’exécution sur un même serveur Tomcat. Si c’est le cas dans votre déploiement, nous vous recommandons vivement d’exécuter chaque application dans un pod distinct. Ainsi, vous optimisez l’utilisation des ressources pour chaque application tout en minimisant la complexité et le couplage.

Provisionner le registre de conteneurs et AKS

Créez un registre de conteneurs et un cluster Azure Kubernetes dont le principal du service a le rôle de lecteur sur le registre. Veillez à choisir le modèle réseau adapté aux exigences de mise en réseau de votre cluster.

az group create \
    --resource-group $resourceGroup \
    --location eastus
az acr create \
    --resource-group $resourceGroup \
    --name $acrName \
    --sku Standard
az aks create \
    --resource-group $resourceGroup \
    --name $aksName \
    --attach-acr $acrName \
    --network-plugin azure

Préparer les artefacts de déploiement

Clonez le dépôt GitHub Tomcat On Containers Quickstart. Celui-ci contient un Dockerfile et des fichiers de configuration Tomcat avec plusieurs optimisations recommandées. Dans les étapes ci-dessous, nous décrivons les modifications que vous devrez probablement apporter à ces fichiers avant de créer l’image conteneur et de la déployer sur AKS.

Ouvrir des ports pour le clustering, si nécessaire

Si vous envisagez d’utiliser un clustering Tomcat sur AKS, vérifiez que les plages de ports nécessaires sont exposées dans le Dockerfile. Pour spécifier l’adresse IP du serveur dans server.xml, veillez à utiliser une valeur d’une variable initialisée au démarrage du conteneur sur l’adresse IP du pod.

L’état de session peut également être rendu persistant à un autre emplacement afin d’être disponible dans tous les réplicas.

Pour déterminer si votre application utilise un clustering, recherchez l’élément <Cluster> à l’intérieur des éléments <Host> ou <Engine> dans le fichier server.xml.

Ajouter des ressources JNDI

Modifiez server.xml pour ajouter les ressources que vous avez préparées lors des étapes de prémigration, notamment les sources de données.

Par exemple :

<!-- Global JNDI resources
      Documentation at /docs/jndi-resources-howto.html
-->
<GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    -->
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml"
               />

    <!-- Migrated datasources here: -->
    <Resource
        name="jdbc/dbconnection"
        type="javax.sql.DataSource"
        url="${postgresdb.connectionString}"
        driverClassName="org.postgresql.Driver"
        username="${postgresdb.username}"
        password="${postgresdb.password}"
    />
    <!-- End of migrated datasources -->
</GlobalNamingResources>

Pour obtenir des instructions supplémentaires sur les sources de données, consultez les sections suivantes de la page JNDI Datasource How-To (Guide pratique sur les sources de données JNDI) dans la documentation Tomcat :

Générer et envoyer (push) l’image

La façon la plus simple de générer et charger l’image sur Azure Container Registry (ACR) afin qu’elle soit utilisée par AKS consiste à utiliser la commande az acr build. Cette commande ne nécessite pas l’installation de Docker sur votre ordinateur. Par exemple, si vous avez le Dockerfile ci-dessus et le package d’application petclinic.war dans le répertoire actif, vous pouvez générer l’image conteneur dans ACR en une seule étape :

az acr build \
    --image "${acrName}.azurecr.io/petclinic:{{.Run.ID}}" \
    --registry $acrName \
    --build-arg APP_FILE=petclinic.war \
    --build-arg=prod.server.xml .

Vous pouvez omettre le paramètre --build-arg APP_FILE... si votre fichier WAR est nommé ROOT.war. Vous pouvez omettre le paramètre --build-arg SERVER_XML... si le fichier XML de votre serveur se nomme server.xml. Les deux fichiers doivent se trouver dans le même répertoire que le Dockerfile.

Vous pouvez également utiliser l’interface CLI de Docker pour générer l’image localement. Cette approche peut simplifier le test et l’affinage de l’image avant son déploiement initial sur ACR. Toutefois, elle nécessite que l’interface CLI de Docker soit installée et le démon de Docker en cours d’exécution.

# Build the image locally
sudo docker build . --build-arg APP_FILE=petclinic.war -t "${acrName}.azurecr.io/petclinic:1"

# Run the image locally
sudo docker run -d -p 8080:8080 "${acrName}.azurecr.io/petclinic:1"

# Your application can now be accessed with a browser at http://localhost:8080.

# Log into ACR
sudo az acr login --name $acrName

# Push the image to ACR
sudo docker push "${acrName}.azurecr.io/petclinic:1"

Pour plus d’informations, consultez le module Learn pour la création et le stockage d’images conteneur dans Azure.

Provisionner une adresse IP publique

Si votre application doit être accessible à l’extérieur de vos réseaux internes ou virtuels, une adresse IP statique publique est nécessaire. Cette adresse IP doit être provisionnée dans le groupe de ressources du nœud du cluster.

export nodeResourceGroup=$(az aks show \
    --resource-group $resourceGroup \
    --name $aksName \
    --query 'nodeResourceGroup' \
    --output tsv)
export publicIp=$(az network public-ip create \
    --resource-group $nodeResourceGroup \
    --name applicationIp \
    --sku Standard \
    --allocation-method Static \
    --query 'publicIp.ipAddress' \
    --output tsv)
echo "Your public IP address is ${publicIp}."

Déployer sur AKS

Créez et appliquez vos fichiers YAML Kubernetes. Si vous créez un équilibreur de charge externe (que ce soit pour votre application ou un contrôleur d’entrée), veillez à fournir l’adresse IP provisionnée dans la section précédente en tant que LoadBalancerIP.

Incluez des paramètres externalisés en tant que variables d’environnement. N’incluez pas de secrets (comme des mots de passe, des clés API et des chaînes de connexion JDBC). Les secrets sont traités dans la section Configurer un FlexVolume de coffre de clés.

Configurer un stockage persistant

Si votre application nécessite un stockage non volatile, configurez un ou plusieurs volumes persistants.

Vous voudrez probablement créer un volume persistant à l’aide d’Azure Files monté dans le répertoire des journaux Tomcat (/tomcat_logs) pour conserver les journaux de manière centralisée. Pour plus d’informations, consultez Créer et utiliser un volume persistant de manière dynamique avec Azure Files dans Azure Kubernetes Service (AKS).

Configurer un FlexVolume de coffre de clés

Créez un coffre de clés Azure et renseignez tous les secrets nécessaires. Ensuite, configurez un FlexVolume de coffre de clés pour rendre ces secrets accessibles aux pods.

Pour importer les certificats dans le magasin de clés local sur le conteneur, vous devez modifier le script de démarrage (startup.sh dans le dépôt GitHub Tomcat sur des conteneurs).

Migrer des tâches planifiées

Pour exécuter des tâches planifiées sur votre cluster AKS, définissez des travaux Cron selon vos besoins.

Post-migration

Maintenant que vous avez migré votre application vers AKS, vous devez vérifier qu’elle fonctionne comme prévu. Une fois que vous avez terminé, nous vous fournissons des recommandations pour rendre votre application plus native dans le cloud.

  • Envisagez d’ajouter un nom DNS à l’adresse IP allouée à votre contrôleur d’entrée ou à votre équilibreur de charge d’application. Pour plus d’informations, consultez Créer un contrôleur d’entrée avec une adresse IP publique statique dans AKS.

  • Envisagez d’ajouter des graphiques HELM pour votre application. Un graphique Helm vous permet de paramétrer le déploiement de votre application pour qu’un ensemble de clients plus diversifié puisse l’utiliser et la personnaliser.

  • Concevez et implémentez une stratégie DevOps. Pour maintenir la fiabilité tout en accélérant le développement, envisagez d’automatiser les déploiements et les tests avec Azure Pipelines.

  • Activez la supervision Azure pour le cluster pour permettre la collecte des journaux de conteneurs, le suivi de l’utilisation, etc.

  • Envisagez d’exposer des métriques propres à l’application par le biais de Prometheus. Prometheus est un framework de métriques open source largement adopté par la communauté Kubernetes. Vous pouvez configurer la capture de métriques Prometheus dans Azure Monitor au lieu d’héberger votre propre serveur Prometheus pour permettre l’agrégation des métriques à partir de vos applications, ainsi que la réponse automatisée ou l’escalade des conditions anormales.

  • Concevez et implémentez une stratégie de continuité de l’activité et de reprise d’activité. Pour les applications stratégiques, envisagez une architecture de déploiement multirégion.

  • Examinez la stratégie de prise en charge des versions de Kubernetes. Il vous incombe de continuellement mettre à jour votre cluster AKS pour veiller à ce qu’il exécute toujours une version prise en charge.

  • Demandez à tous les membres d’équipe responsables de l’administration des clusters et du développement des applications d’examiner les bonnes pratiques AKS pertinentes.

  • Évaluez les éléments inclus dans le fichier logging.properties. Envisagez d’éliminer ou de réduire une partie de la sortie de journalisation pour améliorer les performances.

  • Envisagez de superviser la taille du cache de code et d’ajouter les paramètres -XX:InitialCodeCacheSize et -XX:ReservedCodeCacheSize à la variable JAVA_OPTS dans le Dockerfile pour optimiser davantage les performances.