Usa JLink para crear imágenes de Docker más pequeñas para tu aplicación Java con Spring Boot
24 de agosto de 2023
0 minutos de lecturaLos contenedores aportan flexibilidad y agilidad al desarrollo y la implementación de software. Sin embargo, también introducen una nueva superficie de ataque que los actores maliciosos pueden aprovechar. Si un contenedor se ve comprometido, un atacante puede acceder a otros contenedores e incluso al sistema host. Las imágenes más pequeñas, que contienen menos artefactos, son de gran ayuda para reducir la superficie de ataque.
En esta publicación del blog, exploraremos en profundidad cómo usar JLink para optimizar el tamaño de las imágenes de Docker y mejorar la seguridad y el rendimiento de las aplicaciones. Te mostraremos cómo usar JLink e integrarlo con Docker para implementar de forma eficiente tus aplicaciones Spring Boot o Java en general.
Introducción a JLink
Java es uno de los lenguajes de programación más utilizados en todo el mundo para desarrollar aplicaciones empresariales. Sin embargo, los desarrolladores suelen tener dificultades con el tamaño de las imágenes de Docker al implementar aplicaciones Java en contenedores de Docker. Una forma de resolver este problema es usar JLink, una herramienta incorporada en JDK 9.
JLink (Java Linker) es una herramienta de línea de comandos que ensambla y optimiza un conjunto de módulos y sus dependencias en una imagen de runtime personalizada. En esencia, crea un entorno de ejecución de Java mínimo que contiene solo los módulos que necesita tu aplicación.
En el comando anterior, my.module es tu módulo y myRuntime es la imagen de runtime personalizada que creará JLink.
El papel de JLink en la creación de imágenes de Docker más pequeñas
Al crear imágenes de Docker para aplicaciones Java, el tamaño de la imagen suele ser un motivo de preocupación, sobre todo en el caso de las aplicaciones Spring Boot, que incluyen muchas dependencias. Una imagen de Docker grande puede generar tiempos de inicio más prolongados, mayores costos de almacenamiento y procesos de implementación más lentos.
En las versiones anteriores de Java, el kit de desarrollo de Java (JDK) incluía un entorno de ejecución de Java (JRE). Para ejecutar el artefacto Java creado, solo se necesitaba el JRE. Por eso, antes era común usar el JRE en la imagen de Docker o elegir una imagen base con JRE para los contenedores. Las versiones más recientes de Java no siempre incluyen un JRE, aunque algunos proveedores aún podrían crear uno y ofrecer las imágenes base correspondientes. Puedes usar esas imágenes o un runtime de Java más específico, adaptado a tu aplicación.
JLink te permite crear un entorno de ejecución de Java mínimo que incluye solo los módulos necesarios. Así, reduce considerablemente el tamaño de la imagen de Docker. Por ejemplo, un entorno de ejecución estándar de Java puede superar los 200 MB, pero con JLink puedes reducirlo a menos de 50 MB.
Cómo usar JLink para una aplicación Java con Spring Boot
Spring Boot crea un JAR con todas las dependencias de tus aplicaciones. Además, muchas aplicaciones Spring Boot no tienen una declaración de módulos. Esto no tiene por qué ser un problema, pero debemos determinar qué módulos necesita la aplicación y cuáles son todas sus dependencias.
Cómo usar Jdeps para encontrar los módulos
Jdeps es una herramienta de Java que muestra las dependencias a nivel de paquete o de clase. Esta herramienta, incorporada en Java 8, permite conocer las dependencias de una aplicación, que luego se pueden usar para crear una imagen de runtime personalizada con JLink.
Si nos aseguramos de que todas las dependencias estén en un mismo directorio, podemos usar jdeps para generar un resumen de ellas.
Del mismo modo, podemos usar jdeps para mostrar de forma recursiva todas las dependencias de módulos de la aplicación Spring Boot y sus dependencias.
El resultado que genera jdeps permite que JLink cree un entorno de ejecución de Java que contenga únicamente los módulos necesarios para esta aplicación Spring Boot.
Exportar las dependencias de Spring Boot a una carpeta
Como mencionamos, Spring Boot crea un JAR que incluye todas las dependencias. Sin embargo, las dependencias están empaquetadas de una forma particular dentro del JAR y, por lo tanto, jdeps no puede acceder a ellas fácilmente. Hay dos soluciones sencillas para obtener las dependencias con jdeps.
Desempaqueta el archivo fat JAR creado por Spring Boot.
Esta opción funciona muy bien si ya tienes el artefacto de compilación y no quieres o no puedes volver a compilar la aplicación. Las dependencias se desempaquetarán en
/BOOT/libs/.
Usar un complemento en la herramienta de compilación que copie las dependencias a una carpeta específica.
En Maven, por ejemplo, esto se puede lograr con
maven-dependency-plugin. En el siguiente ejemplo, las dependencias se copian a la carpeta/target/dependencycuando Maven termina la fase de empaquetado.
Crear una imagen de Docker con un entorno de ejecución de Java personalizado
Ahora combinemos jdeps y JLink para crear un entorno de ejecución de Java personalizado. Con este runtime, podemos crear una imagen de Docker mínima y perfecta, diseñada específicamente para una aplicación Spring Boot.
En el ejemplo anterior, usé una compilación de Docker en varias etapas. La etapa inicial de compilación se basa en una imagen eclipse-temurin JDK 17 que incluye Maven. Esta etapa se usa para:
Crear el artefacto Java. Con Maven, creo el archivo JAR ejecutable que contiene la aplicación completa.
Desempaquetar el archivo JAR para obtener todas las dependencias. Esto solo es necesario si no usas
maven-dependency-plugin, como se describió antes. Si lo incluiste, puedes omitir este paso.Usar jdeps para obtener los módulos necesarios. Indica el archivo que contiene todos los archivos JAR de las dependencias y el artefacto final, y guarda la lista en
deps.info.Ejecutar JLink para crear un entorno de ejecución de Java personalizado. Usa
deps.infocomo entrada y guarda el resultado en/myjre. Solo agregamos a JLink los módulos necesarios y eliminamos la información de depuración, las páginas del manual y los archivos de encabezado.
La segunda y última etapa crea la imagen de producción basada en una imagen debian:stable-slim.
Configurar las variables de entorno. Asigna a
JAVA_HOMEla ruta donde copiarémyjrey agregaJAVA_HOMEaPATH.Copiar el entorno de ejecución de Java creado por JLink. Haz referencia a la primera etapa y copia el entorno de ejecución de Java personalizado en la ubicación definida como
JAVA_HOME.Copiar el artefacto Java creado. El JAR ejecutable de Spring Boot creado se copia en el directorio dedicado del proyecto.
Configurar el punto de entrada
JLink ofrece varias ventajas para crear imágenes de Docker para aplicaciones Java con Spring Boot:
1. Menor tamaño de imagen: Como mencionamos antes, JLink puede reducir el tamaño de la imagen de Docker, lo que agiliza la implementación y disminuye los costos de almacenamiento.
2. Menores tiempos de inicio: Una imagen de Docker más pequeña permite que la aplicación se inicie más rápido, algo fundamental para las aplicaciones que necesitan escalar rápidamente.
3. Seguridad: Al incluir solo los módulos necesarios, reduces la superficie de ataque de tu aplicación. Menos módulos significan menos posibles vulnerabilidades de seguridad.
En cuanto a la seguridad, es esencial mencionar el papel de Snyk para proteger tus aplicaciones. Snyk es una herramienta de seguridad para desarrolladores que puede analizar tu código fuente, paquetes de código abierto, imágenes de contenedores y configuraciones de la nube para detectar vulnerabilidades. Con Snyk Container y Snyk Open Source, puedes detectar y corregir problemas de seguridad en tu aplicación y sus dependencias, incluidos los que se encuentran en tus imágenes de Docker.
En el comando anterior, your-repo/your-image:tag es tu imagen de Docker. Snyk la analizará e informará las vulnerabilidades detectadas, junto con sugerencias para corregirlas.
Crea imágenes de Docker más pequeñas y seguras para aplicaciones Java
Ten en cuenta que los ejemplos de esta publicación del blog muestran cómo usar JLink para crear una imagen de Docker más compacta para tus proyectos Java. No cumplen con todas las prácticas recomendadas para crear imágenes de Docker seguras. Si quieres obtener más información, consulta nuestro artículo «10 prácticas recomendadas para crear un contenedor Java con Docker».
En conclusión, JLink es una herramienta potente que puede ayudarte a crear imágenes de Docker más pequeñas y seguras para tus aplicaciones Java con Spring Boot. Si la combinas con herramientas de seguridad como Snyk, puedes asegurarte de que tus aplicaciones tengan un buen rendimiento y sean seguras. ¿Qué esperas? Regístrate en Snyk hoy mismo y empieza a proteger tus aplicaciones.
Seguridad de contenedores centrada en los desarrolladores
Snyk encuentra y corrige automáticamente vulnerabilidades en imágenes de contenedores y cargas de trabajo de Kubernetes.
