Contenedorización de una aplicación Java
En esta unidad, va a contenedorizar una aplicación Java.
Como se mencionó anteriormente, los contenedores se ejecutan directamente en el sistema operativo host, el kernel y el hardware, básicamente como cualquier otro proceso. Los contenedores requieren menos recursos del sistema, lo que conlleva una reducción de la superficie y la sobrecarga, además de menos tiempo para iniciar las aplicaciones. Estos son excelentes casos de uso para el escalado a petición.
Hay contenedores Windows y contenedores Linux. En este módulo, aprovechará el entorno de ejecución de Docker utilizado de forma generalizada para compilar una imagen de contenedor de Linux. A continuación, implementará la imagen de contenedor de Linux en el sistema operativo host de la máquina local. Por último, implementará la imagen de contenedor de Linux en Azure Kubernetes Service.
Información general de Docker
El entorno de ejecución de Docker se usa para compilar, extraer, ejecutar e insertar imágenes de contenedor. En la imagen siguiente se muestran estos casos de uso seguidos de una descripción de cada caso de uso o comando de Docker.
Comando de Docker | Descripción |
---|---|
docker build |
Compile una imagen de contenedor, básicamente las instrucciones o capas necesarias para que Docker cree en última instancia un contenedor en ejecución a partir de una imagen. El resultado de este comando es una imagen. |
docker pull |
Los contenedores se inicializan a partir de imágenes, que se extraen de registros, como Azure Container Registry, y de aquí es donde Azure Kubernetes Service realizará las extracciones. El resultado de este comando es una extracción de red de una imagen que se creará en Azure. Tenga en cuenta que, opcionalmente, puede extraer imágenes localmente, lo que es habitual al compilar imágenes que requieren dependencias o capas que la aplicación puede necesitar, como un servidor de aplicaciones. |
docker run |
Una instancia en ejecución de una imagen es un contenedor y este comando ejecuta todas las capas necesarias para ejecutar e interactuar con la aplicación contenedora en ejecución. El resultado de este comando es un proceso de ejecución de la aplicación en el sistema operativo host. |
docker push |
Azure Container Registry almacenará las imágenes para que estén disponibles fácilmente y se cierren en la red para las implementaciones y la escala de Azure. |
Clonación de la aplicación Java
En primer lugar, clonará el repositorio de Flight Booking System for Airline Reservations y cambiará el directorio a la carpeta del proyecto de aplicación web para compañías aéreas.
Nota
Si la creación de Azure Kubernetes Service se ha completado correctamente en la pestaña de la CLI, úsese esa pestaña; de lo contrario, si todavía se está ejecutando, abra una nueva pestaña y cambie el directorio a la ubicación donde prefiera clonar Flight Booking System for Airline Reservations.
Ejecute el comando siguiente en la CLI:
git clone https://github.com/Azure-Samples/containerize-and-deploy-Java-app-to-Azure.git
Ejecute el comando siguiente en la CLI:
cd containerize-and-deploy-Java-app-to-Azure/Project/Airlines
Nota:
Opcionalmente, si tiene Java y Maven instalados, puede ejecutar los siguientes comandos en la CLI para hacerse una idea de la experiencia de compilación de la aplicación sin Docker. Si no tiene instalado Java y Maven, puede ir directamente a la sección siguiente, Construir un archivo Docker. En esa sección, usará Docker para extraer Java y Maven para ejecutar las compilaciones en su nombre.
Opcionalmente, si tiene Maven y JDK(8) o posterior instalados, puede ejecutar el siguiente comando en la CLI:
mvn clean install
Nota:
Hemos usado el comando mvn clean install
para ilustrar los desafíos operativos derivados de no usar compilaciones de varias fases de Docker, que se tratarán a continuación. De nuevo, este paso es opcional, por lo que puede avanzar sin tener que ejecutar el comando de Maven.
Maven debe haber creado correctamente el artefacto del archivo FlightBookingSystemSample-0.0.-SNAPSHOT.war de la aplicación web Flight Booking System for Airline Reservations, como en la salida siguiente:
[INFO] Building war: /mnt/c/Users/chtrembl/dev/git/containerize-and-deploy-Java-app-to-Azure/Project/FlightBookingSystemSample/target/FlightBookingSystemSample-0.0.1-SNAPSHOT.war
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 17.698 s
[INFO] Finished at: 2021-09-28T15:18:07-04:00
[INFO] ------------------------------------------------------------------------
Imagine que es un desarrollador de Java y acaba de crear este FlightBookingSystemSample-0.0.1-SNAPSHOT.war
. Su siguiente paso probablemente sea trabajar con los ingenieros de operaciones para implementar este artefacto en un servidor local o en una máquina virtual. Para que la aplicación se inicie y se ejecute correctamente, es necesario que los servidores y las máquinas virtuales estén disponibles y configurados con las dependencias necesarias. Esto es complicado y requiere mucho tiempo, especialmente a petición cuando el aumento de la carga está afectando a la aplicación. Con los contenedores, estos desafíos se mitigan.
Construir un Dockerfile
En este momento, está listo para construir un archivo de Docker. Un Dockerfile es un documento de texto que contiene todos los comandos que un usuario podría ejecutar en la línea de comandos para ensamblar una imagen de contenedor, y cada uno consta de capas (que se pueden almacenar en caché para mejorar la eficacia) que se compilan unas sobre otras.
Por ejemplo, Flight Booking System for Airline Reservations debe implementarse y ejecutarse dentro de un servidor de aplicaciones. Un servidor de aplicaciones no se empaqueta dentro de FlightBookingSystemSample-0.0.1-SNAPSHOT.war
; se trata de una dependencia externa necesaria para que FlightBookingSystemSample-0.0.1-SNAPSHOT.war
ejecute, escuche y procese solicitudes HTTP, administre sesiones de usuario y facilite las reservas de vuelos. Si se tratase de una implementación tradicional no contenedorizada, los ingenieros de operaciones instalarían y configurarían un servidor de aplicaciones en algún servidor físico o máquina virtual, antes de implementar FlightBookingSystemSample-0.0.1-SNAPSHOT.war
en él. Estos ingenieros de operaciones también tendrían que asegurarse de que el JDK usado en la máquina (lo que mvn clean install
usaba para compilar el archivo war) se corresponde, de hecho, con el mismo JRE utilizado por el servidor de aplicaciones. La administración de estas dependencias es complicada y requiere mucho tiempo.
Con un Dockerfile, puede escribir las instrucciones (capas) necesarias para realizar esto automáticamente. Para ello, siga los pasos necesarios para asegurarse de que Flight Booking System for Airline Reservations tiene todas las dependencias necesarias para realizar implementaciones en el entorno de ejecución del contenedor de Docker. Esto resulta muy atractivo si empieza a pensar en la escala a petición a intervalos no planeados. Merece la pena tener en cuenta que cada capa aprovecha la memoria caché de Docker, que contiene el estado de la imagen de contenedor en cada hito informativo, lo que optimiza el tiempo de proceso y la reutilización. Si una capa no cambia, se usan capas almacenadas en caché. Los casos de uso comunes de las capas almacenadas en caché son elementos como el entorno de ejecución de Java, el servidor de aplicaciones u otras dependencias de la aplicación web Flight Booking System for Airline Reservations. Cuando cambia una versión en una capa previamente almacenada en caché, se crea una nueva entrada en caché.
En la imagen siguiente se muestran las capas de una imagen de contenedor. Observará que toda la capa superior es la capa de la aplicación web Flight Booking System for Airline Reservations de lectura y escritura que se basa en las capas de solo lectura anteriores, y todas ellas son el resultado de los comandos del Dockerfile.
Docker también tiene el concepto de compilaciones de varias fases, una característica que permite crear una imagen de contenedor más pequeña con un mejor almacenamiento en caché y una superficie de seguridad más pequeña, lo que permite una mayor optimización y mantenimiento del Dockerfile a lo largo del tiempo; Por ejemplo, las instrucciones que puede usar para realizar una compilación de la aplicación (FlightBookingSystemSample-0.0.1-SNAPSHOT.war
) y una compilación de la propia imagen de contenedor, dejando los restos de la compilación FlightBookingSystemSample-0.0.1-SNAPSHOT.war
detrás, lo que da lugar a una superficie más pequeña. A largo plazo, sale a cuenta cuando empezamos a pensar en estas imágenes viajando por toda la red. Con las compilaciones de varias fases, se usan varias instrucciones FROM en el archivo Dockerfile. Cada instrucción FROM puede usar una base diferente y cada una de estas instrucciones comienza desde cero, quitando los archivos innecesarios de la capa de almacenamiento en caché que normalmente se pueden almacenar en caché.
Es indispensable asegurarse de que la aplicación está creada por el mismo JDK correspondiente al mismo JRE que se aislará en la imagen de contenedor en tiempo de ejecución. En el ejemplo siguiente, verá una fase de compilación que aprovecha una versión específica de Maven y una versión específica del JDK para compilar FlightBookingSystemSample-0.0.1-SNAPSHOT.war
. Esta fase garantiza que cualquier entorno de ejecución de Docker que ejecute esta fase obtenga el código de bytes generado esperado que el autor del Dockerfile haya especificado (de lo contrario, los ingenieros de operaciones tendrían que hacer una referencia cruzada de su entorno de ejecución de Java y del servidor de aplicaciones con el de los desarrolladores). A continuación, la fase de empaquetado usará una versión específica de Tomcat y del JRE correspondiente al JDK en la fase de compilación. De nuevo, esto se hace para asegurarse de que todas las dependencias, como el Kit de desarrollo de Java (JDK), Java Runtime Environment (JRE) y el servidor de aplicaciones, están controladas y aisladas para garantizar el comportamiento esperado en todas las máquinas en las que se ejecutará esta imagen.
También merece la pena tener en cuenta que, con esta compilación de varias fases, técnicamente no es necesario instalar Maven y Java en el sistema. Docker los extraerá para usarlos tanto con la compilación de la aplicación como con el entorno de ejecución de la aplicación, evitando cualquier posible conflicto de control de versiones y un comportamiento inesperado, a menos que, por supuesto, compile código y artefactos fuera de Docker.
En la imagen siguiente se muestra la compilación de varias fases y lo que ocurre en cada fase en función de los comandos especificados en el Dockerfile. En la fase 0, la fase de compilación, se compila la aplicación web Booking System for Airline Reservations y se genera FlightBookingSystemSample-0.0.1-SNAPSHOT.war
. Esta fase permite la coherencia de las versiones de Maven y Java que se usan para compilar esta aplicación. Una vez creado FlightBookingSystemSample-0.0.1-SNAPSHOT.war
, esa es la única capa necesaria para la fase 1 (fase en tiempo de ejecución); se pueden descartar todas las capas anteriores. Después, Docker usará esta capa de FlightBookingSystemSample-0.0.1-SNAPSHOT.war
de la fase 0 para construir las capas restantes necesarias para el entorno de ejecución, en este caso, configurando el servidor de aplicaciones e iniciando la aplicación.
En la raíz del proyecto, containerize-and-deploy-Java-app-to-Azure/Project/Airlines, cree un archivo denominado Dockerfile:
vi Dockerfile
Añada el siguiente contenido a Dockerfile, después guarde y salga pulsando ESC, después teclee :wq! y pulse Intro:
#
# Build stage
#
FROM maven:3.6.0-jdk-11-slim AS build
WORKDIR /build
COPY pom.xml .
COPY src ./src
COPY web ./web
RUN mvn clean package
#
# Package stage
#
FROM tomcat:8.5.72-jre11-openjdk-slim
COPY tomcat-users.xml /usr/local/tomcat/conf
COPY --from=build /build/target/*.war /usr/local/tomcat/webapps/FlightBookingSystemSample.war
EXPOSE 8080
CMD ["catalina.sh", "run"]
Nota:
Opcionalmente, Dockerfile_Solution en la raíz del proyecto tiene el contenido necesario.
Esta fase de compilación de Dockerfile tiene seis instrucciones:
Comando de Docker | Descripción |
---|---|
FROM |
FROM maven será la capa base a partir de la que se compila FlightBookingSystemSample-0.0.1-SNAPSHOT.war , una versión específica de Maven y una versión específica del JDK para asegurarse de que se produce la misma compilación de código de bytes en todas las máquinas que ejecutan esta compilación. |
WORKDIR |
WORKDIR se usa para definir el directorio de trabajo de un contenedor en un momento dado, en este caso, donde residirán los artefactos compilados. |
COPY |
COPY agrega archivos desde el directorio actual del cliente de Docker. Configuración de los archivos necesarios para que Maven realice la compilación; el contexto de Docker necesitará pom.xml. |
COPY |
Configura los archivos necesarios para que Maven se compile. El contexto de Docker necesitará la carpeta src que contiene la aplicación web Flight Booking System for Airline Reservations. |
COPY |
Configura los archivos necesarios para que Maven se compile. El contexto del Docket web necesitará la carpeta que contiene las dependencias de la aplicación web Flight Booking System for Airline Reservations. |
EJECUTAR | La instrucción RUN mvn clean package se usa para ejecutar cualquier comando encima de la imagen actual. En este caso, RUN se usa para ejecutar la compilación de Maven, que compilará FlightBookingSystemSample-0.0.1-SNAPSHOT.war . |
Esta fase del paquete de archivos de Docker tiene cinco instrucciones:
Comando de Docker | Descripción |
---|---|
FROM |
FROM tomcat será la capa base en la que se compilará esta imagen de contenedor. La imagen de contenedor de Flight Booking System for Airline Reservations será una imagen creada sobre la imagen de Tomcat. El entorno de ejecución de Docker intentará localizar la imagen de Tomcat localmente. Si no tiene esta versión, bajará una del registro. Si inspeccionó la imagen de tomcat a la que se hace referencia aquí, encontraría que se compila con muchas otras capas, lo que hace que sea reutilizable como una imagen de contenedor del servidor de aplicaciones empaquetada para que el mundo la use al implementar su aplicación Java. Hemos seleccionado y probado tomcat:8.5.72-jre11-openjdk-slim a los efectos del módulo. Tenga en cuenta que todas las capas anteriores de la primera fase de compilación desaparecen una vez que Docker reconoce esta segunda instrucción FROM. |
COPY |
COPY tomcat-users.xml copiará el archivo tomcat-users.xml que administra los usuarios de Flight Booking System for Airline Reservations (administrados dentro del control de código fuente mediante la identidad de Tomcat; normalmente sería en un sistema de administración de identidades externo) en la imagen de contenedor de Tomcat para que esté presente en la imagen de contenedor cada vez que se cree una imagen de contenedor. |
ADD |
ADD target/*.war /usr/local/tomcat/webapps/FlightBookingSystemSample.war copiará FlightBookingSystemSample-0.0.1-SNAPSHOT.war compilado de Maven en la carpeta de aplicaciones web de imágenes de Tomcat para asegurarse de que cuando se inicialice Tomcat, de hecho encontrará FlightBookingSystemSample-0.0.1-SNAPSHOT.war para instalarlo en el servidor de aplicaciones. |
EXPOSE |
EXPOSE 8080 es necesario porque Tomcat está configurado para escuchar el tráfico en el puerto 8080. Esto garantiza que el proceso de Docker escuchará en este puerto. |
CMD |
La instrucción CMD establece un comando que se ejecutará al ejecutar el contenedor. En este caso, CMD ["catalina.sh", "run"] indica a Docker que inicialice el servidor de aplicaciones de Tomcat. |
Nota:
Sin una etiqueta de versión en la línea FROM tomcat
, se aplicará la versión más reciente. Por lo general, querrá sacar provecho de una etiqueta de versión (recuerde que se aplica el almacenamiento en caché, por lo que si las capas cambian constantemente, incurrirá en ancho de banda, latencia, tiempo de proceso o efecto secundario de las compilaciones o capas sin probar). Para este módulo, se han preseleccionado etiquetas específicas de Maven, Tomcat y Java JRE/JDK que se han probado para comprobar el funcionamiento con FlightBookingSystemSample-0.0.1-SNAPSHOT.war
en tiempo de ejecución.
Para obtener más información sobre la construcción de Dockerfile, consulte Referencia de Dockerfile.