Migración de aplicaciones de Tomcat a contenedores en Azure Kubernetes Service (AKS)
En esta guía se describe lo que hay que tener en cuenta para migrar una aplicación de Tomcat existente a un contenedor de Azure Kubernetes Service (AKS).
Antes de la migración
Para asegurarse de que la migración se realiza correctamente, antes de empezar, complete los pasos de evaluación e inventario descritos en las secciones siguientes.
Recursos externos de inventario
Los recursos externos, tales como los orígenes de datos, los agentes de mensajes JMS y otros, se insertan a través de la interfaz de directorio y nomenclatura de Java (JNDI). Algunos de estos recursos pueden requerir una migración o reconfiguración.
Dentro de la aplicación
Inspeccione el archivo META-INF/context.xml. Busque elementos <Resource>
dentro del elemento <Context>
.
En los servidores de aplicaciones
Inspeccione los archivos $CATALINA_BASE/conf/context.xml y $CATALINA_BASE/conf/server.xml, así como los archivos .xml que se encuentran en los directorios $CATALINA_BASE/conf/[nombreDelMotor]/[nombreDelHost].
En los archivos context.xml, los recursos de JNDI se describen con los elementos <Resource>
que están dentro del elemento <Context>
de nivel superior.
En los archivos server.xml, los recursos de JNDI se describen con los elementos <Resource>
que están dentro del elemento <GlobalNamingResources>
.
Orígenes de datos
Los orígenes de datos son recursos de JNDI con el atributo type
con el valor javax.sql.DataSource
. Para cada origen de datos, documente la siguiente información:
- ¿Cuál es el nombre del origen de datos?
- ¿Cuál es la configuración del grupo de conexiones?
- ¿Dónde puedo encontrar el archivo JAR del controlador JDBC?
Para más información, consulte los artículos de procedimientos de los orígenes de datos JNDI en la documentación de Tomcat.
Todos los demás recursos externos
No es factible documentar todas las dependencias externas posibles en esta guía. Es responsabilidad del equipo comprobar que puede cumplir todas las dependencias externas de la aplicación después de la migración.
Secretos de inventario
Contraseñas y cadenas seguras
Compruebe las cadenas secretas y las contraseñas en todas las propiedades y los archivos de configuración de los servidores de producción. Asegúrese de comprobar los archivos server.xml y context.xml en $CATALINA_BASE/conf. También puede encontrar archivos de configuración que contengan contraseñas o credenciales dentro de la aplicación. Estos pueden ser archivos META-INF/context.xml y, para las aplicaciones de Spring Boot, archivos application.properties o application.yml.
Determinación de si se usa el sistema de archivos y cómo
Para usar el sistema de archivos en el servidor de aplicaciones será necesario cambiar la configuración o, en raras ocasiones, la arquitectura. Puede identificar algunos o todos los escenarios siguientes.
Contenido estático de solo lectura
Si su aplicación actualmente sirve contenido estático, necesitará una ubicación alternativa para él. Quizás quiera considerar la posibilidad de mover el contenido estático a Azure Blob Storage y agregar Azure CDN para tener descargas de alta velocidad globalmente. Para más información, consulte Hospedaje de sitios web estáticos en Azure Storage e Inicio rápido: Integración de una cuenta de una instancia de Azure Storage con Azure CDN.
Contenido estático publicado dinámicamente
Si su aplicación permite que haya contenido estático que la aplicación carga o produce, pero que es inmutable una vez creado, puede usar Azure Blob Storage y Azure CDN con una función de Azure para controlar las cargas y la actualización de la red CDN. Hemos proporcionado una implementación de ejemplo para su uso en Cargar y carga previa en CDN de contenido estático con Azure Functions.
Contenido dinámico o interno
En el caso de los archivos que la aplicación lee y escribe con frecuencia (por ejemplo, los archivos de datos temporales) o los archivos estáticos que solo son visibles para la aplicación, puede montar recursos compartidos de Azure Storage como volúmenes persistentes. Para más información, consulte Creación y uso de un volumen con Azure Files en Azure Kubernetes Service (AKS).
Identificación del mecanismo de persistencia de sesión
Para identificar el administrador de persistencia de sesión que se está usando, inspeccione los archivos context.xml de la aplicación y la configuración de Tomcat. Busque el elemento <Manager>
y, a continuación, anote el valor del atributo className
.
Las implementaciones integradas de PersistentManager de Tomcat, como StandardManager o FileStore no están diseñadas para usarse con una plataforma distribuida y escalada como Kubernetes. AKS puede equilibrar la carga entre varios pods y reiniciar de forma transparente cualquier pod en cualquier momento, por lo que no se recomienda conservar el estado mutable en un sistema de archivos.
Si se necesita la persistencia de la sesión, deberá usar una implementación de PersistentManager
alternativa que escribirá en un almacén de datos externo, como VMware Tanzu Session Manager con Redis Cache. Para más información, consulte Uso de Redis como caché de sesión con Tomcat.
Casos especiales
Algunos escenarios de producción pueden requerir otros cambios o imponer limitaciones adicionales. Aunque estos escenarios no son frecuentes, es importante asegurarse de que no son aplicables a la aplicación o que se han resuelto correctamente.
Determinación de si la aplicación se basa en trabajos programados
Los trabajos programados, como las tareas del programador de Quartz o los trabajos de cron, no se pueden usar con implementaciones de Tomcat en contenedor. Si la aplicación se escala horizontalmente, un trabajo programado se podría ejecutar más de una vez por cada período programado. Esta situación puede tener consecuencias no deseadas.
Haga un inventario de todos los trabajos programados, dentro o fuera del servidor de aplicaciones.
Determinación de si la aplicación contiene código específico del sistema operativo
Si la aplicación contiene código adaptado al sistema operativo en el que se ejecuta la aplicación, es necesario refactorizar la aplicación para que no dependa del sistema operativo subyacente. Por ejemplo, los usos de /
o \
en las rutas de acceso del sistema de archivos tendrán que reemplazarse por File.Separator
o Path.get
.
Determinación de si se usa MemoryRealm
MemoryRealm requiere un archivo XML persistente. En Kubernetes, este archivo deberá agregarse a la imagen de contenedor o cargarse en un almacenamiento compartido que esté disponible para los contenedores. El parámetro pathName
tendrá que modificarse según corresponda.
Para determinar si MemoryRealm
se usa actualmente, inspeccione los archivos server.xml y context.xml y busque elementos <Realm>
en los que el atributo className
esté establecido en org.apache.catalina.realm.MemoryRealm
.
Determinación de si se utiliza el seguimiento de sesión SSL
En las implementaciones en contenedor, lo habitual es que las sesiones SSL se descarguen fuera del contenedor de la aplicación, y normalmente lo hace el controlador de entrada. Si su aplicación requiere seguimiento de sesión SSL, asegúrese de que el tráfico SSL pase directamente al contenedor de la aplicación.
Determinación de si se usa AccessLogValve
Si se utiliza AccessLogValve, el parámetro directory
debe establecerse en un recurso compartido de Azure Files montado o en uno de sus subdirectorios.
Pruebas en contexto
Antes de crear imágenes de contenedor, migre la aplicación al JDK y Tomcat que piensa usar en AKS. Pruebe la aplicación exhaustivamente para garantizar su compatibilidad y rendimiento.
Parametrización de la configuración
En la migración previa, es probable que haya identificado secretos y dependencias externas, como orígenes de bits, en los archivos server.xml y context.xml. En cada elemento identificado, reemplace los nombres de usuario, contraseñas, cadenas de conexión o direcciones URL por una variable de entorno.
Nota:
Microsoft recomienda usar el flujo de autenticación más seguro disponible. El flujo de autenticación descrito en este procedimiento, como para bases de datos, memorias caché, mensajería o servicios de inteligencia artificial, requiere un grado de confianza muy alto en la aplicación y conlleva riesgos que no están presentes en otros flujos. Use este flujo solo cuando las opciones más seguras, como las identidades administradas para conexiones sin contraseña o sin claves, no sean viables. En el caso de las operaciones de máquina local, prefiera identidades de usuario para conexiones sin contraseña o sin claves.
Por ejemplo, supongamos que el archivo context.xml contiene el siguiente elemento:
<Resource
name="jdbc/dbconnection"
type="javax.sql.DataSource"
url="jdbc:postgresql://postgresdb.contoso.com/wickedsecret?ssl=true"
driverClassName="org.postgresql.Driver"
username="postgres"
password="{password}"
/>
En este caso, podría cambiarlo como se muestra en el ejemplo siguiente:
<Resource
name="jdbc/dbconnection"
type="javax.sql.DataSource"
url="${postgresdb.connectionString}"
driverClassName="org.postgresql.Driver"
username="${postgresdb.username}"
password="${postgresdb.password}"
/>
Migración
A excepción del primer paso ("Aprovisionamiento del registro de contenedor y AKS"), le recomendamos que siga los pasos que se indican a continuación de forma individual para cada aplicación (archivo WAR) que quiera migrar.
Nota:
Algunas implementaciones de Tomcat pueden tener varias aplicaciones que se ejecutan en un solo servidor de Tomcat. Si este es el caso de su implementación, es muy recomendable ejecutar cada aplicación en un pod independiente. Esto le permite optimizar el uso de recursos para cada aplicación a la vez que minimiza la complejidad y el acoplamiento.
Aprovisionamiento del registro de contenedor y AKS
Cree un registro de contenedor y un clúster de Azure Kubernetes cuya entidad de servicio tenga el rol de lector en el registro. Asegúrese de elegir el modelo de red adecuado para los requisitos de red del clúster.
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
Preparación de los artefactos de implementación
Clone el repositorio de GitHub Tomcat on Containers Quickstart. Contiene un archivo Dockerfile y archivos de configuración de Tomcat con varias optimizaciones recomendadas. En los pasos siguientes, se describen las modificaciones que probablemente deba realizar en estos archivos antes de compilar la imagen de contenedor e implementarla en AKS.
Apertura de los puertos para la agrupación en clústeres, si es necesario
Si tiene previsto usar la agrupación en clústeres de Tomcat en AKS, asegúrese de que los intervalos de puertos necesarios estén expuestos en el archivo Dockerfile. Para especificar la dirección IP del servidor en server.xml, asegúrese de usar un valor de una variable que se inicializa durante el inicio del contenedor en la dirección IP del pod.
Como alternativa, el estado de sesión se puede conservar en una ubicación alternativa para que esté disponible para todas las réplicas.
Para determinar si la aplicación usa la agrupación en clústeres, busque el elemento <Cluster>
dentro de los elementos <Host>
o <Engine>
del archivo server.xml.
Adición de recursos de JNDI
Edite server.xml para agregar los recursos que preparó en los pasos previos a la migración, como los orígenes de datos, tal como aparece en el siguiente ejemplo.
Nota:
Microsoft recomienda usar el flujo de autenticación más seguro disponible. El flujo de autenticación descrito en este procedimiento, como para bases de datos, memorias caché, mensajería o servicios de inteligencia artificial, requiere un grado de confianza muy alto en la aplicación y conlleva riesgos que no están presentes en otros flujos. Use este flujo solo cuando las opciones más seguras, como las identidades administradas para conexiones sin contraseña o sin claves, no sean viables. En el caso de las operaciones de máquina local, prefiera identidades de usuario para conexiones sin contraseña o sin claves.
<!-- 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>
Para más instrucciones sobre orígenes de datos, consulte las siguientes secciones de los artículos de procedimientos de los orígenes de datos JNDI en la documentación de Tomcat:
Compilación e inserción de la imagen
El comando az acr build
es la manera más sencilla de compilar y cargar la imagen en Azure Container Registry (ACR) para que AKS pueda usarla. Este comando no requiere que Docker esté instalado en el equipo. Por ejemplo, si tiene el archivo Dockerfile anterior y el paquete de aplicación petclinic.war en el directorio actual, puede compilar la imagen de contenedor en ACR con un solo paso:
az acr build \
--image "${acrName}.azurecr.io/petclinic:{{.Run.ID}}" \
--registry $acrName \
--build-arg APP_FILE=petclinic.war \
--build-arg=prod.server.xml .
Puede omitir el parámetro --build-arg APP_FILE...
si el archivo WAR se llama ROOT.war. Puede omitir el parámetro --build-arg SERVER_XML...
si el archivo XML del servidor se llama server.xml. Ambos archivos deben estar en el mismo directorio que el archivo Dockerfile.
Como alternativa, puede usar la CLI de Docker para compilar la imagen localmente. Este enfoque puede simplificar las pruebas y perfeccionar la imagen antes de la implementación inicial en ACR. Sin embargo, requiere instalar la CLI de Docker y el demonio de Docker para ejecutarse.
# 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"
Para obtener más información, consulte el módulo Learn para Crear y almacenar imágenes de contenedor en Azure.
Aprovisionamiento de una dirección IP pública
Si la aplicación va a ser accesible desde fuera de las redes internas o virtuales, necesitará una dirección IP estática pública. Esta dirección IP debe aprovisionarse dentro del grupo de recursos del nodo del clúster.
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}."
Implementación en AKS
Cree y aplique los archivos YAML de Kubernetes. Si va a crear un equilibrador de carga externo (ya sea para la aplicación o para un controlador de entrada), asegúrese de proporcionar la dirección IP aprovisionada en la sección anterior como LoadBalancerIP
.
Incluya los parámetros externos como variables de entorno. No incluya secretos (por ejemplo, contraseñas, claves de API y cadenas de conexión de JDBC). Los secretos se describen en la sección Configuración de un volumen flexible de KeyVault.
Configuración de almacenamiento persistente
Si su aplicación requiere almacenamiento no volátil, configure uno o más volúmenes persistentes.
Quizás quiera crear un volumen persistente con Azure Files, montado en el directorio de registros de Tomcat (/tomcat_logs) para conservar los registros de forma centralizada. Para más información, consulte Creación dinámica y uso de un volumen persistente con Azure Files en Azure Kubernetes Service (AKS).
Configuración de un volumen flexible de KeyVault
Cree un almacén de claves de Azure y rellene todos los secretos necesarios. Después, configure un volumen flexible de KeyVault para que esos secretos sean accesibles para los pods.
Tendrá que modificar el script de inicio (startup.sh en el repositorio Tomcat on Containers de GitHub) para importar los certificados en el almacén de claves local del contenedor.
Nota:
Microsoft recomienda usar el flujo de autenticación más seguro disponible. El flujo de autenticación descrito en este procedimiento, como para bases de datos, memorias caché, mensajería o servicios de inteligencia artificial, requiere un grado de confianza muy alto en la aplicación y conlleva riesgos que no están presentes en otros flujos. Use este flujo solo cuando las opciones más seguras, como las identidades administradas para conexiones sin contraseña o sin claves, no sean viables. En el caso de las operaciones de máquina local, prefiera identidades de usuario para conexiones sin contraseña o sin claves.
Migración de los trabajos programados
Para ejecutar trabajos programados en el clúster de AKS, defina los trabajos de cron que sean necesarios.
Después de la migración
Ahora que ha migrado la aplicación a AKS, debe comprobar que funciona como se espera. Una vez hecho esto, tenemos algunas recomendaciones que pueden hacer que su aplicación sea más nativa de la nube.
Considere la posibilidad de agregar un nombre DNS a la dirección IP asignada al controlador de entrada o al equilibrador de carga de la aplicación. Para obtener más información, consulte Uso de TLS con un controlador de entrada en Azure Kubernetes Service (AKS).
Considere la posibilidad de agregar gráficos de HELM para la aplicación. Un gráfico de Helm permite parametrizar la implementación de la aplicación para que un conjunto de clientes más diverso pueda usarla y personalizarla.
Diseñe e implemente una estrategia de DevOps. Para mantener la confiabilidad y, al mismo tiempo, aumentar la velocidad de desarrollo, considere la posibilidad de automatizar las implementaciones y pruebas con Azure Pipelines.
Habilite la supervisión de Azure en el clúster para poder recopilar los registros de contenedor o realizar un seguimiento del uso, entre otras tareas.
Considere la posibilidad de exponer métricas específicas de la aplicación mediante Prometheus. Prometheus es un marco de métricas de código abierto que se ha adoptado ampliamente en la comunidad de Kubernetes. Puede configurar el barrido de métricas de Prometheus en Azure Monitor en lugar de hospedar su propio servidor de Prometheus para habilitar la agregación de métricas de sus aplicaciones y automatizar la respuesta o el escalado en caso de condiciones anómalas.
Diseñe e implemente una estrategia de continuidad empresarial y recuperación ante desastres. En el caso de las aplicaciones críticas, considere la posibilidad de usar una arquitectura de implementación de varias regiones.
Consulte la directiva de compatibilidad de versiones de Kubernetes. Es su responsabilidad mantener actualizado el clúster de AKS para asegurarse de que siempre ejecuta una versión compatible.
Haga que todos los miembros del equipo responsables del desarrollo de aplicaciones y la administración del clúster revisen los procedimientos recomendados de AKS.
Evalúe los elementos del archivo logging.properties. Considere la posibilidad de eliminar o reducir parte de la salida del registro para mejorar el rendimiento.
Considere la posibilidad de supervisar el tamaño de la caché de código y de agregar los parámetros
-XX:InitialCodeCacheSize
y-XX:ReservedCodeCacheSize
a la variableJAVA_OPTS
en Dockerfile para optimizar aún más el rendimiento.